payload-live-preview 2.0.1 → 2.0.2
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/README.md +36 -31
- package/dist/adapters/astro/RichText.astro +1 -1
- package/dist/adapters/astro/index.js +1 -1
- package/dist/adapters/astro/index.js.map +1 -1
- package/dist/adapters/astro/middleware-entry.js +1 -1
- package/dist/adapters/astro/middleware-entry.js.map +1 -1
- package/dist/adapters/nextjs/index.js +1 -1
- package/dist/adapters/nextjs/index.js.map +1 -1
- package/dist/adapters/nuxt/index.js +1 -1
- package/dist/adapters/nuxt/index.js.map +1 -1
- package/dist/adapters/nuxt/module.d.ts +12 -4
- package/dist/adapters/nuxt/module.js.map +1 -1
- package/dist/adapters/react/index.d.ts +6 -5
- package/dist/adapters/react/index.js.map +1 -1
- package/dist/adapters/sveltekit/index.js +1 -1
- package/dist/adapters/sveltekit/index.js.map +1 -1
- package/dist/adapters/vue/index.d.ts +3 -3
- package/dist/adapters/vue/index.js.map +1 -1
- package/dist/annotate.js +1 -1
- package/dist/annotate.js.map +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/codegen-astro.d.ts +4 -1
- package/dist/codegen-astro.js.map +1 -1
- package/dist/codegen-cli.js +1 -1
- package/dist/codegen-cli.js.map +1 -1
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.cjs.map +1 -1
- package/dist/codegen.js +1 -1
- package/dist/codegen.js.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/doctor-cli.d.ts +1 -1
- package/dist/doctor-cli.js +1 -1
- package/dist/doctor-cli.js.map +1 -1
- package/dist/doctor.d.ts +2 -2
- package/dist/doctor.js +1 -1
- package/dist/doctor.js.map +1 -1
- package/dist/fragment.cjs.map +1 -1
- package/dist/fragment.d.cts +6 -3
- package/dist/fragment.d.ts +6 -3
- package/dist/fragment.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lean.cjs +1 -1
- package/dist/lean.cjs.map +1 -1
- package/dist/lean.d.cts +3 -3
- package/dist/lean.d.ts +3 -3
- package/dist/lean.js +1 -1
- package/dist/lean.js.map +1 -1
- package/dist/lexical.cjs +1 -1
- package/dist/lexical.cjs.map +1 -1
- package/dist/lexical.d.cts +11 -1
- package/dist/lexical.d.ts +11 -1
- package/dist/lexical.js +1 -1
- package/dist/lexical.js.map +1 -1
- package/dist/plugins.cjs +1 -1
- package/dist/plugins.cjs.map +1 -1
- package/dist/plugins.js +1 -1
- package/dist/plugins.js.map +1 -1
- package/dist/{probe-wmvfVEsI.d.ts → probe-DqaItcwX.d.ts} +2 -1
- package/dist/structural.cjs +2 -2
- package/dist/structural.cjs.map +1 -1
- package/dist/structural.js +2 -2
- package/dist/structural.js.map +1 -1
- package/package.json +2 -3
package/dist/structural.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structural.cjs","names":["diagnostic","autoPolicy","safeConsoleWarn","args","console","warn","value","then","Promise","resolve","catch","noWriteCallbacks","WeakSet","markNoWriteCallback","callback","add","trustedHtml","html","policy","api","candidate","globalThis","trustedTypes","createPolicy","factory","createHTML","input","resolvePolicy","SAFE_PROTOCOLS","Set","DANGEROUS_PROTOCOL_PATTERN","RELATIVE_PATH","PROTOCOL_RELATIVE","PARSER_IGNORED","isSafeUrl","url","trimmed","trim","replace","length","test","startsWith","parsed","URL","has","protocol","reported","reportDroppedAttribute","name","message","reason","ALLOWED_TAGS","FORM_CONTROLS","REMOVE_COMPLETELY","ATTR_GLOBAL","ATTR_ARIA_PREFIX","ATTR_DATA_PREFIX","ATTR_BY_TAG","a","img","picture","source","audio","video","time","abbr","q","blockquote","table","th","td","col","colgroup","ol","li","code","pre","URL_ATTRIBUTES","SanitizerEnvironmentError","Error","TEMPLATE_ATTRIBUTES","sanitizeFragment","node","child","Array","from","childNodes","nodeType","sanitizeElement","remove","element","tag","tagName","toLowerCase","allowFormControls","allowedTags","replaceWith","tagAttrs","attrByTag","get","attr","attributes","removeAttribute","mode","templateMode","allowedData","isSafeSrcset","sanitizeAttributes","anchor","href","getAttribute","isExternalHttpUrl","setAttribute","hasAttribute","hardenAnchor","split","HTML_ESCAPES","Object","freeze","HTML_ESCAPE_PATTERN","escapeHtml","text","char","BLOCKED_ATTRIBUTES","isWritableAttribute","PLACEHOLDER_PATTERN","safeStringify","String","JSON","stringify","getId","item","id","getBlockType","blockType","diffArray","prev","next","every","patches","prevIndexById","Map","i","set","consumedFromPrev","to","push","kind","index","prevItem","shallowEqual","oldValue","diffById","min","Math","diffByPosition","b","is","aRec","bRec","aKeys","keys","bKeys","key","ISLAND_ATTRIBUTE","OWNED_ATTRIBUTE","STATE_ATTRIBUTES","keyOf","options","attribute","keyAttributes","isMorphBoundary","includes","editable","isMorphCompatible","live","rendered","namespaceURI","morphElement","focus","active","ownerDocument","activeElement","HTMLElement","contains","selection","HTMLInputElement","HTMLTextAreaElement","selectionStart","selectionEnd","captureFocus","syncAttributes","retainChildrenOf","liveKeyed","parent","keyed","duplicate","children","slice","indexOf","onDuplicateKey","indexKeyed","keyedElements","values","liveUnkeyed","filter","claimed","usedKeys","renderedNodes","cursor","firstChild","unkeyedIndex","kept","Element","reconcile","nextSibling","sameKind","replaceChild","following","isBlankText","insertBefore","morphChildren","snapshot","isConnected","preventScroll","start","end","setSelectionRange","restoreFocus","nodeValue","Node","TEXT_NODE","TEMPLATE_EXTRA_TAGS","TEMPLATE_EXTRA_ATTRIBUTES","CUSTOM_TAG_PATTERN","optionsByTemplate","KEY_ATTRIBUTE","NESTED_KEY_ATTRIBUTE","NESTED_TEMPLATE_ATTRIBUTE","createStructuralStore","WeakMap","applyStructuralPatches","plan","prepareStructuralPlan","container","commitStructuralPlan","store","morph","isManagedNestedSlot","_live","env","entries","template","nextItems","forceRender","sanitizerPolicy","memory","shared","items","first","everyItem","sharedItemAttributes","templateKeys","collectTemplateKeys","initialChildren","keyedChildren","indexByAttribute","reserved","readKey","takeIndexedElement","replaces","renders","renderItem","nestedSlots","prepareNestedSlots","prepareReconciliation","patch","createPatchPlan","mutated","retained","liveSlot","renderedSlot","synchronizeAttributes","before","map","getMemory","clear","rememberItem","oldItem","newItem","nextValue","prevValue","oldSlotsByKey","findDirectNestedSlots","plans","newSlot","oldSlot","nextTemplate","previousTemplate","nextNested","readNestedArray","resolvedNext","templateChanged","querySelectorAll","slot","ancestor","parentElement","target","nested","isArray","elements","indexed","bucket","pop","knownKeys","safe","doc","__INLINE_BUILD__","document","resolved","instancePolicy","attrMap","attrs","allowed","additionalAllowedTags","forEach","additionalAllowedAttributes","merged","allowedDataAttributes","createElement","innerHTML","content","sanitizeHtmlWithPolicy","record","placeholder","prototype","hasOwnProperty","call","hasOwn","Reflect","interpolateArrayTemplate","cached","delete","lruGet","tags","match","matchAll","oldest","size","limit","lruTrim","templateSanitizeOptions","host","firstElementChild","inheritItemAttributes","readDomKeySnapshot","itemKey","warnDuplicateKey","warned","owner","fieldName","warnOnce","codes","states","warnedContainers","warnedKeys","render","rawValue","context","isEmptyValue","arrayTemplate","warnMissingTemplate","previousState","domSnapshot","position","__payloadDomPosition","previous","current","sameDomKeySnapshot","needsForcedRender","nextKeys","seen","find","some","previousKeys","stable","warnAboutKeys","applied","dependsOn","maps","dependents","dependent","result","names","raw"],"sources":["../src/core/diagnostics.ts","../src/security/trusted-types.ts","../src/core/thenable.ts","../src/core/internal-outcome.ts","../src/security/url-validator.ts","../src/security/sanitizer-report.ts","../src/security/sanitizer.ts","../src/security/escape.ts","../src/core/attribute-binding.ts","../src/core/array-template.ts","../src/field-types/utils.ts","../src/schema/diff.ts","../src/core/islands.ts","../src/core/morph.ts","../src/core/template-sanitize.ts","../src/core/structural-applier.ts","../src/core/lru.ts","../src/field-types/structural-array.ts","../src/core/dependencies.ts"],"sourcesContent":["import { observeThenableResult } from './thenable';\n\n/**\n * Diagnostics are observability, never control flow: a consumer logger may\n * throw or return a rejected thenable, and reporting a failure must not become\n * a second failure. Invocation stays synchronous for ordinary loggers.\n */\nexport function isolateDiagnostic(\n diagnostic: (...args: unknown[]) => unknown,\n): (...args: unknown[]) => void {\n return (...args): void => {\n try {\n observeThenableResult(diagnostic(...args));\n } catch {\n // Diagnostics must not become a second failure boundary.\n }\n };\n}\n\n/** Shared allocation-free default for disabled diagnostic channels. */\nexport function noopDiagnostic(): void {\n // Intentionally empty.\n}\n\n// Access, invocation and thenable inspection all happen inside the wrapper, so\n// a missing or hostile console cannot escape.\nexport const safeConsoleError = isolateDiagnostic((...args) =>\n (console.error as (...values: unknown[]) => unknown)(...args),\n);\n\nexport const safeConsoleWarn = isolateDiagnostic((...args) =>\n (console.warn as (...values: unknown[]) => unknown)(...args),\n);\n\nexport const safeConsoleDebug = isolateDiagnostic((...args) =>\n // eslint-disable-next-line no-console -- best-effort development diagnostics\n (console.debug as (...values: unknown[]) => unknown)(...args),\n);\n","/**\n * Trusted Types: every HTML sink routes through one policy, `payload-live-preview`,\n * whose `createHTML` is the identity — what reaches a sink is already sanitized\n * or escaped. Without the API, strings pass through untouched.\n */\n\n/** The subset of the Trusted Types API this module needs. */\nexport interface TrustedHtmlPolicyLike {\n createHTML(input: string): unknown;\n}\n\ninterface TrustedTypesFactoryLike {\n createPolicy(\n name: string,\n rules: { createHTML: (input: string) => string },\n ): TrustedHtmlPolicyLike;\n}\n\n/** @internal */\nexport const TRUSTED_TYPES_POLICY_NAME = 'payload-live-preview';\n\nlet policyOverride: TrustedHtmlPolicyLike | null | undefined;\nlet autoPolicy: TrustedHtmlPolicyLike | null | undefined;\n\n/**\n * Use `policy` for every sink, `null` to assign plain strings, `undefined` to\n * return to the auto-created package policy.\n */\nexport function setTrustedTypesPolicy(policy: TrustedHtmlPolicyLike | null | undefined): void {\n policyOverride = policy;\n}\n\nfunction factory(): TrustedTypesFactoryLike | undefined {\n const candidate = (globalThis as { trustedTypes?: unknown }).trustedTypes;\n if (typeof candidate !== 'object' || candidate === null) return undefined;\n const create = (candidate as { createPolicy?: unknown }).createPolicy;\n return typeof create === 'function' ? (candidate as TrustedTypesFactoryLike) : undefined;\n}\n\nfunction resolvePolicy(): TrustedHtmlPolicyLike | null {\n if (policyOverride !== undefined) return policyOverride;\n if (autoPolicy !== undefined) return autoPolicy;\n const api = factory();\n try {\n autoPolicy =\n api === undefined\n ? null\n : api.createPolicy(TRUSTED_TYPES_POLICY_NAME, { createHTML: (input) => input });\n } catch {\n // The site's `trusted-types` directive does not list this name; the\n // sink assignment will surface the enforcement error.\n autoPolicy = null;\n }\n return autoPolicy;\n}\n\n/** `html` as a `TrustedHTML` when a policy exists, else the string. Typed `string` for `innerHTML`. @internal */\nexport function trustedHtml(html: string): string {\n const policy = resolvePolicy();\n if (policy === null) return html;\n return policy.createHTML(html) as string;\n}\n\n/** Test hook: forget the auto-created policy. */\nexport function __resetTrustedTypesForTests(): void {\n policyOverride = undefined;\n autoPolicy = undefined;\n}\n","/**\n * Detect an invalid async result in a synchronous extension point.\n *\n * Rejected native Promises otherwise become unhandled after the caller falls\n * back synchronously. Assimilating the result through a handled Promise keeps\n * that contract violation observable only through the runtime's explicit\n * error channel.\n */\nexport function observeThenableResult(value: unknown): boolean {\n if ((typeof value !== 'object' || value === null) && typeof value !== 'function') return false;\n if (typeof (value as { readonly then?: unknown }).then !== 'function') return false;\n void Promise.resolve(value).catch(() => undefined);\n return true;\n}\n","/**\n * Public renderer callbacks return `void`, but a JavaScript implementation may\n * return anything. Only callbacks marked here may reserve exact `false` as\n * \"no write\", so a custom renderer's incidental boolean cannot change the\n * lifecycle's applied counts.\n */\n\ntype Callback = (...args: never[]) => unknown;\n\nconst noWriteCallbacks = new WeakSet<Callback>();\n\n/** Mark a package-owned callback whose exact `false` return means no write. */\nexport function markNoWriteCallback<T extends Callback>(callback: T): T {\n noWriteCallbacks.add(callback);\n return callback;\n}\n\n/** Whether `callback` owns the internal exact-false sentinel contract. */\nexport function usesNoWriteOutcome(callback: Callback): boolean {\n return noWriteCallbacks.has(callback);\n}\n\n/** Check a renderer object without detaching its public method at the call site. */\nexport function rendererUsesNoWriteOutcome(renderer: { readonly render: Callback }): boolean {\n return noWriteCallbacks.has(renderer.render);\n}\n","/**\n * URL safety: the one scheme allow-list the runtime, the client and the\n * sanitizer share. Empty strings are not safe (`<a href=\"\">` is never emitted).\n */\n\nconst SAFE_PROTOCOLS: ReadonlySet<string> = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n// Browsers strip leading whitespace before scheme detection.\nconst DANGEROUS_PROTOCOL_PATTERN = /^\\s*(?:javascript|data|vbscript|file|blob|about)\\s*:/i;\n\nconst RELATIVE_PATH = /^(?:\\.{1,2}\\/|[a-zA-Z0-9_-]+\\/?)/;\n\n// The URL parser treats `\\` as `/` for special schemes, so `/\\evil.com`\n// resolves to another origin rather than to a same-origin path.\nconst PROTOCOL_RELATIVE = /^[\\\\/]{2}/;\n\n/** The URL parser drops these anywhere in the input before it looks at anything. */\nconst PARSER_IGNORED = /[\\t\\n\\r]/g;\n\n/** `true` only for absolute `http`/`https`/`mailto`/`tel` URLs, protocol-relative URLs, paths, `#`/`?` fragments and relative paths. */\nexport function isSafeUrl(url: unknown): boolean {\n if (typeof url !== 'string') return false;\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n if (trimmed.length === 0) return false;\n if (DANGEROUS_PROTOCOL_PATTERN.test(trimmed)) return false;\n if (trimmed.startsWith('#') || trimmed.startsWith('?')) return true;\n if (PROTOCOL_RELATIVE.test(trimmed)) return true;\n if (trimmed.startsWith('/')) return true;\n try {\n const parsed = new URL(trimmed);\n return SAFE_PROTOCOLS.has(parsed.protocol);\n } catch {\n return RELATIVE_PATH.test(trimmed);\n }\n}\n\n/** Whether a URL points at another HTTP(S) origin, protocol-relative forms included, and so needs `noopener` hardening; every URL these two patterns match is one `isSafeUrl` admits. */\nexport function isExternalHttpUrl(url: string): boolean {\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n return /^https?:\\/\\//i.test(trimmed) || PROTOCOL_RELATIVE.test(trimmed);\n}\n\n/** The safe scheme set, for tests and introspection. */\nexport const SAFE_URL_PROTOCOLS: ReadonlySet<string> = SAFE_PROTOCOLS;\n","/**\n * LP0409 — what the strict sanitizer removed that the 1.x default kept.\n *\n * `sanitizerPolicy` defaults to `'strict'` since 2.0; before that it was\n * `'compat'`, which let `id` and every `data-*` through, and `name` only where\n * a per-tag list allowed it. The difference\n * only shows when a binding *writes* markup, so a project that upgrades and\n * whose rich text carries its own hooks loses them at the moment an editor\n * types — silently, and in the preview only. Measured on a real consumer: a\n * `data-partner-scroll` attribute driving a CSS selector disappeared on the\n * first write, with nothing said anywhere.\n *\n * So it is said here: once per attribute name per page, with the reason that\n * applies to that name rather than one sentence covering three different\n * decisions. This is a report, never a behaviour — the attribute stays removed.\n */\n\n/**\n * `console.warn` behind a try/catch rather than `@core/diagnostics`: `security`\n * is a leaf layer and may not import `core` (scripts/architecture-rules.ts), and\n * the shared helper's extra work — tolerating a logger that returns a thenable —\n * is for consumer-supplied loggers. This sink is fixed.\n */\nfunction warn(message: string): void {\n try {\n console.warn(message);\n } catch {\n // A diagnostic must never become a second failure.\n }\n}\n\nconst reported = new Set<string>();\n\n/** The binding prefix, restated rather than imported: this module must not pull the applier in. */\nconst BINDING_PREFIX = 'data-payload-';\n\nfunction reason(name: string): string {\n if (name.startsWith(BINDING_PREFIX)) {\n return (\n 'A binding inside CMS content is refused by design — an editor could otherwise ' +\n 'aim a write at any element on the page (docs/security.md)'\n );\n }\n if (name === 'id' || name === 'name') {\n return (\n 'CMS content that can name an element can shadow a global of that name — ' +\n 'DOM clobbering, refused by design (docs/security.md)'\n );\n }\n return (\n 'List it in `allowedDataAttributes` if the page needs it, or set ' +\n \"`sanitizerPolicy: 'compat'` to keep every `data-*` as 1.x did\"\n );\n}\n\n/**\n * Report one removal. Only for attributes `'compat'` would have kept: everything\n * else the sanitizer drops was refused in 1.x too and is not news to anyone.\n */\nexport function reportDroppedAttribute(name: string): void {\n if (reported.has(name)) return;\n reported.add(name);\n warn(\n `[live-preview] LP0409: the strict sanitizer removed \\`${name}\\` from written markup; ` +\n `the 1.x default (\\`sanitizerPolicy: 'compat'\\`) kept it. ${reason(name)}.`,\n );\n}\n\n/** Test seam: the report is once per page, and a test is not a page. */\nexport function resetDroppedAttributeReports(): void {\n reported.clear();\n}\n","/**\n * HTML sanitizer built on the host parser (`<template>`): allow-listed tags\n * and attributes, validated URLs, hardened external links, no `style`.\n * Needs a DOM; string-only sanitizers are historically brittle.\n */\n\nimport { trustedHtml } from './trusted-types';\nimport { isSafeUrl, isExternalHttpUrl } from './url-validator';\nimport { reportDroppedAttribute } from './sanitizer-report';\n\ndeclare const __INLINE_BUILD__: boolean | undefined;\n\n/** Tags kept with their content. Others are unwrapped unless in `REMOVE_COMPLETELY`. */\nconst ALLOWED_TAGS: ReadonlySet<string> = new Set([\n 'p',\n 'br',\n 'strong',\n 'b',\n 'em',\n 'i',\n 'u',\n 's',\n 'strike',\n 'mark',\n 'small',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'ul',\n 'ol',\n 'li',\n 'dl',\n 'dt',\n 'dd',\n 'blockquote',\n 'code',\n 'pre',\n 'kbd',\n 'samp',\n 'var',\n 'a',\n 'span',\n 'div',\n 'section',\n 'article',\n 'aside',\n 'header',\n 'footer',\n 'nav',\n 'figure',\n 'figcaption',\n 'img',\n 'picture',\n 'source',\n 'audio',\n 'video',\n 'sub',\n 'sup',\n 'hr',\n 'time',\n 'abbr',\n 'cite',\n 'q',\n 'table',\n 'thead',\n 'tbody',\n 'tfoot',\n 'tr',\n 'th',\n 'td',\n 'caption',\n 'colgroup',\n 'col',\n]);\n\n/** Tags `allowFormControls` re-admits for author templates; `form` is deliberately not one. */\nconst FORM_CONTROLS: ReadonlySet<string> = new Set([\n 'input',\n 'button',\n 'textarea',\n 'select',\n 'option',\n 'label',\n]);\n\n/** Removed with their children: the content itself is the hazard. */\nconst REMOVE_COMPLETELY: ReadonlySet<string> = new Set([\n 'script',\n 'style',\n 'iframe',\n 'object',\n 'embed',\n 'link',\n 'meta',\n 'base',\n 'form',\n 'input',\n 'button',\n 'select',\n 'textarea',\n 'svg',\n 'math',\n 'template',\n 'frame',\n 'frameset',\n 'noframes',\n 'noscript',\n]);\n\nconst ATTR_GLOBAL: ReadonlySet<string> = new Set([\n 'id',\n 'class',\n 'lang',\n 'dir',\n 'title',\n 'role',\n 'tabindex',\n]);\n\nconst ATTR_ARIA_PREFIX = 'aria-';\nconst ATTR_DATA_PREFIX = 'data-';\nconst BINDING_DATA_PREFIX = 'data-payload-';\n\nconst ATTR_BY_TAG: Readonly<Record<string, ReadonlySet<string>>> = {\n a: new Set(['href', 'target', 'rel', 'download', 'hreflang', 'type']),\n img: new Set(['src', 'srcset', 'sizes', 'alt', 'width', 'height', 'loading', 'decoding']),\n picture: new Set([]),\n source: new Set(['src', 'srcset', 'sizes', 'type', 'media']),\n audio: new Set(['src', 'controls', 'autoplay', 'loop', 'muted', 'preload']),\n video: new Set([\n 'src',\n 'poster',\n 'controls',\n 'autoplay',\n 'loop',\n 'muted',\n 'preload',\n 'width',\n 'height',\n 'playsinline',\n ]),\n time: new Set(['datetime']),\n abbr: new Set(['title']),\n q: new Set(['cite']),\n blockquote: new Set(['cite']),\n table: new Set(['summary']),\n th: new Set(['colspan', 'rowspan', 'scope', 'headers', 'abbr']),\n td: new Set(['colspan', 'rowspan', 'headers']),\n col: new Set(['span']),\n colgroup: new Set(['span']),\n ol: new Set(['start', 'reversed', 'type']),\n li: new Set(['value']),\n code: new Set(['class']),\n pre: new Set(['class']),\n};\n\nconst URL_ATTRIBUTES: ReadonlySet<string> = new Set(['href', 'src', 'cite', 'poster']);\n\n// Numeric nodeType constants keep an injected SSR document independent of a\n// browser-global `Node` constructor.\nconst ELEMENT_NODE = 1;\nconst COMMENT_NODE = 8;\n\n/** Thrown by `sanitizeHtml()` when no `document` is available (SSR without `setSanitizerDocument()`). */\nexport class SanitizerEnvironmentError extends Error {\n override readonly name = 'SanitizerEnvironmentError';\n}\n\n/**\n * `'strict'` (default) strips `id`, `name` and `data-payload-*` and passes\n * other `data-*` only via `allowedDataAttributes`; `'compat'` keeps them.\n */\nexport type SanitizerPolicyMode = 'compat' | 'strict';\n\nexport interface SanitizeOptions {\n /** Overrides the module default set by `setSanitizerPolicy()`. */\n readonly policy?: SanitizerPolicyMode;\n /** `data-*` attributes (full names) that pass under `'strict'`; `data-payload-*` never does. */\n readonly allowedDataAttributes?: readonly string[];\n /**\n * Keep `input`, `button`, `textarea`, `select`, `option` and `label` — only\n * for markup the page author wrote, never for CMS content. `form`,\n * handlers, `style` and unsafe URLs stay dropped.\n */\n readonly allowFormControls?: boolean;\n /** Extra tags to allow. Lower-case, untrimmed. */\n readonly additionalAllowedTags?: readonly string[];\n /**\n * Extra per-tag attributes, lower-case. Cannot re-admit handlers, `style`,\n * or — under `'strict'` — `id`, `name` and `data-payload-*`.\n */\n readonly additionalAllowedAttributes?: Readonly<Record<string, readonly string[]>>;\n /**\n * The input is a page-author item template, so `'strict'` keeps the\n * applier's reconciliation attributes (`TEMPLATE_ATTRIBUTES`) and nothing\n * else — every other `data-payload-*` is still stripped, so a template can\n * never add a binding.\n */\n readonly templateMode?: boolean;\n}\n\n/** What `templateMode` keeps under `'strict'`. */\nconst TEMPLATE_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'id',\n 'name',\n 'data-payload-key',\n 'data-payload-nested-key',\n 'data-payload-nested-template',\n]);\n\ninterface ResolvedPolicy {\n readonly allowedTags: ReadonlySet<string>;\n readonly allowFormControls: boolean;\n readonly templateMode: boolean;\n readonly mode: SanitizerPolicyMode;\n readonly allowedData: ReadonlySet<string>;\n readonly attrByTag: ReadonlyMap<string, ReadonlySet<string>>;\n}\n\nlet defaultMode: SanitizerPolicyMode = 'strict';\n\n/**\n * The process-wide default for calls without an explicit `policy`. A runtime\n * instance carries its own `sanitizerPolicy` and never writes here (ADR 0002).\n */\nexport function setSanitizerPolicy(mode: SanitizerPolicyMode): void {\n defaultMode = mode;\n}\n\n/** `instancePolicy` sits between a per-call `options.policy` and the process default. */\nfunction resolvePolicy(\n options: SanitizeOptions | undefined,\n instancePolicy: SanitizerPolicyMode | undefined,\n): ResolvedPolicy {\n const mode = options?.policy ?? instancePolicy ?? defaultMode;\n if (!options) {\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n return {\n allowedTags: ALLOWED_TAGS,\n attrByTag: attrMap,\n allowFormControls: false,\n templateMode: false,\n mode,\n allowedData: new Set(),\n };\n }\n const allowed = new Set(ALLOWED_TAGS);\n options.additionalAllowedTags?.forEach((tag) => allowed.add(tag));\n if (options.allowFormControls === true) for (const tag of FORM_CONTROLS) allowed.add(tag);\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n for (const [tag, attrs] of Object.entries(options.additionalAllowedAttributes ?? {})) {\n const merged = new Set(attrMap.get(tag));\n for (const attr of attrs) merged.add(attr);\n attrMap.set(tag, merged);\n }\n return {\n allowedTags: allowed,\n attrByTag: attrMap,\n allowFormControls: options.allowFormControls === true,\n templateMode: options.templateMode === true,\n mode,\n allowedData: new Set(options.allowedDataAttributes?.map((name) => name.toLowerCase())),\n };\n}\n\n/** The `Document` surface the sanitizer needs; jsdom, linkedom and happy-dom all provide it. */\nexport interface SanitizerDocument {\n createElement: (tagName: string) => {\n innerHTML: string;\n readonly content: ParentNode;\n };\n}\n\nlet documentOverride: SanitizerDocument | undefined;\n\n/** Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`; `null` clears it. */\nexport function setSanitizerDocument(doc: SanitizerDocument | null): void {\n documentOverride = doc ?? undefined;\n}\n\n/**\n * Sanitize `html`; malformed input is recovered by the parser first.\n *\n * @throws {SanitizerEnvironmentError} when no DOM is available.\n */\nexport function sanitizeHtml(html: string, options?: SanitizeOptions): string {\n return sanitizeHtmlWithPolicy(html, undefined, options);\n}\n\n/**\n * The runtime's entry: `policy` is one instance's, applied unless `options`\n * carry their own, so two clients on a page never share a policy through\n * this module. Not public — a direct caller has `options.policy`.\n */\nexport function sanitizeHtmlWithPolicy(\n html: string,\n policy: SanitizerPolicyMode | undefined,\n options?: SanitizeOptions,\n): string {\n const doc = resolveDocument();\n if (!doc) throw environmentError();\n if (html === '') return '';\n\n const resolved = resolvePolicy(options, policy);\n const template = doc.createElement('template');\n // The sanitizer's own parse is a sink too: under Trusted Types it needs the policy.\n template.innerHTML = trustedHtml(html);\n sanitizeFragment(template.content, resolved);\n return template.innerHTML;\n}\n\n// Read the define at each branch rather than through a helper: a bundler\n// folds the substituted literal in place, but will not inline a call, and the\n// SSR-only class and override must not reach the browser runtime.\nfunction environmentError(): Error {\n if (typeof __INLINE_BUILD__ !== 'undefined' && __INLINE_BUILD__) {\n return new Error('sanitizeHtml needs a DOM');\n }\n return new SanitizerEnvironmentError(\n 'sanitizeHtml needs a DOM; provide one with setSanitizerDocument() during SSR.',\n );\n}\n\nfunction resolveDocument(): SanitizerDocument | undefined {\n if (typeof __INLINE_BUILD__ === 'undefined' || !__INLINE_BUILD__) {\n if (documentOverride) return documentOverride;\n }\n if (typeof document === 'undefined') return undefined;\n return document;\n}\n\n/** Whether a DOM is available — the global or an injected one — for callers that treat sanitizing as optional. */\nexport function hasSanitizerDocument(): boolean {\n return resolveDocument() !== undefined;\n}\n\nfunction sanitizeFragment(node: ParentNode, policy: ResolvedPolicy): void {\n // Snapshot: children are mutated during the walk.\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === ELEMENT_NODE) {\n sanitizeElement(child as Element, policy);\n } else if (child.nodeType === COMMENT_NODE) {\n child.remove();\n }\n }\n}\n\nfunction sanitizeElement(element: Element, policy: ResolvedPolicy): void {\n const tag = element.tagName.toLowerCase();\n\n if (REMOVE_COMPLETELY.has(tag) && !(policy.allowFormControls && FORM_CONTROLS.has(tag))) {\n element.remove();\n return;\n }\n\n if (!policy.allowedTags.has(tag)) {\n sanitizeFragment(element, policy);\n element.replaceWith(...element.childNodes);\n return;\n }\n\n sanitizeAttributes(element, tag, policy);\n if (tag === 'a') hardenAnchor(element);\n sanitizeFragment(element, policy);\n}\n\nfunction sanitizeAttributes(element: Element, tag: string, policy: ResolvedPolicy): void {\n const tagAttrs = policy.attrByTag.get(tag);\n\n for (const attr of Array.from(element.attributes)) {\n const name = attr.name.toLowerCase();\n if (name.startsWith('on') || name === 'style') {\n element.removeAttribute(attr.name);\n continue;\n }\n if (policy.mode === 'strict') {\n if (policy.templateMode && TEMPLATE_ATTRIBUTES.has(name)) continue;\n // DOM clobbering and binding injection (docs/security.md §5c). Checked\n // before the allow-list so an extension cannot re-admit them.\n if (name === 'id' || name === 'name' || name.startsWith(BINDING_DATA_PREFIX)) {\n element.removeAttribute(attr.name);\n // `compat` kept `name` only where a per-tag list allowed it, so only\n // there did the upgrade change anything to report.\n if (name !== 'name' || tagAttrs?.has(name) === true) reportDroppedAttribute(name);\n continue;\n }\n if (name.startsWith(ATTR_DATA_PREFIX)) {\n if (!policy.allowedData.has(name)) {\n element.removeAttribute(attr.name);\n reportDroppedAttribute(name);\n }\n continue;\n }\n if (ATTR_GLOBAL.has(name) || name.startsWith(ATTR_ARIA_PREFIX)) continue;\n } else if (\n ATTR_GLOBAL.has(name) ||\n name.startsWith(ATTR_ARIA_PREFIX) ||\n name.startsWith(ATTR_DATA_PREFIX)\n ) {\n continue;\n }\n if (tagAttrs?.has(name)) {\n if (URL_ATTRIBUTES.has(name) && !isSafeUrl(attr.value)) {\n element.removeAttribute(attr.name);\n } else if (name === 'srcset' && !isSafeSrcset(attr.value)) {\n element.removeAttribute(attr.name);\n }\n continue;\n }\n element.removeAttribute(attr.name);\n }\n}\n\n/** Every `srcset` candidate must pass; partial rewriting would silently change what renders. */\nfunction isSafeSrcset(value: string): boolean {\n for (const candidate of value.split(',')) {\n const trimmed = candidate.trim();\n if (trimmed.length === 0) continue;\n // The URL ends at the first whitespace; what follows is the descriptor.\n const [url = trimmed] = trimmed.split(/\\s/, 1);\n if (!isSafeUrl(url)) return false;\n }\n return true;\n}\n\nfunction hardenAnchor(anchor: Element): void {\n const href = anchor.getAttribute('href');\n if (href === null || !isExternalHttpUrl(href)) return;\n anchor.setAttribute('rel', 'noopener noreferrer');\n if (!anchor.hasAttribute('target')) anchor.setAttribute('target', '_blank');\n}\n\n/** The built-in allow-lists, for documentation and tests. */\nexport const SANITIZER_POLICY = Object.freeze({\n allowedTags: ALLOWED_TAGS,\n removeCompletely: REMOVE_COMPLETELY,\n globalAttributes: ATTR_GLOBAL,\n attributesByTag: ATTR_BY_TAG,\n urlAttributes: URL_ATTRIBUTES,\n});\n","/** HTML and CSS escaping primitives (OWASP XSS Prevention Cheat Sheet). DOM-free. */\n\nconst HTML_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '/': '/',\n '`': '`',\n '=': '=',\n});\n\nconst HTML_ESCAPE_PATTERN = /[&<>\"'/`=]/g;\n\n/** Escape `text` for an element body or a *quoted* attribute value; strings only, and unquoted attributes are not covered. */\nexport function escapeHtml(text: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return text.replace(HTML_ESCAPE_PATTERN, (char) => HTML_ESCAPES[char] as string);\n}\n\n/** Escape a value for a CSS `url(...)` literal; this stops the break-out, not the scheme, so pair it with `isSafeUrl()`. */\nexport function escapeCssUrl(value: string): string {\n return value.replace(/['\"()\\\\]/g, '\\\\$&');\n}\n\nconst ATTR_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n});\n\nconst ATTR_ESCAPE_PATTERN = /[&<>\"']/g;\n\n/** Escape a value for a *quoted* HTML attribute, leaving URL characters intact; it validates no scheme, so run `isSafeUrl()` on `href`/`src` first. @internal */\nexport function escapeHtmlAttribute(value: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return value.replace(ATTR_ESCAPE_PATTERN, (char) => ATTR_ESCAPES[char] as string);\n}\n\n/** `escapeHtml()` then newlines to `<br>`; the order is what makes it safe. */\nexport function escapeAndLinebreak(text: string): string {\n return escapeHtml(text).replace(/\\r\\n|\\r|\\n/g, '<br>');\n}\n","/**\n * Policed writes for `data-payload-attribute` bindings. The value is\n * remote-controlled, so event handlers, `style`, `srcdoc`, `formaction`/`form`,\n * `id`/`name` (DOM clobbering) and `srcset` (multi-URL syntax) are refused,\n * URL-bearing attributes must pass `isSafeUrl`, and non-scalars never write.\n */\n\nimport { isSafeUrl } from '@security/url-validator';\n\nconst BLOCKED_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'style',\n 'srcdoc',\n 'formaction',\n 'form',\n 'id',\n 'name',\n 'is',\n 'srcset',\n 'imagesrcset',\n]);\n\nconst URL_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'href',\n 'src',\n 'poster',\n 'cite',\n 'action',\n 'xlink:href',\n 'data',\n]);\n\nexport type AttributeApplyResult = 'applied' | 'blocked';\n\n/**\n * Whether this package may write an attribute of this name at all — event\n * handlers, `style`, the two DOM-clobbering names and the multi-URL ones\n * excluded. One rule, two callers: the binding below writes a remote value into\n * it, and the array renderers copy one from the page's own markup onto an item\n * they rebuilt (`src/core/array-template.ts`).\n */\nexport function isWritableAttribute(name: string): boolean {\n return !name.startsWith('on') && !BLOCKED_ATTRIBUTES.has(name);\n}\n\n/** Returns `'blocked'` without touching the DOM when the write is refused. */\nexport function applyAttributeBinding(\n element: Element,\n attribute: string,\n value: unknown,\n): AttributeApplyResult {\n const name = attribute.toLowerCase().trim();\n if (name.length === 0) return 'blocked';\n if (!isWritableAttribute(name)) return 'blocked';\n\n if (value === null || value === undefined) {\n element.removeAttribute(name);\n return 'applied';\n }\n if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {\n return 'blocked';\n }\n const stringValue = String(value);\n\n if (URL_ATTRIBUTES.has(name) && !isSafeUrl(stringValue)) return 'blocked';\n\n element.setAttribute(name, stringValue);\n return 'applied';\n}\n","/**\n * One array item out of one template: the interpolation, and the attributes the\n * template cannot know about.\n *\n * A replacement value is data, not template syntax: one `replace()` per key\n * would re-interpret `{{index}}` text that an earlier value introduced, and\n * would apply `String.replace`'s `$` semantics to CMS content.\n */\n\nimport { escapeHtml } from '@security/escape';\nimport { isWritableAttribute } from './attribute-binding';\n\nconst PLACEHOLDER_PATTERN = /\\{\\{([\\s\\S]*?)\\}\\}/g;\n\n/** The runtime's own annotations; a rebuilt item gets its own, never a copy. */\nconst BINDING_ATTRIBUTE_PREFIX = 'data-payload-';\n\n/** An attribute name and its value, as they travel from an old item to a new one. */\nexport type InheritedAttribute = readonly [name: string, value: string];\n\nfunction hasOwn(record: object, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(record, key);\n}\n\n/**\n * Every key any item carries. A placeholder naming one of these is a field of\n * this array, so a row that happens to lack it renders as nothing; a\n * placeholder no row can fill is a typo in the template and stays visible.\n */\nexport function collectTemplateKeys(items: readonly unknown[]): ReadonlySet<string> {\n const keys = new Set<string>();\n for (const item of items) {\n if (typeof item !== 'object' || item === null) continue;\n for (const key of Object.keys(item)) keys.add(key);\n }\n return keys;\n}\n\nexport function interpolateArrayTemplate(\n template: string,\n item: unknown,\n index: number,\n stringify: (value: unknown) => string,\n knownKeys?: ReadonlySet<string>,\n): string {\n const record = typeof item === 'object' && item !== null ? item : null;\n\n return template.replace(PLACEHOLDER_PATTERN, (placeholder, key: string) => {\n // Preserve the established object-field precedence when an object itself\n // has an `index` or `value` property. Otherwise these are reserved tokens.\n if (record !== null && hasOwn(record, key)) {\n return escapeHtml(stringify(Reflect.get(record, key)));\n }\n if (record === null && key === 'value') return escapeHtml(stringify(item));\n if (key === 'index') return String(index);\n // A field other rows carry: this one simply has none. Writing the\n // placeholder would print template syntax on the page, which is what an\n // editor sees the moment a row is added and not every field is filled in.\n if (record !== null && knownKeys?.has(key) === true) return '';\n return placeholder;\n });\n}\n\n/**\n * What the items already in `container` all carry, and an item rebuilt from the\n * template therefore has to carry too.\n *\n * A framework's scoped styles hang on a marker its compiler writes into the\n * markup — Astro's `data-astro-cid-…`, Vue's `data-v-…`, Svelte's class — and\n * the author's `data-payload-array-template` has none of it. The rebuilt list\n * then renders unstyled next to the one the server sent, while the write itself\n * succeeds, so nothing in the runtime can notice. Naming no framework is the\n * point: what identifies these attributes is that every item of the list has\n * them with the same value, which per-row state by definition does not.\n */\nexport function sharedItemAttributes(container: Element): readonly InheritedAttribute[] {\n const items = container.children;\n const first = items[0];\n if (first === undefined) return [];\n const shared: InheritedAttribute[] = [];\n for (const { name, value } of Array.from(first.attributes)) {\n if (!isWritableAttribute(name) || name.startsWith(BINDING_ATTRIBUTE_PREFIX)) continue;\n let everyItem = true;\n for (let index = 1; index < items.length && everyItem; index += 1) {\n everyItem = items[index]?.getAttribute(name) === value;\n }\n if (everyItem) shared.push([name, value]);\n }\n return shared;\n}\n\n/** Give a rebuilt item what its predecessors shared; the template's own value wins. */\nexport function inheritItemAttributes(item: Element, shared: readonly InheritedAttribute[]): void {\n for (const [name, value] of shared) {\n if (!item.hasAttribute(name)) item.setAttribute(name, value);\n }\n}\n","/** Value coercion shared by the field renderers. */\n\n/** Display string for any value: primitives as-is, objects as JSON, `null`/`undefined` as `''`. */\nexport function safeStringify(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '';\n }\n}\n\n/** The three values every renderer treats as \"clear\" (docs/renderers.md, value semantics). */\nexport function isEmptyValue(value: unknown): value is null | undefined | '' {\n return value === null || value === undefined || value === '';\n}\n","/**\n * Structural diff for array and blocks fields. Items with an `id` are keyed\n * (moves are detected); without ids the diff is positional.\n * @internal\n */\n\nexport type ArrayPatch =\n | { readonly kind: 'insert'; readonly index: number; readonly value: unknown }\n | { readonly kind: 'remove'; readonly index: number; readonly value: unknown }\n | {\n readonly kind: 'move';\n readonly from: number;\n readonly to: number;\n readonly value: unknown;\n }\n | { readonly kind: 'update'; readonly index: number; readonly value: unknown }\n | {\n readonly kind: 'replace';\n readonly index: number;\n readonly oldValue: unknown;\n readonly value: unknown;\n };\n\nfunction getId(item: unknown): string | number | undefined {\n if (typeof item !== 'object' || item === null) return undefined;\n const id = (item as Record<string, unknown>)['id'];\n if (typeof id === 'string' || typeof id === 'number') return id;\n return undefined;\n}\n\nfunction getBlockType(item: unknown): string | undefined {\n if (typeof item !== 'object' || item === null) return undefined;\n const blockType = (item as Record<string, unknown>)['blockType'];\n return typeof blockType === 'string' ? blockType : undefined;\n}\n\n/** Patches that turn `prev` into `next`; a changed `blockType` is a `replace`, never an `update`. */\nexport function diffArray(\n prev: readonly unknown[],\n next: readonly unknown[],\n): readonly ArrayPatch[] {\n const haveIds = next.every((item) => getId(item) !== undefined);\n if (haveIds) return diffById(prev, next);\n return diffByPosition(prev, next);\n}\n\nfunction diffById(prev: readonly unknown[], next: readonly unknown[]): readonly ArrayPatch[] {\n const patches: ArrayPatch[] = [];\n const prevIndexById = new Map<string | number, number>();\n for (let i = 0; i < prev.length; i += 1) {\n const id = getId(prev[i]);\n if (id !== undefined) prevIndexById.set(id, i);\n }\n\n const consumedFromPrev = new Set<number>();\n for (let to = 0; to < next.length; to += 1) {\n const item = next[to];\n const id = getId(item);\n if (id === undefined) {\n patches.push({ kind: 'insert', index: to, value: item });\n continue;\n }\n const from = prevIndexById.get(id);\n if (from === undefined) {\n patches.push({ kind: 'insert', index: to, value: item });\n continue;\n }\n consumedFromPrev.add(from);\n const prevItem = prev[from];\n if (getBlockType(prevItem) !== getBlockType(item)) {\n patches.push({ kind: 'replace', index: to, oldValue: prevItem, value: item });\n continue;\n }\n if (from !== to) {\n patches.push({ kind: 'move', from, to, value: item });\n }\n if (!shallowEqual(prevItem, item)) {\n patches.push({ kind: 'update', index: to, value: item });\n }\n }\n\n for (let i = 0; i < prev.length; i += 1) {\n if (consumedFromPrev.has(i)) continue;\n patches.push({ kind: 'remove', index: i, value: prev[i] });\n }\n return patches;\n}\n\nfunction diffByPosition(prev: readonly unknown[], next: readonly unknown[]): readonly ArrayPatch[] {\n const patches: ArrayPatch[] = [];\n const min = Math.min(prev.length, next.length);\n for (let i = 0; i < min; i += 1) {\n if (!shallowEqual(prev[i], next[i])) {\n patches.push({ kind: 'update', index: i, value: next[i] });\n }\n }\n if (next.length > prev.length) {\n for (let i = prev.length; i < next.length; i += 1) {\n patches.push({ kind: 'insert', index: i, value: next[i] });\n }\n }\n if (prev.length > next.length) {\n for (let i = next.length; i < prev.length; i += 1) {\n patches.push({ kind: 'remove', index: i, value: prev[i] });\n }\n }\n return patches;\n}\n\n// Shallow on purpose: any nested reference change is an update, and the\n// renderer reconciles deeper differences itself.\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;\n const aRec = a as Record<string, unknown>;\n const bRec = b as Record<string, unknown>;\n const aKeys = Object.keys(aRec);\n const bKeys = Object.keys(bRec);\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) {\n if (!Object.is(aRec[key], bRec[key])) return false;\n }\n return true;\n}\n","/**\n * Hydrated islands own their subtree, so the runtime never patches inside one.\n * Instead every flush dispatches `payload-live-preview:update` on each island\n * root with the update in `detail`. `data-payload-island=\"patch\"` opts back in.\n * @internal\n */\n\nexport const ISLAND_EVENT = 'payload-live-preview:update';\n/** @internal */\nexport const ISLAND_ATTRIBUTE = 'data-payload-island';\nexport const ISLAND_SELECTOR = `astro-island, [${ISLAND_ATTRIBUTE}]`;\n\nexport interface IslandUpdateDetail {\n readonly fields: Readonly<Record<string, unknown>>;\n readonly revision: number;\n readonly receivedAt: number;\n readonly locale: string | undefined;\n}\n\nfunction isIslandRoot(element: Element): boolean {\n return element.tagName.toLowerCase() === 'astro-island' || element.hasAttribute(ISLAND_ATTRIBUTE);\n}\n\nfunction islandAllowsPatching(island: Element): boolean {\n return island.getAttribute(ISLAND_ATTRIBUTE) === 'patch';\n}\n\n/** Whether `element` itself is an island root that did not opt into patching. */\nexport function isIslandBoundary(element: Element): boolean {\n return isIslandRoot(element) && !islandAllowsPatching(element);\n}\n\n/** Whether `element` (or an ancestor) is an island that did not opt into patching. @internal */\nexport function isInsideIsland(element: Element): boolean {\n let current: Element | null = element;\n while (current !== null) {\n if (isIslandBoundary(current)) return true;\n current = current.parentElement;\n }\n return false;\n}\n\n/** Island roots under `root` that receive update events. */\nexport function collectIslands(root: ParentNode): Element[] {\n const islands: Element[] = [];\n for (const island of root.querySelectorAll(ISLAND_SELECTOR)) {\n if (!islandAllowsPatching(island)) islands.push(island);\n }\n return islands;\n}\n\nexport function dispatchIslandUpdate(\n islands: readonly Element[],\n detail: IslandUpdateDetail,\n): number {\n for (const island of islands) {\n island.dispatchEvent(\n new CustomEvent<IslandUpdateDetail>(ISLAND_EVENT, { detail, bubbles: false }),\n );\n }\n return islands.length;\n}\n","/**\n * Keyed DOM morph: edits a live element toward a freshly rendered one while\n * keeping the live nodes, and with them focus, selection, scroll, playback and\n * listeners. Custom elements, islands, `contenteditable` and\n * `data-payload-owned` subtrees are boundaries the morph never enters.\n * See ADR 0008.\n */\n\nimport { ISLAND_ATTRIBUTE } from './islands';\n\nexport { ISLAND_ATTRIBUTE };\n/** @internal */\nexport const OWNED_ATTRIBUTE = 'data-payload-owned';\n\n/** Attributes the CMS controls only when the template names them (ADR 0008 §3). */\nconst STATE_ATTRIBUTES: ReadonlySet<string> = new Set(['open', 'value', 'checked', 'selected']);\n\nexport interface MorphOptions {\n /** Attributes that key child elements for pairing, tried in order; unkeyed children pair by position. */\n readonly keyAttributes: readonly string[];\n /** Called once per parent when two children share a key; the later ones pair by position. */\n readonly onDuplicateKey?: (parent: Element, key: string) => void;\n /** Elements whose attributes are synchronised but whose children are left alone (nested structural slots). */\n readonly retainChildrenOf?: (live: Element, rendered: Element) => boolean;\n}\n\n/** Empty attribute values (boolean markers such as `data-payload-island`) are not keys. */\nfunction keyOf(element: Element, options: MorphOptions): string | undefined {\n for (const attribute of options.keyAttributes) {\n const value = element.getAttribute(attribute);\n if (value !== null && value.length > 0) return `${attribute}=${value}`;\n }\n return undefined;\n}\n\n/** @internal */\nexport function isMorphBoundary(element: Element): boolean {\n if (element.tagName.toLowerCase().includes('-')) return true;\n if (element.hasAttribute(ISLAND_ATTRIBUTE) || element.hasAttribute(OWNED_ATTRIBUTE)) return true;\n const editable = element.getAttribute('contenteditable');\n return editable !== null && editable !== 'false';\n}\n\n/** Whether `live` can be edited toward `rendered` instead of being replaced by it. @internal */\nexport function isMorphCompatible(live: Element, rendered: Element): boolean {\n return (\n live.tagName === rendered.tagName &&\n live.namespaceURI === rendered.namespaceURI &&\n !isMorphBoundary(live) &&\n !isMorphBoundary(rendered)\n );\n}\n\n/**\n * Morph `live` toward `rendered`. Returns `live` when it was retained, or\n * `rendered` when the two are incompatible and the caller must replace.\n * `rendered` is consumed: its children may move into `live`.\n */\nexport function morphElement(live: Element, rendered: Element, options: MorphOptions): Element {\n if (!isMorphCompatible(live, rendered)) return rendered;\n const focus = captureFocus(live);\n syncAttributes(live, rendered);\n if (options.retainChildrenOf?.(live, rendered) !== true) morphChildren(live, rendered, options);\n restoreFocus(focus);\n return live;\n}\n\n/** Match attributes, except that state-bearing ones change only when `rendered` carries them. */\nexport function syncAttributes(live: Element, rendered: Element): void {\n for (const attribute of Array.from(live.attributes)) {\n if (rendered.hasAttribute(attribute.name)) continue;\n if (STATE_ATTRIBUTES.has(attribute.name.toLowerCase())) continue;\n live.removeAttribute(attribute.name);\n }\n for (const attribute of Array.from(rendered.attributes)) {\n if (live.getAttribute(attribute.name) !== attribute.value) {\n live.setAttribute(attribute.name, attribute.value);\n }\n }\n}\n\nfunction morphChildren(live: Element, rendered: Element, options: MorphOptions): void {\n const liveKeyed = indexKeyed(live, options);\n const keyedElements = new Set<Node>(liveKeyed.values());\n const liveUnkeyed = Array.from(live.childNodes).filter((node) => !keyedElements.has(node));\n const claimed = new Set<Node>();\n const usedKeys = new Set<string>();\n const renderedNodes = Array.from(rendered.childNodes);\n let cursor: Node | null = live.firstChild;\n let unkeyedIndex = 0;\n\n for (let i = 0; i < renderedNodes.length; i += 1) {\n const next = renderedNodes[i] as Node;\n let kept: Node | null = null;\n let key = next instanceof Element ? keyOf(next, options) : undefined;\n // A repeated key on the rendered side pairs positionally like a live duplicate.\n if (key !== undefined && usedKeys.has(key)) key = undefined;\n if (key !== undefined) {\n usedKeys.add(key);\n const candidate = liveKeyed.get(key);\n if (candidate !== undefined && !claimed.has(candidate)) {\n kept = reconcile(candidate, next, options) === candidate ? candidate : null;\n if (kept === null) {\n candidate.replaceWith(next);\n claimed.add(next);\n cursor = next.nextSibling;\n continue;\n }\n }\n } else {\n while (unkeyedIndex < liveUnkeyed.length) {\n const candidate = liveUnkeyed[unkeyedIndex] as Node;\n unkeyedIndex += 1;\n if (claimed.has(candidate)) continue;\n if (sameKind(candidate, next)) {\n kept = reconcile(candidate, next, options) === candidate ? candidate : null;\n if (kept === null) {\n live.replaceChild(next, candidate);\n claimed.add(next);\n cursor = next.nextSibling;\n }\n break;\n }\n if (candidate instanceof Element) {\n // `next` is a text/comment, or an element whose kind the following\n // rendered node matches: an insertion, so the live element stays for it.\n const following = renderedNodes[i + 1];\n if (\n !(next instanceof Element) ||\n (following !== undefined && sameKind(candidate, following))\n ) {\n unkeyedIndex -= 1;\n break;\n }\n live.replaceChild(next, candidate);\n claimed.add(next);\n cursor = next.nextSibling;\n break;\n }\n if (!(next instanceof Element)) {\n // Text vs comment: replace rather than rewrite one node type's value into the other.\n live.replaceChild(next, candidate);\n claimed.add(next);\n cursor = next.nextSibling;\n break;\n }\n // A surplus live text/comment before the element `next` needs; removed below.\n }\n if (kept === null && claimed.has(next)) continue;\n }\n\n const node: Node = kept ?? next;\n claimed.add(node);\n // Whitespace-only text the template did not render is surplus. Stepping the\n // cursor over it keeps a retained element where it is: `insertBefore` on a\n // node already in the tree is a remove-and-insert, which blurs a focused input.\n while (cursor !== null && cursor !== node && !claimed.has(cursor) && isBlankText(cursor)) {\n cursor = cursor.nextSibling;\n }\n if (node !== cursor) live.insertBefore(node, cursor);\n cursor = node.nextSibling;\n }\n\n for (const child of Array.from(live.childNodes)) {\n if (!claimed.has(child)) child.remove();\n }\n}\n\n/** Retain `candidate` when it can be edited toward `next`; otherwise report `next`. */\nfunction reconcile(candidate: Node, next: Node, options: MorphOptions): Node {\n if (candidate instanceof Element && next instanceof Element) {\n // A compatible boundary stays exactly as it is (ADR 0008 §4).\n if (isMorphBoundary(candidate) && isMorphBoundary(next)) return candidate;\n return morphElement(candidate, next, options);\n }\n if (candidate.nodeValue !== next.nodeValue) candidate.nodeValue = next.nodeValue;\n return candidate;\n}\n\nfunction isBlankText(node: Node): boolean {\n return node.nodeType === Node.TEXT_NODE && (node.nodeValue ?? '').trim().length === 0;\n}\n\nfunction sameKind(a: Node, b: Node): boolean {\n if (a.nodeType !== b.nodeType) return false;\n if (a instanceof Element && b instanceof Element) {\n return a.tagName === b.tagName && a.namespaceURI === b.namespaceURI;\n }\n return true;\n}\n\n/** First element per key; later duplicates are left as they are and pair positionally. */\nfunction indexKeyed(parent: Element, options: MorphOptions): Map<string, Element> {\n const keyed = new Map<string, Element>();\n let duplicate: string | undefined;\n for (const child of Array.from(parent.children)) {\n const key = keyOf(child, options);\n if (key === undefined) continue;\n if (keyed.has(key)) {\n duplicate ??= key.slice(key.indexOf('=') + 1);\n continue;\n }\n keyed.set(key, child);\n }\n if (duplicate !== undefined) options.onDuplicateKey?.(parent, duplicate);\n return keyed;\n}\n\ninterface FocusSnapshot {\n readonly element: HTMLElement;\n readonly selection: readonly [number | null, number | null] | null;\n}\n\n/** A keyed move is a remove-and-insert, which blurs; remember what had focus. */\nfunction captureFocus(live: Element): FocusSnapshot | null {\n const active = live.ownerDocument.activeElement;\n if (!(active instanceof HTMLElement) || !live.contains(active)) return null;\n const selection =\n active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement\n ? ([active.selectionStart, active.selectionEnd] as const)\n : null;\n return { element: active, selection };\n}\n\nfunction restoreFocus(snapshot: FocusSnapshot | null): void {\n if (snapshot === null) return;\n const { element, selection } = snapshot;\n if (element.ownerDocument.activeElement === element || !element.isConnected) return;\n try {\n element.focus({ preventScroll: true });\n const [start, end] = selection ?? [null, null];\n if (start !== null && end !== null) {\n (element as HTMLInputElement).setSelectionRange(start, end);\n }\n } catch {\n // Not focusable any more; nothing to restore.\n }\n}\n","/**\n * Sanitizer options for item templates (`data-payload-array-template`,\n * nested templates). A template is the page author's markup and every\n * interpolated value is escaped to text before the sanitizer runs, so it may\n * carry form controls and custom elements the rich-text policy refuses.\n * Event handlers, `style` and unsafe URLs are still stripped.\n *\n * Some entries below are already admitted by the sanitizer through another\n * route — `video` and `audio` by the tag allow-list, `select` by\n * `allowFormControls`, `name` by `templateMode`, and `controls`, `muted`,\n * `loop`, `poster` and `src` by the per-tag attribute map. They are kept\n * because this list states what a template may contain, and an allow-list\n * that depends on a second list staying unchanged is the more fragile of the\n * two arrangements. Mutating those entries changes nothing observable, so\n * they survive mutation testing by construction; the behaviour they describe\n * is pinned in `tests/unit/core/template-sanitize.test.ts` instead.\n */\n\nimport type { SanitizeOptions } from '@security/sanitizer';\nimport { lruGet, lruSet } from './lru';\n\nconst TEMPLATE_EXTRA_TAGS: readonly string[] = [\n 'input',\n 'textarea',\n 'select',\n 'option',\n 'button',\n 'label',\n 'details',\n 'summary',\n 'dialog',\n 'video',\n 'audio',\n 'progress',\n 'meter',\n];\n\nconst TEMPLATE_EXTRA_ATTRIBUTES: readonly string[] = [\n 'type',\n 'name',\n 'placeholder',\n 'open',\n 'disabled',\n 'readonly',\n 'required',\n 'checked',\n 'selected',\n 'value',\n 'min',\n 'max',\n 'step',\n 'rows',\n 'cols',\n 'for',\n 'controls',\n 'muted',\n 'loop',\n 'poster',\n 'src',\n];\n\nconst CUSTOM_TAG_PATTERN = /<([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\\b/gi;\n\n// 64 like the intl cache: more than a page declares, and a nested template is\n// interpolated with its parent's, so an outer value or `{{index}}` that lands\n// in it mints a key per item and per keystroke (ADR 0003 §3).\nexport const TEMPLATE_CACHE_LIMIT = 64;\nconst optionsByTemplate = new Map<string, SanitizeOptions>();\n\n/** Options for one template; memoised per template string. */\nexport function templateSanitizeOptions(template: string): SanitizeOptions {\n const cached = lruGet(optionsByTemplate, template);\n if (cached !== undefined) return cached;\n const tags = new Set(TEMPLATE_EXTRA_TAGS);\n for (const match of template.matchAll(CUSTOM_TAG_PATTERN)) {\n const tag = match[1]?.toLowerCase();\n if (tag !== undefined) tags.add(tag);\n }\n const attributes: Record<string, readonly string[]> = {};\n for (const tag of tags) attributes[tag] = TEMPLATE_EXTRA_ATTRIBUTES;\n const options: SanitizeOptions = {\n additionalAllowedTags: [...tags],\n additionalAllowedAttributes: attributes,\n allowFormControls: true,\n templateMode: true,\n };\n return lruSet(optionsByTemplate, template, options, TEMPLATE_CACHE_LIMIT);\n}\n","/**\n * Applies an `ArrayPatch[]` diff to a container as keyed DOM operations\n * instead of rebuilding the list, so consumer state on surviving children is\n * kept. Items are paired by `data-payload-key` (the item `id`); items without\n * one pair by position. Nested arrays reconcile recursively through\n * `data-payload-nested-key` slots. See ADR 0008.\n */\n\nimport { sanitizeHtmlWithPolicy, type SanitizerPolicyMode } from '@security/sanitizer';\nimport { trustedHtml } from '@security/trusted-types';\nimport {\n collectTemplateKeys,\n inheritItemAttributes,\n interpolateArrayTemplate,\n sharedItemAttributes,\n type InheritedAttribute,\n} from './array-template';\nimport { safeStringify } from '@field-types/utils';\nimport { diffArray, type ArrayPatch } from '@schema/diff';\nimport { morphElement } from './morph';\nimport { templateSanitizeOptions } from './template-sanitize';\n\n/** @internal */\nexport const KEY_ATTRIBUTE = 'data-payload-key';\nconst NESTED_KEY_ATTRIBUTE = 'data-payload-nested-key';\nconst NESTED_TEMPLATE_ATTRIBUTE = 'data-payload-nested-template';\n\n/** Last value seen per item key, per container; owned by the caller so instances never share it. @internal */\nexport type StructuralStore = WeakMap<Element, Map<string, unknown>>;\n\n/** @internal */\nexport function createStructuralStore(): StructuralStore {\n return new WeakMap<Element, Map<string, unknown>>();\n}\n\n/** @internal */\nexport interface StructuralApplyOptions {\n readonly template: string;\n readonly container: Element;\n readonly patches: readonly ArrayPatch[];\n /** The full new array; inserts and replaces render by index from it. */\n readonly nextItems: readonly unknown[];\n /** Pass the same store across renders so nested arrays diff incrementally. */\n readonly store: StructuralStore;\n /** Re-render existing items even when unchanged. */\n readonly forceRender?: boolean;\n /** The instance's policy for item markup; absent, the process default applies. */\n readonly sanitizerPolicy?: SanitizerPolicyMode | undefined;\n /** Edit a changed item in place instead of replacing it. Default `true`. */\n readonly morph?: boolean;\n /** Reported once per container when two items share a key (`LP0405`). */\n readonly onDuplicateKey?: (container: Element, key: string) => void;\n}\n\n/**\n * Returns `true` for a DOM mutation, `false` for an already-current tree, and\n * `null` when an item's markup has no sanitized element root — preflighted\n * before any mutation, so the previous DOM and memory stay intact.\n * @internal\n */\nexport function applyStructuralPatches(options: StructuralApplyOptions): boolean | null {\n const plan = prepareStructuralPlan(options.container, options.patches, options);\n if (plan === null) return null;\n return commitStructuralPlan(plan, options.store, {\n morph: options.morph ?? true,\n onDuplicateKey: options.onDuplicateKey,\n });\n}\n\n// Plan records are tuples: many are created per recursive render, and named\n// keys would repeat in the inline bundle.\ntype StructuralPlan = readonly [\n container: Element,\n entries: readonly ReconciliationEntry[],\n nextItems: readonly unknown[],\n];\ntype ReconciliationEntry = readonly [\n index: number,\n live: Element | null,\n rendered: Element | undefined,\n nestedSlots: readonly NestedSlotPlan[],\n /** A `replace` patch: a different item, never morphed toward. */\n replace: boolean,\n];\ntype NestedSlotPlan = readonly [\n live: Element | null,\n rendered: Element,\n children: StructuralPlan | undefined,\n];\n\n// One per container, not per item, so — unlike the tuples above — named keys\n// cost the inline bundle nothing per render.\ntype RenderEnv = Pick<\n StructuralApplyOptions,\n 'template' | 'nextItems' | 'forceRender' | 'store' | 'sanitizerPolicy'\n>;\n\ninterface CommitOptions {\n readonly morph: boolean;\n readonly onDuplicateKey: ((container: Element, key: string) => void) | undefined;\n}\n\n/** A rendered slot that still carries a nested template keeps its children for its own plan. */\nfunction isManagedNestedSlot(_live: Element, rendered: Element): boolean {\n return (\n rendered.hasAttribute(NESTED_KEY_ATTRIBUTE) && rendered.hasAttribute(NESTED_TEMPLATE_ATTRIBUTE)\n );\n}\n\n/** Materialise the whole recursive replacement tree before touching live DOM. */\nfunction prepareStructuralPlan(\n container: Element,\n patches: readonly ArrayPatch[],\n env: RenderEnv,\n): StructuralPlan | null {\n const entries = prepareReconciliation(container, createPatchPlan(patches), env);\n return entries === null ? null : [container, entries, env.nextItems];\n}\n\nfunction commitStructuralPlan(\n plan: StructuralPlan,\n store: StructuralStore,\n options: CommitOptions,\n): boolean {\n const [container, entries, nextItems] = plan;\n const claimed = new Set<Element>();\n let mutated = false;\n for (const [index, live, rendered, nestedSlots, replace] of entries) {\n let node = live;\n if (rendered !== undefined) {\n // Morph a compatible live item in place; otherwise transplant its live\n // nested slots into the rendered item and swap.\n const retained =\n options.morph && !replace && live !== null\n ? morphElement(live, rendered, {\n keyAttributes: [KEY_ATTRIBUTE, NESTED_KEY_ATTRIBUTE],\n retainChildrenOf: isManagedNestedSlot,\n ...(options.onDuplicateKey !== undefined\n ? { onDuplicateKey: options.onDuplicateKey }\n : {}),\n }) === live\n : false;\n if (!retained) {\n for (const [liveSlot, renderedSlot] of nestedSlots) {\n if (liveSlot === null) continue;\n synchronizeAttributes(liveSlot, renderedSlot);\n renderedSlot.replaceWith(liveSlot);\n }\n }\n for (const [, , children] of nestedSlots) {\n if (children !== undefined) commitStructuralPlan(children, store, options);\n }\n if (retained) {\n mutated = true;\n } else {\n if (live !== null) {\n live.replaceWith(rendered);\n mutated = true;\n }\n node = rendered;\n }\n }\n if (node === null) continue;\n const before = container.children[index] ?? null;\n if (node !== before) {\n container.insertBefore(node, before);\n mutated = true;\n }\n claimed.add(node);\n }\n // `nextItems` is the source of truth; this also drops SSR children the first value did not carry.\n for (const child of Array.from(container.children)) {\n if (claimed.has(child)) continue;\n child.remove();\n mutated = true;\n }\n const memory = getMemory(container, store);\n memory.clear();\n for (const value of nextItems) rememberItem(memory, value);\n return mutated;\n}\n\n/**\n * Pair every final item with a live child (by key, else by position) and\n * render what needs rendering. Patch indices describe `next`, live indices\n * move during reconciliation, so keyed nodes are resolved from the DOM first.\n */\nfunction prepareReconciliation(\n container: Element,\n plan: PatchPlan,\n env: RenderEnv,\n): readonly ReconciliationEntry[] | null {\n const { template, nextItems, forceRender = false, store, sanitizerPolicy } = env;\n const memory = store.get(container);\n // Read before anything is rendered: what the current items share is what the\n // template cannot say, and an inserted item has no predecessor of its own.\n const shared = sharedItemAttributes(container);\n const templateKeys = collectTemplateKeys(nextItems);\n const initialChildren = Array.from(container.children);\n const keyedChildren = indexByAttribute(initialChildren, KEY_ATTRIBUTE);\n const reserved = new Set<Element>();\n const entries: ReconciliationEntry[] = [];\n for (let index = 0; index < nextItems.length; index += 1) {\n const value = nextItems[index];\n const key = readKey(value);\n let live =\n key === undefined\n ? (initialChildren[index] ?? null)\n : (takeIndexedElement(keyedChildren, key) ?? null);\n if (live !== null && reserved.has(live)) live = null;\n if (live !== null) reserved.add(live);\n const replace = plan.replaces.has(index);\n const needsRender = forceRender || plan.renders.has(index) || live === null;\n const rendered = needsRender\n ? renderItem(\n container.ownerDocument,\n template,\n value,\n index,\n sanitizerPolicy,\n shared,\n templateKeys,\n )\n : undefined;\n if (rendered === null) return null;\n const nestedSlots =\n rendered === undefined\n ? []\n : prepareNestedSlots(\n replace ? null : live,\n rendered,\n value,\n key === undefined ? undefined : memory?.get(key),\n env,\n );\n if (nestedSlots === null) return null;\n entries.push([index, live, rendered, nestedSlots, replace]);\n }\n return entries;\n}\n\ninterface PatchPlan {\n readonly renders: ReadonlySet<number>;\n readonly replaces: ReadonlySet<number>;\n}\n\nfunction createPatchPlan(patches: readonly ArrayPatch[]): PatchPlan {\n const renders = new Set<number>();\n const replaces = new Set<number>();\n for (const patch of patches) {\n if (patch.kind === 'insert' || patch.kind === 'update') renders.add(patch.index);\n else if (patch.kind === 'replace') {\n renders.add(patch.index);\n replaces.add(patch.index);\n }\n }\n return { renders, replaces };\n}\n\n/** Plan each direct nested slot; a failure at any depth aborts before commit. */\nfunction prepareNestedSlots(\n oldItem: Element | null,\n newItem: Element,\n nextValue: unknown,\n prevValue: unknown,\n env: RenderEnv,\n): readonly NestedSlotPlan[] | null {\n const oldSlots = oldItem === null ? [] : findDirectNestedSlots(oldItem);\n const oldSlotsByKey = indexByAttribute(oldSlots, NESTED_KEY_ATTRIBUTE);\n const plans: NestedSlotPlan[] = [];\n for (const newSlot of findDirectNestedSlots(newItem)) {\n const key = newSlot.getAttribute(NESTED_KEY_ATTRIBUTE);\n if (key === null) continue;\n const oldSlot = takeIndexedElement(oldSlotsByKey, key) ?? null;\n const nextTemplate = newSlot.getAttribute(NESTED_TEMPLATE_ATTRIBUTE);\n // Without a nested template the slot's rendered static content is authoritative.\n const liveSlot = nextTemplate ? oldSlot : null;\n const previousTemplate = liveSlot?.getAttribute(NESTED_TEMPLATE_ATTRIBUTE) ?? null;\n let children: StructuralPlan | undefined;\n if (nextTemplate) {\n const nextNested = readNestedArray(nextValue, key);\n if (nextNested !== undefined || liveSlot !== null) {\n const resolvedNext = nextNested ?? [];\n const prevNested = liveSlot === null ? [] : (readNestedArray(prevValue, key) ?? []);\n const patches = diffArray(prevNested, resolvedNext);\n const templateChanged = liveSlot !== null && previousTemplate !== nextTemplate;\n if (patches.length > 0 || templateChanged) {\n children =\n prepareStructuralPlan(liveSlot ?? newSlot, patches, {\n template: nextTemplate,\n nextItems: resolvedNext,\n forceRender: templateChanged,\n store: env.store,\n sanitizerPolicy: env.sanitizerPolicy,\n }) ?? undefined;\n if (children === undefined) return null;\n }\n }\n }\n plans.push([liveSlot, newSlot, children]);\n }\n return plans;\n}\n\n/** Only the outermost nested slots: a transplanted slot owns the recursion below it. */\nfunction findDirectNestedSlots(item: Element): readonly Element[] {\n return Array.from(item.querySelectorAll(`[${NESTED_KEY_ATTRIBUTE}]`)).filter((slot) => {\n let ancestor = slot.parentElement;\n while (ancestor !== null && ancestor !== item) {\n if (ancestor.hasAttribute(NESTED_KEY_ATTRIBUTE)) return false;\n ancestor = ancestor.parentElement;\n }\n return ancestor === item;\n });\n}\n\nfunction synchronizeAttributes(target: Element, source: Element): void {\n for (const attribute of Array.from(target.attributes)) {\n if (!source.hasAttribute(attribute.name)) target.removeAttribute(attribute.name);\n }\n for (const attribute of Array.from(source.attributes)) {\n if (target.getAttribute(attribute.name) !== attribute.value) {\n target.setAttribute(attribute.name, attribute.value);\n }\n }\n}\n\nfunction readNestedArray(value: unknown, key: string): readonly unknown[] | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const nested = (value as Record<string, unknown>)[key];\n return Array.isArray(nested) ? (nested as readonly unknown[]) : undefined;\n}\n\nfunction getMemory(container: Element, store: StructuralStore): Map<string, unknown> {\n let map = store.get(container);\n if (!map) {\n map = new Map();\n store.set(container, map);\n }\n return map;\n}\n\nfunction rememberItem(memory: Map<string, unknown>, value: unknown): void {\n const key = readKey(value);\n if (key !== undefined) memory.set(key, value);\n}\n\nfunction readKey(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const id = (value as Record<string, unknown>)['id'];\n return typeof id === 'string' || typeof id === 'number' ? String(id) : undefined;\n}\n\nfunction indexByAttribute(elements: readonly Element[], attribute: string): Map<string, Element[]> {\n const indexed = new Map<string, Element[]>();\n // Reverse order so pop() yields duplicates in DOM order.\n for (let index = elements.length - 1; index >= 0; index -= 1) {\n const element = elements[index];\n if (element === undefined) continue;\n const key = element.getAttribute(attribute);\n if (key === null) continue;\n const bucket = indexed.get(key);\n if (bucket === undefined) indexed.set(key, [element]);\n else bucket.push(element);\n }\n return indexed;\n}\n\nfunction takeIndexedElement(indexed: Map<string, Element[]>, key: string): Element | undefined {\n return indexed.get(key)?.pop();\n}\n\n/** Render one item; its `id` is stamped as `data-payload-key` so later diffs find it. */\nfunction renderItem(\n ownerDocument: Document,\n template: string,\n value: unknown,\n index: number,\n policy: SanitizerPolicyMode | undefined,\n shared: readonly InheritedAttribute[],\n knownKeys: ReadonlySet<string>,\n): Element | null {\n const filled = interpolateArrayTemplate(template, value, index, safeStringify, knownKeys);\n const safe = sanitizeHtmlWithPolicy(filled, policy, templateSanitizeOptions(template));\n const host = ownerDocument.createElement('template');\n host.innerHTML = trustedHtml(safe);\n const first = host.content.firstElementChild;\n if (!first) return null;\n // Before the morph, which strips from the live item every attribute the\n // rendered one lacks: the marker has to be on this side to survive.\n inheritItemAttributes(first, shared);\n const key = readKey(value);\n if (key !== undefined) first.setAttribute(KEY_ATTRIBUTE, key);\n return first;\n}\n","/**\n * LRU discipline for a module-scoped lookup `Map` (ADR 0003 §3). Functions\n * over the caller's own `Map` rather than a wrapper class: the inline bundle\n * mangles function names but not property names, so a class would pay for\n * every `this.entries` in full. A `Map` iterates in insertion order, which a\n * touch on every hit turns into recency order. Values are never `undefined`,\n * and a write follows a miss — a key already present keeps its position.\n */\n\n/** Read and touch: a hit becomes the newest entry. */\nexport function lruGet<K, V>(map: Map<K, V>, key: K): V | undefined {\n const value = map.get(key);\n if (value !== undefined) {\n map.delete(key);\n map.set(key, value);\n }\n return value;\n}\n\n/** Write as the newest entry, dropping the oldest ones past `limit`; returns `value`. */\nexport function lruSet<K, V>(map: Map<K, V>, key: K, value: V, limit: number): V {\n map.set(key, value);\n lruTrim(map, limit);\n return value;\n}\n\n/** Drop the oldest entries until `limit` holds. */\nexport function lruTrim<K>(map: Map<K, unknown>, limit: number): void {\n for (const oldest of map.keys()) {\n if (map.size <= limit) break;\n map.delete(oldest);\n }\n}\n","/**\n * `structural-array` renderer (`data-payload-structural`): diffs the previous\n * and next item lists and patches the container through the keyed morph\n * (ADR 0008). All diff memory lives in the closure, one per client.\n */\n\nimport { safeConsoleWarn } from '@core/diagnostics';\nimport { markNoWriteCallback } from '@core/internal-outcome';\nimport {\n applyStructuralPatches,\n createStructuralStore,\n KEY_ATTRIBUTE,\n type StructuralStore,\n} from '@core/structural-applier';\nimport { diffArray } from '@schema/diff';\nimport type { FieldRenderer } from '@core/types';\nimport { isEmptyValue } from './utils';\n\ninterface StructuralRenderState {\n readonly values: readonly unknown[];\n readonly template: string;\n readonly domSnapshot: readonly (string | null)[];\n}\n\ntype WarnedCodes = WeakMap<Element, Set<string>>;\n\n/** @internal */\nexport function createStructuralArrayRenderer(): FieldRenderer {\n const states = new WeakMap<Element, StructuralRenderState>();\n const warnedContainers = new WeakSet<Element>();\n const warnedKeys: WarnedCodes = new WeakMap();\n const store: StructuralStore = createStructuralStore();\n\n return {\n name: 'structural-array',\n render: /* @__PURE__ */ markNoWriteCallback((target, rawValue, context) => {\n const value = isEmptyValue(rawValue) ? [] : rawValue;\n if (!Array.isArray(value)) return false;\n const container = target.element;\n const template = target.arrayTemplate;\n if (template === undefined || template.length === 0) {\n warnMissingTemplate(warnedContainers, container, target.fieldName);\n return false;\n }\n const previousState = states.get(container);\n const domSnapshot = readDomKeySnapshot(container);\n const previous = previousState?.values ?? valuesFromDomSnapshot(domSnapshot);\n const patches = diffArray(previous, value);\n const forceRender = needsForcedRender(previousState, template, domSnapshot);\n if (patches.length === 0 && !forceRender) {\n states.set(container, { values: value.slice(), template, domSnapshot });\n return false;\n }\n warnAboutKeys(warnedKeys, container, target.fieldName, previousState?.values, value);\n const applied = applyStructuralPatches({\n template,\n container,\n patches,\n nextItems: value,\n store,\n forceRender,\n sanitizerPolicy: context.sanitizerPolicy,\n onDuplicateKey: (owner, key) => {\n warnDuplicateKey(warnedKeys, owner, target.fieldName, key);\n },\n });\n if (applied === null) return false;\n states.set(container, {\n values: value.slice(),\n template,\n domSnapshot: readDomKeySnapshot(container),\n });\n return applied ? undefined : false;\n }),\n };\n}\n\nfunction needsForcedRender(\n previous: StructuralRenderState | undefined,\n template: string,\n domSnapshot: readonly (string | null)[],\n): boolean {\n if (previous === undefined) return true;\n return previous.template !== template || !sameDomKeySnapshot(previous.domSnapshot, domSnapshot);\n}\n\n// SSR markup exists before any in-memory snapshot; its direct-child keys let\n// the first update reconcile instead of appending a second copy.\nfunction readDomKeySnapshot(container: Element): readonly (string | null)[] {\n return Array.from(container.children, (child) => child.getAttribute(KEY_ATTRIBUTE));\n}\n\nfunction valuesFromDomSnapshot(snapshot: readonly (string | null)[]): readonly unknown[] {\n return snapshot.map((key, position) =>\n key === null ? { __payloadDomPosition: position } : { id: key },\n );\n}\n\nfunction sameDomKeySnapshot(\n previous: readonly (string | null)[],\n current: readonly (string | null)[],\n): boolean {\n if (previous.length !== current.length) return false;\n return previous.every((key, index) => key === current[index]);\n}\n\nfunction warnMissingTemplate(\n warnedContainers: WeakSet<Element>,\n container: Element,\n fieldName: string,\n): void {\n if (warnedContainers.has(container)) return;\n warnedContainers.add(container);\n safeConsoleWarn(\n `[live-preview] LP0403: Skipping structural update for \"${fieldName}\": ` +\n `<${container.tagName.toLowerCase()} data-payload-structural> needs ` +\n `data-payload-array-template (for example \"<li>{{label}}</li>\").`,\n );\n}\n\nfunction itemKey(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const id = (value as Record<string, unknown>)['id'];\n return typeof id === 'string' || typeof id === 'number' ? String(id) : undefined;\n}\n\n/** Key problems degrade the morph, they do not break it; each is announced once per container (ADR 0008 §5). */\nfunction warnAboutKeys(\n warned: WarnedCodes,\n container: Element,\n fieldName: string,\n previous: readonly unknown[] | undefined,\n next: readonly unknown[],\n): void {\n const nextKeys = next.map(itemKey);\n const seen = new Set<string>();\n const duplicate = nextKeys.find((key) => {\n if (key === undefined) return false;\n if (seen.has(key)) return true;\n seen.add(key);\n return false;\n });\n if (duplicate !== undefined) warnDuplicateKey(warned, container, fieldName, duplicate);\n if (nextKeys.some((key) => key === undefined)) {\n warnOnce(\n warned,\n container,\n 'LP0404',\n `LP0404: an item of \"${fieldName}\" has no id and pairs by ` +\n 'position, so an insert re-renders every row after it. Give items a stable id.',\n );\n }\n if (previous?.length === next.length && next.length > 1) {\n const previousKeys = new Set(previous.map(itemKey).filter((key) => key !== undefined));\n const stable = nextKeys.some((key) => key !== undefined && previousKeys.has(key));\n if (previousKeys.size > 0 && !stable) {\n warnOnce(\n warned,\n container,\n 'LP0406',\n `LP0406: every key of \"${fieldName}\" changed at once; the ` +\n 'source generates ids per message, so no item can be retained across updates.',\n );\n }\n }\n}\n\n// Reached from the pre-diff check and from the morph's nested-slot check; one site, one message.\nfunction warnDuplicateKey(\n warned: WarnedCodes,\n owner: Element,\n fieldName: string,\n key: string,\n): void {\n warnOnce(\n warned,\n owner,\n 'LP0405',\n `LP0405: two items of \"${fieldName}\" share the key \"${key}\"; later ones pair by ` +\n 'position. Make `id` unique per item.',\n );\n}\n\nfunction warnOnce(warned: WarnedCodes, container: Element, code: string, message: string): void {\n let codes = warned.get(container);\n if (codes === undefined) {\n codes = new Set();\n warned.set(container, codes);\n }\n if (codes.has(code)) return;\n codes.add(code);\n safeConsoleWarn(`[live-preview] ${message}`);\n}\n","/**\n * One source → dependents map for `skipUnchanged`. Markup declares it the\n * other way round (`data-payload-depends=\"price\"` on the element bound to\n * `priceLabel`) because an author names what a binding needs; the runtime\n * option is keyed by source because the scheduler asks what changed.\n * @internal\n */\n\nexport type DependencyMap = Readonly<Record<string, readonly string[]>>;\n\n/**\n * Field names from an attribute value. Separators are commas and\n * whitespace; empty entries are dropped; order is kept, duplicates removed.\n * @internal\n */\nexport function parseDependencyList(value: string | null | undefined): readonly string[] {\n if (value === null || value === undefined) return [];\n const seen = new Set<string>();\n const names: string[] = [];\n for (const raw of value.split(/[\\s,]+/)) {\n const name = raw.trim();\n if (name.length === 0 || seen.has(name)) continue;\n seen.add(name);\n names.push(name);\n }\n return names;\n}\n\n/**\n * Merge dependency maps (source → dependents). Later maps add to earlier\n * ones; a dependent is listed once per source.\n * @internal\n */\nexport function mergeDependencyMaps(...maps: readonly DependencyMap[]): DependencyMap {\n const merged = new Map<string, Set<string>>();\n for (const map of maps) {\n for (const [source, dependents] of Object.entries(map)) {\n let bucket = merged.get(source);\n if (bucket === undefined) {\n bucket = new Set();\n merged.set(source, bucket);\n }\n for (const dependent of dependents) bucket.add(dependent);\n }\n }\n const result: Record<string, readonly string[]> = {};\n for (const [source, dependents] of merged) result[source] = [...dependents];\n return result;\n}\n\n/**\n * The map an element's `data-payload-depends` contributes: every declared\n * source points at this binding's field.\n * @internal\n */\nexport function dependencyMapFromBinding(\n fieldName: string,\n dependsOn: readonly string[],\n): DependencyMap {\n const map: Record<string, readonly string[]> = {};\n for (const source of dependsOn) {\n if (source === fieldName) continue;\n map[source] = [fieldName];\n }\n return map;\n}\n"],"mappings":"aA8BO,IAtBLA,ECcEC,EDQSC,GAtBXF,EAsB+C,IAAIG,IAClDC,QAAQC,QAA8CF,GArBhD,IAAIA,KACT,KEFoB,iBADcG,EFIVN,KAAcG,KEHI,OAAVG,GAAoC,mBAAVA,IACD,mBAA/CA,EAAsCC,MAC7CC,QAAQC,QAAQH,GAAOI,MAAM,OFEhC,OAEA,CEPG,IAA+BJ,ICChCK,iBAAA,IAAuBC,QAGtB,SAASC,EAAwCC,GAEtD,OADAH,EAAiBI,IAAID,GACdA,CACT,CF0CO,SAASE,EAAYC,GAC1B,MAAMC,EAnBR,WAEE,QAAmB,IAAfjB,EAA0B,OAAOA,EACrC,MAAMkB,EAVR,WACE,MAAMC,EAAaC,WAA0CC,aAC7D,GAAyB,iBAAdF,GAAwC,OAAdA,EAErC,MAAyB,mBADTA,EAAyCG,aAClBH,OAAwC,CACjF,CAKcI,GACZ,IACEvB,OACU,IAARkB,EACI,KACAA,EAAII,aA5B2B,uBA4Ba,CAAEE,WAAaC,GAAUA,GAC7E,OAGEzB,EAAa,IACf,CACA,OAAOA,CACT,CAIiB0B,GACf,OAAe,OAAXT,EAAwBD,EACrBC,EAAOO,WAAWR,EAC3B,CGxDA,IAAMW,iBAAA,IAA0CC,IAAI,CAAC,QAAS,SAAU,UAAW,SAG7EC,EAA6B,wDAE7BC,EAAgB,mCAIhBC,EAAoB,YAGpBC,EAAiB,YAGhB,SAASC,UAAUC,GACxB,GAAmB,iBAARA,EAAkB,OAAO,EACpC,MAAMC,EAAUD,EAAIE,OAAOC,QAAQL,EAAgB,IACnD,GAAuB,IAAnBG,EAAQG,OAAc,OAAO,EACjC,GAAIT,EAA2BU,KAAKJ,GAAU,OAAO,EACrD,GAAIA,EAAQK,WAAW,MAAQL,EAAQK,WAAW,KAAM,OAAO,EAC/D,GAAIT,EAAkBQ,KAAKJ,GAAU,OAAO,EAC5C,GAAIA,EAAQK,WAAW,KAAM,OAAO,EACpC,IACE,MAAMC,EAAS,IAAIC,IAAIP,GACvB,OAAOR,EAAegB,IAAIF,EAAOG,SACnC,OACE,OAAOd,EAAcS,KAAKJ,EAC5B,CACF,CCHA,IAAMU,iBAAA,IAAejB,IA4Bd,SAASkB,EAAuBC,GACjCF,EAASF,IAAII,KACjBF,EAAS/B,IAAIiC,GAtCf,SAAcC,GACZ,IACE7C,QAAQC,KAAK4C,EACf,OAEA,CACF,CAiCE5C,CACE,yDAAyD2C,qFA3B7D,SAAgBA,GACd,OAAIA,EAAKP,WAHY,iBAKjB,0IAIS,OAATO,GAA0B,SAATA,EAEjB,+HAKF,+HAGJ,CAWkEE,CAAOF,OAEzE,CCrDA,IAAMG,iBAAA,IAAwCtB,IAAI,CAChD,IACA,KACA,SACA,IACA,KACA,IACA,IACA,IACA,SACA,OACA,QACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,aACA,OACA,MACA,MACA,OACA,MACA,IACA,OACA,MACA,UACA,UACA,QACA,SACA,SACA,MACA,SACA,aACA,MACA,UACA,SACA,QACA,QACA,MACA,MACA,KACA,OACA,OACA,OACA,IACA,QACA,QACA,QACA,QACA,KACA,KACA,KACA,UACA,WACA,QAIIuB,iBAAA,IAAyCvB,IAAI,CACjD,QACA,SACA,WACA,SACA,SACA,UAIIwB,iBAAA,IAA6CxB,IAAI,CACrD,SACA,QACA,SACA,SACA,QACA,OACA,OACA,OACA,OACA,QACA,SACA,SACA,WACA,MACA,OACA,WACA,QACA,WACA,WACA,aAGIyB,iBAAA,IAAuCzB,IAAI,CAC/C,KACA,QACA,OACA,MACA,QACA,OACA,aAGI0B,EAAmB,QACnBC,EAAmB,QAGnBC,EAA6D,CACjEC,iBAAG,IAAI7B,IAAI,CAAC,OAAQ,SAAU,MAAO,WAAY,WAAY,SAC7D8B,mBAAK,IAAI9B,IAAI,CAAC,MAAO,SAAU,QAAS,MAAO,QAAS,SAAU,UAAW,aAC7E+B,uBAAS,IAAI/B,IAAI,IACjBgC,sBAAA,IAAYhC,IAAI,CAAC,MAAO,SAAU,QAAS,OAAQ,UACnDiC,qBAAO,IAAIjC,IAAI,CAAC,MAAO,WAAY,WAAY,OAAQ,QAAS,YAChEkC,qBAAA,IAAWlC,IAAI,CACb,MACA,SACA,WACA,WACA,OACA,QACA,UACA,QACA,SACA,gBAEFmC,oBAAM,IAAInC,IAAI,CAAC,aACfoC,oBAAM,IAAIpC,IAAI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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"structural.cjs","names":["diagnostic","autoPolicy","safeConsoleWarn","args","console","warn","value","then","Promise","resolve","catch","noWriteCallbacks","WeakSet","markNoWriteCallback","callback","add","trustedHtml","html","policy","api","candidate","globalThis","trustedTypes","createPolicy","factory","createHTML","input","resolvePolicy","SAFE_PROTOCOLS","Set","DANGEROUS_PROTOCOL_PATTERN","RELATIVE_PATH","PROTOCOL_RELATIVE","PARSER_IGNORED","isSafeUrl","url","trimmed","trim","replace","length","test","startsWith","parsed","URL","has","protocol","reported","reportDroppedAttribute","name","message","reason","ALLOWED_TAGS","FORM_CONTROLS","REMOVE_COMPLETELY","ATTR_GLOBAL","ATTR_ARIA_PREFIX","ATTR_DATA_PREFIX","ATTR_BY_TAG","a","img","picture","source","audio","video","time","abbr","q","blockquote","table","th","td","col","colgroup","ol","li","code","pre","URL_ATTRIBUTES","SanitizerEnvironmentError","Error","TEMPLATE_ATTRIBUTES","DOCUMENT_SLOT","Symbol","for","sanitizeFragment","node","child","Array","from","childNodes","nodeType","sanitizeElement","remove","element","tag","tagName","toLowerCase","allowFormControls","allowedTags","replaceWith","tagAttrs","attrByTag","get","attr","attributes","removeAttribute","mode","templateMode","allowedData","isSafeSrcset","sanitizeAttributes","anchor","href","getAttribute","isExternalHttpUrl","setAttribute","hasAttribute","hardenAnchor","split","HTML_ESCAPES","Object","freeze","HTML_ESCAPE_PATTERN","escapeHtml","text","char","BLOCKED_ATTRIBUTES","isWritableAttribute","PLACEHOLDER_PATTERN","safeStringify","String","JSON","stringify","getId","item","id","getBlockType","blockType","diffArray","prev","next","every","patches","prevIndexById","Map","i","set","consumedFromPrev","to","push","kind","index","prevItem","shallowEqual","oldValue","diffById","min","Math","diffByPosition","b","is","aRec","bRec","aKeys","keys","bKeys","key","ISLAND_ATTRIBUTE","OWNED_ATTRIBUTE","STATE_ATTRIBUTES","keyOf","options","attribute","keyAttributes","isMorphBoundary","includes","editable","isMorphCompatible","live","rendered","namespaceURI","morphElement","focus","active","ownerDocument","activeElement","HTMLElement","contains","selection","HTMLInputElement","HTMLTextAreaElement","selectionStart","selectionEnd","captureFocus","syncAttributes","retainChildrenOf","liveKeyed","parent","keyed","duplicate","children","slice","indexOf","onDuplicateKey","indexKeyed","keyedElements","values","liveUnkeyed","filter","claimed","usedKeys","renderedNodes","cursor","firstChild","unkeyedIndex","kept","Element","reconcile","nextSibling","sameKind","replaceChild","following","isBlankText","insertBefore","morphChildren","snapshot","isConnected","preventScroll","start","end","setSelectionRange","restoreFocus","nodeValue","Node","TEXT_NODE","TEMPLATE_EXTRA_TAGS","TEMPLATE_EXTRA_ATTRIBUTES","CUSTOM_TAG_PATTERN","optionsByTemplate","KEY_ATTRIBUTE","NESTED_KEY_ATTRIBUTE","NESTED_TEMPLATE_ATTRIBUTE","createStructuralStore","WeakMap","applyStructuralPatches","plan","prepareStructuralPlan","container","commitStructuralPlan","store","morph","isManagedNestedSlot","_live","env","entries","template","nextItems","forceRender","sanitizerPolicy","memory","shared","items","first","everyItem","sharedItemAttributes","templateKeys","collectTemplateKeys","initialChildren","keyedChildren","indexByAttribute","reserved","readKey","takeIndexedElement","replaces","renders","renderItem","nestedSlots","prepareNestedSlots","prepareReconciliation","patch","createPatchPlan","mutated","retained","liveSlot","renderedSlot","synchronizeAttributes","before","map","getMemory","clear","rememberItem","oldItem","newItem","nextValue","prevValue","oldSlotsByKey","findDirectNestedSlots","plans","newSlot","oldSlot","nextTemplate","previousTemplate","nextNested","readNestedArray","resolvedNext","templateChanged","querySelectorAll","slot","ancestor","parentElement","target","nested","isArray","elements","indexed","bucket","pop","knownKeys","safe","doc","__INLINE_BUILD__","override","document","resolveDocument","resolved","instancePolicy","attrMap","attrs","allowed","additionalAllowedTags","forEach","additionalAllowedAttributes","merged","allowedDataAttributes","createElement","innerHTML","content","sanitizeHtmlWithPolicy","record","placeholder","prototype","hasOwnProperty","call","hasOwn","Reflect","interpolateArrayTemplate","cached","delete","lruGet","tags","match","matchAll","oldest","size","limit","lruTrim","templateSanitizeOptions","host","firstElementChild","inheritItemAttributes","readDomKeySnapshot","itemKey","warnDuplicateKey","warned","owner","fieldName","warnOnce","codes","states","warnedContainers","warnedKeys","render","rawValue","context","isEmptyValue","arrayTemplate","warnMissingTemplate","previousState","domSnapshot","position","__payloadDomPosition","previous","current","sameDomKeySnapshot","needsForcedRender","nextKeys","seen","find","some","previousKeys","stable","warnAboutKeys","applied","dependsOn","maps","dependents","dependent","result","names","raw"],"sources":["../src/core/diagnostics.ts","../src/security/trusted-types.ts","../src/core/thenable.ts","../src/core/internal-outcome.ts","../src/security/url-validator.ts","../src/security/sanitizer-report.ts","../src/security/sanitizer.ts","../src/security/escape.ts","../src/core/attribute-binding.ts","../src/core/array-template.ts","../src/field-types/utils.ts","../src/schema/diff.ts","../src/core/islands.ts","../src/core/morph.ts","../src/core/template-sanitize.ts","../src/core/structural-applier.ts","../src/core/lru.ts","../src/field-types/structural-array.ts","../src/core/dependencies.ts"],"sourcesContent":["import { observeThenableResult } from './thenable';\n\n/**\n * Diagnostics are observability, never control flow: a consumer logger may\n * throw or return a rejected thenable, and reporting a failure must not become\n * a second failure. Invocation stays synchronous for ordinary loggers.\n */\nexport function isolateDiagnostic(\n diagnostic: (...args: unknown[]) => unknown,\n): (...args: unknown[]) => void {\n return (...args): void => {\n try {\n observeThenableResult(diagnostic(...args));\n } catch {\n // Diagnostics must not become a second failure boundary.\n }\n };\n}\n\n/** Shared allocation-free default for disabled diagnostic channels. */\nexport function noopDiagnostic(): void {\n // Intentionally empty.\n}\n\n// Access, invocation and thenable inspection all happen inside the wrapper, so\n// a missing or hostile console cannot escape.\nexport const safeConsoleError = isolateDiagnostic((...args) =>\n (console.error as (...values: unknown[]) => unknown)(...args),\n);\n\nexport const safeConsoleWarn = isolateDiagnostic((...args) =>\n (console.warn as (...values: unknown[]) => unknown)(...args),\n);\n\nexport const safeConsoleDebug = isolateDiagnostic((...args) =>\n // eslint-disable-next-line no-console -- best-effort development diagnostics\n (console.debug as (...values: unknown[]) => unknown)(...args),\n);\n","/**\n * Trusted Types: every HTML sink routes through one policy, `payload-live-preview`,\n * whose `createHTML` is the identity — what reaches a sink is already sanitized\n * or escaped. Without the API, strings pass through untouched.\n */\n\n/** The subset of the Trusted Types API this module needs. */\nexport interface TrustedHtmlPolicyLike {\n createHTML(input: string): unknown;\n}\n\ninterface TrustedTypesFactoryLike {\n createPolicy(\n name: string,\n rules: { createHTML: (input: string) => string },\n ): TrustedHtmlPolicyLike;\n}\n\n/** @internal */\nexport const TRUSTED_TYPES_POLICY_NAME = 'payload-live-preview';\n\nlet policyOverride: TrustedHtmlPolicyLike | null | undefined;\nlet autoPolicy: TrustedHtmlPolicyLike | null | undefined;\n\n/**\n * Use `policy` for every sink, `null` to assign plain strings, `undefined` to\n * return to the auto-created package policy.\n */\nexport function setTrustedTypesPolicy(policy: TrustedHtmlPolicyLike | null | undefined): void {\n policyOverride = policy;\n}\n\nfunction factory(): TrustedTypesFactoryLike | undefined {\n const candidate = (globalThis as { trustedTypes?: unknown }).trustedTypes;\n if (typeof candidate !== 'object' || candidate === null) return undefined;\n const create = (candidate as { createPolicy?: unknown }).createPolicy;\n return typeof create === 'function' ? (candidate as TrustedTypesFactoryLike) : undefined;\n}\n\nfunction resolvePolicy(): TrustedHtmlPolicyLike | null {\n if (policyOverride !== undefined) return policyOverride;\n if (autoPolicy !== undefined) return autoPolicy;\n const api = factory();\n try {\n autoPolicy =\n api === undefined\n ? null\n : api.createPolicy(TRUSTED_TYPES_POLICY_NAME, { createHTML: (input) => input });\n } catch {\n // The site's `trusted-types` directive does not list this name; the\n // sink assignment will surface the enforcement error.\n autoPolicy = null;\n }\n return autoPolicy;\n}\n\n/** `html` as a `TrustedHTML` when a policy exists, else the string. Typed `string` for `innerHTML`. @internal */\nexport function trustedHtml(html: string): string {\n const policy = resolvePolicy();\n if (policy === null) return html;\n return policy.createHTML(html) as string;\n}\n\n/** Test hook: forget the auto-created policy. */\nexport function __resetTrustedTypesForTests(): void {\n policyOverride = undefined;\n autoPolicy = undefined;\n}\n","/**\n * Detect an invalid async result in a synchronous extension point.\n *\n * Rejected native Promises otherwise become unhandled after the caller falls\n * back synchronously. Assimilating the result through a handled Promise keeps\n * that contract violation observable only through the runtime's explicit\n * error channel.\n */\nexport function observeThenableResult(value: unknown): boolean {\n if ((typeof value !== 'object' || value === null) && typeof value !== 'function') return false;\n if (typeof (value as { readonly then?: unknown }).then !== 'function') return false;\n void Promise.resolve(value).catch(() => undefined);\n return true;\n}\n","/**\n * Public renderer callbacks return `void`, but a JavaScript implementation may\n * return anything. Only callbacks marked here may reserve exact `false` as\n * \"no write\", so a custom renderer's incidental boolean cannot change the\n * lifecycle's applied counts.\n */\n\ntype Callback = (...args: never[]) => unknown;\n\nconst noWriteCallbacks = new WeakSet<Callback>();\n\n/** Mark a package-owned callback whose exact `false` return means no write. */\nexport function markNoWriteCallback<T extends Callback>(callback: T): T {\n noWriteCallbacks.add(callback);\n return callback;\n}\n\n/** Whether `callback` owns the internal exact-false sentinel contract. */\nexport function usesNoWriteOutcome(callback: Callback): boolean {\n return noWriteCallbacks.has(callback);\n}\n\n/** Check a renderer object without detaching its public method at the call site. */\nexport function rendererUsesNoWriteOutcome(renderer: { readonly render: Callback }): boolean {\n return noWriteCallbacks.has(renderer.render);\n}\n","/**\n * URL safety: the one scheme allow-list the runtime, the client and the\n * sanitizer share. Empty strings are not safe (`<a href=\"\">` is never emitted).\n */\n\nconst SAFE_PROTOCOLS: ReadonlySet<string> = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n// Browsers strip leading whitespace before scheme detection.\nconst DANGEROUS_PROTOCOL_PATTERN = /^\\s*(?:javascript|data|vbscript|file|blob|about)\\s*:/i;\n\nconst RELATIVE_PATH = /^(?:\\.{1,2}\\/|[a-zA-Z0-9_-]+\\/?)/;\n\n// The URL parser treats `\\` as `/` for special schemes, so `/\\evil.com`\n// resolves to another origin rather than to a same-origin path.\nconst PROTOCOL_RELATIVE = /^[\\\\/]{2}/;\n\n/** The URL parser drops these anywhere in the input before it looks at anything. */\nconst PARSER_IGNORED = /[\\t\\n\\r]/g;\n\n/** `true` only for absolute `http`/`https`/`mailto`/`tel` URLs, protocol-relative URLs, paths, `#`/`?` fragments and relative paths. */\nexport function isSafeUrl(url: unknown): boolean {\n if (typeof url !== 'string') return false;\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n if (trimmed.length === 0) return false;\n if (DANGEROUS_PROTOCOL_PATTERN.test(trimmed)) return false;\n if (trimmed.startsWith('#') || trimmed.startsWith('?')) return true;\n if (PROTOCOL_RELATIVE.test(trimmed)) return true;\n if (trimmed.startsWith('/')) return true;\n try {\n const parsed = new URL(trimmed);\n return SAFE_PROTOCOLS.has(parsed.protocol);\n } catch {\n return RELATIVE_PATH.test(trimmed);\n }\n}\n\n/** Whether a URL points at another HTTP(S) origin, protocol-relative forms included, and so needs `noopener` hardening; every URL these two patterns match is one `isSafeUrl` admits. */\nexport function isExternalHttpUrl(url: string): boolean {\n const trimmed = url.trim().replace(PARSER_IGNORED, '');\n return /^https?:\\/\\//i.test(trimmed) || PROTOCOL_RELATIVE.test(trimmed);\n}\n\n/** The safe scheme set, for tests and introspection. */\nexport const SAFE_URL_PROTOCOLS: ReadonlySet<string> = SAFE_PROTOCOLS;\n","/**\n * LP0409 — what the strict sanitizer removed that the 1.x default kept.\n *\n * `sanitizerPolicy` defaults to `'strict'` since 2.0; before that it was\n * `'compat'`, which let `id` and every `data-*` through, and `name` only where\n * a per-tag list allowed it. The difference\n * only shows when a binding *writes* markup, so a project that upgrades and\n * whose rich text carries its own hooks loses them at the moment an editor\n * types — silently, and in the preview only. Measured on a real consumer: a\n * `data-partner-scroll` attribute driving a CSS selector disappeared on the\n * first write, with nothing said anywhere.\n *\n * So it is said here: once per attribute name per page, with the reason that\n * applies to that name rather than one sentence covering three different\n * decisions. This is a report, never a behaviour — the attribute stays removed.\n */\n\n/**\n * `console.warn` behind a try/catch rather than `@core/diagnostics`: `security`\n * is a leaf layer and may not import `core` (scripts/architecture-rules.ts), and\n * the shared helper's extra work — tolerating a logger that returns a thenable —\n * is for consumer-supplied loggers. This sink is fixed.\n */\nfunction warn(message: string): void {\n try {\n console.warn(message);\n } catch {\n // A diagnostic must never become a second failure.\n }\n}\n\nconst reported = new Set<string>();\n\n/** The binding prefix, restated rather than imported: this module must not pull the applier in. */\nconst BINDING_PREFIX = 'data-payload-';\n\nfunction reason(name: string): string {\n if (name.startsWith(BINDING_PREFIX)) {\n return (\n 'A binding inside CMS content is refused by design — an editor could otherwise ' +\n 'aim a write at any element on the page (docs/security.md)'\n );\n }\n if (name === 'id' || name === 'name') {\n return (\n 'CMS content that can name an element can shadow a global of that name — ' +\n 'DOM clobbering, refused by design (docs/security.md)'\n );\n }\n return (\n 'List it in `allowedDataAttributes` if the page needs it, or set ' +\n \"`sanitizerPolicy: 'compat'` to keep every `data-*` as 1.x did\"\n );\n}\n\n/**\n * Report one removal. Only for attributes `'compat'` would have kept: everything\n * else the sanitizer drops was refused in 1.x too and is not news to anyone.\n */\nexport function reportDroppedAttribute(name: string): void {\n if (reported.has(name)) return;\n reported.add(name);\n warn(\n `[live-preview] LP0409: the strict sanitizer removed \\`${name}\\` from written markup; ` +\n `the 1.x default (\\`sanitizerPolicy: 'compat'\\`) kept it. ${reason(name)}.`,\n );\n}\n\n/** Test seam: the report is once per page, and a test is not a page. */\nexport function resetDroppedAttributeReports(): void {\n reported.clear();\n}\n","/**\n * HTML sanitizer built on the host parser (`<template>`): allow-listed tags\n * and attributes, validated URLs, hardened external links, no `style`.\n * Needs a DOM; string-only sanitizers are historically brittle.\n */\n\nimport { trustedHtml } from './trusted-types';\nimport { isSafeUrl, isExternalHttpUrl } from './url-validator';\nimport { reportDroppedAttribute } from './sanitizer-report';\n\ndeclare const __INLINE_BUILD__: boolean | undefined;\n\n/** Tags kept with their content. Others are unwrapped unless in `REMOVE_COMPLETELY`. */\nconst ALLOWED_TAGS: ReadonlySet<string> = new Set([\n 'p',\n 'br',\n 'strong',\n 'b',\n 'em',\n 'i',\n 'u',\n 's',\n 'strike',\n 'mark',\n 'small',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'ul',\n 'ol',\n 'li',\n 'dl',\n 'dt',\n 'dd',\n 'blockquote',\n 'code',\n 'pre',\n 'kbd',\n 'samp',\n 'var',\n 'a',\n 'span',\n 'div',\n 'section',\n 'article',\n 'aside',\n 'header',\n 'footer',\n 'nav',\n 'figure',\n 'figcaption',\n 'img',\n 'picture',\n 'source',\n 'audio',\n 'video',\n 'sub',\n 'sup',\n 'hr',\n 'time',\n 'abbr',\n 'cite',\n 'q',\n 'table',\n 'thead',\n 'tbody',\n 'tfoot',\n 'tr',\n 'th',\n 'td',\n 'caption',\n 'colgroup',\n 'col',\n]);\n\n/** Tags `allowFormControls` re-admits for author templates; `form` is deliberately not one. */\nconst FORM_CONTROLS: ReadonlySet<string> = new Set([\n 'input',\n 'button',\n 'textarea',\n 'select',\n 'option',\n 'label',\n]);\n\n/** Removed with their children: the content itself is the hazard. */\nconst REMOVE_COMPLETELY: ReadonlySet<string> = new Set([\n 'script',\n 'style',\n 'iframe',\n 'object',\n 'embed',\n 'link',\n 'meta',\n 'base',\n 'form',\n 'input',\n 'button',\n 'select',\n 'textarea',\n 'svg',\n 'math',\n 'template',\n 'frame',\n 'frameset',\n 'noframes',\n 'noscript',\n]);\n\nconst ATTR_GLOBAL: ReadonlySet<string> = new Set([\n 'id',\n 'class',\n 'lang',\n 'dir',\n 'title',\n 'role',\n 'tabindex',\n]);\n\nconst ATTR_ARIA_PREFIX = 'aria-';\nconst ATTR_DATA_PREFIX = 'data-';\nconst BINDING_DATA_PREFIX = 'data-payload-';\n\nconst ATTR_BY_TAG: Readonly<Record<string, ReadonlySet<string>>> = {\n a: new Set(['href', 'target', 'rel', 'download', 'hreflang', 'type']),\n img: new Set(['src', 'srcset', 'sizes', 'alt', 'width', 'height', 'loading', 'decoding']),\n picture: new Set([]),\n source: new Set(['src', 'srcset', 'sizes', 'type', 'media']),\n audio: new Set(['src', 'controls', 'autoplay', 'loop', 'muted', 'preload']),\n video: new Set([\n 'src',\n 'poster',\n 'controls',\n 'autoplay',\n 'loop',\n 'muted',\n 'preload',\n 'width',\n 'height',\n 'playsinline',\n ]),\n time: new Set(['datetime']),\n abbr: new Set(['title']),\n q: new Set(['cite']),\n blockquote: new Set(['cite']),\n table: new Set(['summary']),\n th: new Set(['colspan', 'rowspan', 'scope', 'headers', 'abbr']),\n td: new Set(['colspan', 'rowspan', 'headers']),\n col: new Set(['span']),\n colgroup: new Set(['span']),\n ol: new Set(['start', 'reversed', 'type']),\n li: new Set(['value']),\n code: new Set(['class']),\n pre: new Set(['class']),\n};\n\nconst URL_ATTRIBUTES: ReadonlySet<string> = new Set(['href', 'src', 'cite', 'poster']);\n\n// Numeric nodeType constants keep an injected SSR document independent of a\n// browser-global `Node` constructor.\nconst ELEMENT_NODE = 1;\nconst COMMENT_NODE = 8;\n\n/** Thrown by `sanitizeHtml()` when no `document` is available (SSR without `setSanitizerDocument()`). */\nexport class SanitizerEnvironmentError extends Error {\n override readonly name = 'SanitizerEnvironmentError';\n}\n\n/**\n * `'strict'` (default) strips `id`, `name` and `data-payload-*` and passes\n * other `data-*` only via `allowedDataAttributes`; `'compat'` keeps them.\n */\nexport type SanitizerPolicyMode = 'compat' | 'strict';\n\nexport interface SanitizeOptions {\n /** Overrides the module default set by `setSanitizerPolicy()`. */\n readonly policy?: SanitizerPolicyMode;\n /** `data-*` attributes (full names) that pass under `'strict'`; `data-payload-*` never does. */\n readonly allowedDataAttributes?: readonly string[];\n /**\n * Keep `input`, `button`, `textarea`, `select`, `option` and `label` — only\n * for markup the page author wrote, never for CMS content. `form`,\n * handlers, `style` and unsafe URLs stay dropped.\n */\n readonly allowFormControls?: boolean;\n /** Extra tags to allow. Lower-case, untrimmed. */\n readonly additionalAllowedTags?: readonly string[];\n /**\n * Extra per-tag attributes, lower-case. Cannot re-admit handlers, `style`,\n * or — under `'strict'` — `id`, `name` and `data-payload-*`.\n */\n readonly additionalAllowedAttributes?: Readonly<Record<string, readonly string[]>>;\n /**\n * The input is a page-author item template, so `'strict'` keeps the\n * applier's reconciliation attributes (`TEMPLATE_ATTRIBUTES`) and nothing\n * else — every other `data-payload-*` is still stripped, so a template can\n * never add a binding.\n */\n readonly templateMode?: boolean;\n}\n\n/** What `templateMode` keeps under `'strict'`. */\nconst TEMPLATE_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'id',\n 'name',\n 'data-payload-key',\n 'data-payload-nested-key',\n 'data-payload-nested-template',\n]);\n\ninterface ResolvedPolicy {\n readonly allowedTags: ReadonlySet<string>;\n readonly allowFormControls: boolean;\n readonly templateMode: boolean;\n readonly mode: SanitizerPolicyMode;\n readonly allowedData: ReadonlySet<string>;\n readonly attrByTag: ReadonlyMap<string, ReadonlySet<string>>;\n}\n\nlet defaultMode: SanitizerPolicyMode = 'strict';\n\n/**\n * The default for calls without an explicit `policy`, per package entry. A\n * runtime carries its own `sanitizerPolicy` and never writes here (ADR 0002).\n */\nexport function setSanitizerPolicy(mode: SanitizerPolicyMode): void {\n defaultMode = mode;\n}\n\n/** `instancePolicy` sits between a per-call `options.policy` and the process default. */\nfunction resolvePolicy(\n options: SanitizeOptions | undefined,\n instancePolicy: SanitizerPolicyMode | undefined,\n): ResolvedPolicy {\n const mode = options?.policy ?? instancePolicy ?? defaultMode;\n if (!options) {\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n return {\n allowedTags: ALLOWED_TAGS,\n attrByTag: attrMap,\n allowFormControls: false,\n templateMode: false,\n mode,\n allowedData: new Set(),\n };\n }\n const allowed = new Set(ALLOWED_TAGS);\n options.additionalAllowedTags?.forEach((tag) => allowed.add(tag));\n if (options.allowFormControls === true) for (const tag of FORM_CONTROLS) allowed.add(tag);\n const attrMap = new Map<string, ReadonlySet<string>>();\n for (const [tag, attrs] of Object.entries(ATTR_BY_TAG)) attrMap.set(tag, attrs);\n for (const [tag, attrs] of Object.entries(options.additionalAllowedAttributes ?? {})) {\n const merged = new Set(attrMap.get(tag));\n for (const attr of attrs) merged.add(attr);\n attrMap.set(tag, merged);\n }\n return {\n allowedTags: allowed,\n attrByTag: attrMap,\n allowFormControls: options.allowFormControls === true,\n templateMode: options.templateMode === true,\n mode,\n allowedData: new Set(options.allowedDataAttributes?.map((name) => name.toLowerCase())),\n };\n}\n\n/** The `Document` surface the sanitizer needs; jsdom, linkedom and happy-dom all provide it. */\nexport interface SanitizerDocument {\n createElement: (tagName: string) => {\n innerHTML: string;\n readonly content: ParentNode;\n };\n}\n\n// Held on the realm, not in this module: every package entry is its own bundle\n// with its own copy of this file, and a document supplied through the root has\n// to reach the rich text `payload-live-preview/lexical` renders.\nconst DOCUMENT_SLOT: unique symbol = Symbol.for('payload-live-preview.sanitizer-document');\n\ninterface DocumentSlot {\n [DOCUMENT_SLOT]?: SanitizerDocument | undefined;\n}\n\n/** Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`; `null` clears it, for every entry. */\nexport function setSanitizerDocument(doc: SanitizerDocument | null): void {\n (globalThis as DocumentSlot)[DOCUMENT_SLOT] = doc ?? undefined;\n}\n\n/**\n * Sanitize `html`; malformed input is recovered by the parser first.\n *\n * @throws {SanitizerEnvironmentError} when no DOM is available.\n */\nexport function sanitizeHtml(html: string, options?: SanitizeOptions): string {\n return sanitizeHtmlWithPolicy(html, undefined, options);\n}\n\n/**\n * The runtime's entry: `policy` is one instance's, applied unless `options`\n * carry their own, so two clients on a page never share a policy through\n * this module. Not public — a direct caller has `options.policy`.\n */\nexport function sanitizeHtmlWithPolicy(\n html: string,\n policy: SanitizerPolicyMode | undefined,\n options?: SanitizeOptions,\n): string {\n const doc = resolveDocument();\n if (!doc) throw environmentError();\n if (html === '') return '';\n\n const resolved = resolvePolicy(options, policy);\n const template = doc.createElement('template');\n // The sanitizer's own parse is a sink too: under Trusted Types it needs the policy.\n template.innerHTML = trustedHtml(html);\n sanitizeFragment(template.content, resolved);\n return template.innerHTML;\n}\n\n// Read the define at each branch rather than through a helper: a bundler\n// folds the substituted literal in place, but will not inline a call, and the\n// SSR-only class and override must not reach the browser runtime.\nfunction environmentError(): Error {\n if (typeof __INLINE_BUILD__ !== 'undefined' && __INLINE_BUILD__) {\n return new Error('sanitizeHtml needs a DOM');\n }\n return new SanitizerEnvironmentError(\n 'sanitizeHtml needs a DOM; provide one with setSanitizerDocument() during SSR.',\n );\n}\n\nfunction resolveDocument(): SanitizerDocument | undefined {\n if (typeof __INLINE_BUILD__ === 'undefined' || !__INLINE_BUILD__) {\n const override = (globalThis as DocumentSlot)[DOCUMENT_SLOT];\n if (override) return override;\n }\n if (typeof document === 'undefined') return undefined;\n return document;\n}\n\n/** Whether a DOM is available — the global or an injected one — for callers that treat sanitizing as optional. */\nexport function hasSanitizerDocument(): boolean {\n return resolveDocument() !== undefined;\n}\n\nfunction sanitizeFragment(node: ParentNode, policy: ResolvedPolicy): void {\n // Snapshot: children are mutated during the walk.\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === ELEMENT_NODE) {\n sanitizeElement(child as Element, policy);\n } else if (child.nodeType === COMMENT_NODE) {\n child.remove();\n }\n }\n}\n\nfunction sanitizeElement(element: Element, policy: ResolvedPolicy): void {\n const tag = element.tagName.toLowerCase();\n\n if (REMOVE_COMPLETELY.has(tag) && !(policy.allowFormControls && FORM_CONTROLS.has(tag))) {\n element.remove();\n return;\n }\n\n if (!policy.allowedTags.has(tag)) {\n sanitizeFragment(element, policy);\n element.replaceWith(...element.childNodes);\n return;\n }\n\n sanitizeAttributes(element, tag, policy);\n if (tag === 'a') hardenAnchor(element);\n sanitizeFragment(element, policy);\n}\n\nfunction sanitizeAttributes(element: Element, tag: string, policy: ResolvedPolicy): void {\n const tagAttrs = policy.attrByTag.get(tag);\n\n for (const attr of Array.from(element.attributes)) {\n const name = attr.name.toLowerCase();\n if (name.startsWith('on') || name === 'style') {\n element.removeAttribute(attr.name);\n continue;\n }\n if (policy.mode === 'strict') {\n if (policy.templateMode && TEMPLATE_ATTRIBUTES.has(name)) continue;\n // DOM clobbering and binding injection (docs/security.md §5c). Checked\n // before the allow-list so an extension cannot re-admit them.\n if (name === 'id' || name === 'name' || name.startsWith(BINDING_DATA_PREFIX)) {\n element.removeAttribute(attr.name);\n // `compat` kept `name` only where a per-tag list allowed it, so only\n // there did the upgrade change anything to report.\n if (name !== 'name' || tagAttrs?.has(name) === true) reportDroppedAttribute(name);\n continue;\n }\n if (name.startsWith(ATTR_DATA_PREFIX)) {\n if (!policy.allowedData.has(name)) {\n element.removeAttribute(attr.name);\n reportDroppedAttribute(name);\n }\n continue;\n }\n if (ATTR_GLOBAL.has(name) || name.startsWith(ATTR_ARIA_PREFIX)) continue;\n } else if (\n ATTR_GLOBAL.has(name) ||\n name.startsWith(ATTR_ARIA_PREFIX) ||\n name.startsWith(ATTR_DATA_PREFIX)\n ) {\n continue;\n }\n if (tagAttrs?.has(name)) {\n if (URL_ATTRIBUTES.has(name) && !isSafeUrl(attr.value)) {\n element.removeAttribute(attr.name);\n } else if (name === 'srcset' && !isSafeSrcset(attr.value)) {\n element.removeAttribute(attr.name);\n }\n continue;\n }\n element.removeAttribute(attr.name);\n }\n}\n\n/** Every `srcset` candidate must pass; partial rewriting would silently change what renders. */\nfunction isSafeSrcset(value: string): boolean {\n for (const candidate of value.split(',')) {\n const trimmed = candidate.trim();\n if (trimmed.length === 0) continue;\n // The URL ends at the first whitespace; what follows is the descriptor.\n const [url = trimmed] = trimmed.split(/\\s/, 1);\n if (!isSafeUrl(url)) return false;\n }\n return true;\n}\n\nfunction hardenAnchor(anchor: Element): void {\n const href = anchor.getAttribute('href');\n if (href === null || !isExternalHttpUrl(href)) return;\n anchor.setAttribute('rel', 'noopener noreferrer');\n if (!anchor.hasAttribute('target')) anchor.setAttribute('target', '_blank');\n}\n\n/** The built-in allow-lists, for documentation and tests. */\nexport const SANITIZER_POLICY = Object.freeze({\n allowedTags: ALLOWED_TAGS,\n removeCompletely: REMOVE_COMPLETELY,\n globalAttributes: ATTR_GLOBAL,\n attributesByTag: ATTR_BY_TAG,\n urlAttributes: URL_ATTRIBUTES,\n});\n","/** HTML and CSS escaping primitives (OWASP XSS Prevention Cheat Sheet). DOM-free. */\n\nconst HTML_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '/': '/',\n '`': '`',\n '=': '=',\n});\n\nconst HTML_ESCAPE_PATTERN = /[&<>\"'/`=]/g;\n\n/** Escape `text` for an element body or a *quoted* attribute value; strings only, and unquoted attributes are not covered. */\nexport function escapeHtml(text: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return text.replace(HTML_ESCAPE_PATTERN, (char) => HTML_ESCAPES[char] as string);\n}\n\n/** Escape a value for a CSS `url(...)` literal; this stops the break-out, not the scheme, so pair it with `isSafeUrl()`. */\nexport function escapeCssUrl(value: string): string {\n return value.replace(/['\"()\\\\]/g, '\\\\$&');\n}\n\nconst ATTR_ESCAPES: Readonly<Record<string, string>> = Object.freeze({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n});\n\nconst ATTR_ESCAPE_PATTERN = /[&<>\"']/g;\n\n/** Escape a value for a *quoted* HTML attribute, leaving URL characters intact; it validates no scheme, so run `isSafeUrl()` on `href`/`src` first. @internal */\nexport function escapeHtmlAttribute(value: string): string {\n // The character class and the map are coupled: every match is a key.\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n return value.replace(ATTR_ESCAPE_PATTERN, (char) => ATTR_ESCAPES[char] as string);\n}\n\n/** `escapeHtml()` then newlines to `<br>`; the order is what makes it safe. */\nexport function escapeAndLinebreak(text: string): string {\n return escapeHtml(text).replace(/\\r\\n|\\r|\\n/g, '<br>');\n}\n","/**\n * Policed writes for `data-payload-attribute` bindings. The value is\n * remote-controlled, so event handlers, `style`, `srcdoc`, `formaction`/`form`,\n * `id`/`name` (DOM clobbering) and `srcset` (multi-URL syntax) are refused,\n * URL-bearing attributes must pass `isSafeUrl`, and non-scalars never write.\n */\n\nimport { isSafeUrl } from '@security/url-validator';\n\nconst BLOCKED_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'style',\n 'srcdoc',\n 'formaction',\n 'form',\n 'id',\n 'name',\n 'is',\n 'srcset',\n 'imagesrcset',\n]);\n\nconst URL_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'href',\n 'src',\n 'poster',\n 'cite',\n 'action',\n 'xlink:href',\n 'data',\n]);\n\nexport type AttributeApplyResult = 'applied' | 'blocked';\n\n/**\n * Whether this package may write an attribute of this name at all — event\n * handlers, `style`, the two DOM-clobbering names and the multi-URL ones\n * excluded. One rule, two callers: the binding below writes a remote value into\n * it, and the array renderers copy one from the page's own markup onto an item\n * they rebuilt (`src/core/array-template.ts`).\n */\nexport function isWritableAttribute(name: string): boolean {\n return !name.startsWith('on') && !BLOCKED_ATTRIBUTES.has(name);\n}\n\n/** Returns `'blocked'` without touching the DOM when the write is refused. */\nexport function applyAttributeBinding(\n element: Element,\n attribute: string,\n value: unknown,\n): AttributeApplyResult {\n const name = attribute.toLowerCase().trim();\n if (name.length === 0) return 'blocked';\n if (!isWritableAttribute(name)) return 'blocked';\n\n if (value === null || value === undefined) {\n element.removeAttribute(name);\n return 'applied';\n }\n if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {\n return 'blocked';\n }\n const stringValue = String(value);\n\n if (URL_ATTRIBUTES.has(name) && !isSafeUrl(stringValue)) return 'blocked';\n\n element.setAttribute(name, stringValue);\n return 'applied';\n}\n","/**\n * One array item out of one template: the interpolation, and the attributes the\n * template cannot know about.\n *\n * A replacement value is data, not template syntax: one `replace()` per key\n * would re-interpret `{{index}}` text that an earlier value introduced, and\n * would apply `String.replace`'s `$` semantics to CMS content.\n */\n\nimport { escapeHtml } from '@security/escape';\nimport { isWritableAttribute } from './attribute-binding';\n\nconst PLACEHOLDER_PATTERN = /\\{\\{([\\s\\S]*?)\\}\\}/g;\n\n/** The runtime's own annotations; a rebuilt item gets its own, never a copy. */\nconst BINDING_ATTRIBUTE_PREFIX = 'data-payload-';\n\n/** An attribute name and its value, as they travel from an old item to a new one. */\nexport type InheritedAttribute = readonly [name: string, value: string];\n\nfunction hasOwn(record: object, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(record, key);\n}\n\n/**\n * Every key any item carries. A placeholder naming one of these is a field of\n * this array, so a row that happens to lack it renders as nothing; a\n * placeholder no row can fill is a typo in the template and stays visible.\n */\nexport function collectTemplateKeys(items: readonly unknown[]): ReadonlySet<string> {\n const keys = new Set<string>();\n for (const item of items) {\n if (typeof item !== 'object' || item === null) continue;\n for (const key of Object.keys(item)) keys.add(key);\n }\n return keys;\n}\n\nexport function interpolateArrayTemplate(\n template: string,\n item: unknown,\n index: number,\n stringify: (value: unknown) => string,\n knownKeys?: ReadonlySet<string>,\n): string {\n const record = typeof item === 'object' && item !== null ? item : null;\n\n return template.replace(PLACEHOLDER_PATTERN, (placeholder, key: string) => {\n // Preserve the established object-field precedence when an object itself\n // has an `index` or `value` property. Otherwise these are reserved tokens.\n if (record !== null && hasOwn(record, key)) {\n return escapeHtml(stringify(Reflect.get(record, key)));\n }\n if (record === null && key === 'value') return escapeHtml(stringify(item));\n if (key === 'index') return String(index);\n // A field other rows carry: this one simply has none. Writing the\n // placeholder would print template syntax on the page, which is what an\n // editor sees the moment a row is added and not every field is filled in.\n if (record !== null && knownKeys?.has(key) === true) return '';\n return placeholder;\n });\n}\n\n/**\n * What the items already in `container` all carry, and an item rebuilt from the\n * template therefore has to carry too.\n *\n * A framework's scoped styles hang on a marker its compiler writes into the\n * markup — Astro's `data-astro-cid-…`, Vue's `data-v-…`, Svelte's class — and\n * the author's `data-payload-array-template` has none of it. The rebuilt list\n * then renders unstyled next to the one the server sent, while the write itself\n * succeeds, so nothing in the runtime can notice. Naming no framework is the\n * point: what identifies these attributes is that every item of the list has\n * them with the same value, which per-row state by definition does not.\n */\nexport function sharedItemAttributes(container: Element): readonly InheritedAttribute[] {\n const items = container.children;\n const first = items[0];\n if (first === undefined) return [];\n const shared: InheritedAttribute[] = [];\n for (const { name, value } of Array.from(first.attributes)) {\n if (!isWritableAttribute(name) || name.startsWith(BINDING_ATTRIBUTE_PREFIX)) continue;\n let everyItem = true;\n for (let index = 1; index < items.length && everyItem; index += 1) {\n everyItem = items[index]?.getAttribute(name) === value;\n }\n if (everyItem) shared.push([name, value]);\n }\n return shared;\n}\n\n/** Give a rebuilt item what its predecessors shared; the template's own value wins. */\nexport function inheritItemAttributes(item: Element, shared: readonly InheritedAttribute[]): void {\n for (const [name, value] of shared) {\n if (!item.hasAttribute(name)) item.setAttribute(name, value);\n }\n}\n","/** Value coercion shared by the field renderers. */\n\n/** Display string for any value: primitives as-is, objects as JSON, `null`/`undefined` as `''`. */\nexport function safeStringify(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '';\n }\n}\n\n/** The three values every renderer treats as \"clear\" (docs/renderers.md, value semantics). */\nexport function isEmptyValue(value: unknown): value is null | undefined | '' {\n return value === null || value === undefined || value === '';\n}\n","/**\n * Structural diff for array and blocks fields. Items with an `id` are keyed\n * (moves are detected); without ids the diff is positional.\n * @internal\n */\n\nexport type ArrayPatch =\n | { readonly kind: 'insert'; readonly index: number; readonly value: unknown }\n | { readonly kind: 'remove'; readonly index: number; readonly value: unknown }\n | {\n readonly kind: 'move';\n readonly from: number;\n readonly to: number;\n readonly value: unknown;\n }\n | { readonly kind: 'update'; readonly index: number; readonly value: unknown }\n | {\n readonly kind: 'replace';\n readonly index: number;\n readonly oldValue: unknown;\n readonly value: unknown;\n };\n\nfunction getId(item: unknown): string | number | undefined {\n if (typeof item !== 'object' || item === null) return undefined;\n const id = (item as Record<string, unknown>)['id'];\n if (typeof id === 'string' || typeof id === 'number') return id;\n return undefined;\n}\n\nfunction getBlockType(item: unknown): string | undefined {\n if (typeof item !== 'object' || item === null) return undefined;\n const blockType = (item as Record<string, unknown>)['blockType'];\n return typeof blockType === 'string' ? blockType : undefined;\n}\n\n/** Patches that turn `prev` into `next`; a changed `blockType` is a `replace`, never an `update`. */\nexport function diffArray(\n prev: readonly unknown[],\n next: readonly unknown[],\n): readonly ArrayPatch[] {\n const haveIds = next.every((item) => getId(item) !== undefined);\n if (haveIds) return diffById(prev, next);\n return diffByPosition(prev, next);\n}\n\nfunction diffById(prev: readonly unknown[], next: readonly unknown[]): readonly ArrayPatch[] {\n const patches: ArrayPatch[] = [];\n const prevIndexById = new Map<string | number, number>();\n for (let i = 0; i < prev.length; i += 1) {\n const id = getId(prev[i]);\n if (id !== undefined) prevIndexById.set(id, i);\n }\n\n const consumedFromPrev = new Set<number>();\n for (let to = 0; to < next.length; to += 1) {\n const item = next[to];\n const id = getId(item);\n if (id === undefined) {\n patches.push({ kind: 'insert', index: to, value: item });\n continue;\n }\n const from = prevIndexById.get(id);\n if (from === undefined) {\n patches.push({ kind: 'insert', index: to, value: item });\n continue;\n }\n consumedFromPrev.add(from);\n const prevItem = prev[from];\n if (getBlockType(prevItem) !== getBlockType(item)) {\n patches.push({ kind: 'replace', index: to, oldValue: prevItem, value: item });\n continue;\n }\n if (from !== to) {\n patches.push({ kind: 'move', from, to, value: item });\n }\n if (!shallowEqual(prevItem, item)) {\n patches.push({ kind: 'update', index: to, value: item });\n }\n }\n\n for (let i = 0; i < prev.length; i += 1) {\n if (consumedFromPrev.has(i)) continue;\n patches.push({ kind: 'remove', index: i, value: prev[i] });\n }\n return patches;\n}\n\nfunction diffByPosition(prev: readonly unknown[], next: readonly unknown[]): readonly ArrayPatch[] {\n const patches: ArrayPatch[] = [];\n const min = Math.min(prev.length, next.length);\n for (let i = 0; i < min; i += 1) {\n if (!shallowEqual(prev[i], next[i])) {\n patches.push({ kind: 'update', index: i, value: next[i] });\n }\n }\n if (next.length > prev.length) {\n for (let i = prev.length; i < next.length; i += 1) {\n patches.push({ kind: 'insert', index: i, value: next[i] });\n }\n }\n if (prev.length > next.length) {\n for (let i = next.length; i < prev.length; i += 1) {\n patches.push({ kind: 'remove', index: i, value: prev[i] });\n }\n }\n return patches;\n}\n\n// Shallow on purpose: any nested reference change is an update, and the\n// renderer reconciles deeper differences itself.\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;\n const aRec = a as Record<string, unknown>;\n const bRec = b as Record<string, unknown>;\n const aKeys = Object.keys(aRec);\n const bKeys = Object.keys(bRec);\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) {\n if (!Object.is(aRec[key], bRec[key])) return false;\n }\n return true;\n}\n","/**\n * Hydrated islands own their subtree, so the runtime never patches inside one.\n * Instead every flush dispatches `payload-live-preview:update` on each island\n * root with the update in `detail`. `data-payload-island=\"patch\"` opts back in.\n * @internal\n */\n\nexport const ISLAND_EVENT = 'payload-live-preview:update';\n/** @internal */\nexport const ISLAND_ATTRIBUTE = 'data-payload-island';\nexport const ISLAND_SELECTOR = `astro-island, [${ISLAND_ATTRIBUTE}]`;\n\nexport interface IslandUpdateDetail {\n readonly fields: Readonly<Record<string, unknown>>;\n readonly revision: number;\n readonly receivedAt: number;\n readonly locale: string | undefined;\n}\n\nfunction isIslandRoot(element: Element): boolean {\n return element.tagName.toLowerCase() === 'astro-island' || element.hasAttribute(ISLAND_ATTRIBUTE);\n}\n\nfunction islandAllowsPatching(island: Element): boolean {\n return island.getAttribute(ISLAND_ATTRIBUTE) === 'patch';\n}\n\n/** Whether `element` itself is an island root that did not opt into patching. */\nexport function isIslandBoundary(element: Element): boolean {\n return isIslandRoot(element) && !islandAllowsPatching(element);\n}\n\n/** Whether `element` (or an ancestor) is an island that did not opt into patching. @internal */\nexport function isInsideIsland(element: Element): boolean {\n let current: Element | null = element;\n while (current !== null) {\n if (isIslandBoundary(current)) return true;\n current = current.parentElement;\n }\n return false;\n}\n\n/** Island roots under `root` that receive update events. */\nexport function collectIslands(root: ParentNode): Element[] {\n const islands: Element[] = [];\n for (const island of root.querySelectorAll(ISLAND_SELECTOR)) {\n if (!islandAllowsPatching(island)) islands.push(island);\n }\n return islands;\n}\n\nexport function dispatchIslandUpdate(\n islands: readonly Element[],\n detail: IslandUpdateDetail,\n): number {\n for (const island of islands) {\n island.dispatchEvent(\n new CustomEvent<IslandUpdateDetail>(ISLAND_EVENT, { detail, bubbles: false }),\n );\n }\n return islands.length;\n}\n","/**\n * Keyed DOM morph: edits a live element toward a freshly rendered one while\n * keeping the live nodes, and with them focus, selection, scroll, playback and\n * listeners. Custom elements, islands, `contenteditable` and\n * `data-payload-owned` subtrees are boundaries the morph never enters.\n * See ADR 0008.\n */\n\nimport { ISLAND_ATTRIBUTE } from './islands';\n\nexport { ISLAND_ATTRIBUTE };\n/** @internal */\nexport const OWNED_ATTRIBUTE = 'data-payload-owned';\n\n/** Attributes the CMS controls only when the template names them (ADR 0008 §3). */\nconst STATE_ATTRIBUTES: ReadonlySet<string> = new Set(['open', 'value', 'checked', 'selected']);\n\nexport interface MorphOptions {\n /** Attributes that key child elements for pairing, tried in order; unkeyed children pair by position. */\n readonly keyAttributes: readonly string[];\n /** Called once per parent when two children share a key; the later ones pair by position. */\n readonly onDuplicateKey?: (parent: Element, key: string) => void;\n /** Elements whose attributes are synchronised but whose children are left alone (nested structural slots). */\n readonly retainChildrenOf?: (live: Element, rendered: Element) => boolean;\n}\n\n/** Empty attribute values (boolean markers such as `data-payload-island`) are not keys. */\nfunction keyOf(element: Element, options: MorphOptions): string | undefined {\n for (const attribute of options.keyAttributes) {\n const value = element.getAttribute(attribute);\n if (value !== null && value.length > 0) return `${attribute}=${value}`;\n }\n return undefined;\n}\n\n/** @internal */\nexport function isMorphBoundary(element: Element): boolean {\n if (element.tagName.toLowerCase().includes('-')) return true;\n if (element.hasAttribute(ISLAND_ATTRIBUTE) || element.hasAttribute(OWNED_ATTRIBUTE)) return true;\n const editable = element.getAttribute('contenteditable');\n return editable !== null && editable !== 'false';\n}\n\n/** Whether `live` can be edited toward `rendered` instead of being replaced by it. @internal */\nexport function isMorphCompatible(live: Element, rendered: Element): boolean {\n return (\n live.tagName === rendered.tagName &&\n live.namespaceURI === rendered.namespaceURI &&\n !isMorphBoundary(live) &&\n !isMorphBoundary(rendered)\n );\n}\n\n/**\n * Morph `live` toward `rendered`. Returns `live` when it was retained, or\n * `rendered` when the two are incompatible and the caller must replace.\n * `rendered` is consumed: its children may move into `live`.\n */\nexport function morphElement(live: Element, rendered: Element, options: MorphOptions): Element {\n if (!isMorphCompatible(live, rendered)) return rendered;\n const focus = captureFocus(live);\n syncAttributes(live, rendered);\n if (options.retainChildrenOf?.(live, rendered) !== true) morphChildren(live, rendered, options);\n restoreFocus(focus);\n return live;\n}\n\n/** Match attributes, except that state-bearing ones change only when `rendered` carries them. */\nexport function syncAttributes(live: Element, rendered: Element): void {\n for (const attribute of Array.from(live.attributes)) {\n if (rendered.hasAttribute(attribute.name)) continue;\n if (STATE_ATTRIBUTES.has(attribute.name.toLowerCase())) continue;\n live.removeAttribute(attribute.name);\n }\n for (const attribute of Array.from(rendered.attributes)) {\n if (live.getAttribute(attribute.name) !== attribute.value) {\n live.setAttribute(attribute.name, attribute.value);\n }\n }\n}\n\nfunction morphChildren(live: Element, rendered: Element, options: MorphOptions): void {\n const liveKeyed = indexKeyed(live, options);\n const keyedElements = new Set<Node>(liveKeyed.values());\n const liveUnkeyed = Array.from(live.childNodes).filter((node) => !keyedElements.has(node));\n const claimed = new Set<Node>();\n const usedKeys = new Set<string>();\n const renderedNodes = Array.from(rendered.childNodes);\n let cursor: Node | null = live.firstChild;\n let unkeyedIndex = 0;\n\n for (let i = 0; i < renderedNodes.length; i += 1) {\n const next = renderedNodes[i] as Node;\n let kept: Node | null = null;\n let key = next instanceof Element ? keyOf(next, options) : undefined;\n // A repeated key on the rendered side pairs positionally like a live duplicate.\n if (key !== undefined && usedKeys.has(key)) key = undefined;\n if (key !== undefined) {\n usedKeys.add(key);\n const candidate = liveKeyed.get(key);\n if (candidate !== undefined && !claimed.has(candidate)) {\n kept = reconcile(candidate, next, options) === candidate ? candidate : null;\n if (kept === null) {\n candidate.replaceWith(next);\n claimed.add(next);\n cursor = next.nextSibling;\n continue;\n }\n }\n } else {\n while (unkeyedIndex < liveUnkeyed.length) {\n const candidate = liveUnkeyed[unkeyedIndex] as Node;\n unkeyedIndex += 1;\n if (claimed.has(candidate)) continue;\n if (sameKind(candidate, next)) {\n kept = reconcile(candidate, next, options) === candidate ? candidate : null;\n if (kept === null) {\n live.replaceChild(next, candidate);\n claimed.add(next);\n cursor = next.nextSibling;\n }\n break;\n }\n if (candidate instanceof Element) {\n // `next` is a text/comment, or an element whose kind the following\n // rendered node matches: an insertion, so the live element stays for it.\n const following = renderedNodes[i + 1];\n if (\n !(next instanceof Element) ||\n (following !== undefined && sameKind(candidate, following))\n ) {\n unkeyedIndex -= 1;\n break;\n }\n live.replaceChild(next, candidate);\n claimed.add(next);\n cursor = next.nextSibling;\n break;\n }\n if (!(next instanceof Element)) {\n // Text vs comment: replace rather than rewrite one node type's value into the other.\n live.replaceChild(next, candidate);\n claimed.add(next);\n cursor = next.nextSibling;\n break;\n }\n // A surplus live text/comment before the element `next` needs; removed below.\n }\n if (kept === null && claimed.has(next)) continue;\n }\n\n const node: Node = kept ?? next;\n claimed.add(node);\n // Whitespace-only text the template did not render is surplus. Stepping the\n // cursor over it keeps a retained element where it is: `insertBefore` on a\n // node already in the tree is a remove-and-insert, which blurs a focused input.\n while (cursor !== null && cursor !== node && !claimed.has(cursor) && isBlankText(cursor)) {\n cursor = cursor.nextSibling;\n }\n if (node !== cursor) live.insertBefore(node, cursor);\n cursor = node.nextSibling;\n }\n\n for (const child of Array.from(live.childNodes)) {\n if (!claimed.has(child)) child.remove();\n }\n}\n\n/** Retain `candidate` when it can be edited toward `next`; otherwise report `next`. */\nfunction reconcile(candidate: Node, next: Node, options: MorphOptions): Node {\n if (candidate instanceof Element && next instanceof Element) {\n // A compatible boundary stays exactly as it is (ADR 0008 §4).\n if (isMorphBoundary(candidate) && isMorphBoundary(next)) return candidate;\n return morphElement(candidate, next, options);\n }\n if (candidate.nodeValue !== next.nodeValue) candidate.nodeValue = next.nodeValue;\n return candidate;\n}\n\nfunction isBlankText(node: Node): boolean {\n return node.nodeType === Node.TEXT_NODE && (node.nodeValue ?? '').trim().length === 0;\n}\n\nfunction sameKind(a: Node, b: Node): boolean {\n if (a.nodeType !== b.nodeType) return false;\n if (a instanceof Element && b instanceof Element) {\n return a.tagName === b.tagName && a.namespaceURI === b.namespaceURI;\n }\n return true;\n}\n\n/** First element per key; later duplicates are left as they are and pair positionally. */\nfunction indexKeyed(parent: Element, options: MorphOptions): Map<string, Element> {\n const keyed = new Map<string, Element>();\n let duplicate: string | undefined;\n for (const child of Array.from(parent.children)) {\n const key = keyOf(child, options);\n if (key === undefined) continue;\n if (keyed.has(key)) {\n duplicate ??= key.slice(key.indexOf('=') + 1);\n continue;\n }\n keyed.set(key, child);\n }\n if (duplicate !== undefined) options.onDuplicateKey?.(parent, duplicate);\n return keyed;\n}\n\ninterface FocusSnapshot {\n readonly element: HTMLElement;\n readonly selection: readonly [number | null, number | null] | null;\n}\n\n/** A keyed move is a remove-and-insert, which blurs; remember what had focus. */\nfunction captureFocus(live: Element): FocusSnapshot | null {\n const active = live.ownerDocument.activeElement;\n if (!(active instanceof HTMLElement) || !live.contains(active)) return null;\n const selection =\n active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement\n ? ([active.selectionStart, active.selectionEnd] as const)\n : null;\n return { element: active, selection };\n}\n\nfunction restoreFocus(snapshot: FocusSnapshot | null): void {\n if (snapshot === null) return;\n const { element, selection } = snapshot;\n if (element.ownerDocument.activeElement === element || !element.isConnected) return;\n try {\n element.focus({ preventScroll: true });\n const [start, end] = selection ?? [null, null];\n if (start !== null && end !== null) {\n (element as HTMLInputElement).setSelectionRange(start, end);\n }\n } catch {\n // Not focusable any more; nothing to restore.\n }\n}\n","/**\n * Sanitizer options for item templates (`data-payload-array-template`,\n * nested templates). A template is the page author's markup and every\n * interpolated value is escaped to text before the sanitizer runs, so it may\n * carry form controls and custom elements the rich-text policy refuses.\n * Event handlers, `style` and unsafe URLs are still stripped.\n *\n * Some entries below are already admitted by the sanitizer through another\n * route — `video` and `audio` by the tag allow-list, `select` by\n * `allowFormControls`, `name` by `templateMode`, and `controls`, `muted`,\n * `loop`, `poster` and `src` by the per-tag attribute map. They are kept\n * because this list states what a template may contain, and an allow-list\n * that depends on a second list staying unchanged is the more fragile of the\n * two arrangements. Mutating those entries changes nothing observable, so\n * they survive mutation testing by construction; the behaviour they describe\n * is pinned in `tests/unit/core/template-sanitize.test.ts` instead.\n */\n\nimport type { SanitizeOptions } from '@security/sanitizer';\nimport { lruGet, lruSet } from './lru';\n\nconst TEMPLATE_EXTRA_TAGS: readonly string[] = [\n 'input',\n 'textarea',\n 'select',\n 'option',\n 'button',\n 'label',\n 'details',\n 'summary',\n 'dialog',\n 'video',\n 'audio',\n 'progress',\n 'meter',\n];\n\nconst TEMPLATE_EXTRA_ATTRIBUTES: readonly string[] = [\n 'type',\n 'name',\n 'placeholder',\n 'open',\n 'disabled',\n 'readonly',\n 'required',\n 'checked',\n 'selected',\n 'value',\n 'min',\n 'max',\n 'step',\n 'rows',\n 'cols',\n 'for',\n 'controls',\n 'muted',\n 'loop',\n 'poster',\n 'src',\n];\n\nconst CUSTOM_TAG_PATTERN = /<([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\\b/gi;\n\n// 64 like the intl cache: more than a page declares, and a nested template is\n// interpolated with its parent's, so an outer value or `{{index}}` that lands\n// in it mints a key per item and per keystroke (ADR 0003 §3).\nexport const TEMPLATE_CACHE_LIMIT = 64;\nconst optionsByTemplate = new Map<string, SanitizeOptions>();\n\n/** Options for one template; memoised per template string. */\nexport function templateSanitizeOptions(template: string): SanitizeOptions {\n const cached = lruGet(optionsByTemplate, template);\n if (cached !== undefined) return cached;\n const tags = new Set(TEMPLATE_EXTRA_TAGS);\n for (const match of template.matchAll(CUSTOM_TAG_PATTERN)) {\n const tag = match[1]?.toLowerCase();\n if (tag !== undefined) tags.add(tag);\n }\n const attributes: Record<string, readonly string[]> = {};\n for (const tag of tags) attributes[tag] = TEMPLATE_EXTRA_ATTRIBUTES;\n const options: SanitizeOptions = {\n additionalAllowedTags: [...tags],\n additionalAllowedAttributes: attributes,\n allowFormControls: true,\n templateMode: true,\n };\n return lruSet(optionsByTemplate, template, options, TEMPLATE_CACHE_LIMIT);\n}\n","/**\n * Applies an `ArrayPatch[]` diff to a container as keyed DOM operations\n * instead of rebuilding the list, so consumer state on surviving children is\n * kept. Items are paired by `data-payload-key` (the item `id`); items without\n * one pair by position. Nested arrays reconcile recursively through\n * `data-payload-nested-key` slots. See ADR 0008.\n */\n\nimport { sanitizeHtmlWithPolicy, type SanitizerPolicyMode } from '@security/sanitizer';\nimport { trustedHtml } from '@security/trusted-types';\nimport {\n collectTemplateKeys,\n inheritItemAttributes,\n interpolateArrayTemplate,\n sharedItemAttributes,\n type InheritedAttribute,\n} from './array-template';\nimport { safeStringify } from '@field-types/utils';\nimport { diffArray, type ArrayPatch } from '@schema/diff';\nimport { morphElement } from './morph';\nimport { templateSanitizeOptions } from './template-sanitize';\n\n/** @internal */\nexport const KEY_ATTRIBUTE = 'data-payload-key';\nconst NESTED_KEY_ATTRIBUTE = 'data-payload-nested-key';\nconst NESTED_TEMPLATE_ATTRIBUTE = 'data-payload-nested-template';\n\n/** Last value seen per item key, per container; owned by the caller so instances never share it. @internal */\nexport type StructuralStore = WeakMap<Element, Map<string, unknown>>;\n\n/** @internal */\nexport function createStructuralStore(): StructuralStore {\n return new WeakMap<Element, Map<string, unknown>>();\n}\n\n/** @internal */\nexport interface StructuralApplyOptions {\n readonly template: string;\n readonly container: Element;\n readonly patches: readonly ArrayPatch[];\n /** The full new array; inserts and replaces render by index from it. */\n readonly nextItems: readonly unknown[];\n /** Pass the same store across renders so nested arrays diff incrementally. */\n readonly store: StructuralStore;\n /** Re-render existing items even when unchanged. */\n readonly forceRender?: boolean;\n /** The instance's policy for item markup; absent, the process default applies. */\n readonly sanitizerPolicy?: SanitizerPolicyMode | undefined;\n /** Edit a changed item in place instead of replacing it. Default `true`. */\n readonly morph?: boolean;\n /** Reported once per container when two items share a key (`LP0405`). */\n readonly onDuplicateKey?: (container: Element, key: string) => void;\n}\n\n/**\n * Returns `true` for a DOM mutation, `false` for an already-current tree, and\n * `null` when an item's markup has no sanitized element root — preflighted\n * before any mutation, so the previous DOM and memory stay intact.\n * @internal\n */\nexport function applyStructuralPatches(options: StructuralApplyOptions): boolean | null {\n const plan = prepareStructuralPlan(options.container, options.patches, options);\n if (plan === null) return null;\n return commitStructuralPlan(plan, options.store, {\n morph: options.morph ?? true,\n onDuplicateKey: options.onDuplicateKey,\n });\n}\n\n// Plan records are tuples: many are created per recursive render, and named\n// keys would repeat in the inline bundle.\ntype StructuralPlan = readonly [\n container: Element,\n entries: readonly ReconciliationEntry[],\n nextItems: readonly unknown[],\n];\ntype ReconciliationEntry = readonly [\n index: number,\n live: Element | null,\n rendered: Element | undefined,\n nestedSlots: readonly NestedSlotPlan[],\n /** A `replace` patch: a different item, never morphed toward. */\n replace: boolean,\n];\ntype NestedSlotPlan = readonly [\n live: Element | null,\n rendered: Element,\n children: StructuralPlan | undefined,\n];\n\n// One per container, not per item, so — unlike the tuples above — named keys\n// cost the inline bundle nothing per render.\ntype RenderEnv = Pick<\n StructuralApplyOptions,\n 'template' | 'nextItems' | 'forceRender' | 'store' | 'sanitizerPolicy'\n>;\n\ninterface CommitOptions {\n readonly morph: boolean;\n readonly onDuplicateKey: ((container: Element, key: string) => void) | undefined;\n}\n\n/** A rendered slot that still carries a nested template keeps its children for its own plan. */\nfunction isManagedNestedSlot(_live: Element, rendered: Element): boolean {\n return (\n rendered.hasAttribute(NESTED_KEY_ATTRIBUTE) && rendered.hasAttribute(NESTED_TEMPLATE_ATTRIBUTE)\n );\n}\n\n/** Materialise the whole recursive replacement tree before touching live DOM. */\nfunction prepareStructuralPlan(\n container: Element,\n patches: readonly ArrayPatch[],\n env: RenderEnv,\n): StructuralPlan | null {\n const entries = prepareReconciliation(container, createPatchPlan(patches), env);\n return entries === null ? null : [container, entries, env.nextItems];\n}\n\nfunction commitStructuralPlan(\n plan: StructuralPlan,\n store: StructuralStore,\n options: CommitOptions,\n): boolean {\n const [container, entries, nextItems] = plan;\n const claimed = new Set<Element>();\n let mutated = false;\n for (const [index, live, rendered, nestedSlots, replace] of entries) {\n let node = live;\n if (rendered !== undefined) {\n // Morph a compatible live item in place; otherwise transplant its live\n // nested slots into the rendered item and swap.\n const retained =\n options.morph && !replace && live !== null\n ? morphElement(live, rendered, {\n keyAttributes: [KEY_ATTRIBUTE, NESTED_KEY_ATTRIBUTE],\n retainChildrenOf: isManagedNestedSlot,\n ...(options.onDuplicateKey !== undefined\n ? { onDuplicateKey: options.onDuplicateKey }\n : {}),\n }) === live\n : false;\n if (!retained) {\n for (const [liveSlot, renderedSlot] of nestedSlots) {\n if (liveSlot === null) continue;\n synchronizeAttributes(liveSlot, renderedSlot);\n renderedSlot.replaceWith(liveSlot);\n }\n }\n for (const [, , children] of nestedSlots) {\n if (children !== undefined) commitStructuralPlan(children, store, options);\n }\n if (retained) {\n mutated = true;\n } else {\n if (live !== null) {\n live.replaceWith(rendered);\n mutated = true;\n }\n node = rendered;\n }\n }\n if (node === null) continue;\n const before = container.children[index] ?? null;\n if (node !== before) {\n container.insertBefore(node, before);\n mutated = true;\n }\n claimed.add(node);\n }\n // `nextItems` is the source of truth; this also drops SSR children the first value did not carry.\n for (const child of Array.from(container.children)) {\n if (claimed.has(child)) continue;\n child.remove();\n mutated = true;\n }\n const memory = getMemory(container, store);\n memory.clear();\n for (const value of nextItems) rememberItem(memory, value);\n return mutated;\n}\n\n/**\n * Pair every final item with a live child (by key, else by position) and\n * render what needs rendering. Patch indices describe `next`, live indices\n * move during reconciliation, so keyed nodes are resolved from the DOM first.\n */\nfunction prepareReconciliation(\n container: Element,\n plan: PatchPlan,\n env: RenderEnv,\n): readonly ReconciliationEntry[] | null {\n const { template, nextItems, forceRender = false, store, sanitizerPolicy } = env;\n const memory = store.get(container);\n // Read before anything is rendered: what the current items share is what the\n // template cannot say, and an inserted item has no predecessor of its own.\n const shared = sharedItemAttributes(container);\n const templateKeys = collectTemplateKeys(nextItems);\n const initialChildren = Array.from(container.children);\n const keyedChildren = indexByAttribute(initialChildren, KEY_ATTRIBUTE);\n const reserved = new Set<Element>();\n const entries: ReconciliationEntry[] = [];\n for (let index = 0; index < nextItems.length; index += 1) {\n const value = nextItems[index];\n const key = readKey(value);\n let live =\n key === undefined\n ? (initialChildren[index] ?? null)\n : (takeIndexedElement(keyedChildren, key) ?? null);\n if (live !== null && reserved.has(live)) live = null;\n if (live !== null) reserved.add(live);\n const replace = plan.replaces.has(index);\n const needsRender = forceRender || plan.renders.has(index) || live === null;\n const rendered = needsRender\n ? renderItem(\n container.ownerDocument,\n template,\n value,\n index,\n sanitizerPolicy,\n shared,\n templateKeys,\n )\n : undefined;\n if (rendered === null) return null;\n const nestedSlots =\n rendered === undefined\n ? []\n : prepareNestedSlots(\n replace ? null : live,\n rendered,\n value,\n key === undefined ? undefined : memory?.get(key),\n env,\n );\n if (nestedSlots === null) return null;\n entries.push([index, live, rendered, nestedSlots, replace]);\n }\n return entries;\n}\n\ninterface PatchPlan {\n readonly renders: ReadonlySet<number>;\n readonly replaces: ReadonlySet<number>;\n}\n\nfunction createPatchPlan(patches: readonly ArrayPatch[]): PatchPlan {\n const renders = new Set<number>();\n const replaces = new Set<number>();\n for (const patch of patches) {\n if (patch.kind === 'insert' || patch.kind === 'update') renders.add(patch.index);\n else if (patch.kind === 'replace') {\n renders.add(patch.index);\n replaces.add(patch.index);\n }\n }\n return { renders, replaces };\n}\n\n/** Plan each direct nested slot; a failure at any depth aborts before commit. */\nfunction prepareNestedSlots(\n oldItem: Element | null,\n newItem: Element,\n nextValue: unknown,\n prevValue: unknown,\n env: RenderEnv,\n): readonly NestedSlotPlan[] | null {\n const oldSlots = oldItem === null ? [] : findDirectNestedSlots(oldItem);\n const oldSlotsByKey = indexByAttribute(oldSlots, NESTED_KEY_ATTRIBUTE);\n const plans: NestedSlotPlan[] = [];\n for (const newSlot of findDirectNestedSlots(newItem)) {\n const key = newSlot.getAttribute(NESTED_KEY_ATTRIBUTE);\n if (key === null) continue;\n const oldSlot = takeIndexedElement(oldSlotsByKey, key) ?? null;\n const nextTemplate = newSlot.getAttribute(NESTED_TEMPLATE_ATTRIBUTE);\n // Without a nested template the slot's rendered static content is authoritative.\n const liveSlot = nextTemplate ? oldSlot : null;\n const previousTemplate = liveSlot?.getAttribute(NESTED_TEMPLATE_ATTRIBUTE) ?? null;\n let children: StructuralPlan | undefined;\n if (nextTemplate) {\n const nextNested = readNestedArray(nextValue, key);\n if (nextNested !== undefined || liveSlot !== null) {\n const resolvedNext = nextNested ?? [];\n const prevNested = liveSlot === null ? [] : (readNestedArray(prevValue, key) ?? []);\n const patches = diffArray(prevNested, resolvedNext);\n const templateChanged = liveSlot !== null && previousTemplate !== nextTemplate;\n if (patches.length > 0 || templateChanged) {\n children =\n prepareStructuralPlan(liveSlot ?? newSlot, patches, {\n template: nextTemplate,\n nextItems: resolvedNext,\n forceRender: templateChanged,\n store: env.store,\n sanitizerPolicy: env.sanitizerPolicy,\n }) ?? undefined;\n if (children === undefined) return null;\n }\n }\n }\n plans.push([liveSlot, newSlot, children]);\n }\n return plans;\n}\n\n/** Only the outermost nested slots: a transplanted slot owns the recursion below it. */\nfunction findDirectNestedSlots(item: Element): readonly Element[] {\n return Array.from(item.querySelectorAll(`[${NESTED_KEY_ATTRIBUTE}]`)).filter((slot) => {\n let ancestor = slot.parentElement;\n while (ancestor !== null && ancestor !== item) {\n if (ancestor.hasAttribute(NESTED_KEY_ATTRIBUTE)) return false;\n ancestor = ancestor.parentElement;\n }\n return ancestor === item;\n });\n}\n\nfunction synchronizeAttributes(target: Element, source: Element): void {\n for (const attribute of Array.from(target.attributes)) {\n if (!source.hasAttribute(attribute.name)) target.removeAttribute(attribute.name);\n }\n for (const attribute of Array.from(source.attributes)) {\n if (target.getAttribute(attribute.name) !== attribute.value) {\n target.setAttribute(attribute.name, attribute.value);\n }\n }\n}\n\nfunction readNestedArray(value: unknown, key: string): readonly unknown[] | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const nested = (value as Record<string, unknown>)[key];\n return Array.isArray(nested) ? (nested as readonly unknown[]) : undefined;\n}\n\nfunction getMemory(container: Element, store: StructuralStore): Map<string, unknown> {\n let map = store.get(container);\n if (!map) {\n map = new Map();\n store.set(container, map);\n }\n return map;\n}\n\nfunction rememberItem(memory: Map<string, unknown>, value: unknown): void {\n const key = readKey(value);\n if (key !== undefined) memory.set(key, value);\n}\n\nfunction readKey(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const id = (value as Record<string, unknown>)['id'];\n return typeof id === 'string' || typeof id === 'number' ? String(id) : undefined;\n}\n\nfunction indexByAttribute(elements: readonly Element[], attribute: string): Map<string, Element[]> {\n const indexed = new Map<string, Element[]>();\n // Reverse order so pop() yields duplicates in DOM order.\n for (let index = elements.length - 1; index >= 0; index -= 1) {\n const element = elements[index];\n if (element === undefined) continue;\n const key = element.getAttribute(attribute);\n if (key === null) continue;\n const bucket = indexed.get(key);\n if (bucket === undefined) indexed.set(key, [element]);\n else bucket.push(element);\n }\n return indexed;\n}\n\nfunction takeIndexedElement(indexed: Map<string, Element[]>, key: string): Element | undefined {\n return indexed.get(key)?.pop();\n}\n\n/** Render one item; its `id` is stamped as `data-payload-key` so later diffs find it. */\nfunction renderItem(\n ownerDocument: Document,\n template: string,\n value: unknown,\n index: number,\n policy: SanitizerPolicyMode | undefined,\n shared: readonly InheritedAttribute[],\n knownKeys: ReadonlySet<string>,\n): Element | null {\n const filled = interpolateArrayTemplate(template, value, index, safeStringify, knownKeys);\n const safe = sanitizeHtmlWithPolicy(filled, policy, templateSanitizeOptions(template));\n const host = ownerDocument.createElement('template');\n host.innerHTML = trustedHtml(safe);\n const first = host.content.firstElementChild;\n if (!first) return null;\n // Before the morph, which strips from the live item every attribute the\n // rendered one lacks: the marker has to be on this side to survive.\n inheritItemAttributes(first, shared);\n const key = readKey(value);\n if (key !== undefined) first.setAttribute(KEY_ATTRIBUTE, key);\n return first;\n}\n","/**\n * LRU discipline for a module-scoped lookup `Map` (ADR 0003 §3). Functions\n * over the caller's own `Map` rather than a wrapper class: the inline bundle\n * mangles function names but not property names, so a class would pay for\n * every `this.entries` in full. A `Map` iterates in insertion order, which a\n * touch on every hit turns into recency order. Values are never `undefined`,\n * and a write follows a miss — a key already present keeps its position.\n */\n\n/** Read and touch: a hit becomes the newest entry. */\nexport function lruGet<K, V>(map: Map<K, V>, key: K): V | undefined {\n const value = map.get(key);\n if (value !== undefined) {\n map.delete(key);\n map.set(key, value);\n }\n return value;\n}\n\n/** Write as the newest entry, dropping the oldest ones past `limit`; returns `value`. */\nexport function lruSet<K, V>(map: Map<K, V>, key: K, value: V, limit: number): V {\n map.set(key, value);\n lruTrim(map, limit);\n return value;\n}\n\n/** Drop the oldest entries until `limit` holds. */\nexport function lruTrim<K>(map: Map<K, unknown>, limit: number): void {\n for (const oldest of map.keys()) {\n if (map.size <= limit) break;\n map.delete(oldest);\n }\n}\n","/**\n * `structural-array` renderer (`data-payload-structural`): diffs the previous\n * and next item lists and patches the container through the keyed morph\n * (ADR 0008). All diff memory lives in the closure, one per client.\n */\n\nimport { safeConsoleWarn } from '@core/diagnostics';\nimport { markNoWriteCallback } from '@core/internal-outcome';\nimport {\n applyStructuralPatches,\n createStructuralStore,\n KEY_ATTRIBUTE,\n type StructuralStore,\n} from '@core/structural-applier';\nimport { diffArray } from '@schema/diff';\nimport type { FieldRenderer } from '@core/types';\nimport { isEmptyValue } from './utils';\n\ninterface StructuralRenderState {\n readonly values: readonly unknown[];\n readonly template: string;\n readonly domSnapshot: readonly (string | null)[];\n}\n\ntype WarnedCodes = WeakMap<Element, Set<string>>;\n\n/** @internal */\nexport function createStructuralArrayRenderer(): FieldRenderer {\n const states = new WeakMap<Element, StructuralRenderState>();\n const warnedContainers = new WeakSet<Element>();\n const warnedKeys: WarnedCodes = new WeakMap();\n const store: StructuralStore = createStructuralStore();\n\n return {\n name: 'structural-array',\n render: /* @__PURE__ */ markNoWriteCallback((target, rawValue, context) => {\n const value = isEmptyValue(rawValue) ? [] : rawValue;\n if (!Array.isArray(value)) return false;\n const container = target.element;\n const template = target.arrayTemplate;\n if (template === undefined || template.length === 0) {\n warnMissingTemplate(warnedContainers, container, target.fieldName);\n return false;\n }\n const previousState = states.get(container);\n const domSnapshot = readDomKeySnapshot(container);\n const previous = previousState?.values ?? valuesFromDomSnapshot(domSnapshot);\n const patches = diffArray(previous, value);\n const forceRender = needsForcedRender(previousState, template, domSnapshot);\n if (patches.length === 0 && !forceRender) {\n states.set(container, { values: value.slice(), template, domSnapshot });\n return false;\n }\n warnAboutKeys(warnedKeys, container, target.fieldName, previousState?.values, value);\n const applied = applyStructuralPatches({\n template,\n container,\n patches,\n nextItems: value,\n store,\n forceRender,\n sanitizerPolicy: context.sanitizerPolicy,\n onDuplicateKey: (owner, key) => {\n warnDuplicateKey(warnedKeys, owner, target.fieldName, key);\n },\n });\n if (applied === null) return false;\n states.set(container, {\n values: value.slice(),\n template,\n domSnapshot: readDomKeySnapshot(container),\n });\n return applied ? undefined : false;\n }),\n };\n}\n\nfunction needsForcedRender(\n previous: StructuralRenderState | undefined,\n template: string,\n domSnapshot: readonly (string | null)[],\n): boolean {\n if (previous === undefined) return true;\n return previous.template !== template || !sameDomKeySnapshot(previous.domSnapshot, domSnapshot);\n}\n\n// SSR markup exists before any in-memory snapshot; its direct-child keys let\n// the first update reconcile instead of appending a second copy.\nfunction readDomKeySnapshot(container: Element): readonly (string | null)[] {\n return Array.from(container.children, (child) => child.getAttribute(KEY_ATTRIBUTE));\n}\n\nfunction valuesFromDomSnapshot(snapshot: readonly (string | null)[]): readonly unknown[] {\n return snapshot.map((key, position) =>\n key === null ? { __payloadDomPosition: position } : { id: key },\n );\n}\n\nfunction sameDomKeySnapshot(\n previous: readonly (string | null)[],\n current: readonly (string | null)[],\n): boolean {\n if (previous.length !== current.length) return false;\n return previous.every((key, index) => key === current[index]);\n}\n\nfunction warnMissingTemplate(\n warnedContainers: WeakSet<Element>,\n container: Element,\n fieldName: string,\n): void {\n if (warnedContainers.has(container)) return;\n warnedContainers.add(container);\n safeConsoleWarn(\n `[live-preview] LP0403: Skipping structural update for \"${fieldName}\": ` +\n `<${container.tagName.toLowerCase()} data-payload-structural> needs ` +\n `data-payload-array-template (for example \"<li>{{label}}</li>\").`,\n );\n}\n\nfunction itemKey(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const id = (value as Record<string, unknown>)['id'];\n return typeof id === 'string' || typeof id === 'number' ? String(id) : undefined;\n}\n\n/** Key problems degrade the morph, they do not break it; each is announced once per container (ADR 0008 §5). */\nfunction warnAboutKeys(\n warned: WarnedCodes,\n container: Element,\n fieldName: string,\n previous: readonly unknown[] | undefined,\n next: readonly unknown[],\n): void {\n const nextKeys = next.map(itemKey);\n const seen = new Set<string>();\n const duplicate = nextKeys.find((key) => {\n if (key === undefined) return false;\n if (seen.has(key)) return true;\n seen.add(key);\n return false;\n });\n if (duplicate !== undefined) warnDuplicateKey(warned, container, fieldName, duplicate);\n if (nextKeys.some((key) => key === undefined)) {\n warnOnce(\n warned,\n container,\n 'LP0404',\n `LP0404: an item of \"${fieldName}\" has no id and pairs by ` +\n 'position, so an insert re-renders every row after it. Give items a stable id.',\n );\n }\n if (previous?.length === next.length && next.length > 1) {\n const previousKeys = new Set(previous.map(itemKey).filter((key) => key !== undefined));\n const stable = nextKeys.some((key) => key !== undefined && previousKeys.has(key));\n if (previousKeys.size > 0 && !stable) {\n warnOnce(\n warned,\n container,\n 'LP0406',\n `LP0406: every key of \"${fieldName}\" changed at once; the ` +\n 'source generates ids per message, so no item can be retained across updates.',\n );\n }\n }\n}\n\n// Reached from the pre-diff check and from the morph's nested-slot check; one site, one message.\nfunction warnDuplicateKey(\n warned: WarnedCodes,\n owner: Element,\n fieldName: string,\n key: string,\n): void {\n warnOnce(\n warned,\n owner,\n 'LP0405',\n `LP0405: two items of \"${fieldName}\" share the key \"${key}\"; later ones pair by ` +\n 'position. Make `id` unique per item.',\n );\n}\n\nfunction warnOnce(warned: WarnedCodes, container: Element, code: string, message: string): void {\n let codes = warned.get(container);\n if (codes === undefined) {\n codes = new Set();\n warned.set(container, codes);\n }\n if (codes.has(code)) return;\n codes.add(code);\n safeConsoleWarn(`[live-preview] ${message}`);\n}\n","/**\n * One source → dependents map for `skipUnchanged`. Markup declares it the\n * other way round (`data-payload-depends=\"price\"` on the element bound to\n * `priceLabel`) because an author names what a binding needs; the runtime\n * option is keyed by source because the scheduler asks what changed.\n * @internal\n */\n\nexport type DependencyMap = Readonly<Record<string, readonly string[]>>;\n\n/**\n * Field names from an attribute value. Separators are commas and\n * whitespace; empty entries are dropped; order is kept, duplicates removed.\n * @internal\n */\nexport function parseDependencyList(value: string | null | undefined): readonly string[] {\n if (value === null || value === undefined) return [];\n const seen = new Set<string>();\n const names: string[] = [];\n for (const raw of value.split(/[\\s,]+/)) {\n const name = raw.trim();\n if (name.length === 0 || seen.has(name)) continue;\n seen.add(name);\n names.push(name);\n }\n return names;\n}\n\n/**\n * Merge dependency maps (source → dependents). Later maps add to earlier\n * ones; a dependent is listed once per source.\n * @internal\n */\nexport function mergeDependencyMaps(...maps: readonly DependencyMap[]): DependencyMap {\n const merged = new Map<string, Set<string>>();\n for (const map of maps) {\n for (const [source, dependents] of Object.entries(map)) {\n let bucket = merged.get(source);\n if (bucket === undefined) {\n bucket = new Set();\n merged.set(source, bucket);\n }\n for (const dependent of dependents) bucket.add(dependent);\n }\n }\n const result: Record<string, readonly string[]> = {};\n for (const [source, dependents] of merged) result[source] = [...dependents];\n return result;\n}\n\n/**\n * The map an element's `data-payload-depends` contributes: every declared\n * source points at this binding's field.\n * @internal\n */\nexport function dependencyMapFromBinding(\n fieldName: string,\n dependsOn: readonly string[],\n): DependencyMap {\n const map: Record<string, readonly string[]> = {};\n for (const source of dependsOn) {\n if (source === fieldName) continue;\n map[source] = [fieldName];\n }\n return map;\n}\n"],"mappings":"aA8BO,IAtBLA,ECcEC,EDQSC,GAtBXF,EAsB+C,IAAIG,IAClDC,QAAQC,QAA8CF,GArBhD,IAAIA,KACT,KEFoB,iBADcG,EFIVN,KAAcG,KEHI,OAAVG,GAAoC,mBAAVA,IACD,mBAA/CA,EAAsCC,MAC7CC,QAAQC,QAAQH,GAAOI,MAAM,OFEhC,OAEA,CEPG,IAA+BJ,ICChCK,iBAAA,IAAuBC,QAGtB,SAASC,EAAwCC,GAEtD,OADAH,EAAiBI,IAAID,GACdA,CACT,CF0CO,SAASE,EAAYC,GAC1B,MAAMC,EAnBR,WAEE,QAAmB,IAAfjB,EAA0B,OAAOA,EACrC,MAAMkB,EAVR,WACE,MAAMC,EAAaC,WAA0CC,aAC7D,GAAyB,iBAAdF,GAAwC,OAAdA,EAErC,MAAyB,mBADTA,EAAyCG,aAClBH,OAAwC,CACjF,CAKcI,GACZ,IACEvB,OACU,IAARkB,EACI,KACAA,EAAII,aA5B2B,uBA4Ba,CAAEE,WAAaC,GAAUA,GAC7E,OAGEzB,EAAa,IACf,CACA,OAAOA,CACT,CAIiB0B,GACf,OAAe,OAAXT,EAAwBD,EACrBC,EAAOO,WAAWR,EAC3B,CGxDA,IAAMW,iBAAA,IAA0CC,IAAI,CAAC,QAAS,SAAU,UAAW,SAG7EC,EAA6B,wDAE7BC,EAAgB,mCAIhBC,EAAoB,YAGpBC,EAAiB,YAGhB,SAASC,UAAUC,GACxB,GAAmB,iBAARA,EAAkB,OAAO,EACpC,MAAMC,EAAUD,EAAIE,OAAOC,QAAQL,EAAgB,IACnD,GAAuB,IAAnBG,EAAQG,OAAc,OAAO,EACjC,GAAIT,EAA2BU,KAAKJ,GAAU,OAAO,EACrD,GAAIA,EAAQK,WAAW,MAAQL,EAAQK,WAAW,KAAM,OAAO,EAC/D,GAAIT,EAAkBQ,KAAKJ,GAAU,OAAO,EAC5C,GAAIA,EAAQK,WAAW,KAAM,OAAO,EACpC,IACE,MAAMC,EAAS,IAAIC,IAAIP,GACvB,OAAOR,EAAegB,IAAIF,EAAOG,SACnC,OACE,OAAOd,EAAcS,KAAKJ,EAC5B,CACF,CCHA,IAAMU,iBAAA,IAAejB,IA4Bd,SAASkB,EAAuBC,GACjCF,EAASF,IAAII,KACjBF,EAAS/B,IAAIiC,GAtCf,SAAcC,GACZ,IACE7C,QAAQC,KAAK4C,EACf,OAEA,CACF,CAiCE5C,CACE,yDAAyD2C,qFA3B7D,SAAgBA,GACd,OAAIA,EAAKP,WAHY,iBAKjB,0IAIS,OAATO,GAA0B,SAATA,EAEjB,+HAKF,+HAGJ,CAWkEE,CAAOF,OAEzE,CCrDA,IAAMG,iBAAA,IAAwCtB,IAAI,CAChD,IACA,KACA,SACA,IACA,KACA,IACA,IACA,IACA,SACA,OACA,QACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,aACA,OACA,MACA,MACA,OACA,MACA,IACA,OACA,MACA,UACA,UACA,QACA,SACA,SACA,MACA,SACA,aACA,MACA,UACA,SACA,QACA,QACA,MACA,MACA,KACA,OACA,OACA,OACA,IACA,QACA,QACA,QACA,QACA,KACA,KACA,KACA,UACA,WACA,QAIIuB,iBAAA,IAAyCvB,IAAI,CACjD,QACA,SACA,WACA,SACA,SACA,UAIIwB,iBAAA,IAA6CxB,IAAI,CACrD,SACA,QACA,SACA,SACA,QACA,OACA,OACA,OACA,OACA,QACA,SACA,SACA,WACA,MACA,OACA,WACA,QACA,WACA,WACA,aAGIyB,iBAAA,IAAuCzB,IAAI,CAC/C,KACA,QACA,OACA,MACA,QACA,OACA,aAGI0B,EAAmB,QACnBC,EAAmB,QAGnBC,EAA6D,CACjEC,iBAAG,IAAI7B,IAAI,CAAC,OAAQ,SAAU,MAAO,WAAY,WAAY,SAC7D8B,mBAAK,IAAI9B,IAAI,CAAC,MAAO,SAAU,QAAS,MAAO,QAAS,SAAU,UAAW,aAC7E+B,uBAAS,IAAI/B,IAAI,IACjBgC,sBAAA,IAAYhC,IAAI,CAAC,MAAO,SAAU,QAAS,OAAQ,UACnDiC,qBAAO,IAAIjC,IAAI,CAAC,MAAO,WAAY,WAAY,OAAQ,QAAS,YAChEkC,qBAAA,IAAWlC,IAAI,CACb,MACA,SACA,WACA,WACA,OACA,QACA,UACA,QACA,SACA,gBAEFmC,oBAAM,IAAInC,IAAI,CAAC,aACfoC,oBAAM,IAAIpC,IAAI,CAAC,UACfqC,iBAAG,IAAIrC,IAAI,CAAC,SACZsC,0BAAY,IAAItC,IAAI,CAAC,SACrBuC,qBAAO,IAAIvC,IAAI,CAAC,YAChBwC,kBAAA,IAAQxC,IAAI,CAAC,UAAW,UAAW,QAAS,UAAW,SACvDyC,kBAAI,IAAIzC,IAAI,CAAC,UAAW,UAAW,YACnC0C,mBAAK,IAAI1C,IAAI,CAAC,SACd2C,wBAAU,IAAI3C,IAAI,CAAC,SACnB4C,kBAAI,IAAI5C,IAAI,CAAC,QAAS,WAAY,SAClC6C,kBAAI,IAAI7C,IAAI,CAAC,UACb8C,oBAAM,IAAI9C,IAAI,CAAC,UACf+C,mBAAK,IAAI/C,IAAI,CAAC,WAGVgD,iBAAA,IAA0ChD,IAAI,CAAC,OAAQ,MAAO,OAAQ,WAQ/DiD,EAAN,cAAwCC,MAC3B/B,KAAO,6BAqCrBgC,iBAAA,IAA+CnD,IAAI,CACvD,KACA,OACA,mBACA,0BACA,iCAuEIoD,iBAA+BC,OAAOC,IAAI,2CAoEhD,SAASC,EAAiBC,EAAkBnE,GAE1C,UAAWoE,KAASC,MAAMC,KAAKH,EAAKI,YA5LjB,IA6LbH,EAAMI,SACRC,EAAgBL,EAAkBpE,GA7LnB,IA8LNoE,EAAMI,UACfJ,EAAMM,QAGZ,CAEA,SAASD,EAAgBE,EAAkB3E,GACzC,MAAM4E,EAAMD,EAAQE,QAAQC,cAE5B,IAAI3C,EAAkBT,IAAIkD,IAAU5E,EAAO+E,mBAAqB7C,EAAcR,IAAIkD,GAAlF,CAKA,IAAK5E,EAAOgF,YAAYtD,IAAIkD,GAG1B,OAFAV,EAAiBS,EAAS3E,QAC1B2E,EAAQM,eAAeN,EAAQJ,aASnC,SAA4BI,EAAkBC,EAAa5E,GACzD,MAAMkF,EAAWlF,EAAOmF,UAAUC,IAAIR,GAEtC,UAAWS,KAAQhB,MAAMC,KAAKK,EAAQW,YAAa,CACjD,MAAMxD,EAAOuD,EAAKvD,KAAKgD,cACvB,GAAIhD,EAAKP,WAAW,OAAkB,UAATO,EAC3B6C,EAAQY,gBAAgBF,EAAKvD,UAD/B,CAIA,GAAoB,WAAhB9B,EAAOwF,KAAmB,CAC5B,GAAIxF,EAAOyF,cAAgB3B,EAAoBpC,IAAII,GAAO,SAG1D,GAAa,OAATA,GAA0B,SAATA,GAAmBA,EAAKP,WA5QvB,iBA4QwD,CAC5EoD,EAAQY,gBAAgBF,EAAKvD,MAGhB,SAATA,IAA2C,IAAxBoD,GAAUxD,IAAII,IAAUD,EAA6BC,GAC5E,QACF,CACA,GAAIA,EAAKP,WAAWe,GAAmB,CAChCtC,EAAO0F,YAAYhE,IAAII,KAC1B6C,EAAQY,gBAAgBF,EAAKvD,MAC7BD,EAAuBC,IAEzB,QACF,CACA,GAAIM,EAAYV,IAAII,IAASA,EAAKP,WAAWc,GAAmB,QAClE,SACED,EAAYV,IAAII,IAChBA,EAAKP,WAAWc,IAChBP,EAAKP,WAAWe,GAEhB,SAEE4C,GAAUxD,IAAII,GACZ6B,EAAejC,IAAII,KAAUd,UAAUqE,EAAKjG,OAC9CuF,EAAQY,gBAAgBF,EAAKvD,MACX,WAATA,GAAsB6D,EAAaN,EAAKjG,QACjDuF,EAAQY,gBAAgBF,EAAKvD,MAIjC6C,EAAQY,gBAAgBF,EAAKvD,KAnC7B,CAoCF,CACF,CAlDE8D,CAAmBjB,EAASC,EAAK5E,GACrB,MAAR4E,GA+DN,SAAsBiB,GACpB,MAAMC,EAAOD,EAAOE,aAAa,QACpB,OAATD,GFnZC,SAASE,kBAAkB/E,GAChC,MAAMC,EAAUD,EAAIE,OAAOC,QAAQL,EAAgB,IACnD,MAAO,gBAAgBO,KAAKJ,IAAYJ,EAAkBQ,KAAKJ,EACjE,CEgZwB8E,CAAkBF,KACxCD,EAAOI,aAAa,MAAO,uBACtBJ,EAAOK,aAAa,WAAWL,EAAOI,aAAa,SAAU,UACpE,CApEmBE,CAAaxB,GAC9BT,EAAiBS,EAAS3E,EAV1B,MAFE2E,EAAQD,QAaZ,CAkDA,SAASiB,EAAavG,GACpB,UAAWc,KAAad,EAAMgH,MAAM,KAAM,CACxC,MAAMlF,EAAUhB,EAAUiB,OAC1B,GAAuB,IAAnBD,EAAQG,OAAc,SAE1B,MAAOJ,EAAMC,GAAWA,EAAQkF,MAAM,KAAM,GAC5C,IAAKpF,UAAUC,GAAM,OAAO,CAC9B,CACA,OAAO,CACT,CClbA,IAAMoF,EAAiDC,OAAOC,OAAO,CACnE,IAAK,QACL,IAAK,OACL,IAAK,OACL,IAAK,SACL,IAAK,SACL,IAAK,SACL,IAAK,SACL,IAAK,WAGDC,EAAsB,cAGrB,SAASC,WAAWC,GAGzB,OAAOA,EAAKtF,QAAQoF,EAAsBG,GAASN,EAAaM,GAClE,CCXA,IAAMC,iBAAA,IAA8CjG,IAAI,CACtD,QACA,SACA,aACA,OACA,KACA,OACA,KACA,SACA,gBAsBK,SAASkG,EAAoB/E,GAClC,OAAQA,EAAKP,WAAW,QAAUqF,EAAmBlF,IAAII,EAC3D,CC9BA,IAAMgF,EAAsB,sBCTrB,SAASC,EAAc3H,GAC5B,GAAIA,QAAuC,MAAO,GAClD,GAAqB,iBAAVA,EAAoB,OAAOA,EACtC,GAAqB,iBAAVA,GAAuC,kBAAVA,GAAwC,iBAAVA,EACpE,OAAO4H,OAAO5H,GAEhB,IACE,OAAO6H,KAAKC,UAAU9H,EACxB,OACE,MAAO,EACT,CACF,CCSA,SAAS+H,EAAMC,GACb,GAAoB,iBAATA,GAA8B,OAATA,EAAe,OAC/C,MAAMC,EAAMD,EAAqC,GACjD,MAAkB,iBAAPC,GAAiC,iBAAPA,EAAwBA,OAA7D,CAEF,CAEA,SAASC,EAAaF,GACpB,GAAoB,iBAATA,GAA8B,OAATA,EAAe,OAC/C,MAAMG,EAAaH,EAA4C,UAC/D,MAA4B,iBAAdG,EAAyBA,OAAY,CACrD,CAGO,SAASC,EACdC,EACAC,GAGA,OADgBA,EAAKC,MAAOP,QAAyB,IAAhBD,EAAMC,IAK7C,SAAkBK,EAA0BC,GAC1C,MAAME,EAAwB,GACxBC,iBAAA,IAAoBC,IAC1B,QAASC,EAAI,EAAGA,EAAIN,EAAKpG,OAAQ0G,GAAK,EAAG,CACvC,MAAMV,EAAKF,EAAMM,EAAKM,SACX,IAAPV,GAAkBQ,EAAcG,IAAIX,EAAIU,EAC9C,CAEA,MAAME,iBAAA,IAAuBtH,IAC7B,QAASuH,EAAK,EAAGA,EAAKR,EAAKrG,OAAQ6G,GAAM,EAAG,CAC1C,MAAMd,EAAOM,EAAKQ,GACZb,EAAKF,EAAMC,GACjB,QAAW,IAAPC,EAAkB,CACpBO,EAAQO,KAAK,CAAEC,KAAM,SAAUC,MAAOH,EAAI9I,MAAOgI,IACjD,QACF,CACA,MAAM9C,EAAOuD,EAAczC,IAAIiC,GAC/B,QAAa,IAAT/C,EAAoB,CACtBsD,EAAQO,KAAK,CAAEC,KAAM,SAAUC,MAAOH,EAAI9I,MAAOgI,IACjD,QACF,CACAa,EAAiBpI,IAAIyE,GACrB,MAAMgE,EAAWb,EAAKnD,GAClBgD,EAAagB,KAAchB,EAAaF,IAIxC9C,IAAS4D,GACXN,EAAQO,KAAK,CAAEC,KAAM,OAAQ9D,OAAM4D,KAAI9I,MAAOgI,IAE3CmB,EAAaD,EAAUlB,IAC1BQ,EAAQO,KAAK,CAAEC,KAAM,SAAUC,MAAOH,EAAI9I,MAAOgI,KAPjDQ,EAAQO,KAAK,CAAEC,KAAM,UAAWC,MAAOH,EAAIM,SAAUF,EAAUlJ,MAAOgI,GAS1E,CAEA,QAASW,EAAI,EAAGA,EAAIN,EAAKpG,OAAQ0G,GAAK,EAChCE,EAAiBvG,IAAIqG,IACzBH,EAAQO,KAAK,CAAEC,KAAM,SAAUC,MAAON,EAAG3I,MAAOqI,EAAKM,KAEvD,OAAOH,CACT,CA5CsBa,CAAShB,EAAMC,GA8CrC,SAAwBD,EAA0BC,GAChD,MAAME,EAAwB,GACxBc,EAAMC,KAAKD,IAAIjB,EAAKpG,OAAQqG,EAAKrG,QACvC,QAAS0G,EAAI,EAAGA,EAAIW,EAAKX,GAAK,EACvBQ,EAAad,EAAKM,GAAIL,EAAKK,KAC9BH,EAAQO,KAAK,CAAEC,KAAM,SAAUC,MAAON,EAAG3I,MAAOsI,EAAKK,KAGzD,GAAIL,EAAKrG,OAASoG,EAAKpG,OACrB,QAAS0G,EAAIN,EAAKpG,OAAQ0G,EAAIL,EAAKrG,OAAQ0G,GAAK,EAC9CH,EAAQO,KAAK,CAAEC,KAAM,SAAUC,MAAON,EAAG3I,MAAOsI,EAAKK,KAGzD,GAAIN,EAAKpG,OAASqG,EAAKrG,OACrB,QAAS0G,EAAIL,EAAKrG,OAAQ0G,EAAIN,EAAKpG,OAAQ0G,GAAK,EAC9CH,EAAQO,KAAK,CAAEC,KAAM,SAAUC,MAAON,EAAG3I,MAAOqI,EAAKM,KAGzD,OAAOH,CACT,CAhESgB,CAAenB,EAAMC,EAC9B,CAmEA,SAASa,EAAa/F,EAAYqG,GAChC,GAAIvC,OAAOwC,GAAGtG,EAAGqG,GAAI,OAAO,EAC5B,GAAiB,iBAANrG,GAA+B,iBAANqG,GAAwB,OAANrG,GAAoB,OAANqG,EAAY,OAAO,EACvF,MAAME,EAAOvG,EACPwG,EAAOH,EACPI,EAAQ3C,OAAO4C,KAAKH,GACpBI,EAAQ7C,OAAO4C,KAAKF,GAC1B,GAAIC,EAAM5H,SAAW8H,EAAM9H,OAAQ,OAAO,EAC1C,UAAW+H,KAAOH,EAChB,IAAK3C,OAAOwC,GAAGC,EAAKK,GAAMJ,EAAKI,IAAO,OAAO,EAE/C,OAAO,CACT,CClHO,IAAMC,EAAmB,sBCGnBC,EAAkB,qBAGzBC,iBAAA,IAA4C5I,IAAI,CAAC,OAAQ,QAAS,UAAW,aAYnF,SAAS6I,EAAM7E,EAAkB8E,GAC/B,UAAWC,KAAaD,EAAQE,cAAe,CAC7C,MAAMvK,EAAQuF,EAAQoB,aAAa2D,GACnC,GAAc,OAAVtK,GAAkBA,EAAMiC,OAAS,EAAG,MAAO,GAAGqI,KAAatK,GACjE,CAEF,CAGO,SAASwK,EAAgBjF,GAC9B,GAAIA,EAAQE,QAAQC,cAAc+E,SAAS,KAAM,OAAO,EACxD,GAAIlF,EAAQuB,aAAamD,IAAqB1E,EAAQuB,aAAaoD,GAAkB,OAAO,EAC5F,MAAMQ,EAAWnF,EAAQoB,aAAa,mBACtC,OAAoB,OAAb+D,GAAkC,UAAbA,CAC9B,CAGO,SAASC,EAAkBC,EAAeC,GAC/C,OACED,EAAKnF,UAAYoF,EAASpF,SAC1BmF,EAAKE,eAAiBD,EAASC,eAC9BN,EAAgBI,KAChBJ,EAAgBK,EAErB,CAOO,SAASE,EAAaH,EAAeC,EAAmBR,GAC7D,IAAKM,EAAkBC,EAAMC,GAAW,OAAOA,EAC/C,MAAMG,EA0JR,SAAsBJ,GACpB,MAAMK,EAASL,EAAKM,cAAcC,cAClC,KAAMF,aAAkBG,aAAiBR,EAAKS,SAASJ,IAAS,OAAO,KAKvE,MAAO,CAAE1F,QAAS0F,EAAQK,UAHxBL,aAAkBM,kBAAoBN,aAAkBO,oBACnD,CAACP,EAAOQ,eAAgBR,EAAOS,cAChC,KAER,CAlKgBC,CAAaf,GAI3B,OAIK,SAAwBA,EAAeC,GAC5C,UAAWP,KAAarF,MAAMC,KAAK0F,EAAK1E,YAClC2E,EAAS/D,aAAawD,EAAU5H,OAChCyH,EAAiB7H,IAAIgI,EAAU5H,KAAKgD,gBACxCkF,EAAKzE,gBAAgBmE,EAAU5H,MAEjC,UAAW4H,KAAarF,MAAMC,KAAK2F,EAAS3E,YACtC0E,EAAKjE,aAAa2D,EAAU5H,QAAU4H,EAAUtK,OAClD4K,EAAK/D,aAAayD,EAAU5H,KAAM4H,EAAUtK,MAGlD,CAlBE4L,CAAehB,EAAMC,IAC8B,IAA/CR,EAAQwB,mBAAmBjB,EAAMC,IAmBvC,SAAuBD,EAAeC,EAAmBR,GACvD,MAAMyB,EA8GR,SAAoBC,EAAiB1B,GACnC,MAAM2B,iBAAA,IAAYtD,IAClB,IAAIuD,EACJ,UAAWjH,KAASC,MAAMC,KAAK6G,EAAOG,UAAW,CAC/C,MAAMlC,EAAMI,EAAMpF,EAAOqF,QACb,IAARL,IACAgC,EAAM1J,IAAI0H,GACZiC,IAAcjC,EAAImC,MAAMnC,EAAIoC,QAAQ,KAAO,GAG7CJ,EAAMpD,IAAIoB,EAAKhF,GACjB,CAEA,YADkB,IAAdiH,GAAyB5B,EAAQgC,iBAAiBN,EAAQE,GACvDD,CACT,CA5HoBM,CAAW1B,EAAMP,GAC7BkC,EAAgB,IAAIhL,IAAUuK,EAAUU,UACxCC,EAAcxH,MAAMC,KAAK0F,EAAKzF,YAAYuH,OAAQ3H,IAAUwH,EAAcjK,IAAIyC,IAC9E4H,iBAAA,IAAcpL,IACdqL,iBAAA,IAAerL,IACfsL,EAAgB5H,MAAMC,KAAK2F,EAAS1F,YAC1C,IAAI2H,EAAsBlC,EAAKmC,WAC3BC,EAAe,EAEnB,QAASrE,EAAI,EAAGA,EAAIkE,EAAc5K,OAAQ0G,GAAK,EAAG,CAChD,MAAML,EAAOuE,EAAclE,GAC3B,IAAIsE,EAAoB,KACpBjD,EAAM1B,aAAgB4E,QAAU9C,EAAM9B,EAAM+B,QAAW,EAG3D,QADY,IAARL,GAAqB4C,EAAStK,IAAI0H,KAAMA,OAAM,QACtC,IAARA,EAAmB,CACrB4C,EAASnM,IAAIuJ,GACb,MAAMlJ,EAAYgL,EAAU9F,IAAIgE,GAChC,QAAkB,IAAdlJ,IAA4B6L,EAAQrK,IAAIxB,KAC1CmM,EAAOE,EAAUrM,EAAWwH,EAAM+B,KAAavJ,EAAYA,EAAY,KAC1D,OAATmM,GAAe,CACjBnM,EAAU+E,YAAYyC,GACtBqE,EAAQlM,IAAI6H,GACZwE,EAASxE,EAAK8E,YACd,QACF,CAEJ,KAAO,CACL,KAAOJ,EAAeP,EAAYxK,QAAQ,CACxC,MAAMnB,EAAY2L,EAAYO,GAE9B,GADAA,GAAgB,GACZL,EAAQrK,IAAIxB,GAAhB,CACA,GAAIuM,EAASvM,EAAWwH,GAAO,CAC7B2E,EAAOE,EAAUrM,EAAWwH,EAAM+B,KAAavJ,EAAYA,EAAY,KAC1D,OAATmM,IACFrC,EAAK0C,aAAahF,EAAMxH,GACxB6L,EAAQlM,IAAI6H,GACZwE,EAASxE,EAAK8E,aAEhB,KACF,CACA,GAAItM,aAAqBoM,QAAS,CAGhC,MAAMK,EAAYV,EAAclE,EAAI,GACpC,KACIL,aAAgB4E,eACH,IAAdK,GAA2BF,EAASvM,EAAWyM,GAChD,CACAP,GAAgB,EAChB,KACF,CACApC,EAAK0C,aAAahF,EAAMxH,GACxB6L,EAAQlM,IAAI6H,GACZwE,EAASxE,EAAK8E,YACd,KACF,CACA,KAAM9E,aAAgB4E,SAAU,CAE9BtC,EAAK0C,aAAahF,EAAMxH,GACxB6L,EAAQlM,IAAI6H,GACZwE,EAASxE,EAAK8E,YACd,KACF,CAhC4B,CAkC9B,CACA,GAAa,OAATH,GAAiBN,EAAQrK,IAAIgG,GAAO,QAC1C,CAEA,MAAMvD,EAAakI,GAAQ3E,EAK3B,IAJAqE,EAAQlM,IAAIsE,GAIM,OAAX+H,GAAmBA,IAAW/H,IAAS4H,EAAQrK,IAAIwK,IAAWU,EAAYV,IAC/EA,EAASA,EAAOM,YAEdrI,IAAS+H,GAAQlC,EAAK6C,aAAa1I,EAAM+H,GAC7CA,EAAS/H,EAAKqI,WAChB,CAEA,UAAWpI,KAASC,MAAMC,KAAK0F,EAAKzF,YAC7BwH,EAAQrK,IAAI0C,IAAKA,EAASM,QAEnC,CAxG2DoI,CAAc9C,EAAMC,EAAUR,GAkKzF,SAAsBsD,GACpB,GAAiB,OAAbA,EAAmB,OACvB,MAAMpI,QAAEA,EAAA+F,UAASA,GAAcqC,EAC/B,GAAIpI,EAAQ2F,cAAcC,gBAAkB5F,GAAYA,EAAQqI,YAChE,IACErI,EAAQyF,MAAM,CAAE6C,eAAe,IAC/B,MAAOC,EAAOC,GAAOzC,GAAa,CAAC,KAAM,MAC3B,OAAVwC,GAA0B,OAARC,GACnBxI,EAA6ByI,kBAAkBF,EAAOC,EAE3D,OAEA,CACF,CA9KEE,CAAajD,GACNJ,CACT,CAwGA,SAASuC,EAAUrM,EAAiBwH,EAAY+B,GAC9C,OAAIvJ,aAAqBoM,SAAW5E,aAAgB4E,QAE9C1C,EAAgB1J,IAAc0J,EAAgBlC,GAAcxH,EACzDiK,EAAajK,EAAWwH,EAAM+B,IAEnCvJ,EAAUoN,YAAc5F,EAAK4F,YAAWpN,EAAUoN,UAAY5F,EAAK4F,WAChEpN,EACT,CAEA,SAAS0M,EAAYzI,GACnB,OAAOA,EAAKK,WAAa+I,KAAKC,WAAsD,KAAxCrJ,EAAKmJ,WAAa,IAAInM,OAAOE,MAC3E,CAEA,SAASoL,EAASjK,EAASqG,GACzB,OAAIrG,EAAEgC,WAAaqE,EAAErE,aACjBhC,aAAa8J,SAAWzD,aAAayD,UAChC9J,EAAEqC,UAAYgE,EAAEhE,SAAWrC,EAAE0H,eAAiBrB,EAAEqB,aAG3D,CCxKA,IAAMuD,EAAyC,CAC7C,QACA,WACA,SACA,SACA,SACA,QACA,UACA,UACA,SACA,QACA,QACA,WACA,SAGIC,EAA+C,CACnD,OACA,OACA,cACA,OACA,WACA,WACA,WACA,UACA,WACA,QACA,MACA,MACA,OACA,OACA,OACA,MACA,WACA,QACA,OACA,SACA,OAGIC,EAAqB,uCAMrBC,iBAAA,IAAwB9F,IC5CjB+F,EAAgB,mBACvBC,EAAuB,0BACvBC,EAA4B,+BAM3B,SAASC;AACd,WAAWC,OACb,CA2BO,SAASC,GAAuBzE,GACrC,MAAM0E,EAAOC,GAAsB3E,EAAQ4E,UAAW5E,EAAQ7B,QAAS6B,GACvE,OAAa,OAAT0E,EAAsB,KACnBG,GAAqBH,EAAM1E,EAAQ8E,MAAO,CAC/CC,MAAO/E,EAAQ+E,QAAS,EACxB/C,eAAgBhC,EAAQgC,gBAE5B,CAoCA,SAASgD,GAAoBC,EAAgBzE,GAC3C,OACEA,EAAS/D,aAAa4H,IAAyB7D,EAAS/D,aAAa6H,EAEzE,CAGA,SAASK,GACPC,EACAzG,EACA+G,GAEA,MAAMC,EAwER,SACEP,EACAF,EACAQ,GAEA,MAAME,SAAEA,EAAAC,UAAUA,EAAAC,YAAWA,GAAc,EAAAR,MAAOA,EAAAS,gBAAOA,GAAoBL,EACvEM,EAASV,EAAMnJ,IAAIiJ,GAGnBa,ENzHD,SAA8Bb,GACnC,MAAMc,EAAQd,EAAU/C,SAClB8D,EAAQD,EAAM,GACpB,QAAc,IAAVC,EAAqB,MAAO,GAChC,MAAMF,EAA+B,GACrC,UAAWpN,KAAEA,EAAA1C,MAAMA,KAAWiF,MAAMC,KAAK8K,EAAM9J,YAAa,CAC1D,IAAKuB,EAAoB/E,IAASA,EAAKP,WAlEV,iBAkEgD,SAC7E,IAAI8N,GAAY,EAChB,QAAShH,EAAQ,EAAGA,EAAQ8G,EAAM9N,QAAUgO,EAAWhH,GAAS,EAC9DgH,EAAYF,EAAM9G,IAAQtC,aAAajE,KAAU1C,EAE/CiQ,GAAWH,EAAO/G,KAAK,CAACrG,EAAM1C,GACpC,CACA,OAAO8P,CACT,CM2GiBI,CAAqBjB,GAC9BkB,ENxKD,SAA6BJ,GAClC,MAAMjG,iBAAA,IAAWvI,IACjB,UAAWyG,KAAQ+H,EACjB,GAAoB,iBAAT/H,GAA8B,OAATA,EAChC,UAAWgC,KAAO9C,OAAO4C,KAAK9B,GAAO8B,EAAKrJ,IAAIuJ,GAEhD,OAAOF,CACT,CMiKuBsG,CAAoBV,GACnCW,EAAkBpL,MAAMC,KAAK+J,EAAU/C,UACvCoE,EAAgBC,GAAiBF,EAAiB5B,GAClD+B,iBAAA,IAAejP,IACfiO,EAAiC,GACvC,QAASvG,EAAQ,EAAGA,EAAQyG,EAAUzN,OAAQgH,GAAS,EAAG,CACxD,MAAMjJ,EAAQ0P,EAAUzG,GAClBe,EAAMyG,GAAQzQ,GACpB,IAAI4K,OACM,IAARZ,EACKqG,EAAgBpH,IAAU,KAC1ByH,GAAmBJ,EAAetG,IAAQ,KACpC,OAATY,GAAiB4F,EAASlO,IAAIsI,KAAOA,EAAO,MACnC,OAATA,GAAe4F,EAAS/P,IAAImK,GAChC,MAAM5I,EAAU+M,EAAK4B,SAASrO,IAAI2G,GAE5B4B,EADc8E,GAAeZ,EAAK6B,QAAQtO,IAAI2G,IAAmB,OAAT2B,EAE1DiG,GACE5B,EAAU/D,cACVuE,EACAzP,EACAiJ,EACA2G,EACAE,EACAK,QAEF,EACJ,GAAiB,OAAbtF,EAAmB,OAAO,KAC9B,MAAMiG,OACS,IAAbjG,EACI,GACAkG,GACE/O,EAAU,KAAO4I,EACjBC,EACA7K,OACQ,IAARgK,OAAoB,EAAY6F,GAAQ7J,IAAIgE,GAC5CuF,GAER,GAAoB,OAAhBuB,EAAsB,OAAO,KACjCtB,EAAQzG,KAAK,CAACE,EAAO2B,EAAMC,EAAUiG,EAAa9O,GACpD,CACA,OAAOwN,CACT,CA5HkBwB,CAAsB/B,EAmIxC,SAAyBzG,GACvB,MAAMoI,iBAAA,IAAcrP,IACdoP,iBAAA,IAAepP,IACrB,UAAW0P,KAASzI,EACC,WAAfyI,EAAMjI,MAAoC,WAAfiI,EAAMjI,KAAmB4H,EAAQnQ,IAAIwQ,EAAMhI,OAClD,YAAfgI,EAAMjI,OACb4H,EAAQnQ,IAAIwQ,EAAMhI,OAClB0H,EAASlQ,IAAIwQ,EAAMhI,QAGvB,MAAO,CAAE2H,UAASD,WACpB,CA9ImDO,CAAgB1I,GAAU+G,GAC3E,OAAmB,OAAZC,EAAmB,KAAO,CAACP,EAAWO,EAASD,EAAIG,UAC5D,CAEA,SAASR,GACPH,EACAI,EACA9E,GAEA,MAAO4E,EAAWO,EAASE,GAAaX,EAClCpC,iBAAA,IAAcpL,IACpB,IAAI4P,GAAU,EACd,UAAYlI,EAAO2B,EAAMC,EAAUiG,EAAa9O,KAAYwN,EAAS,CACnE,IAAIzK,EAAO6F,EACX,QAAiB,IAAbC,EAAwB,CAG1B,MAAMuG,KACJ/G,EAAQ+E,OAAUpN,GAAoB,OAAT4I,IACzBG,EAAaH,EAAMC,EAAU,CAC3BN,cAAe,CAACkE,EAAeC,GAC/B7C,iBAAkBwD,WACa,IAA3BhF,EAAQgC,eACR,CAAEA,eAAgBhC,EAAQgC,gBAC1B,OACCzB,EAEb,IAAKwG,EACH,UAAYC,EAAUC,KAAiBR,EACpB,OAAbO,IACJE,GAAsBF,EAAUC,GAChCA,EAAazL,YAAYwL,IAG7B,UAAW,EAAKnF,KAAa4E,OACV,IAAb5E,GAAwBgD,GAAqBhD,EAAUiD,EAAO9E,GAEhE+G,EACFD,GAAU,GAEG,OAATvG,IACFA,EAAK/E,YAAYgF,GACjBsG,GAAU,GAEZpM,EAAO8F,EAEX,CACA,GAAa,OAAT9F,EAAe,SACnB,MAAMyM,EAASvC,EAAU/C,SAASjD,IAAU,KACxClE,IAASyM,IACXvC,EAAUxB,aAAa1I,EAAMyM,GAC7BL,GAAU,GAEZxE,EAAQlM,IAAIsE,EACd,CAEA,UAAWC,KAASC,MAAMC,KAAK+J,EAAU/C,UACnCS,EAAQrK,IAAI0C,KAChBA,EAAMM,SACN6L,GAAU,GAEZ,MAAMtB,EA6JR,SAAmBZ,EAAoBE,GACrC,IAAIsC,EAAMtC,EAAMnJ,IAAIiJ,GAKpB,OAJKwC,IACHA,iBAAA,IAAU/I,IACVyG,EAAMvG,IAAIqG,EAAWwC,IAEhBA,CACT,CApKiBC,CAAUzC,EAAWE,GACpCU,EAAO8B,QACP,UAAW3R,KAAS0P,EAAWkC,GAAa/B,EAAQ7P,GACpD,OAAOmR,CACT,CAgFA,SAASJ,GACPc,EACAC,EACAC,EACAC,EACAzC,GAEA,MACM0C,EAAgB1B,GADO,OAAZsB,EAAmB,GAAKK,GAAsBL,GACdnD,GAC3CyD,EAA0B,GAChC,UAAWC,KAAWF,GAAsBJ,GAAU,CACpD,MAAM9H,EAAMoI,EAAQzL,aAAa+H,GACjC,GAAY,OAAR1E,EAAc,SAClB,MAAMqI,EAAU3B,GAAmBuB,EAAejI,IAAQ,KACpDsI,EAAeF,EAAQzL,aAAagI,GAEpC0C,EAAWiB,EAAeD,EAAU,KACpCE,EAAmBlB,GAAU1K,aAAagI,IAA8B,KAC9E,IAAIzC,EACJ,GAAIoG,EAAc,CAChB,MAAME,EAAaC,GAAgBV,EAAW/H,GAC9C,QAAmB,IAAfwI,GAAyC,OAAbnB,EAAmB,CACjD,MAAMqB,EAAeF,GAAc,GAE7BhK,EAAUJ,EADgB,OAAbiJ,EAAoB,GAAMoB,GAAgBT,EAAWhI,IAAQ,GAC1C0I,GAChCC,EAA+B,OAAbtB,GAAqBkB,IAAqBD,EAClE,IAAI9J,EAAQvG,OAAS,GAAK0Q,KACxBzG,EACE8C,GAAsBqC,GAAYe,EAAS5J,EAAS,CAClDiH,SAAU6C,EACV5C,UAAWgD,EACX/C,YAAagD,EACbxD,MAAOI,EAAIJ,MACXS,gBAAiBL,EAAIK,wBACjB,OACS,IAAb1D,GAAwB,OAAO,IAEvC,CACF,CACAiG,EAAMpJ,KAAK,CAACsI,EAAUe,EAASlG,GACjC,CACA,OAAOiG,CACT,CAGA,SAASD,GAAsBlK,GAC7B,OAAO/C,MAAMC,KAAK8C,EAAK4K,iBAAiB,IAAIlE,OAA0BhC,OAAQmG,IAC5E,IAAIC,EAAWD,EAAKE,cACpB,KAAoB,OAAbD,GAAqBA,IAAa9K,GAAM,CAC7C,GAAI8K,EAAShM,aAAa4H,GAAuB,OAAO,EACxDoE,EAAWA,EAASC,aACtB,CACA,OAAOD,IAAa9K,GAExB,CAEA,SAASuJ,GAAsByB,EAAiBzP,GAC9C,UAAW+G,KAAarF,MAAMC,KAAK8N,EAAO9M,YACnC3C,EAAOuD,aAAawD,EAAU5H,OAAOsQ,EAAO7M,gBAAgBmE,EAAU5H,MAE7E,UAAW4H,KAAarF,MAAMC,KAAK3B,EAAO2C,YACpC8M,EAAOrM,aAAa2D,EAAU5H,QAAU4H,EAAUtK,OACpDgT,EAAOnM,aAAayD,EAAU5H,KAAM4H,EAAUtK,MAGpD,CAEA,SAASyS,GAAgBzS,EAAgBgK,GACvC,GAAqB,iBAAVhK,GAAgC,OAAVA,EAAgB,OACjD,MAAMiT,EAAUjT,EAAkCgK,GAClD,OAAO/E,MAAMiO,QAAQD,GAAWA,OAAgC,CAClE,CAWA,SAASrB,GAAa/B,EAA8B7P,GAClD,MAAMgK,EAAMyG,GAAQzQ,QACR,IAARgK,GAAmB6F,EAAOjH,IAAIoB,EAAKhK,EACzC,CAEA,SAASyQ,GAAQzQ,GACf,GAAqB,iBAAVA,GAAgC,OAAVA,EAAgB,OACjD,MAAMiI,EAAMjI,EAAsC,GAClD,MAAqB,iBAAPiI,GAAiC,iBAAPA,EAAkBL,OAAOK,QAAM,CACzE,CAEA,SAASsI,GAAiB4C,EAA8B7I,GACtD,MAAM8I,iBAAA,IAAc1K,IAEpB,QAASO,EAAQkK,EAASlR,OAAS,EAAGgH,GAAS,EAAGA,GAAS,EAAG,CAC5D,MAAM1D,EAAU4N,EAASlK,GACzB,QAAgB,IAAZ1D,EAAuB,SAC3B,MAAMyE,EAAMzE,EAAQoB,aAAa2D,GACjC,GAAY,OAARN,EAAc,SAClB,MAAMqJ,EAASD,EAAQpN,IAAIgE,QACZ,IAAXqJ,EAAsBD,EAAQxK,IAAIoB,EAAK,CAACzE,IACvC8N,EAAOtK,KAAKxD,EACnB,CACA,OAAO6N,CACT,CAEA,SAAS1C,GAAmB0C,EAAiCpJ,GAC3D,OAAOoJ,EAAQpN,IAAIgE,IAAMsJ,KAC3B,CAGA,SAASzC,GACP3F,EACAuE,EACAzP,EACAiJ,EACArI,EACAkP,EACAyD,GAEA,MACMC,ET7ED,SACL7S,EACAC,EACAyJ,GAEA,MAAMoJ,EAwBR,WACE,GAAgC,oBAArBC,mBAAqCA,iBAAkB,CAChE,MAAMC,EAAY5S,WAA4B4D,GAC9C,GAAIgP,EAAU,OAAOA,CACvB,CACA,MAAwB,oBAAbC,cAA0B,EAC9BA,QACT,CA/BcC,GACZ,IAAKJ,EAAK,KAesB,oBAArBC,kBAAoCA,iBACtC,IAAIjP,MAAM,4BAEZ,IAAID,EACT,iFAlBF,GAAa,KAAT7D,EAAa,MAAO,GAExB,MAAMmT,EAlFR,SACEzJ,EACA0J,GAEA,MAAM3N,EAAOiE,GAASzJ,QAAUmT,GAfK,SAgBrC,IAAK1J,EAAS,CACZ,MAAM2J,qBAActL,IACpB,UAAYlD,EAAKyO,KAAU/M,OAAOsI,QAAQrM,GAAc6Q,EAAQpL,IAAIpD,EAAKyO,GACzE,MAAO,CACLrO,YAAa/C,EACbkD,UAAWiO,EACXrO,mBAAmB,EACnBU,cAAc,EACdD,OACAE,2BAAA,IAAiB/E,IAErB,CACA,MAAM2S,EAAU,IAAI3S,IAAIsB,GAExB,GADAwH,EAAQ8J,uBAAuBC,QAAS5O,GAAQ0O,EAAQzT,IAAI+E,KAC1B,IAA9B6E,EAAQ1E,kBAA4B,UAAWH,KAAO1C,EAAeoR,EAAQzT,IAAI+E,GACrF,MAAMwO,iBAAA,IAActL,IACpB,UAAYlD,EAAKyO,KAAU/M,OAAOsI,QAAQrM,GAAc6Q,EAAQpL,IAAIpD,EAAKyO,GACzE,UAAYzO,EAAKyO,KAAU/M,OAAOsI,QAAQnF,EAAQgK,6BAA+B,IAAK,CACpF,MAAMC,EAAS,IAAI/S,IAAIyS,EAAQhO,IAAIR,IACnC,UAAWS,KAAQgO,EAAOK,EAAO7T,IAAIwF,GACrC+N,EAAQpL,IAAIpD,EAAK8O,EACnB,CACA,MAAO,CACL1O,YAAasO,EACbnO,UAAWiO,EACXrO,mBAAiD,IAA9B0E,EAAQ1E,kBAC3BU,cAAuC,IAAzBgE,EAAQhE,aACtBD,OACAE,YAAa,IAAI/E,IAAI8I,EAAQkK,uBAAuB9C,IAAK/O,GAASA,EAAKgD,gBAE3E,CA+CmBrE,CAAcgJ,EAASzJ,GAClC6O,EAAWgE,EAAIe,cAAc,YAInC,OAFA/E,EAASgF,UAAY/T,EAAYC,GACjCmE,EAAiB2K,EAASiF,QAASZ,GAC5BrE,EAASgF,SAClB,CS8DeE,CNzVR,SACLlF,EACAzH,EACAiB,EACAnB,EACAyL,GAEA,MAAMqB,EAAyB,iBAAT5M,GAA8B,OAATA,EAAgBA,EAAO,KAElE,OAAOyH,EAASzN,QAAQ0F,EAAqB,CAACmN,EAAa7K,IAG1C,OAAX4K,GA9BR,SAAgBA,EAAgB5K,GAC9B,OAAO9C,OAAO4N,UAAUC,eAAeC,KAAKJ,EAAQ5K,EACtD,CA4B2BiL,CAAOL,EAAQ5K,GAC7B3C,WAAWS,EAAUoN,QAAQlP,IAAI4O,EAAQ5K,KAEnC,OAAX4K,GAA2B,UAAR5K,EAAwB3C,WAAWS,EAAUE,IACxD,UAARgC,EAAwBpC,OAAOqB,GAIpB,OAAX2L,IAA2C,IAAxBrB,GAAWjR,IAAI0H,GAAsB,GACrD6K,EAEX,CMiUiBM,CAAyB1F,EAAUzP,EAAOiJ,EAAOtB,EAAe4L,GACnC3S,EDzTvC,SAAiC6O,GACtC,MAAM2F,EE7DD,SAAsB3D,EAAgBzH,GAC3C,MAAMhK,EAAQyR,EAAIzL,IAAIgE,GAKtB,YAJc,IAAVhK,IACFyR,EAAI4D,OAAOrL,GACXyH,EAAI7I,IAAIoB,EAAKhK,IAERA,CACT,CFsDiBsV,CAAO9G,EAAmBiB,GACzC,QAAe,IAAX2F,EAAsB,OAAOA,EACjC,MAAMG,EAAO,IAAIhU,IAAI8M,GACrB,UAAWmH,KAAS/F,EAASgG,SAASlH,GAAqB,CACzD,MAAM/I,EAAMgQ,EAAM,IAAI9P,mBACV,IAARF,GAAmB+P,EAAK9U,IAAI+E,EAClC,CACA,MAAMU,EAAgD,GACtD,UAAWV,KAAO+P,EAAMrP,EAAWV,GAAO8I,EAO1C,OElE2CtE,EFkEVyF,EElEkBzP,EF4DlB,CAC/BmU,sBAAuB,IAAIoB,GAC3BlB,4BAA6BnO,EAC7BP,mBAAmB,EACnBU,cAAc,IEhEWoL,EFkEbjD,GEjEV5F,IAAIoB,EAAKhK,GAMR,SAAoByR,GACzB,UAAWiE,KAAUjE,EAAI3H,OAAQ,CAC/B,GAAI2H,EAAIkE,MAPGC,GAOY,MACvBnE,EAAI4D,OAAOK,EACb,CACF,CAVEG,CAAQpE,GACDzR,EAHF,IAAsByR,EAAgBzH,EAAQhK,CFmErD,CCwSsD8V,CAAwBrG,IACtEsG,EAAO7K,EAAcsJ,cAAc,YACzCuB,EAAKtB,UAAY/T,EAAY8S,GAC7B,MAAMxD,EAAQ+F,EAAKrB,QAAQsB,kBAC3B,IAAKhG,EAAO,OAAO,MNvSd,SAA+BhI,EAAe8H,GACnD,UAAYpN,EAAM1C,KAAU8P,EACrB9H,EAAKlB,aAAapE,IAAOsF,EAAKnB,aAAanE,EAAM1C,EAE1D,CMsSEiW,CAAsBjG,EAAOF,GAC7B,MAAM9F,EAAMyG,GAAQzQ,GAEpB,YADY,IAARgK,GAAmBgG,EAAMnJ,aAAa4H,EAAezE,GAClDgG,CACT,CElTA,SAASkG,GAAmBjH,GAC1B,OAAOhK,MAAMC,KAAK+J,EAAU/C,SAAWlH,GAAUA,EAAM2B,aAAa8H,GACtE,CA8BA,SAAS0H,GAAQnW,GACf,GAAqB,iBAAVA,GAAgC,OAAVA,EAAgB,OACjD,MAAMiI,EAAMjI,EAAsC,GAClD,MAAqB,iBAAPiI,GAAiC,iBAAPA,EAAkBL,OAAOK,QAAM,CACzE,CA4CA,SAASmO,GACPC,EACAC,EACAC,EACAvM,GAEAwM,GACEH,EACAC,EACA,SACA,yBAAyBC,qBAA6BvM,gEAG1D,CAEA,SAASwM,GAASH,EAAqBpH,EAAoB5K,EAAc1B,GACvE,IAAI8T,EAAQJ,EAAOrQ,IAAIiJ,QACT,IAAVwH,IACFA,iBAAA,IAAYlV,IACZ8U,EAAOzN,IAAIqG,EAAWwH,IAEpBA,EAAMnU,IAAI+B,KACdoS,EAAMhW,IAAI4D,GACVzE,EAAgB,kBAAkB+C,KACpC,C,qJArKO,WACL,MAAM+T,iBAAA,IAAa7H,QACb8H,iBAAA,IAAuBrW,QACvBsW,iBAAA,IAA8B/H,QAC9BM,EAAyBP,KAE/B,MAAO,CACLlM,KAAM,mBACNmU,sBAAwBtW,EAAoB,CAACyS,EAAQ8D,EAAUC,KAC7D,MAAM/W,EPnBL,SAAsBA,GAC3B,OAAOA,SAAmD,KAAVA,CAClD,COiBoBgX,CAAaF,GAAY,GAAKA,EAC5C,IAAK7R,MAAMiO,QAAQlT,GAAQ,OAAO,EAClC,MAAMiP,EAAY+D,EAAOzN,QACnBkK,EAAWuD,EAAOiE,cACxB,QAAiB,IAAbxH,GAA8C,IAApBA,EAASxN,OAErC,OAgER,SACE0U,EACA1H,EACAsH,GAEII,EAAiBrU,IAAI2M,KACzB0H,EAAiBlW,IAAIwO,GACrBrP,EACE,0DAA0D2W,QACpDtH,EAAUxJ,QAAQC,gHAG5B,CA7EQwR,CAAoBP,EAAkB1H,EAAW+D,EAAOuD,YACjD,EAET,MAAMY,EAAgBT,EAAO1Q,IAAIiJ,GAC3BmI,EAAclB,GAAmBjH,GAEjCzG,EAAUJ,EADC+O,GAAe3K,QAAgC4K,EA+CpD3F,IAAI,CAACzH,EAAKqN,IAChB,OAARrN,EAAe,CAAEsN,qBAAsBD,GAAa,CAAEpP,GAAI+B,IA/CpBhK,GAC9B2P,EA6BZ,SACE4H,EACA9H,EACA2H,GAEA,YAAiB,IAAbG,GACGA,EAAS9H,WAAaA,IAe/B,SACE8H,EACAC,GAEA,OAAID,EAAStV,SAAWuV,EAAQvV,QACzBsV,EAAShP,MAAM,CAACyB,EAAKf,IAAUe,IAAQwN,EAAQvO,GACxD,CArB4CwO,CAAmBF,EAASH,YAAaA,EACrF,CApC0BM,CAAkBP,EAAe1H,EAAU2H,GAC/D,GAAuB,IAAnB5O,EAAQvG,SAAiB0N,EAE3B,OADA+G,EAAO9N,IAAIqG,EAAW,CAAEzC,OAAQxM,EAAMmM,QAASsD,WAAU2H,iBAClD,GA4Ef,SACEf,EACApH,EACAsH,EACAgB,EACAjP,GAEA,MAAMqP,EAAWrP,EAAKmJ,IAAI0E,IACpByB,iBAAA,IAAWrW,IACX0K,EAAY0L,EAASE,KAAM7N,UACnB,IAARA,IACA4N,EAAKtV,IAAI0H,KACb4N,EAAKnX,IAAIuJ,GACF,KAYT,QAVkB,IAAdiC,GAAyBmK,GAAiBC,EAAQpH,EAAWsH,EAAWtK,GACxE0L,EAASG,KAAM9N,QAAgB,IAARA,IACzBwM,GACEH,EACApH,EACA,SACA,uBAAuBsH,2GAIvBgB,GAAUtV,SAAWqG,EAAKrG,QAAUqG,EAAKrG,OAAS,EAAG,CACvD,MAAM8V,EAAe,IAAIxW,IAAIgW,EAAS9F,IAAI0E,IAASzJ,OAAQ1C,QAAgB,IAARA,IAC7DgO,EAASL,EAASG,KAAM9N,QAAgB,IAARA,GAAqB+N,EAAazV,IAAI0H,IACxE+N,EAAapC,KAAO,IAAMqC,GAC5BxB,GACEH,EACApH,EACA,SACA,yBAAyBsH,uGAI/B,CACF,CAhHM0B,CAAcrB,EAAY3H,EAAW+D,EAAOuD,UAAWY,GAAe3K,OAAQxM,GAC9E,MAAMkY,EAAUpJ,GAAuB,CACrCW,WACAR,YACAzG,UACAkH,UAAW1P,EACXmP,QACAQ,cACAC,gBAAiBmH,EAAQnH,gBACzBvD,eAAgB,CAACiK,EAAOtM,KACtBoM,GAAiBQ,EAAYN,EAAOtD,EAAOuD,UAAWvM,MAG1D,OAAgB,OAAZkO,IACJxB,EAAO9N,IAAIqG,EAAW,CACpBzC,OAAQxM,EAAMmM,QACdsD,WACA2H,YAAalB,GAAmBjH,OAE3BiJ,QAAU,KAGvB,E,kECpBO,SACL3B,EACA4B,GAEA,MAAM1G,EAAyC,GAC/C,UAAWlO,KAAU4U,EACf5U,IAAWgT,IACf9E,EAAIlO,GAAU,CAACgT,IAEjB,OAAO9E,CACT,E,kFAhCO,YAAgC2G,GACrC,MAAM9D,iBAAA,IAAa5L,IACnB,UAAW+I,KAAO2G,EAChB,UAAY7U,EAAQ8U,KAAenR,OAAOsI,QAAQiC,GAAM,CACtD,IAAI4B,EAASiB,EAAOtO,IAAIzC,QACT,IAAX8P,IACFA,iBAAA,IAAa9R,IACb+S,EAAO1L,IAAIrF,EAAQ8P,IAErB,UAAWiF,KAAaD,EAAYhF,EAAO5S,IAAI6X,EACjD,CAEF,MAAMC,EAA4C,GAClD,UAAYhV,EAAQ8U,KAAe/D,EAAAiE,EAAehV,GAAU,IAAI8U,GAChE,OAAOE,CACT,E,mDAjCO,SAA6BvY,GAClC,GAAIA,QAA4B,MAAkB,GAClD,MAAM4X,iBAAA,IAAWrW,IACXiX,EAAkB,GACxB,UAAWC,KAAOzY,EAAMgH,MAAM,UAAW,CACvC,MAAMtE,EAAO+V,EAAI1W,OACG,IAAhBW,EAAKT,QAAgB2V,EAAKtV,IAAII,KAClCkV,EAAKnX,IAAIiC,GACT8V,EAAMzP,KAAKrG,GACb,CACA,OAAO8V,CACT","ignoreList":[]}
|