payload-live-preview 2.3.2 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +13 -46
  2. package/dist/adapters/astro/index.js +1 -1
  3. package/dist/adapters/astro/index.js.map +1 -1
  4. package/dist/adapters/astro/middleware-entry.js +1 -1
  5. package/dist/adapters/astro/middleware-entry.js.map +1 -1
  6. package/dist/adapters/nextjs/client.d.ts +28 -0
  7. package/dist/adapters/nextjs/client.js +3 -0
  8. package/dist/adapters/nextjs/client.js.map +1 -0
  9. package/dist/adapters/nextjs/index.d.ts +34 -12
  10. package/dist/adapters/nextjs/index.js +1 -1
  11. package/dist/adapters/nextjs/index.js.map +1 -1
  12. package/dist/adapters/nuxt/client.d.ts +29 -0
  13. package/dist/adapters/nuxt/client.js +2 -0
  14. package/dist/adapters/nuxt/client.js.map +1 -0
  15. package/dist/adapters/nuxt/index.js +1 -1
  16. package/dist/adapters/nuxt/index.js.map +1 -1
  17. package/dist/adapters/nuxt/module.d.ts +23 -3
  18. package/dist/adapters/nuxt/module.js +1 -1
  19. package/dist/adapters/nuxt/module.js.map +1 -1
  20. package/dist/adapters/react/index.d.ts +2 -2
  21. package/dist/adapters/react/index.js +1 -1
  22. package/dist/adapters/react/index.js.map +1 -1
  23. package/dist/adapters/sveltekit/client.d.ts +37 -0
  24. package/dist/adapters/sveltekit/client.js +2 -0
  25. package/dist/adapters/sveltekit/client.js.map +1 -0
  26. package/dist/adapters/sveltekit/index.js +1 -1
  27. package/dist/adapters/sveltekit/index.js.map +1 -1
  28. package/dist/adapters/vue/index.d.ts +2 -2
  29. package/dist/adapters/vue/index.js +1 -1
  30. package/dist/adapters/vue/index.js.map +1 -1
  31. package/dist/client.cjs +1 -1
  32. package/dist/client.cjs.map +1 -1
  33. package/dist/client.js +1 -1
  34. package/dist/client.js.map +1 -1
  35. package/dist/core.cjs +1 -1
  36. package/dist/core.cjs.map +1 -1
  37. package/dist/core.d.cts +7 -1
  38. package/dist/core.d.ts +7 -1
  39. package/dist/core.js +1 -1
  40. package/dist/core.js.map +1 -1
  41. package/dist/{document-session-BuYuO3ae.d.ts → document-session-oK92QjES.d.ts} +7 -1
  42. package/dist/index.cjs +1 -1
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.js +1 -1
  45. package/dist/index.js.map +1 -1
  46. package/dist/lean.cjs +1 -1
  47. package/dist/lean.cjs.map +1 -1
  48. package/dist/lean.js +1 -1
  49. package/dist/lean.js.map +1 -1
  50. package/dist/lexical.cjs.map +1 -1
  51. package/dist/lexical.js.map +1 -1
  52. package/dist/plugins.cjs +1 -1
  53. package/dist/plugins.cjs.map +1 -1
  54. package/dist/plugins.js +1 -1
  55. package/dist/plugins.js.map +1 -1
  56. package/dist/server.cjs.map +1 -1
  57. package/dist/server.js.map +1 -1
  58. package/dist/structural.cjs.map +1 -1
  59. package/dist/structural.js.map +1 -1
  60. package/package.json +23 -1
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.cjs","names":["observeThenableResult","value","then","Promise","resolve","catch","isolateDiagnostic","diagnostic","args","safeConsoleError","console","error","noopDisposer","ResourceScope","pluginName","log","resources","Set","state","constructor","this","assertOpen","Error","active","eligible","own","cleanup","track","kind","acquire","finalize","disposed","stage","resource","dispose","activate","counts","transform","renderer","subscription","commit","close","reverse","clear","add","delete","ScopedPluginEvents","events","scope","subscriptions","on","event","handler","subscribe","once","off","untypedHandler","emit","payload","emitWhile","shouldContinue","callerEligible","listenerCount","count","removeAllListeners","eventNames","names","existing","find","subscriptionActive","wrapped","async","STYLE_ID","styleLeases","WeakMap","highlightLeases","highlightPlugin","name","version","init","ctx","document","window","prefersReducedMotion","matchMedia","matches","releaseStyle","lease","get","connected","css","getElementById","HTMLStyleElement","pluginOwned","isConnected","remove","owners","sheet","Array","isArray","adoptedStyleSheets","CSSStyleSheet","replaceSync","adoptSheet","includes","filter","s","style","createElement","id","textContent","head","appendChild","installStyle","set","acquiredLease","acquireStyle","duration","activeTimers","timerCleanups","registerCleanup","e","element","releaseHighlight","pluginAdded","classList","contains","acquireHighlight","disposeTimer","clearTimeout","handle","setTimeout","debugPlugin","origin","reason","elementCount","fieldCount","Object","keys","data","fields","length","updatedCount","durationMs","toFixed","context","message","SCROLL_KEY","reloadPreservingScroll","sessionStorage","setItem","JSON","stringify","href","location","x","scrollX","y","scrollY","saveScrollPosition","reload","parseDependencyList","seen","raw","split","trim","has","push","ISLAND_ATTRIBUTE","isIslandBoundary","tagName","toLowerCase","hasAttribute","isIslandRoot","getAttribute","isInsideIsland","current","parentElement","FIELD_ATTRIBUTE","DEPENDS_ATTRIBUTE","GUESSED_ATTRIBUTE","COVERS_ATTRIBUTE","renderingStrategy","explicit","closest","valueIdentity","is","String","json","isContainer","shapeOf","child","key","populates","samePopulation","before","after","every","hasOwn","sameValue","identity","previous","uncoveredChangedPaths","field","next","coverage","uncovered","visits","visit","path","depth","covers","reachesBelow","childKeys","SYSTEM_FIELD_NAMES","stripLocaleSuffix","locale","suffix","endsWith","slice","namePathCoverage","boundNames","coverPaths","anyBelow","candidates","prefix","candidate","startsWith","some","cover","ELEMENT_ID","POSITIONS","unboundFieldNames","subfieldCoverage","bound","addressable","reaches","fieldName","base","createNameAddressability","found","entries","root","uncoveredNamePaths","sort","left","right","localeCompare","selectInstead","doc","text","setAttribute","cssText","body","append","select","copyButton","label","button","type","title","addEventListener","clipboard","defaultView","navigator","writeText","copy","DIAGNOSTIC_CODES","freeze","NoTrustedOrigin","ReferrerOnlyTrust","PluginIncompatible","ProfileFeatureOmitted","OrphanField","UnattributableUpdate","UnboundField","CoverageDefaultChanges","VisibilityGateDeferred","UnsafeAttributeWrite","TextTargetHasChildren","MissingArrayTemplate","StructuralItemUnkeyed","StructuralDuplicateKey","StructuralUnstableKeys","UnsupportedStrategy","UnknownValueFormat","SanitizerDroppedAttribute","UnrenderedBlockKept","UnfaithfulPatch","ServerFormatReplaced","UnrenderedBlockLost","MessageRejected","TokenRejected","ProtocolShapeUnknown","HandlerThrew","TransformThrew","RendererThrew","StartupFailed","ReadyFailed","HydrationWaitTimedOut","AuditRuntimeMissing","AuditNoFrameAncestors","AuditFrameOptionsBlocks","AuditBindingsExposed","AuditGateThresholdExceeded","AuditUnownedBindings","AuditNoBindings","AuditNotAPage","FragmentRequestFailed","FragmentResponseInvalid","FragmentUnauthorized","FragmentSuperseded","RouteRefreshLoop","FragmentStrategyUnavailable","UnboundChangeRefresh","EscalationUnavailable","IslandStartUnavailable","RouteRefreshUnconfirmed","V2ReadinessGap","RuntimeOnPublicPage","AuditModifierWithoutField","regular","Map","register","emitSequential","invoke","size","snapshot","bucket","err","config","registerRenderer","onTransformError","plugins","initializing","teardowns","destroying","transforms","mutationQueue","queuedHooks","options","registerFieldRenderer","reportError","plugin","registerNow","enqueue","unregister","unregisterNow","destroyAll","destroyAllNow","applyTransforms","isCurrent","registrations","result","registration","allFields","returnedThenable","TypeError","normalized","list","describe","renderers","cleanups","queued","incompatibility","compat","runtimeVersion","runtime","range","parsed","match","exec","Number","parseVersion","alternative","comparators","part","comparator","trimmed","operator","target","order","a","b","index","delta","compare","satisfiesComparator","satisfiesRange","protocol","isInteger","incompatibilityOf","refuse","createContext","cancelled","runHook","code","registerTransform","indexOf","splice","getConfig","existingTeardown","holdQueue","teardown","destroyPlugin","destroy","values","hook","pending","operation","updateCount","totalElements","totalDurationMs","getStats","averageDurationMs","onlyWithDebug","overlay","position","nodeType","ownerDocument","hostDocument","panel","hidden","heading","unboundTitle","guessedTitle","guessedList","update","guessed","replaceChildren","map","matched","mountOverlay","mode","rendering","querySelectorAll","boundNamesIn","paths","strategy","coverPathsIn","guessedBindingsIn","join","g","controllers","controller","abort","getItem","removeItem","saved","parse","scrollTo","restoreScrollPosition","AbortController","signal","aborted","runFetch","isActive","fetch","url","revalidateUrl","ok","response","method","headers","revalidateHeaders","source","status","onRevalidateFailure","runRevalidate","finally"],"sources":["../src/core/thenable.ts","../src/core/diagnostics.ts","../src/plugins/resource-scope.ts","../src/plugins/scoped-events.ts","../src/plugins/built-in/highlight.ts","../src/plugins/built-in/debug.ts","../src/plugins/built-in/document-save.ts","../src/core/dependencies.ts","../src/core/islands.ts","../src/core/strategies.ts","../src/core/cache.ts","../src/core/value-identity.ts","../src/core/subfield-coverage.ts","../src/core/unbound-fields.ts","../src/plugins/built-in/unbound-fields-overlay.ts","../src/events/emitter.ts","../src/core/diagnostic-codes.ts","../src/plugins/manager.ts","../src/plugins/compat.ts","../src/core/protocol-version.ts","../package.json","../src/plugins/built-in/analytics.ts"],"sourcesContent":["/**\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","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 * Registration-local resource scope: every listener, transform, renderer\n * layer and cleanup a plugin registers is staged here until `init` commits\n * and released together, in reverse order, when the plugin goes. See ADR 0005.\n */\n\nimport { observeThenableResult } from '@core/thenable';\nimport type { PluginDisposer } from './types';\n\nexport type ResourceKind = 'transform' | 'renderer' | 'subscription' | 'cleanup';\n\ninterface ScopedResource {\n readonly kind: ResourceKind;\n readonly acquire: (() => PluginDisposer | undefined) | undefined;\n readonly finalize: (() => void) | undefined;\n cleanup: PluginDisposer | undefined;\n disposed: boolean;\n}\n\nexport const noopDisposer: PluginDisposer = () => undefined;\n\nexport class ResourceScope {\n readonly #pluginName: string;\n readonly #log: (...args: unknown[]) => void;\n // Insertion order gives commit/reverse-teardown order; short-lived entries\n // (once listeners) leave immediately instead of accumulating until removal.\n readonly #resources = new Set<ScopedResource>();\n #state: 'staging' | 'committing' | 'active' | 'closed' = 'staging';\n\n constructor(pluginName: string, log: (...args: unknown[]) => void) {\n this.#pluginName = pluginName;\n this.#log = log;\n }\n\n assertOpen(): void {\n if (this.#state === 'closed') {\n throw new Error(`Plugin context for \"${this.#pluginName}\" is no longer active`);\n }\n }\n\n get active(): boolean {\n return this.#state === 'active';\n }\n\n /** Whether a retained context still belongs to this registration. */\n eligible(): boolean {\n return this.#state !== 'closed';\n }\n\n /** Own a resource the plugin itself already acquired. */\n own(cleanup: PluginDisposer): PluginDisposer {\n this.assertOpen();\n return this.#track({\n kind: 'cleanup',\n acquire: undefined,\n finalize: undefined,\n cleanup,\n disposed: false,\n });\n }\n\n /** Stage a manager-owned resource; an active scope acquires it at once. */\n stage(\n kind: ResourceKind,\n acquire: () => PluginDisposer | undefined,\n finalize?: () => void,\n ): PluginDisposer {\n this.assertOpen();\n const resource: ScopedResource = {\n kind,\n acquire,\n finalize,\n cleanup: undefined,\n disposed: false,\n };\n const dispose = this.#track(resource);\n if (this.#state === 'active') {\n try {\n this.#activate(resource);\n } catch (error) {\n this.#dispose(resource);\n throw error;\n }\n }\n return dispose;\n }\n\n /** Live resources by kind, what `inspect().plugins` reports. */\n counts(): Record<ResourceKind, number> {\n const counts: Record<ResourceKind, number> = {\n transform: 0,\n renderer: 0,\n subscription: 0,\n cleanup: 0,\n };\n for (const resource of this.#resources) counts[resource.kind] += 1;\n return counts;\n }\n\n /** Publish every staged resource at once after `init` succeeded. */\n commit(): void {\n if (this.#state !== 'staging') {\n throw new Error(`Plugin context for \"${this.#pluginName}\" cannot be committed`);\n }\n this.#state = 'committing';\n try {\n for (const resource of this.#resources) this.#activate(resource);\n this.#state = 'active';\n } catch (error) {\n this.close();\n throw error;\n }\n }\n\n close(): void {\n if (this.#state === 'closed') return;\n this.#state = 'closed';\n for (const resource of [...this.#resources].reverse()) this.#dispose(resource);\n this.#resources.clear();\n }\n\n #track(resource: ScopedResource): PluginDisposer {\n this.#resources.add(resource);\n return (): void => {\n this.#dispose(resource);\n };\n }\n\n #activate(resource: ScopedResource): void {\n if (resource.disposed || resource.cleanup !== undefined || resource.acquire === undefined) {\n return;\n }\n const cleanup = resource.acquire();\n resource.cleanup = cleanup ?? noopDisposer;\n }\n\n #dispose(resource: ScopedResource): void {\n if (resource.disposed) return;\n resource.disposed = true;\n this.#resources.delete(resource);\n const cleanup = resource.cleanup;\n resource.cleanup = undefined;\n if (cleanup !== undefined) {\n try {\n // A `void` cleanup may still return a thenable; observe it without awaiting.\n const cleanupWithResult: () => unknown = cleanup;\n if (observeThenableResult(cleanupWithResult())) {\n this.#log(\n `plugin \"${this.#pluginName}\" cleanup returned a Promise/thenable; cleanups must be synchronous`,\n );\n }\n } catch (error) {\n this.#log(`plugin \"${this.#pluginName}\" cleanup failed:`, error);\n }\n }\n try {\n resource.finalize?.();\n } catch (error) {\n this.#log(`plugin \"${this.#pluginName}\" cleanup failed:`, error);\n }\n }\n}\n","/**\n * Event facade handed to a plugin: subscriptions are owned by the plugin's\n * scope, emits go to the client's emitter. It implements the emitter surface\n * without extending it, so no unused base emitter is allocated per plugin.\n */\n\nimport type { EventEmitter } from '@events/emitter';\nimport type { EventHandler, LivePreviewEventMap, Unsubscribe } from '@events/types';\nimport { noopDisposer, type ResourceScope } from './resource-scope';\nimport type { PluginEvents } from './types';\n\ninterface OwnedSubscription {\n readonly kind: 'on' | 'once';\n readonly event: keyof LivePreviewEventMap;\n readonly handler: EventHandler<unknown>;\n dispose: Unsubscribe;\n}\n\nexport class ScopedPluginEvents implements PluginEvents {\n readonly #events: EventEmitter;\n readonly #scope: ResourceScope;\n readonly #subscriptions = new Set<OwnedSubscription>();\n\n constructor(events: EventEmitter, scope: ResourceScope) {\n this.#events = events;\n this.#scope = scope;\n }\n\n on<E extends keyof LivePreviewEventMap>(\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): Unsubscribe {\n return this.#subscribe('on', event, handler);\n }\n\n once<E extends keyof LivePreviewEventMap>(\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): Unsubscribe {\n return this.#subscribe('once', event, handler);\n }\n\n off<E extends keyof LivePreviewEventMap>(\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): void {\n const untypedHandler = handler as EventHandler<unknown>;\n for (const subscription of [...this.#subscriptions]) {\n if (subscription.event === event && subscription.handler === untypedHandler) {\n subscription.dispose();\n }\n }\n }\n\n emit<E extends keyof LivePreviewEventMap>(\n event: E,\n payload: LivePreviewEventMap[E],\n ): Promise<void> {\n this.#scope.assertOpen();\n return this.#events.emit(event, payload);\n }\n\n emitWhile<E extends keyof LivePreviewEventMap>(\n event: E,\n payload: LivePreviewEventMap[E],\n shouldContinue: () => boolean,\n ): Promise<boolean> {\n this.#scope.assertOpen();\n return this.#events.emitWhile(event, payload, () => {\n if (!this.#scope.eligible()) return false;\n const callerEligible = shouldContinue();\n // The predicate is plugin code and may close this scope re-entrantly.\n if (!this.#scope.eligible()) return false;\n return callerEligible;\n });\n }\n\n listenerCount(event: keyof LivePreviewEventMap): number {\n let count = 0;\n for (const subscription of this.#subscriptions) {\n if (subscription.event === event) count += 1;\n }\n return count;\n }\n\n removeAllListeners(event?: keyof LivePreviewEventMap): void {\n for (const subscription of [...this.#subscriptions]) {\n if (event === undefined || subscription.event === event) subscription.dispose();\n }\n }\n\n eventNames(): (keyof LivePreviewEventMap)[] {\n const names = new Set<keyof LivePreviewEventMap>();\n for (const subscription of this.#subscriptions) names.add(subscription.event);\n return [...names];\n }\n\n #subscribe<E extends keyof LivePreviewEventMap>(\n kind: 'on' | 'once',\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): Unsubscribe {\n this.#scope.assertOpen();\n\n const untypedHandler = handler as EventHandler<unknown>;\n const existing = [...this.#subscriptions].find(\n (subscription) =>\n subscription.kind === kind &&\n subscription.event === event &&\n subscription.handler === untypedHandler,\n );\n if (existing !== undefined) return existing.dispose;\n\n // A distinct wrapper per scope: two plugins passing the same handler\n // reference must be revocable independently in the Set-based emitter.\n let dispose = noopDisposer;\n let subscriptionActive = true;\n const wrapped: EventHandler<LivePreviewEventMap[E]> = async (payload) => {\n if (!this.#scope.active || !subscriptionActive) return;\n // Mirror the base emitter, which drops a once bucket before dispatch.\n if (kind === 'once') dispose();\n await handler(payload);\n };\n const subscription: OwnedSubscription = {\n kind,\n event,\n handler: untypedHandler,\n dispose: noopDisposer,\n };\n dispose = this.#scope.stage(\n 'subscription',\n () => this.#events[kind](event, wrapped),\n () => {\n subscriptionActive = false;\n this.#subscriptions.delete(subscription);\n },\n );\n subscription.dispose = dispose;\n this.#subscriptions.add(subscription);\n return dispose;\n }\n}\n","/**\n * `highlight` plugin: flashes an outline on updated elements. Respects\n * `prefers-reduced-motion`; the stylesheet is shared per document across\n * clients through a lease (ADR 0002).\n */\n\nimport type { LivePreviewPlugin, PluginDisposer } from '../types';\n\nconst STYLE_ID = 'payload-live-preview-highlight';\nconst REDUCED_MOTION_CSS =\n '.lp-highlight{outline:2px solid rgba(0,102,204,0.85);outline-offset:2px;}';\nconst ANIMATED_CSS =\n '@keyframes lp-highlight{0%{outline:2px solid rgba(0,102,204,0.85);outline-offset:2px}100%{outline:2px solid transparent;outline-offset:2px}}.lp-highlight{animation:lp-highlight 0.6s ease-out;}';\n\ninterface StyleLease {\n readonly pluginOwned: boolean;\n readonly connected: () => boolean;\n readonly remove: () => void;\n owners: number;\n}\n\ninterface HighlightLease {\n owners: number;\n readonly pluginAdded: boolean;\n}\n\nconst styleLeases = new WeakMap<Document, StyleLease>();\nconst highlightLeases = new WeakMap<Element, HighlightLease>();\n\nexport const highlightPlugin: LivePreviewPlugin = {\n name: 'highlight',\n version: '1.0.0',\n init: (ctx) => {\n if (typeof document === 'undefined' || typeof window === 'undefined') return;\n const prefersReducedMotion =\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n const releaseStyle = acquireStyle(document, prefersReducedMotion);\n const duration = prefersReducedMotion ? 1000 : 600;\n const activeTimers = new WeakMap<Element, PluginDisposer>();\n // Only armed timers are retained; one registration-owned cleanup drains them.\n const timerCleanups = new Set<PluginDisposer>();\n ctx.registerCleanup?.(() => {\n for (const cleanup of [...timerCleanups]) cleanup();\n releaseStyle();\n });\n ctx.events.on('elementUpdate', (e) => {\n const element = e.element;\n activeTimers.get(element)?.();\n const releaseHighlight = acquireHighlight(element);\n let disposed = false;\n const disposeTimer: PluginDisposer = () => {\n if (disposed) return;\n disposed = true;\n window.clearTimeout(handle);\n if (activeTimers.get(element) === disposeTimer) activeTimers.delete(element);\n timerCleanups.delete(disposeTimer);\n releaseHighlight();\n };\n const handle = window.setTimeout(disposeTimer, duration);\n timerCleanups.add(disposeTimer);\n activeTimers.set(element, disposeTimer);\n });\n },\n};\n\nfunction acquireStyle(document: Document, prefersReducedMotion: boolean): PluginDisposer {\n let lease = styleLeases.get(document);\n // HMR or a host DOM swap may drop the sheet without plugin teardown.\n if (lease !== undefined && !lease.connected()) {\n styleLeases.delete(document);\n lease = undefined;\n }\n if (lease === undefined) {\n lease = installStyle(document, prefersReducedMotion ? REDUCED_MOTION_CSS : ANIMATED_CSS);\n styleLeases.set(document, lease);\n }\n const acquiredLease = lease;\n acquiredLease.owners += 1;\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n acquiredLease.owners -= 1;\n if (acquiredLease.owners > 0) return;\n if (styleLeases.get(document) === acquiredLease) styleLeases.delete(document);\n if (acquiredLease.pluginOwned) acquiredLease.remove();\n };\n}\n\nfunction installStyle(document: Document, css: string): StyleLease {\n const existing = document.getElementById(STYLE_ID);\n if (existing instanceof HTMLStyleElement) {\n return {\n pluginOwned: false,\n connected: () => existing.isConnected,\n remove: () => undefined,\n owners: 0,\n };\n }\n const sheet = adoptSheet(document, css);\n if (sheet !== undefined) {\n return {\n pluginOwned: true,\n connected: () => document.adoptedStyleSheets.includes(sheet),\n remove: () => {\n document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s) => s !== sheet);\n },\n owners: 0,\n };\n }\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = css;\n document.head.appendChild(style);\n return {\n pluginOwned: true,\n connected: () => style.isConnected,\n remove: () => {\n style.remove();\n },\n owners: 0,\n };\n}\n\n// A constructed sheet needs no nonce under `style-src`; `<style>` is only the fallback.\nfunction adoptSheet(document: Document, css: string): CSSStyleSheet | undefined {\n try {\n if (!Array.isArray(document.adoptedStyleSheets) || typeof CSSStyleSheet !== 'function') {\n return undefined;\n }\n const sheet = new CSSStyleSheet();\n if (typeof sheet.replaceSync !== 'function') return undefined;\n sheet.replaceSync(css);\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];\n return sheet;\n } catch {\n return undefined;\n }\n}\n\nfunction acquireHighlight(element: Element): PluginDisposer {\n let lease = highlightLeases.get(element);\n if (lease === undefined) {\n lease = { owners: 0, pluginAdded: !element.classList.contains('lp-highlight') };\n highlightLeases.set(element, lease);\n }\n const acquiredLease = lease;\n acquiredLease.owners += 1;\n element.classList.add('lp-highlight');\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n acquiredLease.owners -= 1;\n if (acquiredLease.owners > 0) return;\n highlightLeases.delete(element);\n if (acquiredLease.pluginAdded) element.classList.remove('lp-highlight');\n };\n}\n","/** `debug` plugin: logs init, connect, disconnect, cacheRefresh, beforeUpdate, afterUpdate and error through the plugin context. */\n\nimport type { LivePreviewPlugin } from '../types';\n\nexport const debugPlugin: LivePreviewPlugin = {\n name: 'debug',\n version: '1.0.0',\n init: (ctx) => {\n ctx.events.on('init', () => {\n ctx.log('init');\n });\n ctx.events.on('connect', (e) => {\n ctx.log('connect ←', e.origin);\n });\n ctx.events.on('disconnect', (e) => {\n ctx.log('disconnect (', e.reason, ')');\n });\n ctx.events.on('cacheRefresh', (e) => {\n ctx.log('cacheRefresh', e.elementCount, 'elements,', e.fieldCount, 'fields');\n });\n ctx.events.on('beforeUpdate', (e) => {\n ctx.log('beforeUpdate', Object.keys(e.data.fields).length, 'fields');\n });\n ctx.events.on('afterUpdate', (e) => {\n ctx.log('afterUpdate', e.updatedCount, 'in', e.durationMs.toFixed(2), 'ms');\n });\n ctx.events.on('error', (e) => {\n ctx.log('error in', e.context, ':', e.error.message);\n });\n },\n};\n","/**\n * `documentSave` plugin: what to do when Payload saves the document.\n * `'silent'` (default) emits only; `'reload'` reloads and restores the scroll\n * position; `'revalidate'` POSTs to a revalidation endpoint; `'fetch'` runs\n * a custom handler.\n */\n\nimport type { LivePreviewPlugin } from '../types';\n\nconst SCROLL_KEY = 'payload-live-preview:scroll';\n\nfunction saveScrollPosition(): void {\n if (typeof window === 'undefined') return;\n try {\n sessionStorage.setItem(\n SCROLL_KEY,\n JSON.stringify({ href: window.location.href, x: window.scrollX, y: window.scrollY }),\n );\n } catch {\n // sessionStorage is unavailable in a sandboxed iframe without allow-same-origin.\n }\n}\n\nfunction restoreScrollPosition(): void {\n if (typeof window === 'undefined') return;\n try {\n const raw = sessionStorage.getItem(SCROLL_KEY);\n if (raw === null) return;\n sessionStorage.removeItem(SCROLL_KEY);\n const saved = JSON.parse(raw) as { href?: string; x?: number; y?: number };\n if (saved.href !== window.location.href) return;\n window.scrollTo(saved.x ?? 0, saved.y ?? 0);\n } catch {\n // A corrupt entry or unavailable storage: nothing to restore.\n }\n}\n\nfunction reloadPreservingScroll(): void {\n if (typeof window === 'undefined') return;\n saveScrollPosition();\n window.location.reload();\n}\n\nexport type DocumentSaveStrategy = 'silent' | 'reload' | 'revalidate' | 'fetch';\n\n/** Handler for the `fetch` strategy; the signal aborts when the plugin is removed. */\nexport type DocumentSaveHandler = {\n bivarianceHack(signal?: AbortSignal): void | Promise<void>;\n}['bivarianceHack'];\n\nexport interface DocumentSavePluginOptions {\n /** Default `'silent'`. */\n readonly strategy?: DocumentSaveStrategy;\n /**\n * `'revalidate'` endpoint, default `/api/revalidate`; the body is\n * `{ source: 'payload-live-preview' }`. The request is a plain `fetch` from\n * the preview page: cookies travel with it, there is no CSRF token, and a\n * bearer secret in `revalidateHeaders` would sit in page JavaScript. The\n * endpoint must authorise on its own (session cookie, same-origin check).\n */\n readonly revalidateUrl?: string;\n /** Extra request headers for `'revalidate'`; `Content-Type` is set already. */\n readonly revalidateHeaders?: Readonly<Record<string, string>>;\n /** `'fetch'` handler; rejections are logged, never thrown. */\n readonly handler?: DocumentSaveHandler;\n /** `'reload'` hard-refreshes when the revalidate request fails or returns non-2xx. */\n readonly onRevalidateFailure?: 'silent' | 'reload';\n}\n\nconst DEFAULT_REVALIDATE_URL = '/api/revalidate';\n\nexport function documentSavePlugin(options: DocumentSavePluginOptions = {}): LivePreviewPlugin {\n const strategy = options.strategy ?? 'silent';\n return {\n name: 'document-save',\n version: '1.1.0',\n init: (ctx) => {\n let active = true;\n const controllers = new Set<AbortController>();\n ctx.registerCleanup?.(() => {\n active = false;\n for (const controller of controllers) controller.abort();\n controllers.clear();\n });\n restoreScrollPosition();\n ctx.events.on('documentSave', () => {\n if (!active) return;\n if (strategy === 'silent') return;\n if (strategy === 'reload') {\n reloadPreservingScroll();\n return;\n }\n const controller = new AbortController();\n controllers.add(controller);\n const operation =\n strategy === 'fetch'\n ? runFetch(options, ctx.log, controller.signal, () => active)\n : runRevalidate(options, ctx.log, controller.signal, () => active);\n void operation.finally(() => {\n controllers.delete(controller);\n });\n });\n },\n };\n}\n\nasync function runFetch(\n options: DocumentSavePluginOptions,\n log: (...args: unknown[]) => void,\n signal: AbortSignal,\n isActive: () => boolean,\n): Promise<void> {\n if (!options.handler) {\n log('document-save: fetch strategy selected but no handler supplied');\n return;\n }\n try {\n await options.handler(signal);\n } catch (err) {\n if (!isActive() || signal.aborted) return;\n log('document-save handler threw:', err);\n }\n}\n\nasync function runRevalidate(\n options: DocumentSavePluginOptions,\n log: (...args: unknown[]) => void,\n signal: AbortSignal,\n isActive: () => boolean,\n): Promise<void> {\n if (typeof fetch === 'undefined') {\n log('document-save: revalidate strategy needs fetch — not available');\n return;\n }\n const url = options.revalidateUrl ?? DEFAULT_REVALIDATE_URL;\n let ok = false;\n try {\n const response = await fetch(url, {\n method: 'POST',\n signal,\n headers: {\n 'Content-Type': 'application/json',\n ...(options.revalidateHeaders ?? {}),\n },\n body: JSON.stringify({ source: 'payload-live-preview' }),\n });\n if (!isActive() || signal.aborted) return;\n ok = response.ok;\n if (!ok) log('document-save revalidate non-2xx:', response.status);\n } catch (err) {\n if (!isActive() || signal.aborted) return;\n log('document-save revalidate failed:', err);\n }\n if (!ok && options.onRevalidateFailure === 'reload') {\n reloadPreservingScroll();\n }\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","/**\n * Hydrated islands own their subtree, so the runtime never patches inside one.\n * Instead every flush that carried a change dispatches `payload-live-preview:update`\n * on each island root with the update in `detail`, whether or not a binding\n * outside the islands was written. `data-payload-island=\"patch\"` opts back in.\n * Server HTML reaches an Astro island only through Astro's own props handoff\n * (ADR 0021). @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/** The opt-out for a subtree the site scripts itself: the morph never enters it. @internal */\nexport const OWNED_ATTRIBUTE = 'data-payload-owned';\n/**\n * The opt-in for a custom element: present on the live and on the rendered host\n * (its value is ignored), the morph edits the host's attributes and light DOM\n * instead of retaining it whole (ADR 0008 §10). @internal\n */\nexport const MORPH_ATTRIBUTE = 'data-payload-morph';\n\n/**\n * The ownership rule (ADR 0008 §4): a subtree the morph never enters. Custom\n * elements own their subtree unless the template opts in with\n * `data-payload-morph` (§10), islands are a framework's, `contenteditable`\n * is the visitor's, `data-payload-owned` is the site's. The coordinators hand\n * this rule to the engine as `MorphOptions.boundary`; the engine itself only\n * pairs, edits and keeps focus (§9). @beta\n */\nexport function isMorphBoundary(element: Element): boolean {\n const customElement = element.tagName.toLowerCase().includes('-');\n if (customElement && !element.hasAttribute(MORPH_ATTRIBUTE)) return true;\n if (isIslandBoundary(element) || element.hasAttribute(OWNED_ATTRIBUTE)) return true;\n const editable = element.getAttribute('contenteditable');\n return editable !== null && editable !== 'false';\n}\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 * Call once the island has rendered this revision, for instance from an\n * effect after its framework committed. Until every island handed the\n * revision has called it, `inspect().revisions.display` says `unconfirmed`\n * (ADR 0023). Repeated, late or superseded calls do nothing.\n */\n readonly displayed: () => void;\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\n/** Astro keeps `ssr` until the framework listener has finished hydrating. @internal */\nexport function isAwaitingIslandHydration(island: Element): boolean {\n return island.tagName.toLowerCase() === 'astro-island' && island.hasAttribute('ssr');\n}\n\nexport function dispatchIslandUpdate(\n islands: readonly Element[],\n detail: IslandUpdateDetail,\n isCurrent: () => boolean,\n): number {\n let dispatched = 0;\n for (const island of islands) {\n if (!isCurrent()) break;\n island.dispatchEvent(\n new CustomEvent<IslandUpdateDetail>(ISLAND_EVENT, { detail, bubbles: false }),\n );\n dispatched += 1;\n if (!isCurrent()) break;\n }\n return dispatched;\n}\n\n/** What decides whether a live `astro-island` still renders the rendered one's component (ADR 0021). */\nconst ISLAND_IDENTITY = [\n 'component-url',\n 'component-export',\n 'renderer-url',\n 'client',\n 'opts',\n 'before-hydration-url',\n] as const;\n/** Slot markup each island was last rendered with; Astro reads slots once, at hydration. */\nconst renderedSlots = new WeakMap<Element, string>();\nconst unmountedIslands = new WeakSet<Element>();\n\nfunction isAstroIsland(element: Element): boolean {\n return element.tagName.toLowerCase() === 'astro-island';\n}\n\nfunction slotMarkup(island: Element): string {\n let markup = '';\n for (const slot of island.querySelectorAll('astro-slot, template[data-astro-template]')) {\n if (slot.parentElement?.closest('astro-island') !== island) continue;\n const name = slot.getAttribute('name') ?? slot.getAttribute('data-astro-template') ?? '';\n markup += `${name}\\u0000${slot.innerHTML}\\u0000`;\n }\n return markup;\n}\n\n/** Only an upgraded island whose class observes `props` re-hydrates in place. */\nfunction observesProps(island: Element): boolean {\n const constructor = island.ownerDocument.defaultView?.customElements.get('astro-island') as\n (CustomElementConstructor & { readonly observedAttributes?: unknown }) | undefined;\n return (\n constructor !== undefined &&\n island instanceof constructor &&\n Array.isArray(constructor.observedAttributes) &&\n constructor.observedAttributes.includes('props')\n );\n}\n\n/**\n * The package's decision for a boundary pair (ADR 0021). A boundary other than\n * an Astro island stays whole (ADR 0008 §4). An island that still renders the\n * same component, with the same slots, keeps its framework state: it takes the\n * rendered props the way Astro's router hands them to a persisted island,\n * `ssr` first, then `props`. Anything else is replaced, and hydrates fresh.\n * @beta\n */\nexport function retainIslandBoundary(live: Element, rendered: Element): boolean {\n if (!isAstroIsland(live) || !isAstroIsland(rendered)) return true;\n const slots = slotMarkup(rendered);\n const retained =\n ISLAND_IDENTITY.every((name) => live.getAttribute(name) === rendered.getAttribute(name)) &&\n (renderedSlots.get(live) ?? slotMarkup(live)) === slots &&\n (live.getAttribute('props') === rendered.getAttribute('props') || observesProps(live));\n if (!retained) {\n renderedSlots.set(rendered, slots);\n return false;\n }\n renderedSlots.set(live, slots);\n const props = rendered.getAttribute('props');\n if (props !== live.getAttribute('props')) {\n live.setAttribute('ssr', '');\n if (props === null) live.removeAttribute('props');\n else live.setAttribute('props', props);\n }\n return true;\n}\n\n/** The Astro islands under `root`, to compare before and after a morph. @internal */\nexport function astroIslandsIn(root: ParentNode): Element[] {\n return Array.from(root.querySelectorAll('astro-island'));\n}\n\n/**\n * Astro's framework clients release their roots on `astro:unmount`, which its\n * router sends after a swap. A morph that disconnects an island sends it once\n * itself, so a removed React root does not outlive its markup. @internal\n */\nexport function releaseDisconnectedIslands(islands: readonly Element[]): void {\n for (const island of islands) {\n if (island.isConnected || unmountedIslands.has(island)) continue;\n unmountedIslands.add(island);\n island.dispatchEvent(new CustomEvent('astro:unmount'));\n }\n}\n\n/**\n * Why an inserted island cannot start: fragment scripts never run, so the page\n * itself must have loaded Astro's island element and this client directive.\n * @internal\n */\nexport function islandStartBlocker(island: Element): 'element' | 'directive' | undefined {\n const view = island.ownerDocument.defaultView;\n if (view?.customElements.get('astro-island') === undefined) return 'element';\n const directive = island.getAttribute('client');\n const astro: unknown = Reflect.get(view, 'Astro');\n if (directive === null || typeof astro !== 'object' || astro === null) return 'directive';\n return Reflect.get(astro, directive) === undefined ? 'directive' : undefined;\n}\n","/**\n * How a bound region is brought up to date: the runtime patches it, a server\n * renders a `data-payload-fragment` boundary from the unsaved form state, or\n * the whole route refreshes. Core carries only the seam — which boundaries a\n * strategy owns and what it may do — so a patch-only page pays for nothing\n * more; the orchestration lives in `payload-live-preview/fragment`.\n */\nimport type { DiagnosticCode } from './diagnostic-codes';\nimport type { CachedElement } from './types';\nimport type { OwnerScope } from './unbound-fields';\n\n/** What produced an update: the runtime's DOM patching, a server-rendered fragment, or a route refresh. */\nexport type UpdateSource = 'patch' | 'fragment' | 'route';\n\n/** Marks a server-rendered boundary; the value is the registry id the server may render. @internal */\nexport const FRAGMENT_ATTRIBUTE = 'data-payload-fragment';\n/** Distinguishes several boundaries of one registry id; unique among siblings. @internal */\nexport const FRAGMENT_KEY_ATTRIBUTE = 'data-payload-fragment-key';\n\n/** The nearest fragment boundary enclosing `element` (the element itself included). */\nexport function enclosingFragment(element: Element): Element | null {\n return element.closest(`[${FRAGMENT_ATTRIBUTE}]`);\n}\n\n/**\n * Where a render planned for `planned` lands. A host component that re-renders\n * its region while the render is in flight swaps the element and keeps the\n * identity, so a boundary no longer in the document stands for the one that\n * is: the single connected boundary with its id and key that `inScope` admits.\n * Two candidates name no single region, and none means it is gone (H06).\n */\nexport function liveBoundary(\n root: Document | Element,\n planned: Element,\n inScope: (boundary: Element) => boolean,\n): Element | undefined {\n if (planned.isConnected) return planned;\n const id = planned.getAttribute(FRAGMENT_ATTRIBUTE);\n const key = planned.getAttribute(FRAGMENT_KEY_ATTRIBUTE);\n let found: Element | undefined;\n for (const candidate of root.querySelectorAll(`[${FRAGMENT_ATTRIBUTE}]`)) {\n if (candidate.getAttribute(FRAGMENT_ATTRIBUTE) !== id) continue;\n if (candidate.getAttribute(FRAGMENT_KEY_ATTRIBUTE) !== key || !inScope(candidate)) continue;\n if (found !== undefined) return undefined;\n found = candidate;\n }\n return found;\n}\n\n/** One revision, as a strategy sees it, with the runtime capabilities it may use. */\nexport interface FragmentContext {\n readonly root: ParentNode;\n readonly revision: number;\n readonly receivedAt: number;\n readonly fields: Readonly<Record<string, unknown>>;\n readonly locale: string | undefined;\n readonly collectionSlug: string | undefined;\n readonly globalSlug: string | undefined;\n /** Aborted when a newer revision arrives or the runtime stops. */\n readonly signal: AbortSignal;\n /** Whether this revision is still the current one. */\n readonly isCurrent: () => boolean;\n /** Morph server-rendered HTML into a boundary; no-op after supersession (Trusted Types and the keyed morph apply). */\n readonly morph: (boundary: Element, html: string) => void;\n /** Patch the boundary's owned bindings from this revision; no-op after supersession. */\n readonly patch: (boundary: Element) => void;\n /** Debug log through the runtime's logger, with the diagnostic code. */\n readonly log: (code: DiagnosticCode, detail: string) => void;\n /** Report a boundary rendered. */\n readonly rendered: (boundary: Element, id: string, key: string | undefined) => void;\n /** Report a boundary failed and patched instead; emits the `error` and `fragmentRender` events. */\n readonly failed: (\n boundary: Element,\n id: string,\n key: string | undefined,\n code: DiagnosticCode,\n reason: string,\n ) => void;\n}\n\nexport interface FragmentReport {\n readonly rendered: number;\n readonly failed: number;\n readonly superseded: number;\n}\n\n/** A fragment strategy: which boundaries it owns for a revision, and how it renders them. */\nexport interface FragmentStrategy {\n /** The boundaries this update re-renders; their inner bindings are left to the strategy. */\n readonly plan: (root: ParentNode, changedFields: ReadonlySet<string>) => readonly Element[];\n /** Render the planned boundaries; resolves once every one settled. */\n readonly render: (\n context: FragmentContext,\n boundaries: readonly Element[],\n ) => Promise<FragmentReport>;\n}\n\n/** The boundaries a revision hands the fragment strategy, and the bindings they take from the patch. */\nexport interface FragmentPlan {\n readonly boundaries: readonly Element[];\n readonly strategy: FragmentStrategy;\n readonly ownerKeys: OwnerScope;\n /** Whether a binding sits inside a boundary the strategy renders this revision. */\n readonly covers: (target: CachedElement) => boolean;\n}\n\n/** A plan over boundaries already chosen, whichever question chose them. */\nexport function planBoundaries(\n strategy: FragmentStrategy,\n boundaries: readonly Element[],\n ownerKeys: OwnerScope,\n): FragmentPlan {\n const covered = new Set(boundaries);\n return {\n boundaries,\n strategy,\n ownerKeys,\n covers: (target) =>\n target.fragmentBoundary !== undefined && covered.has(target.fragmentBoundary),\n };\n}\n\n/** One revision, as the route strategy sees it. */\nexport interface RouteContext {\n readonly revision: number;\n readonly receivedAt: number;\n /** Aborted when a newer revision asks for a refresh of its own, a navigation commits, or the runtime stops. */\n readonly signal: AbortSignal;\n /**\n * Whether the refresh may still land. A newer revision that asks for no\n * refresh of its own does not end it: the route is the server's, so the\n * refresh lands for that revision, which the runtime then re-applies.\n */\n readonly isCurrent: () => boolean;\n readonly log: (code: DiagnosticCode, detail: string) => void;\n /**\n * Ask to be run again in `delayMs`, once. A strategy that refuses a refresh\n * because it is rate-limiting itself uses this: the window is a rate limit\n * and not a filter, so what falls inside it still has to reach the preview.\n * The runtime runs at most one such request, and only while the revision that\n * asked is still the current one.\n */\n readonly retryAfter?: (delayMs: number) => void;\n}\n\n/**\n * What one refresh did. `refreshed` asserts that the strategy rendered the\n * current unsaved revision. `partial` completed a render whose data source was\n * not proven current; the runtime still reapplies every binding it can reach.\n * `refused` is the strategy's own brake and not a failure.\n */\nexport type RouteOutcome = 'refreshed' | 'partial' | 'failed' | 'refused' | 'superseded';\n\n/** What the runtime tells a route planner about the update it plans for. */\nexport interface RoutePlanContext {\n /**\n * Whether an element belongs to the update: always `true` without\n * `scopeBindingsByOwner`, otherwise only inside the document the update\n * names. A marker outside it asks for nothing.\n */\n readonly inScope: (element: Element) => boolean;\n}\n\n/**\n * Whether a revision needs the whole route re-rendered, and how. After a\n * refresh the runtime rescans and re-applies the revision, so reachable\n * unsaved bindings land on the fresh markup. The runtime always passes\n * `context`; a planner written before it existed still works, but plans for\n * markers of every document.\n */\nexport interface RouteStrategy {\n readonly plan: (\n root: ParentNode,\n changedFields: ReadonlySet<string>,\n context?: RoutePlanContext,\n ) => boolean;\n readonly refresh: (context: RouteContext) => Promise<RouteOutcome>;\n}\n\nexport interface StrategyHandlers {\n readonly fragment?: FragmentStrategy;\n readonly route?: RouteStrategy;\n}\n\nconst STRATEGY_ATTRIBUTE = 'data-payload-strategy';\n\n/**\n * Explicit `data-payload-strategy` wins; otherwise a binding inside a fragment\n * boundary belongs to the fragment, one in `<head>` to the route, the rest is\n * patched. An unknown explicit value resolves to `undefined` (LP0407).\n * @internal\n */\nexport function resolveStrategy(element: Element): UpdateSource | undefined {\n const explicit = element.getAttribute(STRATEGY_ATTRIBUTE);\n if (explicit !== null && explicit.length > 0) {\n return explicit === 'patch' || explicit === 'fragment' || explicit === 'route'\n ? explicit\n : undefined;\n }\n if (enclosingFragment(element) !== null) return 'fragment';\n if (element.closest('head') !== null) return 'route';\n return 'patch';\n}\n","/**\n * Maps field names to their bound elements so an update walks the cache, not\n * the DOM. Everything an update needs about a binding is resolved here, once,\n * at build time.\n */\n\nimport {\n dependencyMapFromBinding,\n mergeDependencyMaps,\n parseDependencyList,\n type DependencyMap,\n} from './dependencies';\nimport { collectIslands } from './islands';\nimport { enclosingFragment, FRAGMENT_ATTRIBUTE, resolveStrategy } from './strategies';\nimport type { CachedElement, ElementPredicate, FieldType, RendererKey } from './types';\n\nexport const FIELD_ATTRIBUTE = 'data-payload-field';\nexport const TYPE_ATTRIBUTE = 'data-payload-type';\nexport const TARGET_ATTRIBUTE_ATTRIBUTE = 'data-payload-attribute';\nexport const HREF_ATTRIBUTE = 'data-payload-href';\nexport const SRC_ATTRIBUTE = 'data-payload-src';\nexport const ALT_ATTRIBUTE = 'data-payload-alt';\nexport const ARRAY_TEMPLATE_ATTRIBUTE = 'data-payload-array-template';\nexport const ARRAY_SEPARATOR_ATTRIBUTE = 'data-payload-array-separator';\nexport const LOCALE_ATTRIBUTE = 'data-payload-locale';\nexport const FORMAT_ATTRIBUTE = 'data-payload-format';\nexport const RICH_TEXT_ATTRIBUTE = 'data-payload-richtext';\nexport const HTML_ATTRIBUTE = 'data-payload-html';\nexport const ARRAY_ATTRIBUTE = 'data-payload-array';\nexport const STRUCTURAL_ATTRIBUTE = 'data-payload-structural';\nexport const OWNER_ATTRIBUTE = 'data-payload-owner';\nexport const DEPENDS_ATTRIBUTE = 'data-payload-depends';\nexport const STRATEGY_ATTRIBUTE = 'data-payload-strategy';\nexport const BOUNDARY_ATTRIBUTE = 'data-payload-boundary';\n/**\n * Written by the runtime, never by a template: the value an auto-binding\n * matched on (ADR 0014). Its presence is what tells a guessed binding from a\n * declared one, in `inspect()` and in the overlay.\n */\nexport const GUESSED_ATTRIBUTE = 'data-payload-guessed';\n/** Field paths a page accounts for without binding them, and everything below them (ADR 0022). */\nexport const COVERS_ATTRIBUTE = 'data-payload-covers';\nexport const INPUT_TYPE_ATTRIBUTE = 'type';\n\n/**\n * Attributes captured in a `CachedElement`. The mutation observer watches\n * exactly this list, so a snapshot can never go stale on a mounted element.\n */\nexport const BINDING_ATTRIBUTES: readonly string[] = [\n FIELD_ATTRIBUTE,\n TYPE_ATTRIBUTE,\n TARGET_ATTRIBUTE_ATTRIBUTE,\n HREF_ATTRIBUTE,\n SRC_ATTRIBUTE,\n ALT_ATTRIBUTE,\n ARRAY_TEMPLATE_ATTRIBUTE,\n ARRAY_SEPARATOR_ATTRIBUTE,\n LOCALE_ATTRIBUTE,\n FORMAT_ATTRIBUTE,\n RICH_TEXT_ATTRIBUTE,\n HTML_ATTRIBUTE,\n ARRAY_ATTRIBUTE,\n STRUCTURAL_ATTRIBUTE,\n OWNER_ATTRIBUTE,\n DEPENDS_ATTRIBUTE,\n STRATEGY_ATTRIBUTE,\n BOUNDARY_ATTRIBUTE,\n INPUT_TYPE_ATTRIBUTE,\n];\n\nconst FIELD_SELECTOR = `[${FIELD_ATTRIBUTE}]`;\nconst OWNER_SELECTOR = `[${OWNER_ATTRIBUTE}]`;\n/** Structural strategy roots whose arrival after navigation needs the retained document. @internal */\nexport const NAVIGATION_REPLAY_SELECTOR = `[${FRAGMENT_ATTRIBUTE}], [${STRATEGY_ATTRIBUTE}=\"route\"]`;\n\n/** The document a binding belongs to: its nearest `data-payload-owner`, itself included. */\nexport function resolveBindingOwner(element: Element): string | undefined {\n const owner = element.closest(OWNER_SELECTOR)?.getAttribute(OWNER_ATTRIBUTE);\n return owner === null || owner === undefined || owner.length === 0 ? undefined : owner;\n}\n\n/** `namespace:name` — a project renderer key can never be a typo of a built-in type. */\nconst CUSTOM_RENDERER_KEY = /^[a-z][a-z0-9-]*:[a-z][a-z0-9-]*$/i;\n\nconst VALID_FIELD_TYPES: ReadonlySet<FieldType> = new Set<FieldType>([\n 'text',\n 'textarea',\n 'richText',\n 'email',\n 'number',\n 'checkbox',\n 'date',\n 'select',\n 'radio',\n 'array',\n 'blocks',\n 'group',\n 'tabs',\n 'row',\n 'collapsible',\n 'relationship',\n 'upload',\n 'point',\n 'json',\n 'code',\n 'ui',\n 'html',\n 'url',\n 'image',\n 'structural-array',\n]);\n\nfunction isRendererKey(value: string): value is RendererKey {\n return VALID_FIELD_TYPES.has(value as FieldType) || CUSTOM_RENDERER_KEY.test(value);\n}\n\n/** One `data-payload-covers` declaration: the paths it names, for the owner it sits under. */\nexport interface CoverDeclaration {\n readonly paths: readonly string[];\n readonly owner: string | undefined;\n}\n\n/** The fields a fragment boundary or a route marker depends on, which its strategy renders. */\nexport interface RenderedDeclaration extends CoverDeclaration {\n readonly strategy: 'fragment' | 'route';\n}\n\n/**\n * The strategy that renders what an element depends on, by the planners' own\n * rules: the fragment planner takes every named boundary, the route planner a\n * route-bound element — marked `route`, or a binding in `<head>` left unmarked\n * (`src/fragment/boundary.ts`, `src/fragment/route.ts`). @internal\n */\nexport function renderingStrategy(element: Element): RenderedDeclaration['strategy'] | undefined {\n if ((element.getAttribute(FRAGMENT_ATTRIBUTE) ?? '').length > 0) return 'fragment';\n const explicit = element.getAttribute(STRATEGY_ATTRIBUTE);\n if (explicit !== null) return explicit === 'route' ? 'route' : undefined;\n return element.hasAttribute(FIELD_ATTRIBUTE) && element.closest('head') !== null\n ? 'route'\n : undefined;\n}\n\nexport interface CacheBuildStats {\n readonly elementCount: number;\n readonly fieldCount: number;\n readonly durationMs: number;\n}\n\nexport interface ElementCacheOptions {\n /** Restricts which elements are accepted. Defaults to all. */\n readonly filter?: ElementPredicate;\n}\n\n/** Metadata that decides whether buffered work still addresses the same owned strategy target. */\nexport function hasSameBindingIdentity(a: CachedElement, b: CachedElement): boolean {\n return (\n a.fieldName === b.fieldName &&\n a.locale === b.locale &&\n a.owner === b.owner &&\n a.strategyKind === b.strategyKind &&\n a.fragmentBoundary === b.fragmentBoundary\n );\n}\n\n/**\n * Elements share a field name when the same field is rendered in several\n * places; within a field the order is DOM order.\n */\nexport class ElementCache {\n private readonly entriesByField = new Map<string, CachedElement[]>();\n private entryByElement = new WeakMap<Element, CachedElement>();\n private readonly filter: ElementPredicate;\n private count = 0;\n private dependencies: DependencyMap | null = null;\n private islandRoots: readonly Element[] = [];\n private ownersByIsland: ReadonlyMap<Element, string | undefined> = new Map();\n private navigationRoots: readonly Element[] = [];\n private coverDeclarations: readonly CoverDeclaration[] = [];\n private renderedDeclarations: readonly RenderedDeclaration[] = [];\n\n constructor(options: ElementCacheOptions = {}) {\n this.filter = options.filter ?? alwaysTrue;\n }\n\n /** Source → dependents declared with `data-payload-depends`; memoised until the cache changes. */\n dependencyMap(): DependencyMap {\n if (this.dependencies !== null) return this.dependencies;\n const maps: DependencyMap[] = [];\n for (const binding of this.values()) {\n if (binding.dependsOn !== undefined) {\n maps.push(dependencyMapFromBinding(binding.fieldName, binding.dependsOn));\n }\n }\n this.dependencies = mergeDependencyMaps(...maps);\n return this.dependencies;\n }\n\n /** Island roots under the last built root, for update events. */\n get islands(): readonly Element[] {\n return this.islandRoots;\n }\n\n /** Owner identities captured with `islands`; used to detect a live retarget. @internal */\n get islandOwners(): ReadonlyMap<Element, string | undefined> {\n return this.ownersByIsland;\n }\n\n /** `data-payload-covers` declarations under the last built root. */\n get covers(): readonly CoverDeclaration[] {\n return this.coverDeclarations;\n }\n\n /** Boundaries and route markers under the last built root that name the fields they depend on. */\n get rendered(): readonly RenderedDeclaration[] {\n return this.renderedDeclarations;\n }\n\n /** Fieldless strategy roots under the last built root, for navigation replay. */\n get navigationReplayRoots(): readonly Element[] {\n return this.navigationRoots;\n }\n\n buildFromRoot(root: ParentNode): CacheBuildStats {\n const t0 = performance.now();\n this.clear();\n let elementCount = 0;\n for (const element of root.querySelectorAll(FIELD_SELECTOR)) {\n if (this.add(element) !== undefined) elementCount += 1;\n }\n this.islandRoots = collectIslands(root);\n this.ownersByIsland = new Map(\n this.islandRoots.map((island) => [island, resolveBindingOwner(island)]),\n );\n this.navigationRoots = [...root.querySelectorAll(NAVIGATION_REPLAY_SELECTOR)].filter(\n (element) =>\n this.filter(element) &&\n (element.hasAttribute(FRAGMENT_ATTRIBUTE) ||\n (element.getAttribute(FIELD_ATTRIBUTE) ?? '').length === 0),\n );\n this.coverDeclarations = [...root.querySelectorAll(`[${COVERS_ATTRIBUTE}]`)]\n .filter((element) => this.filter(element))\n .map((element) => ({\n paths: parseDependencyList(element.getAttribute(COVERS_ATTRIBUTE)),\n owner: resolveBindingOwner(element),\n }));\n this.renderedDeclarations = [...root.querySelectorAll(`[${DEPENDS_ATTRIBUTE}]`)]\n .filter((element) => this.filter(element))\n .flatMap((element): RenderedDeclaration[] => {\n const strategy = renderingStrategy(element);\n if (strategy === undefined) return [];\n const paths = parseDependencyList(element.getAttribute(DEPENDS_ATTRIBUTE));\n return [{ strategy, paths, owner: resolveBindingOwner(element) }];\n });\n return {\n elementCount,\n fieldCount: this.entriesByField.size,\n durationMs: performance.now() - t0,\n };\n }\n\n /**\n * Insert or replace a single element's binding. Re-adding refreshes the\n * snapshot in place; an element that is now filtered or unbound is removed.\n */\n add(element: Element): CachedElement | undefined {\n // Resolve before mutating so a throwing filter leaves the old entry intact.\n const entry = this.filter(element) ? this.resolveBinding(element) : undefined;\n const previous = this.entryByElement.get(element);\n this.dependencies = null;\n if (entry === undefined) {\n if (previous !== undefined) this.removeEntry(element, previous);\n return undefined;\n }\n if (previous !== undefined && this.replaceEntry(previous, entry)) {\n this.entryByElement.set(element, entry);\n return entry;\n }\n if (previous !== undefined) this.removeEntry(element, previous);\n this.append(entry);\n this.entryByElement.set(element, entry);\n return entry;\n }\n\n /** Returns whether a binding was removed. */\n remove(element: Element): boolean {\n const entry = this.entryByElement.get(element);\n if (!entry) return false;\n this.dependencies = null;\n return this.removeEntry(element, entry);\n }\n\n get(fieldName: string): readonly CachedElement[] | undefined {\n return this.entriesByField.get(fieldName);\n }\n\n getByElement(element: Element): CachedElement | undefined {\n return this.entryByElement.get(element);\n }\n\n get fieldCount(): number {\n return this.entriesByField.size;\n }\n\n get elementCount(): number {\n return this.count;\n }\n\n entries(): IterableIterator<[string, readonly CachedElement[]]> {\n return this.entriesByField.entries() as IterableIterator<[string, readonly CachedElement[]]>;\n }\n\n *values(): IterableIterator<CachedElement> {\n for (const bucket of this.entriesByField.values()) yield* bucket;\n }\n\n has(element: Element): boolean {\n return this.entryByElement.has(element);\n }\n\n clear(): void {\n this.entriesByField.clear();\n // WeakMap cannot be cleared; a detached element must not observe stale membership.\n this.entryByElement = new WeakMap();\n this.count = 0;\n this.dependencies = null;\n this.islandRoots = [];\n this.ownersByIsland = new Map();\n this.navigationRoots = [];\n this.coverDeclarations = [];\n this.renderedDeclarations = [];\n }\n\n /** Replace in place when the field bucket is unchanged, preserving order. */\n private replaceEntry(previous: CachedElement, next: CachedElement): boolean {\n if (previous.fieldName !== next.fieldName) return false;\n const bucket = this.entriesByField.get(previous.fieldName);\n const index = bucket === undefined ? -1 : bucket.indexOf(previous);\n if (bucket === undefined || index < 0) return false;\n bucket[index] = next;\n return true;\n }\n\n private removeEntry(element: Element, entry: CachedElement): boolean {\n this.entryByElement.delete(element);\n const bucket = this.entriesByField.get(entry.fieldName);\n const index = bucket === undefined ? -1 : bucket.indexOf(entry);\n if (bucket === undefined || index < 0) return false;\n bucket.splice(index, 1);\n if (bucket.length === 0) this.entriesByField.delete(entry.fieldName);\n this.count -= 1;\n return true;\n }\n\n private append(entry: CachedElement): void {\n const bucket = this.entriesByField.get(entry.fieldName);\n if (bucket) bucket.push(entry);\n else this.entriesByField.set(entry.fieldName, [entry]);\n this.count += 1;\n }\n\n private resolveBinding(element: Element): CachedElement | undefined {\n const fieldName = element.getAttribute(FIELD_ATTRIBUTE);\n if (fieldName === null || fieldName.length === 0) return undefined;\n const explicit = element.getAttribute(TYPE_ATTRIBUTE);\n const targetAttribute = element.getAttribute(TARGET_ATTRIBUTE_ATTRIBUTE);\n const hrefField = element.getAttribute(HREF_ATTRIBUTE);\n const srcField = element.getAttribute(SRC_ATTRIBUTE);\n const altField = element.getAttribute(ALT_ATTRIBUTE);\n const arrayTemplate = element.getAttribute(ARRAY_TEMPLATE_ATTRIBUTE);\n const arraySeparator = element.getAttribute(ARRAY_SEPARATOR_ATTRIBUTE);\n const locale = element.getAttribute(LOCALE_ATTRIBUTE);\n const format = element.getAttribute(FORMAT_ATTRIBUTE);\n const owner = resolveBindingOwner(element);\n const dependsOn = parseDependencyList(element.getAttribute(DEPENDS_ATTRIBUTE));\n const strategy = element.getAttribute(STRATEGY_ATTRIBUTE);\n const guessed = element.getAttribute(GUESSED_ATTRIBUTE);\n const fragmentBoundary = enclosingFragment(element);\n return {\n element,\n fieldName,\n fieldType: resolveFieldType(element),\n explicitFieldType: explicit !== null && isRendererKey(explicit),\n strategyKind: resolveStrategy(element) ?? 'unknown',\n ...(fragmentBoundary !== null ? { fragmentBoundary } : {}),\n ...(targetAttribute !== null && targetAttribute.length > 0 ? { targetAttribute } : {}),\n ...(hrefField !== null && hrefField.length > 0 ? { hrefField } : {}),\n ...(srcField !== null && srcField.length > 0 ? { srcField } : {}),\n ...(altField !== null && altField.length > 0 ? { altField } : {}),\n ...(arrayTemplate !== null ? { arrayTemplate } : {}),\n ...(arraySeparator !== null ? { arraySeparator } : {}),\n ...(locale !== null && locale.length > 0 ? { locale } : {}),\n ...(format !== null && format.length > 0 ? { format } : {}),\n ...(owner !== undefined ? { owner } : {}),\n ...(dependsOn.length > 0 ? { dependsOn } : {}),\n ...(strategy !== null && strategy.length > 0 ? { strategy } : {}),\n ...(element.hasAttribute(BOUNDARY_ATTRIBUTE) ? { hidesWhenEmpty: true } : {}),\n ...(guessed !== null ? { guessed } : {}),\n };\n }\n}\n\n/** Explicit `data-payload-type`, then element heuristics, then `text`. */\nexport function resolveFieldType(element: Element): RendererKey {\n const explicit = element.getAttribute(TYPE_ATTRIBUTE);\n if (explicit !== null && isRendererKey(explicit)) return explicit;\n if (element.hasAttribute(RICH_TEXT_ATTRIBUTE)) return 'richText';\n if (element.hasAttribute(HTML_ATTRIBUTE)) return 'html';\n if (element.hasAttribute(STRUCTURAL_ATTRIBUTE)) return 'structural-array';\n if (element.hasAttribute(ARRAY_ATTRIBUTE)) return 'array';\n if (element.tagName === 'IMG') return 'image';\n if (element.tagName === 'A') return 'url';\n if (element.tagName === 'TIME') return 'date';\n if (element.tagName === 'INPUT') {\n const inputType = (element as HTMLInputElement).type;\n if (inputType === 'checkbox') return 'checkbox';\n if (inputType === 'number') return 'number';\n if (inputType === 'date' || inputType === 'datetime-local') return 'date';\n }\n return 'text';\n}\n\nfunction alwaysTrue(): boolean {\n return true;\n}\n","/**\n * Stable identity for a field value, so two messages can be compared without\n * rendering either — every keystroke ships the whole document, of which one\n * field changed. Equality is structural (plain, unsorted JSON): Payload\n * allocates a fresh object graph per message, so reference identity would skip\n * nothing. A value JSON cannot represent has no identity and counts as\n * changed, which is the safe direction — a false \"equal\" leaves a stale\n * binding, a false \"different\" only renders once more.\n */\n\n/** Past this size the comparison is no longer obviously cheaper than the render it avoids. */\nexport const IDENTITY_SIZE_LIMIT = 64 * 1024;\n\n/**\n * Canonical string for `value`, or `undefined` when it cannot have one.\n * Primitives carry a type tag, so `1` and `'1'` differ even though a text\n * renderer prints them alike — that is the renderer's decision, not this one.\n */\nexport function valueIdentity(value: unknown): string | undefined {\n switch (typeof value) {\n case 'string':\n return value.length > IDENTITY_SIZE_LIMIT ? undefined : `s:${value}`;\n case 'number':\n // Object.is semantics at the top level: NaN equals NaN, -0 is not 0.\n return `n:${Object.is(value, -0) ? '-0' : String(value)}`;\n case 'boolean':\n return `b:${value ? '1' : '0'}`;\n case 'bigint':\n return `i:${String(value)}`;\n case 'undefined':\n return 'u';\n case 'object': {\n if (value === null) return 'z';\n let json: string;\n try {\n // Throws on a cycle and on a nested BigInt; both mean \"no identity\".\n json = JSON.stringify(value);\n } catch {\n return undefined;\n }\n return json.length > IDENTITY_SIZE_LIMIT ? undefined : `o:${json}`;\n }\n case 'symbol':\n case 'function':\n return undefined;\n }\n}\n","/**\n * Which paths below a group changed without anything on the page to show\n * them (ADR 0022). The diff names top-level fields; under\n * `subfieldCoverage: 'declared'` a group covered only through its descendants\n * is compared with the previous message path by path, and a changed path\n * needs its own binding or a declared cover. A document a merge populated and\n * the id it replaced are the same value: population is not an edit.\n */\n\nimport { valueIdentity } from './value-identity';\n\nexport type SubfieldCoverage = 'descendant' | 'declared';\n\n/** Deeper than this, what is left counts as one changed path. */\nexport const SUBFIELD_DEPTH_LIMIT = 8;\n/** Nodes compared per field before the rest counts as one changed path. */\nexport const SUBFIELD_VISIT_LIMIT = 1024;\n\n/** What the page offers for a path; built once per update from the cache and the owner scope. */\nexport interface PathCoverage {\n /** A binding on the path, or a cover on it or on an ancestor. */\n readonly covers: (path: string) => boolean;\n /** A binding or a cover somewhere below the path. */\n readonly reachesBelow: (path: string) => boolean;\n}\n\nexport interface UncoveredPath {\n readonly path: string;\n /** The current value there, `undefined` where the path was removed. */\n readonly value: unknown;\n}\n\nfunction isContainer(value: unknown): value is Record<string, unknown> | readonly unknown[] {\n return typeof value === 'object' && value !== null;\n}\n\nfunction shapeOf(value: unknown): 'array' | 'object' | 'scalar' {\n if (Array.isArray(value)) return 'array';\n return isContainer(value) ? 'object' : 'scalar';\n}\n\n/** The keys to compare below a container: the new ones, and any the previous value had. */\nfunction childKeys(\n previous: unknown,\n next: Record<string, unknown> | readonly unknown[],\n): string[] {\n const keys = new Set(Object.keys(next));\n if (isContainer(previous)) for (const key of Object.keys(previous)) keys.add(key);\n return [...keys];\n}\n\nfunction child(value: unknown, key: string): unknown {\n return isContainer(value) ? (value as Record<string, unknown>)[key] : undefined;\n}\n\n/** Whether `document` is what a merge puts where the message has the bare `id`. */\nfunction populates(document: unknown, id: unknown): boolean {\n return (\n (typeof id === 'string' || typeof id === 'number') &&\n isContainer(document) &&\n !Array.isArray(document) &&\n (document as Record<string, unknown>)['id'] === id\n );\n}\n\n/**\n * Whether two values differ only in what the server populated: the same shape\n * all the way down, except that one holds a document where the other holds its\n * id. The admin posts a relationship or an upload as its id in every message\n * and the merge answers with the document, so a revision rendered before the\n * answer and the one after it meet both forms of one value.\n */\nfunction samePopulation(before: unknown, after: unknown): boolean {\n if (!isContainer(before) || !isContainer(after)) {\n return (\n populates(before, after) ||\n populates(after, before) ||\n valueIdentity(before) === valueIdentity(after)\n );\n }\n if (Array.isArray(before) !== Array.isArray(after)) return false;\n const keys = Object.keys(after);\n if (keys.length !== Object.keys(before).length) return false;\n return keys.every(\n (key) => Object.hasOwn(before, key) && samePopulation(child(before, key), child(after, key)),\n );\n}\n\n/**\n * Whether the two values are one: equal, or equal but for population. An id\n * and its document are told apart without a walk, whatever the document's\n * size. The walk itself needs an identity on both sides, which bounds it by\n * the identity's size limit and keeps it out of a cycle; a value without one\n * counts as changed, as it does for the top-level diff.\n */\nfunction sameValue(before: unknown, after: unknown): boolean {\n const identity = valueIdentity(after);\n const previous = valueIdentity(before);\n if (identity !== undefined && identity === previous) return true;\n if (populates(before, after) || populates(after, before)) return true;\n return identity !== undefined && previous !== undefined && samePopulation(before, after);\n}\n\n/**\n * Whether the value at a dotted path changed between two messages, by the\n * rule the walk below applies. A route-bound element names such a path\n * (`layout.1.note`) while the diff names only its field.\n */\nexport function pathChanged(\n path: string,\n previous: Readonly<Record<string, unknown>>,\n next: Readonly<Record<string, unknown>>,\n): boolean {\n let before: unknown = previous;\n let after: unknown = next;\n for (const key of path.split('.')) {\n before = child(before, key);\n after = child(after, key);\n }\n return !sameValue(before, after);\n}\n\n/**\n * The changed paths below `field` that nothing covers, as the largest\n * uncovered subtrees: a path with nothing bound or covered beneath it is\n * reported whole rather than leaf by leaf. `previous` is `undefined` for a\n * document read without a diff, which makes every path \"changed\".\n */\nexport function uncoveredChangedPaths(\n field: string,\n previous: unknown,\n next: unknown,\n coverage: PathCoverage,\n): UncoveredPath[] {\n const uncovered: UncoveredPath[] = [];\n let visits = 0;\n const visit = (path: string, before: unknown, after: unknown, depth: number): void => {\n visits += 1;\n if (coverage.covers(path) || sameValue(before, after)) return;\n // A path that changed shape — a group that became a scalar, went away or\n // replaced one — changed as a whole, whatever is covered inside it. Without\n // a previous message (`undefined`) there is no shape to compare.\n const reshaped = before !== undefined && shapeOf(before) !== shapeOf(after);\n const descend =\n !reshaped &&\n isContainer(after) &&\n coverage.reachesBelow(path) &&\n depth < SUBFIELD_DEPTH_LIMIT;\n if (!descend) {\n uncovered.push({ path, value: after });\n return;\n }\n const keys = childKeys(before, after);\n // A new, empty group: nothing inside to compare, so the node itself changed.\n if (keys.length === 0) uncovered.push({ path, value: after });\n for (const key of keys) {\n // Out of budget: this node stands for whatever of it is left unvisited.\n if (visits >= SUBFIELD_VISIT_LIMIT) {\n uncovered.push({ path, value: after });\n return;\n }\n visit(`${path}.${key}`, child(before, key), child(after, key), depth + 1);\n }\n };\n visit(field, previous, next, 0);\n return uncovered;\n}\n","/**\n * Whether an incoming field has somewhere on the page to land.\n *\n * Two callers ask, for different reasons: LP0201 reports a field that never\n * has an anchor, and `onUnfaithfulPatch` decides whether a revision needs the\n * whole route. They have to answer the same way, so the lookup lives here\n * rather than in either of them — the locale suffix Payload appends, the owner\n * scope, and the fact that the diff names top-level fields while a binding may\n * name a path inside one.\n */\n\nimport { isBindingInScope } from './binding-owner';\nimport type { ElementCache } from './cache';\nimport {\n pathChanged,\n uncoveredChangedPaths,\n type PathCoverage,\n type SubfieldCoverage,\n type UncoveredPath,\n} from './subfield-coverage';\n\n/** Document fields Payload ships in every update that nobody binds to. */\nexport const SYSTEM_FIELD_NAMES: ReadonlySet<string> = new Set([\n 'id',\n '_id',\n 'createdAt',\n 'updatedAt',\n 'createdBy',\n 'updatedBy',\n '_status',\n 'globalType',\n 'collection',\n 'locale',\n 'localized',\n]);\n\n/** Owner keys as the update resolved them; `false` means scoping is off. */\nexport type OwnerScope = readonly string[] | null | false;\n\n/** Answers for one update; the locale index behind it is built at most once. */\nexport type FieldAddressability = (fieldName: string) => boolean;\n\n/**\n * `field_locale` names an element-local locale may consume while the message\n * locale differs, so those bindings are addressable under their suffixed name.\n */\nfunction localisedBindingNames(cache: ElementCache, ownerKeys: OwnerScope): Set<string> {\n const names = new Set<string>();\n for (const [fieldName, bindings] of cache.entries()) {\n for (const binding of bindings) {\n if (ownerKeys !== false && !isBindingInScope(binding.owner, ownerKeys)) continue;\n if (binding.locale !== undefined) names.add(`${fieldName}_${binding.locale}`);\n }\n }\n return names;\n}\n\n/**\n * A binding on a path inside the field — `hero.eyebrow` for the field `hero` —\n * makes it addressable. The diff names top-level fields only, so without this\n * every group and array on the page would look unbound.\n */\nexport function hasBindingBelow(\n cache: ElementCache,\n fieldName: string,\n ownerKeys: OwnerScope,\n): boolean {\n const prefix = `${fieldName}.`;\n for (const [boundName, bindings] of cache.entries()) {\n if (!boundName.startsWith(prefix)) continue;\n if (ownerKeys === false) return true;\n if (bindings.some((binding) => isBindingInScope(binding.owner, ownerKeys))) return true;\n }\n return false;\n}\n\n/** The strategies configured for this page; only they render what a boundary or marker depends on. */\nexport interface ServerRendering {\n readonly fragment?: unknown;\n readonly route?: unknown;\n}\n\n/**\n * The page's answer for any path in one update's owner scope: the bound names,\n * the declared covers (ADR 0022) and the fields a boundary or route marker\n * depends on when its strategy is configured, read once, then the same name\n * rule the overlay applies.\n */\nexport function createPathCoverage(\n cache: ElementCache,\n ownerKeys: OwnerScope,\n rendering: ServerRendering = {},\n): PathCoverage {\n const inScope = (owner: string | undefined): boolean =>\n ownerKeys === false || isBindingInScope(owner, ownerKeys);\n const names: string[] = [];\n for (const [fieldName, bindings] of cache.entries()) {\n if (bindings.some((binding) => inScope(binding.owner))) names.push(fieldName);\n }\n const rendered = cache.rendered.filter(\n (declaration) => rendering[declaration.strategy] !== undefined,\n );\n const covers = [...cache.covers, ...rendered]\n .filter((cover) => inScope(cover.owner))\n .flatMap((cover) => cover.paths);\n return namePathCoverage(names, covers);\n}\n\nexport function stripLocaleSuffix(name: string, locale: string | undefined): string {\n if (locale === undefined || locale.length === 0) return name;\n const suffix = `_${locale}`;\n return name.endsWith(suffix) ? name.slice(0, -suffix.length) : name;\n}\n\n/** Whether any binding on the page belongs to the document this update carries. */\nexport function ownsAnyBinding(cache: ElementCache, ownerKeys: readonly string[] | null): boolean {\n for (const binding of cache.values()) {\n if (isBindingInScope(binding.owner, ownerKeys)) return true;\n }\n return false;\n}\n\n/**\n * The same rule for a caller that has names rather than the cache: the\n * `data-payload-field` values in a document, which is all a plugin can see\n * (`src/plugins/built-in/unbound-fields-overlay.ts`).\n *\n * It answers the first three of the four questions below — exact name, the\n * locale-stripped base, a binding on a path inside the field. The fourth needs\n * each binding's own `data-payload-locale`, which is a property of the element\n * rather than of its name, so a caller with names alone cannot ask it.\n */\nexport function createNameAddressability(\n boundNames: Iterable<string>,\n locale: string | undefined,\n coverPaths: Iterable<string>,\n): FieldAddressability {\n const coverage = namePathCoverage(boundNames, coverPaths);\n const reaches = (name: string): boolean => coverage.covers(name) || coverage.reachesBelow(name);\n return (fieldName) => {\n if (reaches(fieldName)) return true;\n const base = stripLocaleSuffix(fieldName, locale);\n return base !== fieldName && reaches(base);\n };\n}\n\n/** Coverage from names alone: the bound names and the declared cover paths in a document. */\nfunction namePathCoverage(\n boundNames: Iterable<string>,\n coverPaths: Iterable<string>,\n): PathCoverage {\n const names = new Set(boundNames);\n const covers = [...coverPaths];\n const anyBelow = (candidates: Iterable<string>, path: string): boolean => {\n const prefix = `${path}.`;\n for (const candidate of candidates) if (candidate.startsWith(prefix)) return true;\n return false;\n };\n return {\n covers: (path) =>\n names.has(path) || covers.some((cover) => cover === path || path.startsWith(`${cover}.`)),\n reachesBelow: (path) => anyBelow(names, path) || anyBelow(covers, path),\n };\n}\n\n/**\n * The declared mode for a caller with names (the overlay): the uncovered paths\n * inside the groups the document reaches only below the top level.\n */\nexport function uncoveredNamePaths(\n fields: Readonly<Record<string, unknown>>,\n boundNames: Iterable<string>,\n locale: string | undefined,\n coverPaths: Iterable<string>,\n): string[] {\n const coverage = namePathCoverage(boundNames, coverPaths);\n const found: string[] = [];\n for (const [fieldName, value] of Object.entries(fields)) {\n if (SYSTEM_FIELD_NAMES.has(fieldName)) continue;\n const root = stripLocaleSuffix(fieldName, locale);\n if (coverage.covers(root) || !coverage.reachesBelow(root)) continue;\n for (const { path } of uncoveredChangedPaths(root, undefined, value, coverage)) {\n found.push(path);\n }\n }\n return found;\n}\n\n/**\n * The predicate for one update. The localised index is built on first use:\n * most fields are answered by the two cheap lookups before it.\n */\nexport function createFieldAddressability(\n cache: ElementCache,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n rendering?: ServerRendering,\n): FieldAddressability {\n const coverage = createPathCoverage(cache, ownerKeys, rendering);\n const reach = createFieldReach(cache, locale, ownerKeys, coverage);\n return (fieldName) => reach(fieldName) !== 'none';\n}\n\n/**\n * How far the page reaches into a field: `whole` when a binding or a cover\n * sits on it, `below` when only paths inside it are bound or covered — the\n * case ADR 0022's declared mode looks into — and `none`.\n */\nfunction createFieldReach(\n cache: ElementCache,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n coverage: PathCoverage = createPathCoverage(cache, ownerKeys),\n): (fieldName: string) => 'whole' | 'below' | 'none' {\n let localised: Set<string> | undefined;\n const whole = coverage.covers;\n const below = coverage.reachesBelow;\n return (fieldName) => {\n const base = stripLocaleSuffix(fieldName, locale);\n if (whole(fieldName) || (base !== fieldName && whole(base))) return 'whole';\n localised ??= localisedBindingNames(cache, ownerKeys);\n if (localised.has(fieldName)) return 'whole';\n if (below(fieldName) || (base !== fieldName && below(base))) return 'below';\n return 'none';\n };\n}\n\n/** The previous and current message, when the declared mode compares below the top level. */\nexport interface SubfieldValues {\n readonly previous: Readonly<Record<string, unknown>>;\n readonly next: Readonly<Record<string, unknown>>;\n}\n\n/**\n * The declared mode asked of a document rather than a diff, for LP0203: the\n * uncovered paths inside the groups the page reaches only below the top level.\n */\nexport function uncoveredDocumentPaths(\n cache: ElementCache,\n fields: Readonly<Record<string, unknown>>,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n rendering?: ServerRendering,\n): UncoveredPath[] {\n const coverage = createPathCoverage(cache, ownerKeys, rendering);\n const reach = createFieldReach(cache, locale, ownerKeys, coverage);\n const found: UncoveredPath[] = [];\n for (const [fieldName, value] of Object.entries(fields)) {\n if (SYSTEM_FIELD_NAMES.has(fieldName) || reach(fieldName) !== 'below') continue;\n const root = stripLocaleSuffix(fieldName, locale);\n found.push(...uncoveredChangedPaths(root, undefined, value, coverage));\n }\n return found;\n}\n\n/** What the declared mode compares for one revision, or `undefined` where it does not apply. */\nexport function declaredSubfields(\n mode: SubfieldCoverage,\n previous: Readonly<Record<string, unknown>> | undefined,\n next: Readonly<Record<string, unknown>> | undefined,\n): SubfieldValues | undefined {\n return mode === 'declared' && previous !== undefined && next !== undefined\n ? { previous, next }\n : undefined;\n}\n\n/**\n * `touched` with the paths inside its fields that route-bound elements name and\n * that changed, for the route planners: a marker on `layout.1.note` asks about\n * that path while the diff names `layout`. Without the previous message, which\n * only the declared mode keeps, a path changes with its field.\n */\nexport function routeTouched(\n cache: ElementCache,\n touched: ReadonlySet<string>,\n subfields?: SubfieldValues,\n): ReadonlySet<string> {\n const named = cache.rendered.flatMap((declaration) =>\n declaration.strategy === 'route' ? declaration.paths : [],\n );\n for (const [fieldName, bindings] of cache.entries()) {\n if (bindings.some((binding) => binding.strategyKind === 'route')) named.push(fieldName);\n }\n const changed = new Set(touched);\n for (const path of named) {\n const [field = path] = path.split('.');\n if (!touched.has(field)) continue;\n if (subfields === undefined || pathChanged(path, subfields.previous, subfields.next)) {\n changed.add(path);\n }\n }\n return changed;\n}\n\n/**\n * The fields a revision changed that the page has nowhere to put: the rule\n * above, asked of a diff instead of a document. Both profiles ask it — the full\n * one to decide whether the whole route is the only honest answer, the lean one\n * because the finding is worth recording even where nothing can act on it — so\n * it stands here, beside the rule it is made of, rather than in either runner.\n */\nexport function unboundChangedFields(\n cache: ElementCache,\n touched: ReadonlySet<string>,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n subfields?: SubfieldValues,\n rendering?: ServerRendering,\n): string[] {\n const coverage = createPathCoverage(cache, ownerKeys, rendering);\n const reach = createFieldReach(cache, locale, ownerKeys, coverage);\n const unbound: string[] = [];\n for (const fieldName of touched) {\n if (SYSTEM_FIELD_NAMES.has(fieldName)) continue;\n const kind = reach(fieldName);\n if (kind === 'none') unbound.push(fieldName);\n if (kind !== 'below' || subfields === undefined) continue;\n const root = stripLocaleSuffix(fieldName, locale);\n const { previous, next } = subfields;\n for (const { path } of uncoveredChangedPaths(\n root,\n previous[fieldName],\n next[fieldName],\n coverage,\n )) {\n unbound.push(path);\n }\n }\n return unbound;\n}\n","/**\n * `unbound-fields` plugin: a development overlay listing the fields an update\n * carried that the page has nowhere to put.\n *\n * Annotating a template is the work this package asks for, and the hardest part\n * of it is knowing what is still missing — `inspect().bindings.orphanFields`\n * answers that in the console, which is the wrong place while you are editing\n * markup. This puts the same answer in the preview, with the attribute to paste\n * one click away.\n *\n * Since ADR 0014 it answers a second question the same way: which bindings the\n * runtime *guessed* (`autoBind: 'unique'`) rather than read from the template.\n * Those are listed apart, with the value each one matched on, so an element\n * that changes without an attribute in the source is never a mystery — and\n * the button offers the attribute that would make the guess a declaration.\n *\n * It is a plugin, not part of the runtime: the inline artifact every page\n * carries must not grow by a development tool (the budget in\n * `scripts/bundle-budgets.ts` is the proof). Register it on a client you build\n * yourself, and only in development.\n */\n\nimport type { LivePreviewPlugin, PluginDisposer } from '../types';\nimport {\n COVERS_ATTRIBUTE,\n DEPENDS_ATTRIBUTE,\n FIELD_ATTRIBUTE,\n GUESSED_ATTRIBUTE,\n renderingStrategy,\n} from '@core/cache';\nimport { parseDependencyList } from '@core/dependencies';\nimport { isInsideIsland } from '@core/islands';\nimport {\n createNameAddressability,\n SYSTEM_FIELD_NAMES,\n uncoveredNamePaths,\n type ServerRendering,\n} from '@core/unbound-fields';\n\nconst ELEMENT_ID = 'payload-live-preview-unbound';\n\nexport interface UnboundFieldsOverlayOptions {\n /**\n * Mount only when the client runs with `debug: true`. Default `true`: the\n * overlay is a development tool, and a production preview should not grow one\n * because a plugin list was copied between environments.\n */\n readonly onlyWithDebug?: boolean;\n /** Where to look for bindings and where to mount. Default `document`. */\n readonly root?: Document | Element;\n /** Corner of the preview to sit in. Default `'bottom-right'`. */\n readonly position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n}\n\nconst POSITIONS: Readonly<Record<NonNullable<UnboundFieldsOverlayOptions['position']>, string>> = {\n 'bottom-right': 'bottom:12px;right:12px;',\n 'bottom-left': 'bottom:12px;left:12px;',\n 'top-right': 'top:12px;right:12px;',\n 'top-left': 'top:12px;left:12px;',\n};\n\n// Applied through `element.style`, never as a `style` attribute: a strict\n// `style-src` refuses the attribute and would leave the panel unstyled in flow.\nconst PANEL_STYLE =\n 'position:fixed;z-index:2147483646;max-width:280px;max-height:40vh;overflow:auto;' +\n 'font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;background:#111;color:#eee;' +\n 'border:1px solid #333;border-radius:6px;padding:8px 10px;box-shadow:0 4px 16px rgba(0,0,0,0.4);';\n\nconst BUTTON_STYLE =\n 'display:block;width:100%;text-align:left;margin:2px 0;padding:2px 4px;border:0;border-radius:3px;' +\n 'background:#222;color:#7fd1ff;font:inherit;cursor:pointer;';\n\n/**\n * The document this update named, minus everything the page can already show\n * or declares with `data-payload-covers`. Under `subfieldCoverage: 'declared'`\n * the uncovered paths inside partly bound groups are listed too (ADR 0022).\n * @internal\n */\nexport function unboundFieldNames(\n fields: Readonly<Record<string, unknown>>,\n boundNames: Iterable<string>,\n locale?: string,\n coverPaths: readonly string[] = [],\n subfieldCoverage: 'descendant' | 'declared' = 'descendant',\n): readonly string[] {\n const bound = [...boundNames];\n const addressable = createNameAddressability(bound, locale, coverPaths);\n const names = Object.keys(fields).filter(\n (name) => !SYSTEM_FIELD_NAMES.has(name) && !addressable(name),\n );\n if (subfieldCoverage === 'declared') {\n names.push(...uncoveredNamePaths(fields, bound, locale, coverPaths));\n }\n return [...new Set(names)].sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * The declared covers and, as in the runtime (ADR 0022 §1a), what a boundary\n * or route marker depends on when the client has the strategy that renders it.\n */\nfunction coverPathsIn(root: Document | Element, rendering: ServerRendering): string[] {\n const paths: string[] = [];\n for (const element of root.querySelectorAll(`[${COVERS_ATTRIBUTE}]`)) {\n paths.push(...parseDependencyList(element.getAttribute(COVERS_ATTRIBUTE)));\n }\n for (const element of root.querySelectorAll(`[${DEPENDS_ATTRIBUTE}]`)) {\n const strategy = renderingStrategy(element);\n if (strategy === undefined || rendering[strategy] === undefined) continue;\n if (!isInsideIsland(element)) {\n paths.push(...parseDependencyList(element.getAttribute(DEPENDS_ATTRIBUTE)));\n }\n }\n return paths;\n}\n\nfunction boundNamesIn(root: Document | Element): string[] {\n const names: string[] = [];\n for (const element of root.querySelectorAll(`[${FIELD_ATTRIBUTE}]`)) {\n const name = element.getAttribute(FIELD_ATTRIBUTE);\n if (name !== null && name.length > 0) names.push(name);\n }\n return names;\n}\n\nexport interface GuessedBinding {\n readonly field: string;\n /** The value the runtime found the element by. */\n readonly matched: string;\n}\n\n/** The bindings the runtime stamped on the page itself, in document order. */\nexport function guessedBindingsIn(root: Document | Element): readonly GuessedBinding[] {\n const guessed: GuessedBinding[] = [];\n for (const element of root.querySelectorAll(`[${GUESSED_ATTRIBUTE}]`)) {\n const field = element.getAttribute(FIELD_ATTRIBUTE);\n if (field === null || field.length === 0) continue;\n guessed.push({ field, matched: element.getAttribute(GUESSED_ATTRIBUTE) ?? '' });\n }\n return guessed;\n}\n\nfunction hostDocument(root: Document | Element): Document | null {\n return root.nodeType === 9 ? (root as Document) : root.ownerDocument;\n}\n\n/** Copy through the async clipboard, falling back to a selection nobody has to see. */\nfunction copy(doc: Document, text: string): void {\n const clipboard: unknown = doc.defaultView?.navigator.clipboard;\n if (clipboard !== undefined && clipboard !== null) {\n void (clipboard as Clipboard).writeText(text).catch(() => {\n selectInstead(doc, text);\n });\n return;\n }\n selectInstead(doc, text);\n}\n\nfunction selectInstead(doc: Document, text: string): void {\n const field = doc.createElement('textarea');\n field.value = text;\n field.setAttribute('readonly', '');\n field.style.cssText = 'position:fixed;opacity:0;pointer-events:none;';\n doc.body.append(field);\n field.select();\n field.remove();\n}\n\ninterface Overlay {\n readonly update: (names: readonly string[], guessed: readonly GuessedBinding[]) => void;\n readonly destroy: PluginDisposer;\n}\n\n/** One click copies the attribute to paste into the template. */\nfunction copyButton(doc: Document, field: string, label: string): HTMLButtonElement {\n const button = doc.createElement('button');\n button.type = 'button';\n button.textContent = label;\n button.style.cssText = BUTTON_STYLE;\n button.title = `Copy ${FIELD_ATTRIBUTE}=\"${field}\"`;\n button.addEventListener('click', () => {\n copy(doc, `${FIELD_ATTRIBUTE}=\"${field}\"`);\n button.textContent = `${label} ✓`;\n });\n return button;\n}\n\nfunction mountOverlay(root: Document | Element, position: string): Overlay | null {\n const doc = hostDocument(root);\n if (doc?.body == null) return null;\n const panel = doc.createElement('aside');\n panel.id = ELEMENT_ID;\n panel.style.cssText = PANEL_STYLE + position;\n // Development furniture, not content: no screen reader should read it, and\n // no binding scan should ever reach into it.\n panel.setAttribute('aria-hidden', 'true');\n panel.hidden = true;\n const heading = (text: string): HTMLElement => {\n const title = doc.createElement('div');\n title.textContent = text;\n title.style.cssText = 'font-weight:600;margin-bottom:4px;';\n return title;\n };\n const unboundTitle = heading('Unbound fields');\n const list = doc.createElement('div');\n // Apart from the unbound ones on purpose: a guessed field is bound, but by\n // the runtime's reading of the page, not by the template's say-so.\n const guessedTitle = heading('Guessed bindings');\n guessedTitle.setAttribute('data-testid', 'guessed-bindings');\n const guessedList = doc.createElement('div');\n panel.append(unboundTitle, list, guessedTitle, guessedList);\n doc.body.append(panel);\n\n return {\n update: (names, guessed) => {\n // A page that rewrote its body (a framework re-render, a route morph)\n // took the panel with it and may have left a serialized copy behind.\n // Re-attaching the real one is cheaper than watching for the rewrite.\n if (!panel.isConnected) {\n doc.getElementById(ELEMENT_ID)?.remove();\n doc.body.append(panel);\n }\n panel.hidden = names.length === 0 && guessed.length === 0;\n unboundTitle.hidden = names.length === 0;\n list.replaceChildren(...names.map((name) => copyButton(doc, name, name)));\n guessedTitle.hidden = guessed.length === 0;\n guessedList.replaceChildren(\n ...guessed.map(({ field, matched }) =>\n copyButton(doc, field, `${field} ← ${JSON.stringify(matched)}`),\n ),\n );\n },\n destroy: () => {\n panel.remove();\n },\n };\n}\n\n/**\n * ```ts\n * client.use(createUnboundFieldsOverlayPlugin());\n * ```\n *\n * Every update recomputes the list from the message's own fields and the\n * bindings currently in the DOM, so annotating the template makes entries\n * disappear as you save the file.\n */\nexport function createUnboundFieldsOverlayPlugin(\n options: UnboundFieldsOverlayOptions = {},\n): LivePreviewPlugin {\n return {\n name: 'unbound-fields',\n version: '1.0.0',\n init: (ctx) => {\n const root = options.root ?? (typeof document === 'undefined' ? undefined : document);\n if (root === undefined) return;\n if ((options.onlyWithDebug ?? true) && ctx.getConfig()['debug'] !== true) {\n ctx.log('not mounted: the client runs without `debug: true`');\n return;\n }\n const overlay = mountOverlay(root, POSITIONS[options.position ?? 'bottom-right']);\n if (overlay === null) return;\n ctx.registerCleanup?.(overlay.destroy);\n const mode = ctx.getConfig()['subfieldCoverage'] === 'declared' ? 'declared' : 'descendant';\n const rendering = (ctx.getConfig()['strategies'] ?? {}) as ServerRendering;\n ctx.events.on('afterUpdate', (e) => {\n const names = unboundFieldNames(\n e.data.fields,\n boundNamesIn(root),\n e.data.locale,\n coverPathsIn(root, rendering),\n mode,\n );\n const guessed = guessedBindingsIn(root);\n overlay.update(names, guessed);\n if (names.length > 0) ctx.log('unbound:', names.join(', '));\n if (guessed.length > 0) ctx.log('guessed:', guessed.map((g) => g.field).join(', '));\n });\n },\n };\n}\n","/**\n * Per-instance typed emitter: handlers run sequentially in registration order,\n * may be async, and a throwing one is logged and isolated. See ADR 0002.\n */\n\nimport type { EventHandler, LivePreviewEventMap, Unsubscribe } from './types';\nimport { safeConsoleError } from '@core/diagnostics';\n\ntype AnyHandler = EventHandler<unknown>;\n\n// `object`, not `Record<string, unknown>`: interfaces with readonly and\n// exact-optional properties must be usable as maps.\nexport class EventEmitter<TMap extends object = LivePreviewEventMap> {\n readonly #regular = new Map<keyof TMap, Set<AnyHandler>>();\n readonly #once = new Map<keyof TMap, Set<AnyHandler>>();\n\n on<E extends keyof TMap>(event: E, handler: EventHandler<TMap[E]>): Unsubscribe {\n return this.#register(this.#regular, event, handler as AnyHandler);\n }\n\n once<E extends keyof TMap>(event: E, handler: EventHandler<TMap[E]>): Unsubscribe {\n return this.#register(this.#once, event, handler as AnyHandler);\n }\n\n off<E extends keyof TMap>(event: E, handler: EventHandler<TMap[E]>): void {\n this.#remove(this.#regular, event, handler as AnyHandler);\n this.#remove(this.#once, event, handler as AnyHandler);\n }\n\n /** Dispatch to every handler: regular ones first, then `once` handlers. */\n async emit<E extends keyof TMap>(event: E, payload: TMap[E]): Promise<void> {\n await this.#emitSequential(event, payload);\n }\n\n /**\n * Dispatch while `shouldContinue()` holds — checked around every handler, so\n * an obsolete transaction cannot resume across an await.\n * @internal\n */\n async emitWhile<E extends keyof TMap>(\n event: E,\n payload: TMap[E],\n shouldContinue: () => boolean,\n ): Promise<boolean> {\n return this.#emitSequential(event, payload, shouldContinue);\n }\n\n async #emitSequential<E extends keyof TMap>(\n event: E,\n payload: TMap[E],\n shouldContinue?: () => boolean,\n ): Promise<boolean> {\n const eligible = (): boolean => shouldContinue?.() ?? true;\n if (!eligible()) return false;\n const regular = this.#regular.get(event);\n if (regular) {\n for (const handler of [...regular]) {\n if (!eligible()) return false;\n await this.#invoke(handler, payload, event);\n if (!eligible()) return false;\n }\n }\n if (!eligible()) return false;\n const once = this.#once.get(event);\n if (once && once.size > 0) {\n const snapshot = [...once];\n this.#once.delete(event);\n for (const handler of snapshot) {\n if (!eligible()) return false;\n await this.#invoke(handler, payload, event);\n if (!eligible()) return false;\n }\n }\n return eligible();\n }\n\n /** Registered handlers for `event`, `on` and `once` together. */\n listenerCount(event: keyof TMap): number {\n return (this.#regular.get(event)?.size ?? 0) + (this.#once.get(event)?.size ?? 0);\n }\n\n /** Remove every handler, or only those of `event`. */\n removeAllListeners(event?: keyof TMap): void {\n if (event === undefined) {\n this.#regular.clear();\n this.#once.clear();\n return;\n }\n this.#regular.delete(event);\n this.#once.delete(event);\n }\n\n /** Event names with at least one handler. */\n eventNames(): (keyof TMap)[] {\n const names = new Set<keyof TMap>();\n for (const key of this.#regular.keys()) names.add(key);\n for (const key of this.#once.keys()) names.add(key);\n return [...names];\n }\n\n #register(\n bucket: Map<keyof TMap, Set<AnyHandler>>,\n event: keyof TMap,\n handler: AnyHandler,\n ): Unsubscribe {\n let set = bucket.get(event);\n if (!set) {\n set = new Set();\n bucket.set(event, set);\n }\n set.add(handler);\n return () => {\n this.#remove(bucket, event, handler);\n };\n }\n\n #remove(bucket: Map<keyof TMap, Set<AnyHandler>>, event: keyof TMap, handler: AnyHandler): void {\n const set = bucket.get(event);\n if (set === undefined) return;\n set.delete(handler);\n if (set.size === 0) bucket.delete(event);\n }\n\n async #invoke(handler: AnyHandler, payload: unknown, event: keyof TMap): Promise<void> {\n try {\n await handler(payload);\n } catch (err) {\n const label =\n typeof event === 'string' || typeof event === 'number' ? String(event) : '<event>';\n safeConsoleError(`[live-preview] LP0601: handler for \"${label}\" threw:`, err);\n }\n }\n}\n","/**\n * Every diagnostic code the runtime and tools emit, so a consumer can branch\n * on `e.code` instead of matching message text. A code is never reused for a\n * different meaning; a retired one stays reserved.\n *\n * Browser-side reporting sites write the literal (`code: 'LP0603'`) rather than\n * reading it from this record: the frozen table would then ship in the inline\n * runtime for the sake of six characters — it did, 1 287 B in every page, for\n * the one read Z6 left in the strategy runner, and `diagnostic-codes.test.ts`\n * now holds the artifact free of it. Server-side tools may import it.\n */\n\n/**\n * Every diagnostic code the runtime can report, by name.\n *\n * ```ts\n * client.events.on('error', (e) => {\n * if (e.code === DIAGNOSTIC_CODES.TransformThrew) reportToSentry(e.error);\n * });\n * ```\n */\nexport const DIAGNOSTIC_CODES = Object.freeze({\n /** No trusted origin configured in production; nothing will be accepted. */\n NoTrustedOrigin: 'LP0101',\n /** Origin trust rests on `document.referrer`, so any framing site is trusted. */\n ReferrerOnlyTrust: 'LP0102',\n /** A plugin declares a runtime range this runtime does not satisfy; it was refused. */\n PluginIncompatible: 'LP0103',\n /** The page carries the lean runtime and needs a feature that profile leaves out. */\n ProfileFeatureOmitted: 'LP0104',\n\n /** An update named an empty field with no binding anchor on the page; an edit to it has nowhere to land. */\n OrphanField: 'LP0201',\n /** Owner scoping is on and the update names no document it could belong to. */\n UnattributableUpdate: 'LP0202',\n /** An update carried a value for a field the page binds nowhere; editing it changes nothing on this page. */\n UnboundField: 'LP0203',\n /** In development: a bound path covers its group under the `descendant` default, which 3.0 changes. */\n CoverageDefaultChanges: 'LP0204',\n\n /** The visibility gate held offscreen writes back until they scroll into view. */\n VisibilityGateDeferred: 'LP0301',\n\n /** A value was refused because the attribute or the value itself is unsafe. */\n UnsafeAttributeWrite: 'LP0401',\n /** A text element has structured children, so replacing its text was skipped. */\n TextTargetHasChildren: 'LP0402',\n /** A structural container has no array template, so the update was skipped. */\n MissingArrayTemplate: 'LP0403',\n /** A structural item has no `id`; it pairs positionally, so an insert re-renders every row after it. */\n StructuralItemUnkeyed: 'LP0404',\n /** Two structural items share a key; later ones pair positionally. */\n StructuralDuplicateKey: 'LP0405',\n /** Every structural key changed while the length did not; the source generates keys per message. */\n StructuralUnstableKeys: 'LP0406',\n /** A binding asks for a delivery strategy this release does not have; it is left unchanged. */\n UnsupportedStrategy: 'LP0407',\n /** `data-payload-format` names a format the vocabulary does not contain; the default formatting was used instead. */\n UnknownValueFormat: 'LP0408',\n /** The strict sanitizer removed an attribute the 1.x `'compat'` policy kept. */\n SanitizerDroppedAttribute: 'LP0409',\n /** A Lexical block has no renderer; the markup the server rendered for it is kept instead. */\n UnrenderedBlockKept: 'LP0410',\n /** A patch cannot reach what the server would have drawn; `onUnfaithfulPatch` decided what happens next. */\n UnfaithfulPatch: 'LP0411',\n /** The first write to a date, number, checkbox, select or radio binding replaced a different reading of the same value. */\n ServerFormatReplaced: 'LP0412',\n /** A Lexical block has no renderer, and the write could not keep the markup the server rendered for it; it is gone. */\n UnrenderedBlockLost: 'LP0413',\n\n /** A message was rejected before it reached the update pipeline. */\n MessageRejected: 'LP0501',\n /** A preview token was rejected. */\n TokenRejected: 'LP0502',\n /** A trusted origin sent a message this protocol version does not recognise. */\n ProtocolShapeUnknown: 'LP0503',\n\n /** A consumer event handler threw. */\n HandlerThrew: 'LP0601',\n /** A consumer transform threw; the original value was kept. */\n TransformThrew: 'LP0602',\n /** A renderer threw while writing a value. */\n RendererThrew: 'LP0603',\n // LP0604 is reserved and unassigned; codes are never reused or renumbered.\n /** Runtime startup failed. */\n StartupFailed: 'LP0605',\n /** Sending the ready handshake failed. */\n ReadyFailed: 'LP0606',\n /** The page declared hydration, but no React commit, Vue mount, SvelteKit mount or `markHydrated()` call came within the cap; the runtime started without waiting. */\n HydrationWaitTimedOut: 'LP0607',\n\n /** The audit found no runtime in a response that carried preview intent. */\n AuditRuntimeMissing: 'LP0701',\n /** The preview response declares no `frame-ancestors`. */\n AuditNoFrameAncestors: 'LP0702',\n /** `X-Frame-Options` forbids framing on a response that declares no `frame-ancestors`; `SAMEORIGIN` forbids it from another origin only. */\n AuditFrameOptionsBlocks: 'LP0703',\n /** Binding attributes are served to anonymous visitors. */\n AuditBindingsExposed: 'LP0704',\n /** More bindings than the visibility gate will write eagerly. */\n AuditGateThresholdExceeded: 'LP0705',\n /** Owner markers exist, but some bindings are outside all of them. */\n AuditUnownedBindings: 'LP0706',\n /** The preview response carries no bindings and no fragment boundary. */\n AuditNoBindings: 'LP0707',\n /** The URL did not return an HTML page, so nothing else can be judged. */\n AuditNotAPage: 'LP0708',\n /** A fragment request failed (network, timeout, server error); the boundary was patched instead. */\n FragmentRequestFailed: 'LP0801',\n /** The fragment response had the wrong content type or shape; the boundary was patched instead. */\n FragmentResponseInvalid: 'LP0802',\n /** The fragment endpoint refused the preview (not authorized); the boundary was patched instead. */\n FragmentUnauthorized: 'LP0803',\n /** A fragment response arrived for a revision that was already superseded and was discarded. */\n FragmentSuperseded: 'LP0804',\n /** A route refresh was refused: the loop guard, or the strategy's minimum interval. */\n RouteRefreshLoop: 'LP0805',\n /** A boundary asks for the fragment strategy but no fragment handler is configured; it is patched. */\n FragmentStrategyUnavailable: 'LP0806',\n /** A revision changed a field with no binding; `onUnfaithfulPatch` refreshed the route. */\n UnboundChangeRefresh: 'LP0807',\n /** `onUnfaithfulPatch: 'escalate'` found no route or fragment strategy, or no boundary, to hand an unfaithful patch to; the page keeps it. */\n EscalationUnavailable: 'LP0808',\n /** A fragment inserted an Astro island the page cannot start: it never loaded the island element or that client directive. */\n IslandStartUnavailable: 'LP0809',\n /** The host's route refresh returned no promise, so the revision was re-applied before the host committed. */\n RouteRefreshUnconfirmed: 'LP0810',\n /** A readiness row is not yet at its 2.0 value; `pll doctor --v2` reports it. */\n V2ReadinessGap: 'LP0709',\n /** The preview runtime is served to anonymous visitors, not only inside the admin frame. */\n RuntimeOnPublicPage: 'LP0710',\n /** An element carries attributes that only mean something beside `data-payload-field`, and has none. */\n AuditModifierWithoutField: 'LP0711',\n} as const);\n\n/** A diagnostic code, as it appears in log output and on the `error` event. */\nexport type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];\n","/**\n * Per-instance plugin manager. Mutations run through one call-order queue;\n * while a queue-held hook is pending, a requested mutation takes the direct\n * path because that hook may be awaiting it. See ADR 0005.\n */\n\nimport type { FieldRenderer } from '@core/types';\nimport type { PluginInspection } from '@core/inspection/types';\nimport { LIBRARY_PROTOCOL_VERSION } from '@core/protocol-version';\nimport { VERSION } from '@/version';\nimport { incompatibilityOf } from './compat';\nimport { isolateDiagnostic } from '@core/diagnostics';\nimport { observeThenableResult } from '@core/thenable';\nimport type { EventEmitter } from '@events/emitter';\nimport { ResourceScope } from './resource-scope';\nimport { ScopedPluginEvents } from './scoped-events';\nimport type { FieldTransform, LivePreviewPlugin, PluginContext } from './types';\n\nexport interface PluginManagerOptions {\n readonly events: EventEmitter;\n readonly config: Readonly<Record<string, unknown>>;\n /** Add one renderer layer to the host; may return the layer's disposer. */\n readonly registerFieldRenderer: (renderer: FieldRenderer) => void;\n /** Receives transform contract failures for the runtime's `error` event. */\n readonly onTransformError?: (error: Error) => unknown;\n readonly log: (...args: unknown[]) => void;\n}\n\ninterface PluginRegistration {\n readonly plugin: LivePreviewPlugin;\n readonly scope: ResourceScope;\n}\n\ninterface InitializingPluginRegistration {\n readonly scope: ResourceScope;\n cancelled: boolean;\n}\n\ninterface TransformRegistration {\n readonly transform: FieldTransform;\n active: boolean;\n}\n\nfunction isPluginDisposer(value: unknown): value is (() => void) | undefined {\n return typeof value === 'function';\n}\n\nexport class PluginManager {\n readonly #events: EventEmitter;\n readonly #config: Readonly<Record<string, unknown>>;\n // The public callback type is void; the client host returns its layer disposer through it.\n readonly #registerRenderer: (renderer: FieldRenderer) => unknown;\n readonly #onTransformError: ((error: Error) => void) | undefined;\n readonly #log: (...args: unknown[]) => void;\n readonly #plugins = new Map<string, PluginRegistration>();\n readonly #initializing = new Map<string, InitializingPluginRegistration>();\n readonly #teardowns = new Map<string, Promise<void>>();\n readonly #destroying = new Set<string>();\n readonly #transforms = new Map<string, TransformRegistration[]>();\n #mutationQueue: Promise<void> = Promise.resolve();\n // Hooks awaited by the queue entry in flight. Hooks started on the direct\n // path never hold the queue, so they must not open it for others.\n #queuedHooks = 0;\n\n constructor(options: PluginManagerOptions) {\n this.#events = options.events;\n this.#config = options.config;\n this.#registerRenderer = options.registerFieldRenderer;\n this.#log = isolateDiagnostic(options.log);\n const onTransformError = options.onTransformError;\n this.#onTransformError =\n onTransformError === undefined\n ? undefined\n : isolateDiagnostic((...args: unknown[]): unknown => {\n // Private and single-callered: `applyTransforms` normalizes to an\n // Error before it reports one.\n const error = args[0] as Error;\n try {\n return onTransformError(error);\n } catch (reportError) {\n this.#log('transform error reporter failed:', reportError);\n return undefined;\n }\n });\n }\n\n /** Register a plugin transactionally; concurrent mutations run in call order. */\n register(plugin: LivePreviewPlugin): Promise<void> {\n if (this.#queuedHooks > 0) return this.#registerNow(plugin, false);\n return this.#enqueue(() => this.#registerNow(plugin, true));\n }\n\n /** Remove one plugin and every resource its registration created. */\n unregister(name: string): Promise<void> {\n if (this.#queuedHooks > 0) return this.#unregisterNow(name, false);\n return this.#enqueue(async () => {\n await this.#unregisterNow(name, true);\n });\n }\n\n /** Destroy every registration; one failure never strands another. */\n destroyAll(): Promise<void> {\n if (this.#queuedHooks > 0) return this.#destroyAllNow(false);\n return this.#enqueue(async () => {\n await this.#destroyAllNow(true);\n });\n }\n\n /** Apply active transforms in registration order; a failure returns the original value. */\n applyTransforms(\n fieldName: string,\n value: unknown,\n context: { readonly element: Element; readonly allFields: Record<string, unknown> },\n isCurrent?: () => boolean,\n ): unknown {\n const registrations = this.#transforms.get(fieldName);\n if (registrations === undefined || registrations.length === 0) return value;\n\n let result: unknown = value;\n for (const registration of [...registrations]) {\n if (!registration.active) continue;\n const { transform } = registration;\n if (isCurrent?.() === false) return value;\n try {\n result = transform(result, {\n fieldName,\n element: context.element,\n allFields: context.allFields,\n });\n const returnedThenable = observeThenableResult(result);\n // A transform may synchronously let a newer message in; then its\n // result belongs to a superseded revision and is not reported.\n if (isCurrent?.() === false) return value;\n if (returnedThenable) {\n throw new TypeError(\n `Transform for \"${fieldName}\" returned a Promise/thenable; transforms must be synchronous`,\n );\n }\n } catch (error) {\n if (isCurrent?.() === false) return value;\n const normalized = error instanceof Error ? error : new Error(String(error));\n this.#log(`transform for \"${fieldName}\" failed:`, normalized);\n this.#onTransformError?.(normalized);\n return value;\n }\n }\n return result;\n }\n\n list(): readonly string[] {\n return [...this.#plugins.keys()];\n }\n\n /** Every plugin with its state and live registrations (`inspect().plugins`). */\n snapshot(): readonly PluginInspection[] {\n const entries: PluginInspection[] = [];\n const describe = (\n name: string,\n version: string | undefined,\n state: PluginInspection['state'],\n scope: ResourceScope,\n ): PluginInspection => {\n const counts = scope.counts();\n return {\n name,\n version,\n state,\n registrations: {\n transforms: counts.transform,\n renderers: counts.renderer,\n subscriptions: counts.subscription,\n cleanups: counts.cleanup,\n },\n };\n };\n for (const [name, initializing] of this.#initializing) {\n entries.push(describe(name, undefined, 'initializing', initializing.scope));\n }\n for (const [name, registration] of this.#plugins) {\n entries.push(describe(name, registration.plugin.version, 'active', registration.scope));\n }\n // A name with a pending teardown left `#plugins` before the teardown began.\n for (const name of this.#teardowns.keys()) {\n entries.push({\n name,\n version: undefined,\n state: 'tearing-down',\n registrations: { transforms: 0, renderers: 0, subscriptions: 0, cleanups: 0 },\n });\n }\n return entries;\n }\n\n get size(): number {\n return this.#plugins.size;\n }\n\n async #registerNow(plugin: LivePreviewPlugin, queued: boolean): Promise<void> {\n if (\n this.#plugins.has(plugin.name) ||\n this.#initializing.has(plugin.name) ||\n this.#teardowns.has(plugin.name)\n ) {\n this.#log(`plugin \"${plugin.name}\" already registered`);\n return;\n }\n\n const incompatibility = incompatibilityOf(plugin.compat, VERSION, LIBRARY_PROTOCOL_VERSION);\n if (incompatibility !== undefined) {\n this.#refuse(plugin.name, incompatibility);\n return;\n }\n const scope = new ResourceScope(plugin.name, this.#log);\n const context = this.#createContext(plugin.name, scope);\n const initializing: InitializingPluginRegistration = { scope, cancelled: false };\n this.#initializing.set(plugin.name, initializing);\n try {\n await this.#runHook(() => plugin.init(context), queued);\n if (initializing.cancelled) return;\n scope.commit();\n } catch (error) {\n scope.close();\n if (!initializing.cancelled) this.#log(`plugin \"${plugin.name}\" init failed:`, error);\n return;\n } finally {\n if (this.#initializing.get(plugin.name) === initializing) {\n this.#initializing.delete(plugin.name);\n }\n }\n\n this.#plugins.set(plugin.name, { plugin, scope });\n this.#log(`plugin \"${plugin.name}\" registered`);\n }\n\n /** A refused plugin is an integration mistake; it reaches the `error` event, not only the log. */\n #refuse(name: string, reason: string): void {\n const message = `plugin \"${name}\" refused: ${reason}`;\n this.#log(message);\n void this.#events.emit('error', {\n error: new Error(message),\n context: 'plugin',\n code: 'LP0103',\n });\n }\n\n #createContext(pluginName: string, scope: ResourceScope): PluginContext {\n return {\n events: new ScopedPluginEvents(this.#events, scope),\n registerFieldRenderer: (renderer) => {\n scope.stage('renderer', () => {\n const result = this.#registerRenderer(renderer);\n return isPluginDisposer(result) ? result : undefined;\n });\n },\n registerTransform: (fieldName, transform) => {\n const registration: TransformRegistration = { transform, active: false };\n scope.stage('transform', () => {\n registration.active = true;\n const existing = this.#transforms.get(fieldName);\n if (existing === undefined) this.#transforms.set(fieldName, [registration]);\n else existing.push(registration);\n\n return () => {\n registration.active = false;\n const current = this.#transforms.get(fieldName);\n if (current === undefined) return;\n const index = current.indexOf(registration);\n if (index >= 0) current.splice(index, 1);\n if (current.length === 0) this.#transforms.delete(fieldName);\n };\n });\n },\n registerCleanup: (cleanup) => {\n scope.own(cleanup);\n },\n getConfig: () => this.#config,\n log: (...args) => {\n this.#log(`[${pluginName}]`, ...args);\n },\n };\n }\n\n #unregisterNow(name: string, queued: boolean): Promise<void> {\n const initializing = this.#initializing.get(name);\n if (initializing !== undefined) {\n initializing.cancelled = true;\n initializing.scope.close();\n return Promise.resolve();\n }\n\n const existingTeardown = this.#teardowns.get(name);\n if (existingTeardown !== undefined) {\n // A destroy hook removing its own name cannot await the teardown that\n // awaits it; its resources are already revoked, so this is complete.\n if (this.#destroying.has(name)) return Promise.resolve();\n return queued ? this.#holdQueue(existingTeardown) : existingTeardown;\n }\n const registration = this.#plugins.get(name);\n if (registration === undefined) return Promise.resolve();\n\n // Revoke before consumer code runs: a throwing destroy keeps no access,\n // and a same-name registration from inside destroy stays a duplicate.\n this.#plugins.delete(name);\n registration.scope.close();\n const teardown = Promise.resolve().then(() =>\n this.#destroyPlugin(name, registration.plugin, queued),\n );\n this.#teardowns.set(name, teardown);\n void teardown.then(() => {\n if (this.#teardowns.get(name) === teardown) this.#teardowns.delete(name);\n });\n return teardown;\n }\n\n async #destroyPlugin(name: string, plugin: LivePreviewPlugin, queued: boolean): Promise<void> {\n if (plugin.destroy === undefined) return;\n this.#destroying.add(name);\n try {\n await this.#runHook(() => plugin.destroy?.(), queued);\n } catch (error) {\n this.#log(`plugin \"${name}\" destroy failed:`, error);\n } finally {\n this.#destroying.delete(name);\n }\n }\n\n async #destroyAllNow(queued: boolean): Promise<void> {\n for (const initializing of this.#initializing.values()) {\n initializing.cancelled = true;\n initializing.scope.close();\n }\n const names = [...this.#plugins.keys()];\n for (const name of names) await this.#unregisterNow(name, queued);\n }\n\n async #runHook(hook: () => void | Promise<void>, queued: boolean): Promise<void> {\n if (!queued) {\n await hook();\n return;\n }\n await this.#holdQueue(Promise.resolve().then(hook));\n }\n\n async #holdQueue(pending: Promise<void>): Promise<void> {\n this.#queuedHooks += 1;\n try {\n await pending;\n } finally {\n this.#queuedHooks -= 1;\n }\n }\n\n #enqueue(operation: () => void | Promise<void>): Promise<void> {\n const result = this.#mutationQueue.then(operation);\n // Keep the tail usable after an escaped error; the caller still sees it on `result`.\n this.#mutationQueue = result.catch((error: unknown) => {\n this.#log('plugin manager mutation failed:', error);\n });\n return result;\n }\n}\n","/**\n * Plugin compatibility claims. The range grammar is the subset a plugin\n * author writes (`*`, `1.2.3`, `^`, `~`, `>=`, `>`, `<`, `<=`, space-joined\n * conjunctions, `||` alternatives); prerelease tags are ignored.\n */\n\nexport interface PluginCompatibility {\n /** A semver range the runtime's `VERSION` must satisfy, e.g. `>=2.0.0`. */\n readonly runtime?: string;\n /** The highest postMessage protocol version the plugin understands. */\n readonly protocol?: number;\n}\n\ntype Version = readonly [number, number, number];\n\nfunction parseVersion(text: string): Version | undefined {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(text.trim());\n if (match === null) return undefined;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n}\n\nfunction compare(a: Version, b: Version): number {\n for (let index = 0; index < 3; index += 1) {\n const delta = (a[index] ?? 0) - (b[index] ?? 0);\n if (delta !== 0) return delta;\n }\n return 0;\n}\n\nfunction satisfiesComparator(version: Version, comparator: string): boolean {\n const trimmed = comparator.trim();\n if (trimmed === '' || trimmed === '*') return true;\n const match = /^(\\^|~|>=|<=|>|<|=)?\\s*v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(trimmed);\n if (match === null) return false;\n const operator = match[1] ?? '=';\n const target: Version = [Number(match[2]), Number(match[3]), Number(match[4])];\n const order = compare(version, target);\n switch (operator) {\n case '=':\n return order === 0;\n case '>':\n return order > 0;\n case '>=':\n return order >= 0;\n case '<':\n return order < 0;\n case '<=':\n return order <= 0;\n case '~':\n return order >= 0 && version[0] === target[0] && version[1] === target[1];\n case '^':\n if (order < 0) return false;\n if (target[0] > 0) return version[0] === target[0];\n if (target[1] > 0) return version[0] === 0 && version[1] === target[1];\n return version[0] === 0 && version[1] === 0 && version[2] === target[2];\n default:\n return false;\n }\n}\n\n/** Whether `version` satisfies `range`; anything unparsable never satisfies. */\nexport function satisfiesRange(version: string, range: string): boolean {\n const parsed = parseVersion(version);\n if (parsed === undefined) return false;\n const alternatives = range.split('||');\n return alternatives.some((alternative) => {\n const comparators = alternative\n .trim()\n .split(/\\s+/)\n .filter((part) => part.length > 0);\n if (comparators.length === 0) return alternative.trim() === '' && range.trim() === '';\n return comparators.every((comparator) => satisfiesComparator(parsed, comparator));\n });\n}\n\n/** Why a plugin was refused, or `undefined` when it fits. */\nexport function incompatibilityOf(\n compat: PluginCompatibility | undefined,\n runtimeVersion: string,\n protocolVersion: number,\n): string | undefined {\n if (compat === undefined) return undefined;\n if (compat.runtime !== undefined && !satisfiesRange(runtimeVersion, compat.runtime)) {\n return `declares runtime ${compat.runtime}, this runtime is ${runtimeVersion}`;\n }\n if (compat.protocol !== undefined) {\n if (!Number.isInteger(compat.protocol) || compat.protocol < 1) {\n return `declares an invalid protocol version ${String(compat.protocol)}`;\n }\n if (compat.protocol < protocolVersion) {\n return `declares protocol ${String(compat.protocol)}, this runtime speaks ${String(protocolVersion)}`;\n }\n }\n return undefined;\n}\n","/**\n * Protocol negotiation. A capability is granted either by the version a peer\n * announces or by observation, since the stock Payload admin announces none:\n * what it can do is read off the messages it sends. See ADR 0010.\n */\n\n/** Bumped only when this library's understanding of the wire format changes. @internal */\nexport const LIBRARY_PROTOCOL_VERSION = 4;\n\n/** How a capability becomes active. @internal */\nexport type CapabilitySource = 'version' | 'observed';\n\n/** @internal */\nexport interface CapabilityDeclaration {\n /** Enabled once the negotiated version reaches this (for announced peers). */\n readonly since: number;\n /** The wire signal that grants this capability to a peer announcing no version. */\n readonly observed?:\n 'schema' | 'locale' | 'preview-token' | 'document-event' | 'relationship-event';\n}\n\n/** What activates each capability; the prose lives in `CAPABILITY_DOCUMENTATION`. */\nexport const CAPABILITY_DECLARATIONS = {\n basic: { since: 1 },\n 'schema-json': { since: 2, observed: 'schema' },\n locale: { since: 2, observed: 'locale' },\n 'preview-token': { since: 3, observed: 'preview-token' },\n 'nested-arrays': { since: 4 },\n 'recursive-diffs': { since: 4 },\n 'document-events': { since: 4, observed: 'document-event' },\n 'relationship-events': { since: 4, observed: 'relationship-event' },\n} as const satisfies Record<string, CapabilityDeclaration>;\n\nexport type ProtocolCapability = keyof typeof CAPABILITY_DECLARATIONS;\n\n/** Every declared capability, in declaration order. @internal */\nexport const PROTOCOL_CAPABILITIES = Object.keys(\n CAPABILITY_DECLARATIONS,\n) as readonly ProtocolCapability[];\n\nexport interface ProtocolNegotiation {\n /** This library's protocol version. */\n readonly ours: number;\n /** The remote party's version, when it announced one. */\n readonly theirs: number | undefined;\n /** `min(ours, theirs ?? 1)` — the version both sides actually share. */\n readonly negotiated: number;\n /** Capabilities active at the negotiated version or seen on the wire. */\n readonly capabilities: ReadonlySet<ProtocolCapability>;\n /** The subset that was observed on the wire rather than granted by version. */\n readonly observed: ReadonlySet<ProtocolCapability>;\n}\n\n/** Deterministic; the runtime re-runs it whenever either input changes. */\nexport function negotiateProtocol(\n theirs: number | undefined,\n observed: Iterable<ProtocolCapability> = [],\n): ProtocolNegotiation {\n const sanitisedTheirs =\n typeof theirs === 'number' && Number.isFinite(theirs) && theirs >= 1\n ? Math.floor(theirs)\n : undefined;\n const effectiveTheirs = sanitisedTheirs ?? 1;\n const negotiated = Math.min(LIBRARY_PROTOCOL_VERSION, effectiveTheirs);\n const seen = new Set<ProtocolCapability>(observed);\n const capabilities = new Set<ProtocolCapability>();\n for (const capability of PROTOCOL_CAPABILITIES) {\n if (negotiated >= CAPABILITY_DECLARATIONS[capability].since || seen.has(capability)) {\n capabilities.add(capability);\n }\n }\n return {\n ours: LIBRARY_PROTOCOL_VERSION,\n ...(sanitisedTheirs !== undefined ? { theirs: sanitisedTheirs } : { theirs: undefined }),\n negotiated,\n capabilities,\n observed: seen,\n };\n}\n\n/** @internal */\nexport function hasCapability(\n negotiation: ProtocolNegotiation,\n capability: ProtocolCapability,\n): boolean {\n return negotiation.capabilities.has(capability);\n}\n\n/** What a project on Payload 2 hears in development, from the runtime and from a hook. @internal */\nexport const PAYLOAD_2_HINT =\n '[payload-live-preview] This admin sends fieldSchemaJSON, which only Payload 2 does. ' +\n 'Every 2.x release of this package supports Payload 2; 3.0 supports Payload 3 and 4.';\n\n/** The capabilities a single message demonstrates, by its shape alone. */\nexport function observeCapabilities(message: {\n readonly fieldSchemaJSON?: unknown;\n readonly locale?: unknown;\n readonly previewToken?: unknown;\n readonly externallyUpdatedRelationship?: unknown;\n}): readonly ProtocolCapability[] {\n const seen: ProtocolCapability[] = [];\n if (Array.isArray(message.fieldSchemaJSON)) seen.push('schema-json');\n if (typeof message.locale === 'string') seen.push('locale');\n if (typeof message.previewToken === 'string') seen.push('preview-token');\n if (\n typeof message.externallyUpdatedRelationship === 'object' &&\n message.externallyUpdatedRelationship !== null\n ) {\n seen.push('relationship-events');\n }\n return seen;\n}\n","{\n \"name\": \"payload-live-preview\",\n \"version\": \"2.3.2\",\n \"description\": \"Live preview for Payload CMS on server-rendered and static frontends (Astro, Next.js, SvelteKit, Nuxt, plain HTML), with React and Vue hooks for client-rendered apps.\",\n \"author\": \"relative23\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"packageManager\": \"npm@12.0.2\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.cts\",\n \"default\": \"./dist/index.cjs\"\n }\n },\n \"./core\": {\n \"import\": {\n \"types\": \"./dist/core.d.ts\",\n \"default\": \"./dist/core.js\"\n },\n \"require\": {\n \"types\": \"./dist/core.d.cts\",\n \"default\": \"./dist/core.cjs\"\n }\n },\n \"./astro\": {\n \"import\": {\n \"types\": \"./dist/adapters/astro/index.d.ts\",\n \"default\": \"./dist/adapters/astro/index.js\"\n }\n },\n \"./nextjs\": {\n \"import\": {\n \"types\": \"./dist/adapters/nextjs/index.d.ts\",\n \"default\": \"./dist/adapters/nextjs/index.js\"\n },\n \"default\": {\n \"types\": \"./dist/adapters/nextjs/index.d.ts\",\n \"default\": \"./dist/adapters/nextjs/index.js\"\n }\n },\n \"./sveltekit\": {\n \"import\": {\n \"types\": \"./dist/adapters/sveltekit/index.d.ts\",\n \"default\": \"./dist/adapters/sveltekit/index.js\"\n }\n },\n \"./nuxt\": {\n \"import\": {\n \"types\": \"./dist/adapters/nuxt/index.d.ts\",\n \"default\": \"./dist/adapters/nuxt/index.js\"\n }\n },\n \"./nuxt-module\": {\n \"import\": {\n \"types\": \"./dist/adapters/nuxt/module.d.ts\",\n \"default\": \"./dist/adapters/nuxt/module.js\"\n }\n },\n \"./react\": {\n \"import\": {\n \"types\": \"./dist/adapters/react/index.d.ts\",\n \"default\": \"./dist/adapters/react/index.js\"\n }\n },\n \"./vue\": {\n \"import\": {\n \"types\": \"./dist/adapters/vue/index.d.ts\",\n \"default\": \"./dist/adapters/vue/index.js\"\n }\n },\n \"./codegen\": {\n \"import\": {\n \"types\": \"./dist/codegen.d.ts\",\n \"default\": \"./dist/codegen.js\"\n },\n \"require\": {\n \"types\": \"./dist/codegen.d.cts\",\n \"default\": \"./dist/codegen.cjs\"\n }\n },\n \"./codegen/astro\": {\n \"import\": {\n \"types\": \"./dist/codegen-astro.d.ts\",\n \"default\": \"./dist/codegen-astro.js\"\n }\n },\n \"./annotate\": {\n \"import\": {\n \"types\": \"./dist/annotate.d.ts\",\n \"default\": \"./dist/annotate.js\"\n }\n },\n \"./doctor\": {\n \"import\": {\n \"types\": \"./dist/doctor.d.ts\",\n \"default\": \"./dist/doctor.js\"\n }\n },\n \"./migrate\": {\n \"import\": {\n \"types\": \"./dist/migrate.d.ts\",\n \"default\": \"./dist/migrate.js\"\n }\n },\n \"./payload\": {\n \"import\": {\n \"types\": \"./dist/payload.d.ts\",\n \"default\": \"./dist/payload.js\"\n },\n \"require\": {\n \"types\": \"./dist/payload.d.cts\",\n \"default\": \"./dist/payload.cjs\"\n }\n },\n \"./plugin\": {\n \"import\": {\n \"types\": \"./dist/plugin.d.ts\",\n \"default\": \"./dist/plugin.js\"\n },\n \"require\": {\n \"types\": \"./dist/plugin.d.cts\",\n \"default\": \"./dist/plugin.cjs\"\n }\n },\n \"./server\": {\n \"import\": {\n \"types\": \"./dist/server.d.ts\",\n \"default\": \"./dist/server.js\"\n },\n \"require\": {\n \"types\": \"./dist/server.d.cts\",\n \"default\": \"./dist/server.cjs\"\n }\n },\n \"./client\": {\n \"import\": {\n \"types\": \"./dist/client.d.ts\",\n \"default\": \"./dist/client.js\"\n },\n \"require\": {\n \"types\": \"./dist/client.d.cts\",\n \"default\": \"./dist/client.cjs\"\n }\n },\n \"./structural\": {\n \"import\": {\n \"types\": \"./dist/structural.d.ts\",\n \"default\": \"./dist/structural.js\"\n },\n \"require\": {\n \"types\": \"./dist/structural.d.cts\",\n \"default\": \"./dist/structural.cjs\"\n }\n },\n \"./lexical\": {\n \"import\": {\n \"types\": \"./dist/lexical.d.ts\",\n \"default\": \"./dist/lexical.js\"\n },\n \"require\": {\n \"types\": \"./dist/lexical.d.cts\",\n \"default\": \"./dist/lexical.cjs\"\n }\n },\n \"./plugins\": {\n \"import\": {\n \"types\": \"./dist/plugins.d.ts\",\n \"default\": \"./dist/plugins.js\"\n },\n \"require\": {\n \"types\": \"./dist/plugins.d.cts\",\n \"default\": \"./dist/plugins.cjs\"\n }\n },\n \"./lean\": {\n \"import\": {\n \"types\": \"./dist/lean.d.ts\",\n \"default\": \"./dist/lean.js\"\n },\n \"require\": {\n \"types\": \"./dist/lean.d.cts\",\n \"default\": \"./dist/lean.cjs\"\n }\n },\n \"./fragment\": {\n \"import\": {\n \"types\": \"./dist/fragment.d.ts\",\n \"default\": \"./dist/fragment.js\"\n },\n \"require\": {\n \"types\": \"./dist/fragment.d.cts\",\n \"default\": \"./dist/fragment.cjs\"\n }\n },\n \"./astro/RichText.astro\": \"./dist/adapters/astro/RichText.astro\",\n \"./astro/PreviewBoundary.astro\": \"./dist/adapters/astro/PreviewBoundary.astro\",\n \"./astro/middleware-entry\": {\n \"import\": {\n \"types\": \"./dist/adapters/astro/middleware-entry.d.ts\",\n \"default\": \"./dist/adapters/astro/middleware-entry.js\"\n }\n },\n \"./package.json\": \"./package.json\"\n },\n \"bin\": {\n \"pll-codegen\": \"./dist/codegen-cli.js\",\n \"pll\": \"./dist/doctor-cli.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"sideEffects\": false,\n \"scripts\": {\n \"build:runtime\": \"node -e \\\"const c=require('node:child_process'),e={...process.env};if(!e.SOURCE_DATE_EPOCH){const g=c.spawnSync('git',['show','-s','--format=%ct','HEAD'],{encoding:'utf8'});if(g.status===0)e.SOURCE_DATE_EPOCH=g.stdout.trim()}process.exit(c.spawnSync(process.execPath,['--import','tsx',process.argv[1]],{stdio:'inherit',env:e}).status??1)\\\" scripts/build-runtime.ts\",\n \"build\": \"npm run build:runtime && tsx scripts/build-dist.ts && npm run build:assets && npm run test:bundle && npm run test:treeshake && npm run test:edge && npm run test:interaction && npm run test:protocol-semantics\",\n \"build:assets\": \"node -e \\\"const fs=require('node:fs');for(const f of ['RichText','PreviewBoundary','FragmentBridge'])fs.copyFileSync('src/adapters/astro/'+f+'.astro','dist/adapters/astro/'+f+'.astro')\\\"\",\n \"dev\": \"tsup --watch\",\n \"pretest\": \"npm run build:runtime\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:security-corpus\": \"vitest run tests/unit/security/sanitizer-corpus.test.ts tests/unit/property/sanitizer-fuzz.property.test.ts\",\n \"test:unit\": \"vitest run tests/unit\",\n \"test:integration\": \"vitest run tests/integration\",\n \"test:e2e\": \"playwright test\",\n \"test:e2e:next-base-path\": \"playwright test --config playwright.next-base-path.config.ts\",\n \"test:e2e:next-production\": \"playwright test --config playwright.next-production.config.ts\",\n \"test:e2e:next-webpack-production\": \"playwright test --config playwright.next-webpack-production.config.ts\",\n \"test:e2e:next-continuation\": \"playwright test --config playwright.next-continuation.config.ts\",\n \"test:e2e:sveltekit-continuation\": \"playwright test --config playwright.sveltekit-continuation.config.ts\",\n \"test:e2e:nuxt-continuation\": \"playwright test --config playwright.nuxt-continuation.config.ts\",\n \"test:e2e:astro-continuation\": \"playwright test --config playwright.astro-continuation.config.ts\",\n \"test:e2e:astro-resources\": \"playwright test --config playwright.astro-resources.config.ts\",\n \"test:e2e:html-continuation\": \"playwright test --config playwright.html-continuation.config.ts\",\n \"test:e2e:vue-continuation\": \"playwright test --config playwright.vue-continuation.config.ts\",\n \"test:e2e:react-continuation\": \"playwright test --config playwright.react-continuation.config.ts\",\n \"test:e2e:nuxt-production\": \"playwright test --config playwright.nuxt-production.config.ts\",\n \"test:e2e:sveltekit-production\": \"playwright test --config playwright.sveltekit-production.config.ts\",\n \"check:fixtures\": \"tsx scripts/check-fixture-freshness.ts\",\n \"check:generated\": \"tsx scripts/check-generated-runtime.ts\",\n \"test:e2e:real-payload\": \"playwright test --config playwright.real-payload.config.ts\",\n \"test:acl:real-payload\": \"tsx scripts/check-payload-acl.ts\",\n \"test:a11y\": \"playwright test tests/e2e/specs/accessibility.spec.ts\",\n \"test:soak\": \"playwright test --config playwright.soak.config.ts\",\n \"test:browser-bench\": \"playwright test --config playwright.bench.config.ts\",\n \"test:bench\": \"vitest bench tests/benchmarks\",\n \"test:bench:codspeed\": \"vitest bench --run --config vitest.bench.config.ts\",\n \"test:bundle\": \"tsx scripts/check-bundle-size.ts\",\n \"test:interaction\": \"tsx scripts/check-interaction-budgets.ts\",\n \"test:protocol-semantics\": \"tsx scripts/check-protocol-semantics.ts\",\n \"test:upstream-findings\": \"tsx scripts/check-upstream-findings.ts\",\n \"test:treeshake\": \"tsx scripts/check-tree-shaking.ts\",\n \"test:edge\": \"NODE_OPTIONS='--experimental-vm-modules --no-warnings' tsx scripts/check-edge-runtime.ts\",\n \"compat:check\": \"tsx scripts/compat-table.ts --check\",\n \"compat:write\": \"tsx scripts/compat-table.ts --write\",\n \"compat:refresh\": \"tsx scripts/compat-table.ts --refresh\",\n \"compat:record\": \"tsx scripts/record-compat-results.ts && prettier --write quality/compat-matrix.json && tsx scripts/compat-table.ts --write && prettier --write README.md\",\n \"diagnostics:check\": \"tsx scripts/diagnostic-table.ts --check\",\n \"test:package\": \"tsx scripts/check-package.ts\",\n \"audit:gate\": \"tsx scripts/audit-gate.ts\",\n \"test:smoke\": \"tsx scripts/post-publish-smoke.ts\",\n \"test:coverage\": \"vitest run --coverage\",\n \"test:coverage:diff\": \"tsx scripts/coverage-policy.ts\",\n \"test:policy\": \"tsx scripts/test-policy.ts\",\n \"test:architecture\": \"tsx scripts/architecture-policy.ts && tsx scripts/check-complexity.ts && tsx scripts/check-trusted-core.ts && tsx scripts/compare-scope.ts --check && tsx scripts/workflow-contracts.ts && tsx scripts/docs-contracts.ts && tsx scripts/check-resource-inventory.ts && knip --no-progress --treat-config-hints-as-errors\",\n \"test:property\": \"vitest run tests/unit/property\",\n \"test:mutation\": \"stryker run stryker.config.js\",\n \"test:mutation:policy:pr\": \"tsx scripts/mutation-policy.ts --policy quality/mutation-policy-pr.json --report test-results/stryker-pr.json\",\n \"test:mutation:policy:core\": \"tsx scripts/mutation-policy.ts --policy quality/mutation-policy-core.json --report test-results/stryker-core.json\",\n \"test:mutation:policy\": \"tsx scripts/mutation-policy.ts\",\n \"test:leak\": \"node --expose-gc --import tsx scripts/leak-soak.ts\",\n \"test:leak:quick\": \"node --expose-gc --import tsx scripts/leak-soak.ts --quick\",\n \"api:update\": \"npm run build && tsx scripts/check-package.ts --update-api-reports\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"tests/**/*.ts\\\" \\\"scripts/**/*.ts\\\" \\\"*.{js,cjs,mjs,ts,json,jsonc,yml,yaml,md}\\\" \\\"quality/**/*.json\\\" \\\"docs/**/*.md\\\" \\\"type-tests/**/*.md\\\" \\\".prettierrc.json\\\" \\\".changeset/*.{json,md}\\\" \\\".github/**/*.{yml,yaml,json}\\\" \\\"examples/**/*.{ts,tsx,js,cjs,mjs,json}\\\" && prettier --write \\\"type-tests/packed/*.fixture\\\" --parser typescript\",\n \"format:check\": \"prettier --check \\\"src/**/*.ts\\\" \\\"tests/**/*.ts\\\" \\\"scripts/**/*.ts\\\" \\\"*.{js,cjs,mjs,ts,json,jsonc,yml,yaml,md}\\\" \\\"quality/**/*.json\\\" \\\"docs/**/*.md\\\" \\\"type-tests/**/*.md\\\" \\\".prettierrc.json\\\" \\\".changeset/*.{json,md}\\\" \\\".github/**/*.{yml,yaml,json}\\\" \\\"examples/**/*.{ts,tsx,js,cjs,mjs,json}\\\" && prettier --check \\\"type-tests/packed/*.fixture\\\" --parser typescript\",\n \"check\": \"npm run typecheck && npm run lint && npm run format:check && npm run test:policy && npm run test:architecture && npm run compat:check && npm run diagnostics:check && npm run test\",\n \"prepublishOnly\": \"npm run build && npm run check && npm run format:check && npm run test:package\",\n \"changeset\": \"changeset\",\n \"version\": \"changeset version && tsx scripts/sync-lockfile-metadata.ts && npm run build:runtime\",\n \"version:release\": \"npm run version && npm run compat:record\",\n \"release\": \"tsx scripts/publish-artifact.ts\",\n \"test:docs\": \"tsx scripts/docs-contracts.ts\"\n },\n \"devDependencies\": {\n \"@arethetypeswrong/cli\": \"^0.18.5\",\n \"@axe-core/playwright\": \"^4.13.0\",\n \"@changesets/cli\": \"^2.31.1\",\n \"@codspeed/vitest-plugin\": \"^5.7.1\",\n \"@eslint/js\": \"^10.0.1\",\n \"@fast-check/vitest\": \"^0.4.1\",\n \"@microsoft/api-extractor\": \"^7.58.12\",\n \"@payloadcms/live-preview\": \"^3.88.0\",\n \"@playwright/test\": \"^1.62.1\",\n \"@stryker-mutator/core\": \"^9.6.1\",\n \"@stryker-mutator/vitest-runner\": \"^9.6.1\",\n \"@testing-library/react\": \"^16.3.3\",\n \"@types/jsdom\": \"^30.0.0\",\n \"@types/node\": \"^22.20.1\",\n \"@types/react\": \"^19.2.18\",\n \"@types/react-dom\": \"^19.2.7\",\n \"@vitest/coverage-v8\": \"^4.1.12\",\n \"dompurify\": \"^3.4.15\",\n \"esbuild\": \"^0.28.2\",\n \"eslint\": \"^10.8.1\",\n \"fast-check\": \"^4.9.0\",\n \"globals\": \"^17.11.0\",\n \"jsdom\": \"^29.1.1\",\n \"knip\": \"^6.32.2\",\n \"linkedom\": \"^0.18.14\",\n \"prettier\": \"^3.9.6\",\n \"publint\": \"^0.3.23\",\n \"react\": \"^19.3.1\",\n \"react-dom\": \"^19.3.1\",\n \"svelte\": \"^5.57.3\",\n \"terser\": \"^5.46.1\",\n \"ts-morph\": \"^28.0.0\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.23.12\",\n \"typescript\": \"^5.9.3\",\n \"typescript-eslint\": \"^8.67.0\",\n \"vite\": \"^7.3.6\",\n \"vitest\": \"^4.1.12\",\n \"vue\": \"^3.5.44\",\n \"yaml\": \"^2.9.0\"\n },\n \"overrides\": {\n \"qs\": \"6.16.1\",\n \"tsup\": {\n \"esbuild\": \"0.28.2\"\n }\n },\n \"allowScripts\": {\n \"esbuild@0.28.2\": true,\n \"fsevents@2.3.2\": false,\n \"fsevents@2.3.3\": false\n },\n \"keywords\": [\n \"astro\",\n \"astro-payload\",\n \"astro-cms\",\n \"astro-integration\",\n \"astro-live-preview\",\n \"payload\",\n \"payload-cms\",\n \"payload-plugin\",\n \"payload-live-preview\",\n \"live-preview\",\n \"preview\",\n \"cms\",\n \"headless\",\n \"headless-cms\",\n \"lexical\",\n \"sveltekit\",\n \"nuxt\",\n \"nextjs\",\n \"react\",\n \"vue\",\n \"ssr\",\n \"framework-agnostic\"\n ],\n \"peerDependencies\": {\n \"astro\": \">=4.0.0 <8.0.0\",\n \"payload\": \"^2.0.0 || ^3.0.0 || ^4.0.0-0\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\",\n \"svelte\": \">=5\",\n \"ts-morph\": \"^28.0.0\",\n \"vite\": \">=5.4.0 <9.0.0\",\n \"vue\": \">=3.3\"\n },\n \"peerDependenciesMeta\": {\n \"astro\": {\n \"optional\": true\n },\n \"payload\": {\n \"optional\": true\n },\n \"react\": {\n \"optional\": true\n },\n \"react-dom\": {\n \"optional\": true\n },\n \"svelte\": {\n \"optional\": true\n },\n \"ts-morph\": {\n \"optional\": true\n },\n \"vue\": {\n \"optional\": true\n },\n \"vite\": {\n \"optional\": true\n }\n },\n \"engines\": {\n \"node\": \">=20.19.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"provenance\": true\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/relative23/payload-live-preview.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/relative23/payload-live-preview/issues\"\n },\n \"homepage\": \"https://github.com/relative23/payload-live-preview#readme\"\n}\n","/** `analytics` plugin: running totals over the update stream, read through `getStats()`. */\n\nimport type { LivePreviewPlugin } from '../types';\n\nexport interface AnalyticsSnapshot {\n readonly updateCount: number;\n readonly totalElements: number;\n readonly totalDurationMs: number;\n readonly averageDurationMs: number;\n}\n\nexport function createAnalyticsPlugin(): LivePreviewPlugin & {\n readonly getStats: () => AnalyticsSnapshot;\n} {\n let updateCount = 0;\n let totalElements = 0;\n let totalDurationMs = 0;\n\n return {\n name: 'analytics',\n version: '1.0.0',\n init: (ctx) => {\n ctx.events.on('afterUpdate', (e) => {\n updateCount += 1;\n totalElements += e.updatedCount;\n totalDurationMs += e.durationMs;\n });\n },\n getStats: (): AnalyticsSnapshot => ({\n updateCount,\n totalElements,\n totalDurationMs,\n averageDurationMs: updateCount === 0 ? 0 : totalDurationMs / updateCount,\n }),\n };\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"plugins.cjs","names":["observeThenableResult","value","then","Promise","resolve","catch","isolateDiagnostic","diagnostic","args","safeConsoleError","console","error","noopDisposer","ResourceScope","pluginName","log","resources","Set","state","constructor","this","assertOpen","Error","active","eligible","own","cleanup","track","kind","acquire","finalize","disposed","stage","resource","dispose","activate","counts","transform","renderer","subscription","commit","close","reverse","clear","add","delete","ScopedPluginEvents","events","scope","subscriptions","on","event","handler","subscribe","once","off","untypedHandler","emit","payload","emitWhile","shouldContinue","callerEligible","listenerCount","count","removeAllListeners","eventNames","names","existing","find","subscriptionActive","wrapped","async","STYLE_ID","styleLeases","WeakMap","highlightLeases","highlightPlugin","name","version","init","ctx","document","window","prefersReducedMotion","matchMedia","matches","releaseStyle","lease","get","connected","css","getElementById","HTMLStyleElement","pluginOwned","isConnected","remove","owners","sheet","Array","isArray","adoptedStyleSheets","CSSStyleSheet","replaceSync","adoptSheet","includes","filter","s","style","createElement","id","textContent","head","appendChild","installStyle","set","acquiredLease","acquireStyle","duration","activeTimers","timerCleanups","registerCleanup","e","element","releaseHighlight","pluginAdded","classList","contains","acquireHighlight","disposeTimer","clearTimeout","handle","setTimeout","debugPlugin","origin","reason","elementCount","fieldCount","Object","keys","data","fields","length","updatedCount","durationMs","toFixed","context","message","SCROLL_KEY","reloadPreservingScroll","sessionStorage","setItem","JSON","stringify","href","location","x","scrollX","y","scrollY","saveScrollPosition","reload","parseDependencyList","seen","raw","split","trim","has","push","ISLAND_ATTRIBUTE","isIslandBoundary","tagName","toLowerCase","hasAttribute","isIslandRoot","getAttribute","isInsideIsland","current","parentElement","FIELD_ATTRIBUTE","DEPENDS_ATTRIBUTE","GUESSED_ATTRIBUTE","COVERS_ATTRIBUTE","renderingStrategy","explicit","closest","valueIdentity","is","String","json","isContainer","shapeOf","child","key","populates","samePopulation","before","after","every","hasOwn","sameValue","identity","previous","uncoveredChangedPaths","field","next","coverage","uncovered","visits","visit","path","depth","covers","reachesBelow","childKeys","SYSTEM_FIELD_NAMES","stripLocaleSuffix","locale","suffix","endsWith","slice","namePathCoverage","boundNames","coverPaths","anyBelow","candidates","prefix","candidate","startsWith","some","cover","ELEMENT_ID","POSITIONS","unboundFieldNames","subfieldCoverage","bound","addressable","reaches","fieldName","base","createNameAddressability","found","entries","root","uncoveredNamePaths","sort","left","right","localeCompare","selectInstead","doc","text","setAttribute","cssText","body","append","select","copyButton","label","button","type","title","addEventListener","clipboard","defaultView","navigator","writeText","copy","DIAGNOSTIC_CODES","freeze","NoTrustedOrigin","ReferrerOnlyTrust","PluginIncompatible","ProfileFeatureOmitted","OrphanField","UnattributableUpdate","UnboundField","CoverageDefaultChanges","VisibilityGateDeferred","UnsafeAttributeWrite","TextTargetHasChildren","MissingArrayTemplate","StructuralItemUnkeyed","StructuralDuplicateKey","StructuralUnstableKeys","UnsupportedStrategy","UnknownValueFormat","SanitizerDroppedAttribute","UnrenderedBlockKept","UnfaithfulPatch","ServerFormatReplaced","UnrenderedBlockLost","MessageRejected","TokenRejected","ProtocolShapeUnknown","HandlerThrew","TransformThrew","RendererThrew","StartupFailed","ReadyFailed","HydrationWaitTimedOut","AuditRuntimeMissing","AuditNoFrameAncestors","AuditFrameOptionsBlocks","AuditBindingsExposed","AuditGateThresholdExceeded","AuditUnownedBindings","AuditNoBindings","AuditNotAPage","FragmentRequestFailed","FragmentResponseInvalid","FragmentUnauthorized","FragmentSuperseded","RouteRefreshLoop","FragmentStrategyUnavailable","UnboundChangeRefresh","EscalationUnavailable","IslandStartUnavailable","RouteRefreshUnconfirmed","V2ReadinessGap","RuntimeOnPublicPage","AuditModifierWithoutField","regular","Map","register","emitSequential","invoke","size","snapshot","bucket","err","config","registerRenderer","onTransformError","plugins","initializing","teardowns","destroying","transforms","mutationQueue","queuedHooks","options","registerFieldRenderer","reportError","plugin","registerNow","enqueue","unregister","unregisterNow","destroyAll","destroyAllNow","applyTransforms","isCurrent","registrations","result","registration","allFields","returnedThenable","TypeError","normalized","list","describe","renderers","cleanups","queued","incompatibility","compat","runtimeVersion","runtime","range","parsed","match","exec","Number","parseVersion","alternative","comparators","part","comparator","trimmed","operator","target","order","a","b","index","delta","compare","satisfiesComparator","satisfiesRange","protocol","isInteger","incompatibilityOf","refuse","createContext","cancelled","runHook","code","registerTransform","indexOf","splice","getConfig","existingTeardown","holdQueue","teardown","destroyPlugin","destroy","values","hook","pending","operation","updateCount","totalElements","totalDurationMs","getStats","averageDurationMs","onlyWithDebug","overlay","position","nodeType","ownerDocument","hostDocument","panel","hidden","heading","unboundTitle","guessedTitle","guessedList","update","guessed","replaceChildren","map","matched","mountOverlay","mode","rendering","querySelectorAll","boundNamesIn","paths","strategy","coverPathsIn","guessedBindingsIn","join","g","controllers","controller","abort","getItem","removeItem","saved","parse","scrollTo","restoreScrollPosition","AbortController","signal","aborted","runFetch","isActive","fetch","url","revalidateUrl","ok","response","method","headers","revalidateHeaders","source","status","onRevalidateFailure","runRevalidate","finally"],"sources":["../src/core/thenable.ts","../src/core/diagnostics.ts","../src/plugins/resource-scope.ts","../src/plugins/scoped-events.ts","../src/plugins/built-in/highlight.ts","../src/plugins/built-in/debug.ts","../src/plugins/built-in/document-save.ts","../src/core/dependencies.ts","../src/core/islands.ts","../src/core/strategies.ts","../src/core/cache.ts","../src/core/value-identity.ts","../src/core/subfield-coverage.ts","../src/core/unbound-fields.ts","../src/plugins/built-in/unbound-fields-overlay.ts","../src/events/emitter.ts","../src/core/diagnostic-codes.ts","../src/plugins/manager.ts","../src/plugins/compat.ts","../src/core/protocol-version.ts","../package.json","../src/plugins/built-in/analytics.ts"],"sourcesContent":["/**\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","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 * Registration-local resource scope: every listener, transform, renderer\n * layer and cleanup a plugin registers is staged here until `init` commits\n * and released together, in reverse order, when the plugin goes. See ADR 0005.\n */\n\nimport { observeThenableResult } from '@core/thenable';\nimport type { PluginDisposer } from './types';\n\nexport type ResourceKind = 'transform' | 'renderer' | 'subscription' | 'cleanup';\n\ninterface ScopedResource {\n readonly kind: ResourceKind;\n readonly acquire: (() => PluginDisposer | undefined) | undefined;\n readonly finalize: (() => void) | undefined;\n cleanup: PluginDisposer | undefined;\n disposed: boolean;\n}\n\nexport const noopDisposer: PluginDisposer = () => undefined;\n\nexport class ResourceScope {\n readonly #pluginName: string;\n readonly #log: (...args: unknown[]) => void;\n // Insertion order gives commit/reverse-teardown order; short-lived entries\n // (once listeners) leave immediately instead of accumulating until removal.\n readonly #resources = new Set<ScopedResource>();\n #state: 'staging' | 'committing' | 'active' | 'closed' = 'staging';\n\n constructor(pluginName: string, log: (...args: unknown[]) => void) {\n this.#pluginName = pluginName;\n this.#log = log;\n }\n\n assertOpen(): void {\n if (this.#state === 'closed') {\n throw new Error(`Plugin context for \"${this.#pluginName}\" is no longer active`);\n }\n }\n\n get active(): boolean {\n return this.#state === 'active';\n }\n\n /** Whether a retained context still belongs to this registration. */\n eligible(): boolean {\n return this.#state !== 'closed';\n }\n\n /** Own a resource the plugin itself already acquired. */\n own(cleanup: PluginDisposer): PluginDisposer {\n this.assertOpen();\n return this.#track({\n kind: 'cleanup',\n acquire: undefined,\n finalize: undefined,\n cleanup,\n disposed: false,\n });\n }\n\n /** Stage a manager-owned resource; an active scope acquires it at once. */\n stage(\n kind: ResourceKind,\n acquire: () => PluginDisposer | undefined,\n finalize?: () => void,\n ): PluginDisposer {\n this.assertOpen();\n const resource: ScopedResource = {\n kind,\n acquire,\n finalize,\n cleanup: undefined,\n disposed: false,\n };\n const dispose = this.#track(resource);\n if (this.#state === 'active') {\n try {\n this.#activate(resource);\n } catch (error) {\n this.#dispose(resource);\n throw error;\n }\n }\n return dispose;\n }\n\n /** Live resources by kind, what `inspect().plugins` reports. */\n counts(): Record<ResourceKind, number> {\n const counts: Record<ResourceKind, number> = {\n transform: 0,\n renderer: 0,\n subscription: 0,\n cleanup: 0,\n };\n for (const resource of this.#resources) counts[resource.kind] += 1;\n return counts;\n }\n\n /** Publish every staged resource at once after `init` succeeded. */\n commit(): void {\n if (this.#state !== 'staging') {\n throw new Error(`Plugin context for \"${this.#pluginName}\" cannot be committed`);\n }\n this.#state = 'committing';\n try {\n for (const resource of this.#resources) this.#activate(resource);\n this.#state = 'active';\n } catch (error) {\n this.close();\n throw error;\n }\n }\n\n close(): void {\n if (this.#state === 'closed') return;\n this.#state = 'closed';\n for (const resource of [...this.#resources].reverse()) this.#dispose(resource);\n this.#resources.clear();\n }\n\n #track(resource: ScopedResource): PluginDisposer {\n this.#resources.add(resource);\n return (): void => {\n this.#dispose(resource);\n };\n }\n\n #activate(resource: ScopedResource): void {\n if (resource.disposed || resource.cleanup !== undefined || resource.acquire === undefined) {\n return;\n }\n const cleanup = resource.acquire();\n resource.cleanup = cleanup ?? noopDisposer;\n }\n\n #dispose(resource: ScopedResource): void {\n if (resource.disposed) return;\n resource.disposed = true;\n this.#resources.delete(resource);\n const cleanup = resource.cleanup;\n resource.cleanup = undefined;\n if (cleanup !== undefined) {\n try {\n // A `void` cleanup may still return a thenable; observe it without awaiting.\n const cleanupWithResult: () => unknown = cleanup;\n if (observeThenableResult(cleanupWithResult())) {\n this.#log(\n `plugin \"${this.#pluginName}\" cleanup returned a Promise/thenable; cleanups must be synchronous`,\n );\n }\n } catch (error) {\n this.#log(`plugin \"${this.#pluginName}\" cleanup failed:`, error);\n }\n }\n try {\n resource.finalize?.();\n } catch (error) {\n this.#log(`plugin \"${this.#pluginName}\" cleanup failed:`, error);\n }\n }\n}\n","/**\n * Event facade handed to a plugin: subscriptions are owned by the plugin's\n * scope, emits go to the client's emitter. It implements the emitter surface\n * without extending it, so no unused base emitter is allocated per plugin.\n */\n\nimport type { EventEmitter } from '@events/emitter';\nimport type { EventHandler, LivePreviewEventMap, Unsubscribe } from '@events/types';\nimport { noopDisposer, type ResourceScope } from './resource-scope';\nimport type { PluginEvents } from './types';\n\ninterface OwnedSubscription {\n readonly kind: 'on' | 'once';\n readonly event: keyof LivePreviewEventMap;\n readonly handler: EventHandler<unknown>;\n dispose: Unsubscribe;\n}\n\nexport class ScopedPluginEvents implements PluginEvents {\n readonly #events: EventEmitter;\n readonly #scope: ResourceScope;\n readonly #subscriptions = new Set<OwnedSubscription>();\n\n constructor(events: EventEmitter, scope: ResourceScope) {\n this.#events = events;\n this.#scope = scope;\n }\n\n on<E extends keyof LivePreviewEventMap>(\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): Unsubscribe {\n return this.#subscribe('on', event, handler);\n }\n\n once<E extends keyof LivePreviewEventMap>(\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): Unsubscribe {\n return this.#subscribe('once', event, handler);\n }\n\n off<E extends keyof LivePreviewEventMap>(\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): void {\n const untypedHandler = handler as EventHandler<unknown>;\n for (const subscription of [...this.#subscriptions]) {\n if (subscription.event === event && subscription.handler === untypedHandler) {\n subscription.dispose();\n }\n }\n }\n\n emit<E extends keyof LivePreviewEventMap>(\n event: E,\n payload: LivePreviewEventMap[E],\n ): Promise<void> {\n this.#scope.assertOpen();\n return this.#events.emit(event, payload);\n }\n\n emitWhile<E extends keyof LivePreviewEventMap>(\n event: E,\n payload: LivePreviewEventMap[E],\n shouldContinue: () => boolean,\n ): Promise<boolean> {\n this.#scope.assertOpen();\n return this.#events.emitWhile(event, payload, () => {\n if (!this.#scope.eligible()) return false;\n const callerEligible = shouldContinue();\n // The predicate is plugin code and may close this scope re-entrantly.\n if (!this.#scope.eligible()) return false;\n return callerEligible;\n });\n }\n\n listenerCount(event: keyof LivePreviewEventMap): number {\n let count = 0;\n for (const subscription of this.#subscriptions) {\n if (subscription.event === event) count += 1;\n }\n return count;\n }\n\n removeAllListeners(event?: keyof LivePreviewEventMap): void {\n for (const subscription of [...this.#subscriptions]) {\n if (event === undefined || subscription.event === event) subscription.dispose();\n }\n }\n\n eventNames(): (keyof LivePreviewEventMap)[] {\n const names = new Set<keyof LivePreviewEventMap>();\n for (const subscription of this.#subscriptions) names.add(subscription.event);\n return [...names];\n }\n\n #subscribe<E extends keyof LivePreviewEventMap>(\n kind: 'on' | 'once',\n event: E,\n handler: EventHandler<LivePreviewEventMap[E]>,\n ): Unsubscribe {\n this.#scope.assertOpen();\n\n const untypedHandler = handler as EventHandler<unknown>;\n const existing = [...this.#subscriptions].find(\n (subscription) =>\n subscription.kind === kind &&\n subscription.event === event &&\n subscription.handler === untypedHandler,\n );\n if (existing !== undefined) return existing.dispose;\n\n // A distinct wrapper per scope: two plugins passing the same handler\n // reference must be revocable independently in the Set-based emitter.\n let dispose = noopDisposer;\n let subscriptionActive = true;\n const wrapped: EventHandler<LivePreviewEventMap[E]> = async (payload) => {\n if (!this.#scope.active || !subscriptionActive) return;\n // Mirror the base emitter, which drops a once bucket before dispatch.\n if (kind === 'once') dispose();\n await handler(payload);\n };\n const subscription: OwnedSubscription = {\n kind,\n event,\n handler: untypedHandler,\n dispose: noopDisposer,\n };\n dispose = this.#scope.stage(\n 'subscription',\n () => this.#events[kind](event, wrapped),\n () => {\n subscriptionActive = false;\n this.#subscriptions.delete(subscription);\n },\n );\n subscription.dispose = dispose;\n this.#subscriptions.add(subscription);\n return dispose;\n }\n}\n","/**\n * `highlight` plugin: flashes an outline on updated elements. Respects\n * `prefers-reduced-motion`; the stylesheet is shared per document across\n * clients through a lease (ADR 0002).\n */\n\nimport type { LivePreviewPlugin, PluginDisposer } from '../types';\n\nconst STYLE_ID = 'payload-live-preview-highlight';\nconst REDUCED_MOTION_CSS =\n '.lp-highlight{outline:2px solid rgba(0,102,204,0.85);outline-offset:2px;}';\nconst ANIMATED_CSS =\n '@keyframes lp-highlight{0%{outline:2px solid rgba(0,102,204,0.85);outline-offset:2px}100%{outline:2px solid transparent;outline-offset:2px}}.lp-highlight{animation:lp-highlight 0.6s ease-out;}';\n\ninterface StyleLease {\n readonly pluginOwned: boolean;\n readonly connected: () => boolean;\n readonly remove: () => void;\n owners: number;\n}\n\ninterface HighlightLease {\n owners: number;\n readonly pluginAdded: boolean;\n}\n\nconst styleLeases = new WeakMap<Document, StyleLease>();\nconst highlightLeases = new WeakMap<Element, HighlightLease>();\n\nexport const highlightPlugin: LivePreviewPlugin = {\n name: 'highlight',\n version: '1.0.0',\n init: (ctx) => {\n if (typeof document === 'undefined' || typeof window === 'undefined') return;\n const prefersReducedMotion =\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n const releaseStyle = acquireStyle(document, prefersReducedMotion);\n const duration = prefersReducedMotion ? 1000 : 600;\n const activeTimers = new WeakMap<Element, PluginDisposer>();\n // Only armed timers are retained; one registration-owned cleanup drains them.\n const timerCleanups = new Set<PluginDisposer>();\n ctx.registerCleanup?.(() => {\n for (const cleanup of [...timerCleanups]) cleanup();\n releaseStyle();\n });\n ctx.events.on('elementUpdate', (e) => {\n const element = e.element;\n activeTimers.get(element)?.();\n const releaseHighlight = acquireHighlight(element);\n let disposed = false;\n const disposeTimer: PluginDisposer = () => {\n if (disposed) return;\n disposed = true;\n window.clearTimeout(handle);\n if (activeTimers.get(element) === disposeTimer) activeTimers.delete(element);\n timerCleanups.delete(disposeTimer);\n releaseHighlight();\n };\n const handle = window.setTimeout(disposeTimer, duration);\n timerCleanups.add(disposeTimer);\n activeTimers.set(element, disposeTimer);\n });\n },\n};\n\nfunction acquireStyle(document: Document, prefersReducedMotion: boolean): PluginDisposer {\n let lease = styleLeases.get(document);\n // HMR or a host DOM swap may drop the sheet without plugin teardown.\n if (lease !== undefined && !lease.connected()) {\n styleLeases.delete(document);\n lease = undefined;\n }\n if (lease === undefined) {\n lease = installStyle(document, prefersReducedMotion ? REDUCED_MOTION_CSS : ANIMATED_CSS);\n styleLeases.set(document, lease);\n }\n const acquiredLease = lease;\n acquiredLease.owners += 1;\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n acquiredLease.owners -= 1;\n if (acquiredLease.owners > 0) return;\n if (styleLeases.get(document) === acquiredLease) styleLeases.delete(document);\n if (acquiredLease.pluginOwned) acquiredLease.remove();\n };\n}\n\nfunction installStyle(document: Document, css: string): StyleLease {\n const existing = document.getElementById(STYLE_ID);\n if (existing instanceof HTMLStyleElement) {\n return {\n pluginOwned: false,\n connected: () => existing.isConnected,\n remove: () => undefined,\n owners: 0,\n };\n }\n const sheet = adoptSheet(document, css);\n if (sheet !== undefined) {\n return {\n pluginOwned: true,\n connected: () => document.adoptedStyleSheets.includes(sheet),\n remove: () => {\n document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s) => s !== sheet);\n },\n owners: 0,\n };\n }\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = css;\n document.head.appendChild(style);\n return {\n pluginOwned: true,\n connected: () => style.isConnected,\n remove: () => {\n style.remove();\n },\n owners: 0,\n };\n}\n\n// A constructed sheet needs no nonce under `style-src`; `<style>` is only the fallback.\nfunction adoptSheet(document: Document, css: string): CSSStyleSheet | undefined {\n try {\n if (!Array.isArray(document.adoptedStyleSheets) || typeof CSSStyleSheet !== 'function') {\n return undefined;\n }\n const sheet = new CSSStyleSheet();\n if (typeof sheet.replaceSync !== 'function') return undefined;\n sheet.replaceSync(css);\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];\n return sheet;\n } catch {\n return undefined;\n }\n}\n\nfunction acquireHighlight(element: Element): PluginDisposer {\n let lease = highlightLeases.get(element);\n if (lease === undefined) {\n lease = { owners: 0, pluginAdded: !element.classList.contains('lp-highlight') };\n highlightLeases.set(element, lease);\n }\n const acquiredLease = lease;\n acquiredLease.owners += 1;\n element.classList.add('lp-highlight');\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n acquiredLease.owners -= 1;\n if (acquiredLease.owners > 0) return;\n highlightLeases.delete(element);\n if (acquiredLease.pluginAdded) element.classList.remove('lp-highlight');\n };\n}\n","/** `debug` plugin: logs init, connect, disconnect, cacheRefresh, beforeUpdate, afterUpdate and error through the plugin context. */\n\nimport type { LivePreviewPlugin } from '../types';\n\nexport const debugPlugin: LivePreviewPlugin = {\n name: 'debug',\n version: '1.0.0',\n init: (ctx) => {\n ctx.events.on('init', () => {\n ctx.log('init');\n });\n ctx.events.on('connect', (e) => {\n ctx.log('connect ←', e.origin);\n });\n ctx.events.on('disconnect', (e) => {\n ctx.log('disconnect (', e.reason, ')');\n });\n ctx.events.on('cacheRefresh', (e) => {\n ctx.log('cacheRefresh', e.elementCount, 'elements,', e.fieldCount, 'fields');\n });\n ctx.events.on('beforeUpdate', (e) => {\n ctx.log('beforeUpdate', Object.keys(e.data.fields).length, 'fields');\n });\n ctx.events.on('afterUpdate', (e) => {\n ctx.log('afterUpdate', e.updatedCount, 'in', e.durationMs.toFixed(2), 'ms');\n });\n ctx.events.on('error', (e) => {\n ctx.log('error in', e.context, ':', e.error.message);\n });\n },\n};\n","/**\n * `documentSave` plugin: what to do when Payload saves the document.\n * `'silent'` (default) emits only; `'reload'` reloads and restores the scroll\n * position; `'revalidate'` POSTs to a revalidation endpoint; `'fetch'` runs\n * a custom handler.\n */\n\nimport type { LivePreviewPlugin } from '../types';\n\nconst SCROLL_KEY = 'payload-live-preview:scroll';\n\nfunction saveScrollPosition(): void {\n if (typeof window === 'undefined') return;\n try {\n sessionStorage.setItem(\n SCROLL_KEY,\n JSON.stringify({ href: window.location.href, x: window.scrollX, y: window.scrollY }),\n );\n } catch {\n // sessionStorage is unavailable in a sandboxed iframe without allow-same-origin.\n }\n}\n\nfunction restoreScrollPosition(): void {\n if (typeof window === 'undefined') return;\n try {\n const raw = sessionStorage.getItem(SCROLL_KEY);\n if (raw === null) return;\n sessionStorage.removeItem(SCROLL_KEY);\n const saved = JSON.parse(raw) as { href?: string; x?: number; y?: number };\n if (saved.href !== window.location.href) return;\n window.scrollTo(saved.x ?? 0, saved.y ?? 0);\n } catch {\n // A corrupt entry or unavailable storage: nothing to restore.\n }\n}\n\nfunction reloadPreservingScroll(): void {\n if (typeof window === 'undefined') return;\n saveScrollPosition();\n window.location.reload();\n}\n\nexport type DocumentSaveStrategy = 'silent' | 'reload' | 'revalidate' | 'fetch';\n\n/** Handler for the `fetch` strategy; the signal aborts when the plugin is removed. */\nexport type DocumentSaveHandler = {\n bivarianceHack(signal?: AbortSignal): void | Promise<void>;\n}['bivarianceHack'];\n\nexport interface DocumentSavePluginOptions {\n /** Default `'silent'`. */\n readonly strategy?: DocumentSaveStrategy;\n /**\n * `'revalidate'` endpoint, default `/api/revalidate`; the body is\n * `{ source: 'payload-live-preview' }`. The request is a plain `fetch` from\n * the preview page: cookies travel with it, there is no CSRF token, and a\n * bearer secret in `revalidateHeaders` would sit in page JavaScript. The\n * endpoint must authorise on its own (session cookie, same-origin check).\n */\n readonly revalidateUrl?: string;\n /** Extra request headers for `'revalidate'`; `Content-Type` is set already. */\n readonly revalidateHeaders?: Readonly<Record<string, string>>;\n /** `'fetch'` handler; rejections are logged, never thrown. */\n readonly handler?: DocumentSaveHandler;\n /** `'reload'` hard-refreshes when the revalidate request fails or returns non-2xx. */\n readonly onRevalidateFailure?: 'silent' | 'reload';\n}\n\nconst DEFAULT_REVALIDATE_URL = '/api/revalidate';\n\nexport function documentSavePlugin(options: DocumentSavePluginOptions = {}): LivePreviewPlugin {\n const strategy = options.strategy ?? 'silent';\n return {\n name: 'document-save',\n version: '1.1.0',\n init: (ctx) => {\n let active = true;\n const controllers = new Set<AbortController>();\n ctx.registerCleanup?.(() => {\n active = false;\n for (const controller of controllers) controller.abort();\n controllers.clear();\n });\n restoreScrollPosition();\n ctx.events.on('documentSave', () => {\n if (!active) return;\n if (strategy === 'silent') return;\n if (strategy === 'reload') {\n reloadPreservingScroll();\n return;\n }\n const controller = new AbortController();\n controllers.add(controller);\n const operation =\n strategy === 'fetch'\n ? runFetch(options, ctx.log, controller.signal, () => active)\n : runRevalidate(options, ctx.log, controller.signal, () => active);\n void operation.finally(() => {\n controllers.delete(controller);\n });\n });\n },\n };\n}\n\nasync function runFetch(\n options: DocumentSavePluginOptions,\n log: (...args: unknown[]) => void,\n signal: AbortSignal,\n isActive: () => boolean,\n): Promise<void> {\n if (!options.handler) {\n log('document-save: fetch strategy selected but no handler supplied');\n return;\n }\n try {\n await options.handler(signal);\n } catch (err) {\n if (!isActive() || signal.aborted) return;\n log('document-save handler threw:', err);\n }\n}\n\nasync function runRevalidate(\n options: DocumentSavePluginOptions,\n log: (...args: unknown[]) => void,\n signal: AbortSignal,\n isActive: () => boolean,\n): Promise<void> {\n if (typeof fetch === 'undefined') {\n log('document-save: revalidate strategy needs fetch — not available');\n return;\n }\n const url = options.revalidateUrl ?? DEFAULT_REVALIDATE_URL;\n let ok = false;\n try {\n const response = await fetch(url, {\n method: 'POST',\n signal,\n headers: {\n 'Content-Type': 'application/json',\n ...(options.revalidateHeaders ?? {}),\n },\n body: JSON.stringify({ source: 'payload-live-preview' }),\n });\n if (!isActive() || signal.aborted) return;\n ok = response.ok;\n if (!ok) log('document-save revalidate non-2xx:', response.status);\n } catch (err) {\n if (!isActive() || signal.aborted) return;\n log('document-save revalidate failed:', err);\n }\n if (!ok && options.onRevalidateFailure === 'reload') {\n reloadPreservingScroll();\n }\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","/**\n * Hydrated islands own their subtree, so the runtime never patches inside one.\n * Instead every flush that carried a change dispatches `payload-live-preview:update`\n * on each island root with the update in `detail`, whether or not a binding\n * outside the islands was written. `data-payload-island=\"patch\"` opts back in.\n * Server HTML reaches an Astro island only through Astro's own props handoff\n * (ADR 0021). @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/** The opt-out for a subtree the site scripts itself: the morph never enters it. @internal */\nexport const OWNED_ATTRIBUTE = 'data-payload-owned';\n/**\n * The opt-in for a custom element: present on the live and on the rendered host\n * (its value is ignored), the morph edits the host's attributes and light DOM\n * instead of retaining it whole (ADR 0008 §10). @internal\n */\nexport const MORPH_ATTRIBUTE = 'data-payload-morph';\n\n/**\n * The ownership rule (ADR 0008 §4): a subtree the morph never enters. Custom\n * elements own their subtree unless the template opts in with\n * `data-payload-morph` (§10), islands are a framework's, `contenteditable`\n * is the visitor's, `data-payload-owned` is the site's. The coordinators hand\n * this rule to the engine as `MorphOptions.boundary`; the engine itself only\n * pairs, edits and keeps focus (§9). @beta\n */\nexport function isMorphBoundary(element: Element): boolean {\n const customElement = element.tagName.toLowerCase().includes('-');\n if (customElement && !element.hasAttribute(MORPH_ATTRIBUTE)) return true;\n if (isIslandBoundary(element) || element.hasAttribute(OWNED_ATTRIBUTE)) return true;\n const editable = element.getAttribute('contenteditable');\n return editable !== null && editable !== 'false';\n}\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 * Call once the island has rendered this revision, for instance from an\n * effect after its framework committed. Until every island handed the\n * revision has called it, `inspect().revisions.display` says `unconfirmed`\n * (ADR 0023). Repeated, late or superseded calls do nothing.\n */\n readonly displayed: () => void;\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\n/** Astro keeps `ssr` until the framework listener has finished hydrating. @internal */\nexport function isAwaitingIslandHydration(island: Element): boolean {\n return island.tagName.toLowerCase() === 'astro-island' && island.hasAttribute('ssr');\n}\n\nexport function dispatchIslandUpdate(\n islands: readonly Element[],\n detail: IslandUpdateDetail,\n isCurrent: () => boolean,\n): number {\n let dispatched = 0;\n for (const island of islands) {\n if (!isCurrent()) break;\n island.dispatchEvent(\n new CustomEvent<IslandUpdateDetail>(ISLAND_EVENT, { detail, bubbles: false }),\n );\n dispatched += 1;\n if (!isCurrent()) break;\n }\n return dispatched;\n}\n\n/** What decides whether a live `astro-island` still renders the rendered one's component (ADR 0021). */\nconst ISLAND_IDENTITY = [\n 'component-url',\n 'component-export',\n 'renderer-url',\n 'client',\n 'opts',\n 'before-hydration-url',\n] as const;\n/** Slot markup each island was last rendered with; Astro reads slots once, at hydration. */\nconst renderedSlots = new WeakMap<Element, string>();\nconst unmountedIslands = new WeakSet<Element>();\n\nfunction isAstroIsland(element: Element): boolean {\n return element.tagName.toLowerCase() === 'astro-island';\n}\n\nfunction slotMarkup(island: Element): string {\n let markup = '';\n for (const slot of island.querySelectorAll('astro-slot, template[data-astro-template]')) {\n if (slot.parentElement?.closest('astro-island') !== island) continue;\n const name = slot.getAttribute('name') ?? slot.getAttribute('data-astro-template') ?? '';\n markup += `${name}\\u0000${slot.innerHTML}\\u0000`;\n }\n return markup;\n}\n\n/** Only an upgraded island whose class observes `props` re-hydrates in place. */\nfunction observesProps(island: Element): boolean {\n const constructor = island.ownerDocument.defaultView?.customElements.get('astro-island') as\n (CustomElementConstructor & { readonly observedAttributes?: unknown }) | undefined;\n return (\n constructor !== undefined &&\n island instanceof constructor &&\n Array.isArray(constructor.observedAttributes) &&\n constructor.observedAttributes.includes('props')\n );\n}\n\n/**\n * The package's decision for a boundary pair (ADR 0021). A boundary other than\n * an Astro island stays whole (ADR 0008 §4). An island that still renders the\n * same component, with the same slots, keeps its framework state: it takes the\n * rendered props the way Astro's router hands them to a persisted island,\n * `ssr` first, then `props`. Anything else is replaced, and hydrates fresh.\n * @beta\n */\nexport function retainIslandBoundary(live: Element, rendered: Element): boolean {\n if (!isAstroIsland(live) || !isAstroIsland(rendered)) return true;\n const slots = slotMarkup(rendered);\n const retained =\n ISLAND_IDENTITY.every((name) => live.getAttribute(name) === rendered.getAttribute(name)) &&\n (renderedSlots.get(live) ?? slotMarkup(live)) === slots &&\n (live.getAttribute('props') === rendered.getAttribute('props') || observesProps(live));\n if (!retained) {\n renderedSlots.set(rendered, slots);\n return false;\n }\n renderedSlots.set(live, slots);\n const props = rendered.getAttribute('props');\n if (props !== live.getAttribute('props')) {\n live.setAttribute('ssr', '');\n if (props === null) live.removeAttribute('props');\n else live.setAttribute('props', props);\n }\n return true;\n}\n\n/** The Astro islands under `root`, to compare before and after a morph. @internal */\nexport function astroIslandsIn(root: ParentNode): Element[] {\n return Array.from(root.querySelectorAll('astro-island'));\n}\n\n/**\n * Astro's framework clients release their roots on `astro:unmount`, which its\n * router sends after a swap. A morph that disconnects an island sends it once\n * itself, so a removed React root does not outlive its markup. @internal\n */\nexport function releaseDisconnectedIslands(islands: readonly Element[]): void {\n for (const island of islands) {\n if (island.isConnected || unmountedIslands.has(island)) continue;\n unmountedIslands.add(island);\n island.dispatchEvent(new CustomEvent('astro:unmount'));\n }\n}\n\n/**\n * Why an inserted island cannot start: fragment scripts never run, so the page\n * itself must have loaded Astro's island element and this client directive.\n * @internal\n */\nexport function islandStartBlocker(island: Element): 'element' | 'directive' | undefined {\n const view = island.ownerDocument.defaultView;\n if (view?.customElements.get('astro-island') === undefined) return 'element';\n const directive = island.getAttribute('client');\n const astro: unknown = Reflect.get(view, 'Astro');\n if (directive === null || typeof astro !== 'object' || astro === null) return 'directive';\n return Reflect.get(astro, directive) === undefined ? 'directive' : undefined;\n}\n","/**\n * How a bound region is brought up to date: the runtime patches it, a server\n * renders a `data-payload-fragment` boundary from the unsaved form state, or\n * the whole route refreshes. Core carries only the seam — which boundaries a\n * strategy owns and what it may do — so a patch-only page pays for nothing\n * more; the orchestration lives in `payload-live-preview/fragment`.\n */\nimport type { DiagnosticCode } from './diagnostic-codes';\nimport type { CachedElement } from './types';\nimport type { OwnerScope } from './unbound-fields';\n\n/** What produced an update: the runtime's DOM patching, a server-rendered fragment, or a route refresh. */\nexport type UpdateSource = 'patch' | 'fragment' | 'route';\n\n/** Marks a server-rendered boundary; the value is the registry id the server may render. @internal */\nexport const FRAGMENT_ATTRIBUTE = 'data-payload-fragment';\n/** Distinguishes several boundaries of one registry id; unique among siblings. @internal */\nexport const FRAGMENT_KEY_ATTRIBUTE = 'data-payload-fragment-key';\n\n/** The nearest fragment boundary enclosing `element` (the element itself included). */\nexport function enclosingFragment(element: Element): Element | null {\n return element.closest(`[${FRAGMENT_ATTRIBUTE}]`);\n}\n\n/**\n * Where a render planned for `planned` lands. A host component that re-renders\n * its region while the render is in flight swaps the element and keeps the\n * identity, so a boundary no longer in the document stands for the one that\n * is: the single connected boundary with its id and key that `inScope` admits.\n * Two candidates name no single region, and none means it is gone (H06).\n */\nexport function liveBoundary(\n root: Document | Element,\n planned: Element,\n inScope: (boundary: Element) => boolean,\n): Element | undefined {\n if (planned.isConnected) return planned;\n const id = planned.getAttribute(FRAGMENT_ATTRIBUTE);\n const key = planned.getAttribute(FRAGMENT_KEY_ATTRIBUTE);\n let found: Element | undefined;\n for (const candidate of root.querySelectorAll(`[${FRAGMENT_ATTRIBUTE}]`)) {\n if (candidate.getAttribute(FRAGMENT_ATTRIBUTE) !== id) continue;\n if (candidate.getAttribute(FRAGMENT_KEY_ATTRIBUTE) !== key || !inScope(candidate)) continue;\n if (found !== undefined) return undefined;\n found = candidate;\n }\n return found;\n}\n\n/** One revision, as a strategy sees it, with the runtime capabilities it may use. */\nexport interface FragmentContext {\n readonly root: ParentNode;\n readonly revision: number;\n readonly receivedAt: number;\n readonly fields: Readonly<Record<string, unknown>>;\n readonly locale: string | undefined;\n readonly collectionSlug: string | undefined;\n readonly globalSlug: string | undefined;\n /** Aborted when a newer revision arrives or the runtime stops. */\n readonly signal: AbortSignal;\n /** Whether this revision is still the current one. */\n readonly isCurrent: () => boolean;\n /** Morph server-rendered HTML into a boundary; no-op after supersession (Trusted Types and the keyed morph apply). */\n readonly morph: (boundary: Element, html: string) => void;\n /** Patch the boundary's owned bindings from this revision; no-op after supersession. */\n readonly patch: (boundary: Element) => void;\n /** Debug log through the runtime's logger, with the diagnostic code. */\n readonly log: (code: DiagnosticCode, detail: string) => void;\n /** Report a boundary rendered. */\n readonly rendered: (boundary: Element, id: string, key: string | undefined) => void;\n /** Report a boundary failed and patched instead; emits the `error` and `fragmentRender` events. */\n readonly failed: (\n boundary: Element,\n id: string,\n key: string | undefined,\n code: DiagnosticCode,\n reason: string,\n ) => void;\n}\n\nexport interface FragmentReport {\n readonly rendered: number;\n readonly failed: number;\n readonly superseded: number;\n}\n\n/** A fragment strategy: which boundaries it owns for a revision, and how it renders them. */\nexport interface FragmentStrategy {\n /** The boundaries this update re-renders; their inner bindings are left to the strategy. */\n readonly plan: (root: ParentNode, changedFields: ReadonlySet<string>) => readonly Element[];\n /** Render the planned boundaries; resolves once every one settled. */\n readonly render: (\n context: FragmentContext,\n boundaries: readonly Element[],\n ) => Promise<FragmentReport>;\n}\n\n/** The boundaries a revision hands the fragment strategy, and the bindings they take from the patch. */\nexport interface FragmentPlan {\n readonly boundaries: readonly Element[];\n readonly strategy: FragmentStrategy;\n readonly ownerKeys: OwnerScope;\n /** Whether a binding sits inside a boundary the strategy renders this revision. */\n readonly covers: (target: CachedElement) => boolean;\n}\n\n/** A plan over boundaries already chosen, whichever question chose them. */\nexport function planBoundaries(\n strategy: FragmentStrategy,\n boundaries: readonly Element[],\n ownerKeys: OwnerScope,\n): FragmentPlan {\n const covered = new Set(boundaries);\n return {\n boundaries,\n strategy,\n ownerKeys,\n covers: (target) =>\n target.fragmentBoundary !== undefined && covered.has(target.fragmentBoundary),\n };\n}\n\n/** One revision, as the route strategy sees it. */\nexport interface RouteContext {\n readonly revision: number;\n readonly receivedAt: number;\n /** Aborted when a newer revision asks for a refresh of its own, a navigation commits, or the runtime stops. */\n readonly signal: AbortSignal;\n /**\n * Whether the refresh may still land. A newer revision that asks for no\n * refresh of its own does not end it: the route is the server's, so the\n * refresh lands for that revision, which the runtime then re-applies.\n */\n readonly isCurrent: () => boolean;\n readonly log: (code: DiagnosticCode, detail: string) => void;\n /**\n * Ask to be run again in `delayMs`, once. A strategy that refuses a refresh\n * because it is rate-limiting itself uses this: the window is a rate limit\n * and not a filter, so what falls inside it still has to reach the preview.\n * The runtime runs at most one such request, and only while the revision that\n * asked is still the current one.\n */\n readonly retryAfter?: (delayMs: number) => void;\n}\n\n/**\n * What one refresh did. `refreshed` asserts that the strategy rendered the\n * current unsaved revision. `partial` completed a render whose data source was\n * not proven current; the runtime still reapplies every binding it can reach.\n * `refused` is the strategy's own brake and not a failure.\n */\nexport type RouteOutcome = 'refreshed' | 'partial' | 'failed' | 'refused' | 'superseded';\n\n/** What the runtime tells a route planner about the update it plans for. */\nexport interface RoutePlanContext {\n /**\n * Whether an element belongs to the update: always `true` without\n * `scopeBindingsByOwner`, otherwise only inside the document the update\n * names. A marker outside it asks for nothing.\n */\n readonly inScope: (element: Element) => boolean;\n}\n\n/**\n * Whether a revision needs the whole route re-rendered, and how. After a\n * refresh the runtime rescans and re-applies the revision, so reachable\n * unsaved bindings land on the fresh markup. The runtime always passes\n * `context`; a planner written before it existed still works, but plans for\n * markers of every document.\n */\nexport interface RouteStrategy {\n readonly plan: (\n root: ParentNode,\n changedFields: ReadonlySet<string>,\n context?: RoutePlanContext,\n ) => boolean;\n readonly refresh: (context: RouteContext) => Promise<RouteOutcome>;\n}\n\nexport interface StrategyHandlers {\n readonly fragment?: FragmentStrategy;\n readonly route?: RouteStrategy;\n}\n\nconst STRATEGY_ATTRIBUTE = 'data-payload-strategy';\n\n/**\n * Explicit `data-payload-strategy` wins; otherwise a binding inside a fragment\n * boundary belongs to the fragment, one in `<head>` to the route, the rest is\n * patched. An unknown explicit value resolves to `undefined` (LP0407).\n * @internal\n */\nexport function resolveStrategy(element: Element): UpdateSource | undefined {\n const explicit = element.getAttribute(STRATEGY_ATTRIBUTE);\n if (explicit !== null && explicit.length > 0) {\n return explicit === 'patch' || explicit === 'fragment' || explicit === 'route'\n ? explicit\n : undefined;\n }\n if (enclosingFragment(element) !== null) return 'fragment';\n if (element.closest('head') !== null) return 'route';\n return 'patch';\n}\n","/**\n * Maps field names to their bound elements so an update walks the cache, not\n * the DOM. Everything an update needs about a binding is resolved here, once,\n * at build time.\n */\n\nimport {\n dependencyMapFromBinding,\n mergeDependencyMaps,\n parseDependencyList,\n type DependencyMap,\n} from './dependencies';\nimport { collectIslands } from './islands';\nimport { enclosingFragment, FRAGMENT_ATTRIBUTE, resolveStrategy } from './strategies';\nimport type { CachedElement, ElementPredicate, FieldType, RendererKey } from './types';\n\nexport const FIELD_ATTRIBUTE = 'data-payload-field';\nexport const TYPE_ATTRIBUTE = 'data-payload-type';\nexport const TARGET_ATTRIBUTE_ATTRIBUTE = 'data-payload-attribute';\nexport const HREF_ATTRIBUTE = 'data-payload-href';\nexport const SRC_ATTRIBUTE = 'data-payload-src';\nexport const ALT_ATTRIBUTE = 'data-payload-alt';\nexport const ARRAY_TEMPLATE_ATTRIBUTE = 'data-payload-array-template';\nexport const ARRAY_SEPARATOR_ATTRIBUTE = 'data-payload-array-separator';\nexport const LOCALE_ATTRIBUTE = 'data-payload-locale';\nexport const FORMAT_ATTRIBUTE = 'data-payload-format';\nexport const RICH_TEXT_ATTRIBUTE = 'data-payload-richtext';\nexport const HTML_ATTRIBUTE = 'data-payload-html';\nexport const ARRAY_ATTRIBUTE = 'data-payload-array';\nexport const STRUCTURAL_ATTRIBUTE = 'data-payload-structural';\nexport const OWNER_ATTRIBUTE = 'data-payload-owner';\nexport const DEPENDS_ATTRIBUTE = 'data-payload-depends';\nexport const STRATEGY_ATTRIBUTE = 'data-payload-strategy';\nexport const BOUNDARY_ATTRIBUTE = 'data-payload-boundary';\n/**\n * Written by the runtime, never by a template: the value an auto-binding\n * matched on (ADR 0014). Its presence is what tells a guessed binding from a\n * declared one, in `inspect()` and in the overlay.\n */\nexport const GUESSED_ATTRIBUTE = 'data-payload-guessed';\n/** Field paths a page accounts for without binding them, and everything below them (ADR 0022). */\nexport const COVERS_ATTRIBUTE = 'data-payload-covers';\nexport const INPUT_TYPE_ATTRIBUTE = 'type';\n\n/**\n * Attributes captured in a `CachedElement`. The mutation observer watches\n * exactly this list, so a snapshot can never go stale on a mounted element.\n */\nexport const BINDING_ATTRIBUTES: readonly string[] = [\n FIELD_ATTRIBUTE,\n TYPE_ATTRIBUTE,\n TARGET_ATTRIBUTE_ATTRIBUTE,\n HREF_ATTRIBUTE,\n SRC_ATTRIBUTE,\n ALT_ATTRIBUTE,\n ARRAY_TEMPLATE_ATTRIBUTE,\n ARRAY_SEPARATOR_ATTRIBUTE,\n LOCALE_ATTRIBUTE,\n FORMAT_ATTRIBUTE,\n RICH_TEXT_ATTRIBUTE,\n HTML_ATTRIBUTE,\n ARRAY_ATTRIBUTE,\n STRUCTURAL_ATTRIBUTE,\n OWNER_ATTRIBUTE,\n DEPENDS_ATTRIBUTE,\n STRATEGY_ATTRIBUTE,\n BOUNDARY_ATTRIBUTE,\n INPUT_TYPE_ATTRIBUTE,\n];\n\nconst FIELD_SELECTOR = `[${FIELD_ATTRIBUTE}]`;\nconst OWNER_SELECTOR = `[${OWNER_ATTRIBUTE}]`;\n/** Structural strategy roots whose arrival after navigation needs the retained document. @internal */\nexport const NAVIGATION_REPLAY_SELECTOR = `[${FRAGMENT_ATTRIBUTE}], [${STRATEGY_ATTRIBUTE}=\"route\"]`;\n\n/** The document a binding belongs to: its nearest `data-payload-owner`, itself included. */\nexport function resolveBindingOwner(element: Element): string | undefined {\n const owner = element.closest(OWNER_SELECTOR)?.getAttribute(OWNER_ATTRIBUTE);\n return owner === null || owner === undefined || owner.length === 0 ? undefined : owner;\n}\n\n/** `namespace:name` — a project renderer key can never be a typo of a built-in type. */\nconst CUSTOM_RENDERER_KEY = /^[a-z][a-z0-9-]*:[a-z][a-z0-9-]*$/i;\n\nconst VALID_FIELD_TYPES: ReadonlySet<FieldType> = new Set<FieldType>([\n 'text',\n 'textarea',\n 'richText',\n 'email',\n 'number',\n 'checkbox',\n 'date',\n 'select',\n 'radio',\n 'array',\n 'blocks',\n 'group',\n 'tabs',\n 'row',\n 'collapsible',\n 'relationship',\n 'upload',\n 'point',\n 'json',\n 'code',\n 'ui',\n 'html',\n 'url',\n 'image',\n 'structural-array',\n]);\n\nfunction isRendererKey(value: string): value is RendererKey {\n return VALID_FIELD_TYPES.has(value as FieldType) || CUSTOM_RENDERER_KEY.test(value);\n}\n\n/** One `data-payload-covers` declaration: the paths it names, for the owner it sits under. */\nexport interface CoverDeclaration {\n readonly paths: readonly string[];\n readonly owner: string | undefined;\n}\n\n/** The fields a fragment boundary or a route marker depends on, which its strategy renders. */\nexport interface RenderedDeclaration extends CoverDeclaration {\n readonly strategy: 'fragment' | 'route';\n}\n\n/**\n * The strategy that renders what an element depends on, by the planners' own\n * rules: the fragment planner takes every named boundary, the route planner a\n * route-bound element — marked `route`, or a binding in `<head>` left unmarked\n * (`src/fragment/boundary.ts`, `src/fragment/route.ts`). @internal\n */\nexport function renderingStrategy(element: Element): RenderedDeclaration['strategy'] | undefined {\n if ((element.getAttribute(FRAGMENT_ATTRIBUTE) ?? '').length > 0) return 'fragment';\n const explicit = element.getAttribute(STRATEGY_ATTRIBUTE);\n if (explicit !== null) return explicit === 'route' ? 'route' : undefined;\n return element.hasAttribute(FIELD_ATTRIBUTE) && element.closest('head') !== null\n ? 'route'\n : undefined;\n}\n\nexport interface CacheBuildStats {\n readonly elementCount: number;\n readonly fieldCount: number;\n readonly durationMs: number;\n}\n\nexport interface ElementCacheOptions {\n /** Restricts which elements are accepted. Defaults to all. */\n readonly filter?: ElementPredicate;\n}\n\n/** Metadata that decides whether buffered work still addresses the same owned strategy target. */\nexport function hasSameBindingIdentity(a: CachedElement, b: CachedElement): boolean {\n return (\n a.fieldName === b.fieldName &&\n a.locale === b.locale &&\n a.owner === b.owner &&\n a.strategyKind === b.strategyKind &&\n a.fragmentBoundary === b.fragmentBoundary\n );\n}\n\n/**\n * Elements share a field name when the same field is rendered in several\n * places; within a field the order is DOM order.\n */\nexport class ElementCache {\n private readonly entriesByField = new Map<string, CachedElement[]>();\n private entryByElement = new WeakMap<Element, CachedElement>();\n private readonly filter: ElementPredicate;\n private count = 0;\n private dependencies: DependencyMap | null = null;\n private islandRoots: readonly Element[] = [];\n private ownersByIsland: ReadonlyMap<Element, string | undefined> = new Map();\n private navigationRoots: readonly Element[] = [];\n private coverDeclarations: readonly CoverDeclaration[] = [];\n private renderedDeclarations: readonly RenderedDeclaration[] = [];\n\n constructor(options: ElementCacheOptions = {}) {\n this.filter = options.filter ?? alwaysTrue;\n }\n\n /** Source → dependents declared with `data-payload-depends`; memoised until the cache changes. */\n dependencyMap(): DependencyMap {\n if (this.dependencies !== null) return this.dependencies;\n const maps: DependencyMap[] = [];\n for (const binding of this.values()) {\n if (binding.dependsOn !== undefined) {\n maps.push(dependencyMapFromBinding(binding.fieldName, binding.dependsOn));\n }\n }\n this.dependencies = mergeDependencyMaps(...maps);\n return this.dependencies;\n }\n\n /** Island roots under the last built root, for update events. */\n get islands(): readonly Element[] {\n return this.islandRoots;\n }\n\n /** Owner identities captured with `islands`; used to detect a live retarget. @internal */\n get islandOwners(): ReadonlyMap<Element, string | undefined> {\n return this.ownersByIsland;\n }\n\n /** `data-payload-covers` declarations under the last built root. */\n get covers(): readonly CoverDeclaration[] {\n return this.coverDeclarations;\n }\n\n /** Boundaries and route markers under the last built root that name the fields they depend on. */\n get rendered(): readonly RenderedDeclaration[] {\n return this.renderedDeclarations;\n }\n\n /** Fieldless strategy roots under the last built root, for navigation replay. */\n get navigationReplayRoots(): readonly Element[] {\n return this.navigationRoots;\n }\n\n buildFromRoot(root: ParentNode): CacheBuildStats {\n const t0 = performance.now();\n this.clear();\n let elementCount = 0;\n for (const element of root.querySelectorAll(FIELD_SELECTOR)) {\n if (this.add(element) !== undefined) elementCount += 1;\n }\n this.islandRoots = collectIslands(root);\n this.ownersByIsland = new Map(\n this.islandRoots.map((island) => [island, resolveBindingOwner(island)]),\n );\n this.navigationRoots = [...root.querySelectorAll(NAVIGATION_REPLAY_SELECTOR)].filter(\n (element) =>\n this.filter(element) &&\n (element.hasAttribute(FRAGMENT_ATTRIBUTE) ||\n (element.getAttribute(FIELD_ATTRIBUTE) ?? '').length === 0),\n );\n this.coverDeclarations = [...root.querySelectorAll(`[${COVERS_ATTRIBUTE}]`)]\n .filter((element) => this.filter(element))\n .map((element) => ({\n paths: parseDependencyList(element.getAttribute(COVERS_ATTRIBUTE)),\n owner: resolveBindingOwner(element),\n }));\n this.renderedDeclarations = [...root.querySelectorAll(`[${DEPENDS_ATTRIBUTE}]`)]\n .filter((element) => this.filter(element))\n .flatMap((element): RenderedDeclaration[] => {\n const strategy = renderingStrategy(element);\n if (strategy === undefined) return [];\n const paths = parseDependencyList(element.getAttribute(DEPENDS_ATTRIBUTE));\n return [{ strategy, paths, owner: resolveBindingOwner(element) }];\n });\n return {\n elementCount,\n fieldCount: this.entriesByField.size,\n durationMs: performance.now() - t0,\n };\n }\n\n /**\n * Insert or replace a single element's binding. Re-adding refreshes the\n * snapshot in place; an element that is now filtered or unbound is removed.\n */\n add(element: Element): CachedElement | undefined {\n // Resolve before mutating so a throwing filter leaves the old entry intact.\n const entry = this.filter(element) ? this.resolveBinding(element) : undefined;\n const previous = this.entryByElement.get(element);\n this.dependencies = null;\n if (entry === undefined) {\n if (previous !== undefined) this.removeEntry(element, previous);\n return undefined;\n }\n if (previous !== undefined && this.replaceEntry(previous, entry)) {\n this.entryByElement.set(element, entry);\n return entry;\n }\n if (previous !== undefined) this.removeEntry(element, previous);\n this.append(entry);\n this.entryByElement.set(element, entry);\n return entry;\n }\n\n /** Returns whether a binding was removed. */\n remove(element: Element): boolean {\n const entry = this.entryByElement.get(element);\n if (!entry) return false;\n this.dependencies = null;\n return this.removeEntry(element, entry);\n }\n\n get(fieldName: string): readonly CachedElement[] | undefined {\n return this.entriesByField.get(fieldName);\n }\n\n getByElement(element: Element): CachedElement | undefined {\n return this.entryByElement.get(element);\n }\n\n get fieldCount(): number {\n return this.entriesByField.size;\n }\n\n get elementCount(): number {\n return this.count;\n }\n\n entries(): IterableIterator<[string, readonly CachedElement[]]> {\n return this.entriesByField.entries() as IterableIterator<[string, readonly CachedElement[]]>;\n }\n\n *values(): IterableIterator<CachedElement> {\n for (const bucket of this.entriesByField.values()) yield* bucket;\n }\n\n has(element: Element): boolean {\n return this.entryByElement.has(element);\n }\n\n clear(): void {\n this.entriesByField.clear();\n // WeakMap cannot be cleared; a detached element must not observe stale membership.\n this.entryByElement = new WeakMap();\n this.count = 0;\n this.dependencies = null;\n this.islandRoots = [];\n this.ownersByIsland = new Map();\n this.navigationRoots = [];\n this.coverDeclarations = [];\n this.renderedDeclarations = [];\n }\n\n /** Replace in place when the field bucket is unchanged, preserving order. */\n private replaceEntry(previous: CachedElement, next: CachedElement): boolean {\n if (previous.fieldName !== next.fieldName) return false;\n const bucket = this.entriesByField.get(previous.fieldName);\n const index = bucket === undefined ? -1 : bucket.indexOf(previous);\n if (bucket === undefined || index < 0) return false;\n bucket[index] = next;\n return true;\n }\n\n private removeEntry(element: Element, entry: CachedElement): boolean {\n this.entryByElement.delete(element);\n const bucket = this.entriesByField.get(entry.fieldName);\n const index = bucket === undefined ? -1 : bucket.indexOf(entry);\n if (bucket === undefined || index < 0) return false;\n bucket.splice(index, 1);\n if (bucket.length === 0) this.entriesByField.delete(entry.fieldName);\n this.count -= 1;\n return true;\n }\n\n private append(entry: CachedElement): void {\n const bucket = this.entriesByField.get(entry.fieldName);\n if (bucket) bucket.push(entry);\n else this.entriesByField.set(entry.fieldName, [entry]);\n this.count += 1;\n }\n\n private resolveBinding(element: Element): CachedElement | undefined {\n const fieldName = element.getAttribute(FIELD_ATTRIBUTE);\n if (fieldName === null || fieldName.length === 0) return undefined;\n const explicit = element.getAttribute(TYPE_ATTRIBUTE);\n const targetAttribute = element.getAttribute(TARGET_ATTRIBUTE_ATTRIBUTE);\n const hrefField = element.getAttribute(HREF_ATTRIBUTE);\n const srcField = element.getAttribute(SRC_ATTRIBUTE);\n const altField = element.getAttribute(ALT_ATTRIBUTE);\n const arrayTemplate = element.getAttribute(ARRAY_TEMPLATE_ATTRIBUTE);\n const arraySeparator = element.getAttribute(ARRAY_SEPARATOR_ATTRIBUTE);\n const locale = element.getAttribute(LOCALE_ATTRIBUTE);\n const format = element.getAttribute(FORMAT_ATTRIBUTE);\n const owner = resolveBindingOwner(element);\n const dependsOn = parseDependencyList(element.getAttribute(DEPENDS_ATTRIBUTE));\n const strategy = element.getAttribute(STRATEGY_ATTRIBUTE);\n const guessed = element.getAttribute(GUESSED_ATTRIBUTE);\n const fragmentBoundary = enclosingFragment(element);\n return {\n element,\n fieldName,\n fieldType: resolveFieldType(element),\n explicitFieldType: explicit !== null && isRendererKey(explicit),\n strategyKind: resolveStrategy(element) ?? 'unknown',\n ...(fragmentBoundary !== null ? { fragmentBoundary } : {}),\n ...(targetAttribute !== null && targetAttribute.length > 0 ? { targetAttribute } : {}),\n ...(hrefField !== null && hrefField.length > 0 ? { hrefField } : {}),\n ...(srcField !== null && srcField.length > 0 ? { srcField } : {}),\n ...(altField !== null && altField.length > 0 ? { altField } : {}),\n ...(arrayTemplate !== null ? { arrayTemplate } : {}),\n ...(arraySeparator !== null ? { arraySeparator } : {}),\n ...(locale !== null && locale.length > 0 ? { locale } : {}),\n ...(format !== null && format.length > 0 ? { format } : {}),\n ...(owner !== undefined ? { owner } : {}),\n ...(dependsOn.length > 0 ? { dependsOn } : {}),\n ...(strategy !== null && strategy.length > 0 ? { strategy } : {}),\n ...(element.hasAttribute(BOUNDARY_ATTRIBUTE) ? { hidesWhenEmpty: true } : {}),\n ...(guessed !== null ? { guessed } : {}),\n };\n }\n}\n\n/** Explicit `data-payload-type`, then element heuristics, then `text`. */\nexport function resolveFieldType(element: Element): RendererKey {\n const explicit = element.getAttribute(TYPE_ATTRIBUTE);\n if (explicit !== null && isRendererKey(explicit)) return explicit;\n if (element.hasAttribute(RICH_TEXT_ATTRIBUTE)) return 'richText';\n if (element.hasAttribute(HTML_ATTRIBUTE)) return 'html';\n if (element.hasAttribute(STRUCTURAL_ATTRIBUTE)) return 'structural-array';\n if (element.hasAttribute(ARRAY_ATTRIBUTE)) return 'array';\n if (element.tagName === 'IMG') return 'image';\n if (element.tagName === 'A') return 'url';\n if (element.tagName === 'TIME') return 'date';\n if (element.tagName === 'INPUT') {\n const inputType = (element as HTMLInputElement).type;\n if (inputType === 'checkbox') return 'checkbox';\n if (inputType === 'number') return 'number';\n if (inputType === 'date' || inputType === 'datetime-local') return 'date';\n }\n return 'text';\n}\n\nfunction alwaysTrue(): boolean {\n return true;\n}\n","/**\n * Stable identity for a field value, so two messages can be compared without\n * rendering either — every keystroke ships the whole document, of which one\n * field changed. Equality is structural (plain, unsorted JSON): Payload\n * allocates a fresh object graph per message, so reference identity would skip\n * nothing. A value JSON cannot represent has no identity and counts as\n * changed, which is the safe direction — a false \"equal\" leaves a stale\n * binding, a false \"different\" only renders once more.\n */\n\n/** Past this size the comparison is no longer obviously cheaper than the render it avoids. */\nexport const IDENTITY_SIZE_LIMIT = 64 * 1024;\n\n/**\n * Canonical string for `value`, or `undefined` when it cannot have one.\n * Primitives carry a type tag, so `1` and `'1'` differ even though a text\n * renderer prints them alike — that is the renderer's decision, not this one.\n */\nexport function valueIdentity(value: unknown): string | undefined {\n switch (typeof value) {\n case 'string':\n return value.length > IDENTITY_SIZE_LIMIT ? undefined : `s:${value}`;\n case 'number':\n // Object.is semantics at the top level: NaN equals NaN, -0 is not 0.\n return `n:${Object.is(value, -0) ? '-0' : String(value)}`;\n case 'boolean':\n return `b:${value ? '1' : '0'}`;\n case 'bigint':\n return `i:${String(value)}`;\n case 'undefined':\n return 'u';\n case 'object': {\n if (value === null) return 'z';\n let json: string;\n try {\n // Throws on a cycle and on a nested BigInt; both mean \"no identity\".\n json = JSON.stringify(value);\n } catch {\n return undefined;\n }\n return json.length > IDENTITY_SIZE_LIMIT ? undefined : `o:${json}`;\n }\n case 'symbol':\n case 'function':\n return undefined;\n }\n}\n","/**\n * Which paths below a group changed without anything on the page to show\n * them (ADR 0022). The diff names top-level fields; under\n * `subfieldCoverage: 'declared'` a group covered only through its descendants\n * is compared with the previous message path by path, and a changed path\n * needs its own binding or a declared cover. A document a merge populated and\n * the id it replaced are the same value: population is not an edit.\n */\n\nimport { valueIdentity } from './value-identity';\n\nexport type SubfieldCoverage = 'descendant' | 'declared';\n\n/** Deeper than this, what is left counts as one changed path. */\nexport const SUBFIELD_DEPTH_LIMIT = 8;\n/** Nodes compared per field before the rest counts as one changed path. */\nexport const SUBFIELD_VISIT_LIMIT = 1024;\n\n/** What the page offers for a path; built once per update from the cache and the owner scope. */\nexport interface PathCoverage {\n /** A binding on the path, or a cover on it or on an ancestor. */\n readonly covers: (path: string) => boolean;\n /** A binding or a cover somewhere below the path. */\n readonly reachesBelow: (path: string) => boolean;\n}\n\nexport interface UncoveredPath {\n readonly path: string;\n /** The current value there, `undefined` where the path was removed. */\n readonly value: unknown;\n}\n\nfunction isContainer(value: unknown): value is Record<string, unknown> | readonly unknown[] {\n return typeof value === 'object' && value !== null;\n}\n\nfunction shapeOf(value: unknown): 'array' | 'object' | 'scalar' {\n if (Array.isArray(value)) return 'array';\n return isContainer(value) ? 'object' : 'scalar';\n}\n\n/** The keys to compare below a container: the new ones, and any the previous value had. */\nfunction childKeys(\n previous: unknown,\n next: Record<string, unknown> | readonly unknown[],\n): string[] {\n const keys = new Set(Object.keys(next));\n if (isContainer(previous)) for (const key of Object.keys(previous)) keys.add(key);\n return [...keys];\n}\n\nfunction child(value: unknown, key: string): unknown {\n return isContainer(value) ? (value as Record<string, unknown>)[key] : undefined;\n}\n\n/** Whether `document` is what a merge puts where the message has the bare `id`. */\nfunction populates(document: unknown, id: unknown): boolean {\n return (\n (typeof id === 'string' || typeof id === 'number') &&\n isContainer(document) &&\n !Array.isArray(document) &&\n (document as Record<string, unknown>)['id'] === id\n );\n}\n\n/**\n * Whether two values differ only in what the server populated: the same shape\n * all the way down, except that one holds a document where the other holds its\n * id. The admin posts a relationship or an upload as its id in every message\n * and the merge answers with the document, so a revision rendered before the\n * answer and the one after it meet both forms of one value.\n */\nfunction samePopulation(before: unknown, after: unknown): boolean {\n if (!isContainer(before) || !isContainer(after)) {\n return (\n populates(before, after) ||\n populates(after, before) ||\n valueIdentity(before) === valueIdentity(after)\n );\n }\n if (Array.isArray(before) !== Array.isArray(after)) return false;\n const keys = Object.keys(after);\n if (keys.length !== Object.keys(before).length) return false;\n return keys.every(\n (key) => Object.hasOwn(before, key) && samePopulation(child(before, key), child(after, key)),\n );\n}\n\n/**\n * Whether the two values are one: equal, or equal but for population. An id\n * and its document are told apart without a walk, whatever the document's\n * size. The walk itself needs an identity on both sides, which bounds it by\n * the identity's size limit and keeps it out of a cycle; a value without one\n * counts as changed, as it does for the top-level diff.\n */\nfunction sameValue(before: unknown, after: unknown): boolean {\n const identity = valueIdentity(after);\n const previous = valueIdentity(before);\n if (identity !== undefined && identity === previous) return true;\n if (populates(before, after) || populates(after, before)) return true;\n return identity !== undefined && previous !== undefined && samePopulation(before, after);\n}\n\n/**\n * Whether the value at a dotted path changed between two messages, by the\n * rule the walk below applies. A route-bound element names such a path\n * (`layout.1.note`) while the diff names only its field.\n */\nexport function pathChanged(\n path: string,\n previous: Readonly<Record<string, unknown>>,\n next: Readonly<Record<string, unknown>>,\n): boolean {\n let before: unknown = previous;\n let after: unknown = next;\n for (const key of path.split('.')) {\n before = child(before, key);\n after = child(after, key);\n }\n return !sameValue(before, after);\n}\n\n/**\n * The changed paths below `field` that nothing covers, as the largest\n * uncovered subtrees: a path with nothing bound or covered beneath it is\n * reported whole rather than leaf by leaf. `previous` is `undefined` for a\n * document read without a diff, which makes every path \"changed\".\n */\nexport function uncoveredChangedPaths(\n field: string,\n previous: unknown,\n next: unknown,\n coverage: PathCoverage,\n): UncoveredPath[] {\n const uncovered: UncoveredPath[] = [];\n let visits = 0;\n const visit = (path: string, before: unknown, after: unknown, depth: number): void => {\n visits += 1;\n if (coverage.covers(path) || sameValue(before, after)) return;\n // A path that changed shape — a group that became a scalar, went away or\n // replaced one — changed as a whole, whatever is covered inside it. Without\n // a previous message (`undefined`) there is no shape to compare.\n const reshaped = before !== undefined && shapeOf(before) !== shapeOf(after);\n const descend =\n !reshaped &&\n isContainer(after) &&\n coverage.reachesBelow(path) &&\n depth < SUBFIELD_DEPTH_LIMIT;\n if (!descend) {\n uncovered.push({ path, value: after });\n return;\n }\n const keys = childKeys(before, after);\n // A new, empty group: nothing inside to compare, so the node itself changed.\n if (keys.length === 0) uncovered.push({ path, value: after });\n for (const key of keys) {\n // Out of budget: this node stands for whatever of it is left unvisited.\n if (visits >= SUBFIELD_VISIT_LIMIT) {\n uncovered.push({ path, value: after });\n return;\n }\n visit(`${path}.${key}`, child(before, key), child(after, key), depth + 1);\n }\n };\n visit(field, previous, next, 0);\n return uncovered;\n}\n","/**\n * Whether an incoming field has somewhere on the page to land.\n *\n * Two callers ask, for different reasons: LP0201 reports a field that never\n * has an anchor, and `onUnfaithfulPatch` decides whether a revision needs the\n * whole route. They have to answer the same way, so the lookup lives here\n * rather than in either of them — the locale suffix Payload appends, the owner\n * scope, and the fact that the diff names top-level fields while a binding may\n * name a path inside one.\n */\n\nimport { isBindingInScope } from './binding-owner';\nimport type { ElementCache } from './cache';\nimport {\n pathChanged,\n uncoveredChangedPaths,\n type PathCoverage,\n type SubfieldCoverage,\n type UncoveredPath,\n} from './subfield-coverage';\n\n/** Document fields Payload ships in every update that nobody binds to. */\nexport const SYSTEM_FIELD_NAMES: ReadonlySet<string> = new Set([\n 'id',\n '_id',\n 'createdAt',\n 'updatedAt',\n 'createdBy',\n 'updatedBy',\n '_status',\n 'globalType',\n 'collection',\n 'locale',\n 'localized',\n]);\n\n/** Owner keys as the update resolved them; `false` means scoping is off. */\nexport type OwnerScope = readonly string[] | null | false;\n\n/** Answers for one update; the locale index behind it is built at most once. */\nexport type FieldAddressability = (fieldName: string) => boolean;\n\n/**\n * `field_locale` names an element-local locale may consume while the message\n * locale differs, so those bindings are addressable under their suffixed name.\n */\nfunction localisedBindingNames(cache: ElementCache, ownerKeys: OwnerScope): Set<string> {\n const names = new Set<string>();\n for (const [fieldName, bindings] of cache.entries()) {\n for (const binding of bindings) {\n if (ownerKeys !== false && !isBindingInScope(binding.owner, ownerKeys)) continue;\n if (binding.locale !== undefined) names.add(`${fieldName}_${binding.locale}`);\n }\n }\n return names;\n}\n\n/**\n * A binding on a path inside the field — `hero.eyebrow` for the field `hero` —\n * makes it addressable. The diff names top-level fields only, so without this\n * every group and array on the page would look unbound.\n */\nexport function hasBindingBelow(\n cache: ElementCache,\n fieldName: string,\n ownerKeys: OwnerScope,\n): boolean {\n const prefix = `${fieldName}.`;\n for (const [boundName, bindings] of cache.entries()) {\n if (!boundName.startsWith(prefix)) continue;\n if (ownerKeys === false) return true;\n if (bindings.some((binding) => isBindingInScope(binding.owner, ownerKeys))) return true;\n }\n return false;\n}\n\n/** The strategies configured for this page; only they render what a boundary or marker depends on. */\nexport interface ServerRendering {\n readonly fragment?: unknown;\n readonly route?: unknown;\n}\n\n/**\n * The page's answer for any path in one update's owner scope: the bound names,\n * the declared covers (ADR 0022) and the fields a boundary or route marker\n * depends on when its strategy is configured, read once, then the same name\n * rule the overlay applies.\n */\nexport function createPathCoverage(\n cache: ElementCache,\n ownerKeys: OwnerScope,\n rendering: ServerRendering = {},\n): PathCoverage {\n const inScope = (owner: string | undefined): boolean =>\n ownerKeys === false || isBindingInScope(owner, ownerKeys);\n const names: string[] = [];\n for (const [fieldName, bindings] of cache.entries()) {\n if (bindings.some((binding) => inScope(binding.owner))) names.push(fieldName);\n }\n const rendered = cache.rendered.filter(\n (declaration) => rendering[declaration.strategy] !== undefined,\n );\n const covers = [...cache.covers, ...rendered]\n .filter((cover) => inScope(cover.owner))\n .flatMap((cover) => cover.paths);\n return namePathCoverage(names, covers);\n}\n\nexport function stripLocaleSuffix(name: string, locale: string | undefined): string {\n if (locale === undefined || locale.length === 0) return name;\n const suffix = `_${locale}`;\n return name.endsWith(suffix) ? name.slice(0, -suffix.length) : name;\n}\n\n/** Whether any binding on the page belongs to the document this update carries. */\nexport function ownsAnyBinding(cache: ElementCache, ownerKeys: readonly string[] | null): boolean {\n for (const binding of cache.values()) {\n if (isBindingInScope(binding.owner, ownerKeys)) return true;\n }\n return false;\n}\n\n/**\n * The same rule for a caller that has names rather than the cache: the\n * `data-payload-field` values in a document, which is all a plugin can see\n * (`src/plugins/built-in/unbound-fields-overlay.ts`).\n *\n * It answers the first three of the four questions below — exact name, the\n * locale-stripped base, a binding on a path inside the field. The fourth needs\n * each binding's own `data-payload-locale`, which is a property of the element\n * rather than of its name, so a caller with names alone cannot ask it.\n */\nexport function createNameAddressability(\n boundNames: Iterable<string>,\n locale: string | undefined,\n coverPaths: Iterable<string>,\n): FieldAddressability {\n const coverage = namePathCoverage(boundNames, coverPaths);\n const reaches = (name: string): boolean => coverage.covers(name) || coverage.reachesBelow(name);\n return (fieldName) => {\n if (reaches(fieldName)) return true;\n const base = stripLocaleSuffix(fieldName, locale);\n return base !== fieldName && reaches(base);\n };\n}\n\n/** Coverage from names alone: the bound names and the declared cover paths in a document. */\nfunction namePathCoverage(\n boundNames: Iterable<string>,\n coverPaths: Iterable<string>,\n): PathCoverage {\n const names = new Set(boundNames);\n const covers = [...coverPaths];\n const anyBelow = (candidates: Iterable<string>, path: string): boolean => {\n const prefix = `${path}.`;\n for (const candidate of candidates) if (candidate.startsWith(prefix)) return true;\n return false;\n };\n return {\n covers: (path) =>\n names.has(path) || covers.some((cover) => cover === path || path.startsWith(`${cover}.`)),\n reachesBelow: (path) => anyBelow(names, path) || anyBelow(covers, path),\n };\n}\n\n/**\n * The declared mode for a caller with names (the overlay): the uncovered paths\n * inside the groups the document reaches only below the top level.\n */\nexport function uncoveredNamePaths(\n fields: Readonly<Record<string, unknown>>,\n boundNames: Iterable<string>,\n locale: string | undefined,\n coverPaths: Iterable<string>,\n): string[] {\n const coverage = namePathCoverage(boundNames, coverPaths);\n const found: string[] = [];\n for (const [fieldName, value] of Object.entries(fields)) {\n if (SYSTEM_FIELD_NAMES.has(fieldName)) continue;\n const root = stripLocaleSuffix(fieldName, locale);\n if (coverage.covers(root) || !coverage.reachesBelow(root)) continue;\n for (const { path } of uncoveredChangedPaths(root, undefined, value, coverage)) {\n found.push(path);\n }\n }\n return found;\n}\n\n/**\n * The predicate for one update. The localised index is built on first use:\n * most fields are answered by the two cheap lookups before it.\n */\nexport function createFieldAddressability(\n cache: ElementCache,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n rendering?: ServerRendering,\n): FieldAddressability {\n const coverage = createPathCoverage(cache, ownerKeys, rendering);\n const reach = createFieldReach(cache, locale, ownerKeys, coverage);\n return (fieldName) => reach(fieldName) !== 'none';\n}\n\n/**\n * How far the page reaches into a field: `whole` when a binding or a cover\n * sits on it, `below` when only paths inside it are bound or covered — the\n * case ADR 0022's declared mode looks into — and `none`.\n */\nfunction createFieldReach(\n cache: ElementCache,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n coverage: PathCoverage = createPathCoverage(cache, ownerKeys),\n): (fieldName: string) => 'whole' | 'below' | 'none' {\n let localised: Set<string> | undefined;\n const whole = coverage.covers;\n const below = coverage.reachesBelow;\n return (fieldName) => {\n const base = stripLocaleSuffix(fieldName, locale);\n if (whole(fieldName) || (base !== fieldName && whole(base))) return 'whole';\n localised ??= localisedBindingNames(cache, ownerKeys);\n if (localised.has(fieldName)) return 'whole';\n if (below(fieldName) || (base !== fieldName && below(base))) return 'below';\n return 'none';\n };\n}\n\n/** The previous and current message, when the declared mode compares below the top level. */\nexport interface SubfieldValues {\n readonly previous: Readonly<Record<string, unknown>>;\n readonly next: Readonly<Record<string, unknown>>;\n}\n\n/**\n * The declared mode asked of a document rather than a diff, for LP0203: the\n * uncovered paths inside the groups the page reaches only below the top level.\n */\nexport function uncoveredDocumentPaths(\n cache: ElementCache,\n fields: Readonly<Record<string, unknown>>,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n rendering?: ServerRendering,\n): UncoveredPath[] {\n const coverage = createPathCoverage(cache, ownerKeys, rendering);\n const reach = createFieldReach(cache, locale, ownerKeys, coverage);\n const found: UncoveredPath[] = [];\n for (const [fieldName, value] of Object.entries(fields)) {\n if (SYSTEM_FIELD_NAMES.has(fieldName) || reach(fieldName) !== 'below') continue;\n const root = stripLocaleSuffix(fieldName, locale);\n found.push(...uncoveredChangedPaths(root, undefined, value, coverage));\n }\n return found;\n}\n\n/** What the declared mode compares for one revision, or `undefined` where it does not apply. */\nexport function declaredSubfields(\n mode: SubfieldCoverage,\n previous: Readonly<Record<string, unknown>> | undefined,\n next: Readonly<Record<string, unknown>> | undefined,\n): SubfieldValues | undefined {\n return mode === 'declared' && previous !== undefined && next !== undefined\n ? { previous, next }\n : undefined;\n}\n\n/**\n * `touched` with the paths inside its fields that route-bound elements name and\n * that changed, for the route planners: a marker on `layout.1.note` asks about\n * that path while the diff names `layout`. Without the previous message, which\n * only the declared mode keeps, a path changes with its field.\n */\nexport function routeTouched(\n cache: ElementCache,\n touched: ReadonlySet<string>,\n subfields?: SubfieldValues,\n): ReadonlySet<string> {\n const named = cache.rendered.flatMap((declaration) =>\n declaration.strategy === 'route' ? declaration.paths : [],\n );\n for (const [fieldName, bindings] of cache.entries()) {\n if (bindings.some((binding) => binding.strategyKind === 'route')) named.push(fieldName);\n }\n const changed = new Set(touched);\n for (const path of named) {\n const [field = path] = path.split('.');\n if (!touched.has(field)) continue;\n if (subfields === undefined || pathChanged(path, subfields.previous, subfields.next)) {\n changed.add(path);\n }\n }\n return changed;\n}\n\n/**\n * The fields a revision changed that the page has nowhere to put: the rule\n * above, asked of a diff instead of a document. Both profiles ask it — the full\n * one to decide whether the whole route is the only honest answer, the lean one\n * because the finding is worth recording even where nothing can act on it — so\n * it stands here, beside the rule it is made of, rather than in either runner.\n */\nexport function unboundChangedFields(\n cache: ElementCache,\n touched: ReadonlySet<string>,\n locale: string | undefined,\n ownerKeys: OwnerScope,\n subfields?: SubfieldValues,\n rendering?: ServerRendering,\n): string[] {\n const coverage = createPathCoverage(cache, ownerKeys, rendering);\n const reach = createFieldReach(cache, locale, ownerKeys, coverage);\n const unbound: string[] = [];\n for (const fieldName of touched) {\n if (SYSTEM_FIELD_NAMES.has(fieldName)) continue;\n const kind = reach(fieldName);\n if (kind === 'none') unbound.push(fieldName);\n if (kind !== 'below' || subfields === undefined) continue;\n const root = stripLocaleSuffix(fieldName, locale);\n const { previous, next } = subfields;\n for (const { path } of uncoveredChangedPaths(\n root,\n previous[fieldName],\n next[fieldName],\n coverage,\n )) {\n unbound.push(path);\n }\n }\n return unbound;\n}\n","/**\n * `unbound-fields` plugin: a development overlay listing the fields an update\n * carried that the page has nowhere to put.\n *\n * Annotating a template is the work this package asks for, and the hardest part\n * of it is knowing what is still missing — `inspect().bindings.orphanFields`\n * answers that in the console, which is the wrong place while you are editing\n * markup. This puts the same answer in the preview, with the attribute to paste\n * one click away.\n *\n * Since ADR 0014 it answers a second question the same way: which bindings the\n * runtime *guessed* (`autoBind: 'unique'`) rather than read from the template.\n * Those are listed apart, with the value each one matched on, so an element\n * that changes without an attribute in the source is never a mystery — and\n * the button offers the attribute that would make the guess a declaration.\n *\n * It is a plugin, not part of the runtime: the inline artifact every page\n * carries must not grow by a development tool (the budget in\n * `scripts/bundle-budgets.ts` is the proof). Register it on a client you build\n * yourself, and only in development.\n */\n\nimport type { LivePreviewPlugin, PluginDisposer } from '../types';\nimport {\n COVERS_ATTRIBUTE,\n DEPENDS_ATTRIBUTE,\n FIELD_ATTRIBUTE,\n GUESSED_ATTRIBUTE,\n renderingStrategy,\n} from '@core/cache';\nimport { parseDependencyList } from '@core/dependencies';\nimport { isInsideIsland } from '@core/islands';\nimport {\n createNameAddressability,\n SYSTEM_FIELD_NAMES,\n uncoveredNamePaths,\n type ServerRendering,\n} from '@core/unbound-fields';\n\nconst ELEMENT_ID = 'payload-live-preview-unbound';\n\nexport interface UnboundFieldsOverlayOptions {\n /**\n * Mount only when the client runs with `debug: true`. Default `true`: the\n * overlay is a development tool, and a production preview should not grow one\n * because a plugin list was copied between environments.\n */\n readonly onlyWithDebug?: boolean;\n /** Where to look for bindings and where to mount. Default `document`. */\n readonly root?: Document | Element;\n /** Corner of the preview to sit in. Default `'bottom-right'`. */\n readonly position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n}\n\nconst POSITIONS: Readonly<Record<NonNullable<UnboundFieldsOverlayOptions['position']>, string>> = {\n 'bottom-right': 'bottom:12px;right:12px;',\n 'bottom-left': 'bottom:12px;left:12px;',\n 'top-right': 'top:12px;right:12px;',\n 'top-left': 'top:12px;left:12px;',\n};\n\n// Applied through `element.style`, never as a `style` attribute: a strict\n// `style-src` refuses the attribute and would leave the panel unstyled in flow.\nconst PANEL_STYLE =\n 'position:fixed;z-index:2147483646;max-width:280px;max-height:40vh;overflow:auto;' +\n 'font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;background:#111;color:#eee;' +\n 'border:1px solid #333;border-radius:6px;padding:8px 10px;box-shadow:0 4px 16px rgba(0,0,0,0.4);';\n\nconst BUTTON_STYLE =\n 'display:block;width:100%;text-align:left;margin:2px 0;padding:2px 4px;border:0;border-radius:3px;' +\n 'background:#222;color:#7fd1ff;font:inherit;cursor:pointer;';\n\n/**\n * The document this update named, minus everything the page can already show\n * or declares with `data-payload-covers`. Under `subfieldCoverage: 'declared'`\n * the uncovered paths inside partly bound groups are listed too (ADR 0022).\n * @internal\n */\nexport function unboundFieldNames(\n fields: Readonly<Record<string, unknown>>,\n boundNames: Iterable<string>,\n locale?: string,\n coverPaths: readonly string[] = [],\n subfieldCoverage: 'descendant' | 'declared' = 'descendant',\n): readonly string[] {\n const bound = [...boundNames];\n const addressable = createNameAddressability(bound, locale, coverPaths);\n const names = Object.keys(fields).filter(\n (name) => !SYSTEM_FIELD_NAMES.has(name) && !addressable(name),\n );\n if (subfieldCoverage === 'declared') {\n names.push(...uncoveredNamePaths(fields, bound, locale, coverPaths));\n }\n return [...new Set(names)].sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * The declared covers and, as in the runtime (ADR 0022 §1a), what a boundary\n * or route marker depends on when the client has the strategy that renders it.\n */\nfunction coverPathsIn(root: Document | Element, rendering: ServerRendering): string[] {\n const paths: string[] = [];\n for (const element of root.querySelectorAll(`[${COVERS_ATTRIBUTE}]`)) {\n paths.push(...parseDependencyList(element.getAttribute(COVERS_ATTRIBUTE)));\n }\n for (const element of root.querySelectorAll(`[${DEPENDS_ATTRIBUTE}]`)) {\n const strategy = renderingStrategy(element);\n if (strategy === undefined || rendering[strategy] === undefined) continue;\n if (!isInsideIsland(element)) {\n paths.push(...parseDependencyList(element.getAttribute(DEPENDS_ATTRIBUTE)));\n }\n }\n return paths;\n}\n\nfunction boundNamesIn(root: Document | Element): string[] {\n const names: string[] = [];\n for (const element of root.querySelectorAll(`[${FIELD_ATTRIBUTE}]`)) {\n const name = element.getAttribute(FIELD_ATTRIBUTE);\n if (name !== null && name.length > 0) names.push(name);\n }\n return names;\n}\n\nexport interface GuessedBinding {\n readonly field: string;\n /** The value the runtime found the element by. */\n readonly matched: string;\n}\n\n/** The bindings the runtime stamped on the page itself, in document order. */\nexport function guessedBindingsIn(root: Document | Element): readonly GuessedBinding[] {\n const guessed: GuessedBinding[] = [];\n for (const element of root.querySelectorAll(`[${GUESSED_ATTRIBUTE}]`)) {\n const field = element.getAttribute(FIELD_ATTRIBUTE);\n if (field === null || field.length === 0) continue;\n guessed.push({ field, matched: element.getAttribute(GUESSED_ATTRIBUTE) ?? '' });\n }\n return guessed;\n}\n\nfunction hostDocument(root: Document | Element): Document | null {\n return root.nodeType === 9 ? (root as Document) : root.ownerDocument;\n}\n\n/** Copy through the async clipboard, falling back to a selection nobody has to see. */\nfunction copy(doc: Document, text: string): void {\n const clipboard: unknown = doc.defaultView?.navigator.clipboard;\n if (clipboard !== undefined && clipboard !== null) {\n void (clipboard as Clipboard).writeText(text).catch(() => {\n selectInstead(doc, text);\n });\n return;\n }\n selectInstead(doc, text);\n}\n\nfunction selectInstead(doc: Document, text: string): void {\n const field = doc.createElement('textarea');\n field.value = text;\n field.setAttribute('readonly', '');\n field.style.cssText = 'position:fixed;opacity:0;pointer-events:none;';\n doc.body.append(field);\n field.select();\n field.remove();\n}\n\ninterface Overlay {\n readonly update: (names: readonly string[], guessed: readonly GuessedBinding[]) => void;\n readonly destroy: PluginDisposer;\n}\n\n/** One click copies the attribute to paste into the template. */\nfunction copyButton(doc: Document, field: string, label: string): HTMLButtonElement {\n const button = doc.createElement('button');\n button.type = 'button';\n button.textContent = label;\n button.style.cssText = BUTTON_STYLE;\n button.title = `Copy ${FIELD_ATTRIBUTE}=\"${field}\"`;\n button.addEventListener('click', () => {\n copy(doc, `${FIELD_ATTRIBUTE}=\"${field}\"`);\n button.textContent = `${label} ✓`;\n });\n return button;\n}\n\nfunction mountOverlay(root: Document | Element, position: string): Overlay | null {\n const doc = hostDocument(root);\n if (doc?.body == null) return null;\n const panel = doc.createElement('aside');\n panel.id = ELEMENT_ID;\n panel.style.cssText = PANEL_STYLE + position;\n // Development furniture, not content: no screen reader should read it, and\n // no binding scan should ever reach into it.\n panel.setAttribute('aria-hidden', 'true');\n panel.hidden = true;\n const heading = (text: string): HTMLElement => {\n const title = doc.createElement('div');\n title.textContent = text;\n title.style.cssText = 'font-weight:600;margin-bottom:4px;';\n return title;\n };\n const unboundTitle = heading('Unbound fields');\n const list = doc.createElement('div');\n // Apart from the unbound ones on purpose: a guessed field is bound, but by\n // the runtime's reading of the page, not by the template's say-so.\n const guessedTitle = heading('Guessed bindings');\n guessedTitle.setAttribute('data-testid', 'guessed-bindings');\n const guessedList = doc.createElement('div');\n panel.append(unboundTitle, list, guessedTitle, guessedList);\n doc.body.append(panel);\n\n return {\n update: (names, guessed) => {\n // A page that rewrote its body (a framework re-render, a route morph)\n // took the panel with it and may have left a serialized copy behind.\n // Re-attaching the real one is cheaper than watching for the rewrite.\n if (!panel.isConnected) {\n doc.getElementById(ELEMENT_ID)?.remove();\n doc.body.append(panel);\n }\n panel.hidden = names.length === 0 && guessed.length === 0;\n unboundTitle.hidden = names.length === 0;\n list.replaceChildren(...names.map((name) => copyButton(doc, name, name)));\n guessedTitle.hidden = guessed.length === 0;\n guessedList.replaceChildren(\n ...guessed.map(({ field, matched }) =>\n copyButton(doc, field, `${field} ← ${JSON.stringify(matched)}`),\n ),\n );\n },\n destroy: () => {\n panel.remove();\n },\n };\n}\n\n/**\n * ```ts\n * client.use(createUnboundFieldsOverlayPlugin());\n * ```\n *\n * Every update recomputes the list from the message's own fields and the\n * bindings currently in the DOM, so annotating the template makes entries\n * disappear as you save the file.\n */\nexport function createUnboundFieldsOverlayPlugin(\n options: UnboundFieldsOverlayOptions = {},\n): LivePreviewPlugin {\n return {\n name: 'unbound-fields',\n version: '1.0.0',\n init: (ctx) => {\n const root = options.root ?? (typeof document === 'undefined' ? undefined : document);\n if (root === undefined) return;\n if ((options.onlyWithDebug ?? true) && ctx.getConfig()['debug'] !== true) {\n ctx.log('not mounted: the client runs without `debug: true`');\n return;\n }\n const overlay = mountOverlay(root, POSITIONS[options.position ?? 'bottom-right']);\n if (overlay === null) return;\n ctx.registerCleanup?.(overlay.destroy);\n const mode = ctx.getConfig()['subfieldCoverage'] === 'declared' ? 'declared' : 'descendant';\n const rendering = (ctx.getConfig()['strategies'] ?? {}) as ServerRendering;\n ctx.events.on('afterUpdate', (e) => {\n const names = unboundFieldNames(\n e.data.fields,\n boundNamesIn(root),\n e.data.locale,\n coverPathsIn(root, rendering),\n mode,\n );\n const guessed = guessedBindingsIn(root);\n overlay.update(names, guessed);\n if (names.length > 0) ctx.log('unbound:', names.join(', '));\n if (guessed.length > 0) ctx.log('guessed:', guessed.map((g) => g.field).join(', '));\n });\n },\n };\n}\n","/**\n * Per-instance typed emitter: handlers run sequentially in registration order,\n * may be async, and a throwing one is logged and isolated. See ADR 0002.\n */\n\nimport type { EventHandler, LivePreviewEventMap, Unsubscribe } from './types';\nimport { safeConsoleError } from '@core/diagnostics';\n\ntype AnyHandler = EventHandler<unknown>;\n\n// `object`, not `Record<string, unknown>`: interfaces with readonly and\n// exact-optional properties must be usable as maps.\nexport class EventEmitter<TMap extends object = LivePreviewEventMap> {\n readonly #regular = new Map<keyof TMap, Set<AnyHandler>>();\n readonly #once = new Map<keyof TMap, Set<AnyHandler>>();\n\n on<E extends keyof TMap>(event: E, handler: EventHandler<TMap[E]>): Unsubscribe {\n return this.#register(this.#regular, event, handler as AnyHandler);\n }\n\n once<E extends keyof TMap>(event: E, handler: EventHandler<TMap[E]>): Unsubscribe {\n return this.#register(this.#once, event, handler as AnyHandler);\n }\n\n off<E extends keyof TMap>(event: E, handler: EventHandler<TMap[E]>): void {\n this.#remove(this.#regular, event, handler as AnyHandler);\n this.#remove(this.#once, event, handler as AnyHandler);\n }\n\n /** Dispatch to every handler: regular ones first, then `once` handlers. */\n async emit<E extends keyof TMap>(event: E, payload: TMap[E]): Promise<void> {\n await this.#emitSequential(event, payload);\n }\n\n /**\n * Dispatch while `shouldContinue()` holds — checked around every handler, so\n * an obsolete transaction cannot resume across an await.\n * @internal\n */\n async emitWhile<E extends keyof TMap>(\n event: E,\n payload: TMap[E],\n shouldContinue: () => boolean,\n ): Promise<boolean> {\n return this.#emitSequential(event, payload, shouldContinue);\n }\n\n async #emitSequential<E extends keyof TMap>(\n event: E,\n payload: TMap[E],\n shouldContinue?: () => boolean,\n ): Promise<boolean> {\n const eligible = (): boolean => shouldContinue?.() ?? true;\n if (!eligible()) return false;\n const regular = this.#regular.get(event);\n if (regular) {\n for (const handler of [...regular]) {\n if (!eligible()) return false;\n await this.#invoke(handler, payload, event);\n if (!eligible()) return false;\n }\n }\n if (!eligible()) return false;\n const once = this.#once.get(event);\n if (once && once.size > 0) {\n const snapshot = [...once];\n this.#once.delete(event);\n for (const handler of snapshot) {\n if (!eligible()) return false;\n await this.#invoke(handler, payload, event);\n if (!eligible()) return false;\n }\n }\n return eligible();\n }\n\n /** Registered handlers for `event`, `on` and `once` together. */\n listenerCount(event: keyof TMap): number {\n return (this.#regular.get(event)?.size ?? 0) + (this.#once.get(event)?.size ?? 0);\n }\n\n /** Remove every handler, or only those of `event`. */\n removeAllListeners(event?: keyof TMap): void {\n if (event === undefined) {\n this.#regular.clear();\n this.#once.clear();\n return;\n }\n this.#regular.delete(event);\n this.#once.delete(event);\n }\n\n /** Event names with at least one handler. */\n eventNames(): (keyof TMap)[] {\n const names = new Set<keyof TMap>();\n for (const key of this.#regular.keys()) names.add(key);\n for (const key of this.#once.keys()) names.add(key);\n return [...names];\n }\n\n #register(\n bucket: Map<keyof TMap, Set<AnyHandler>>,\n event: keyof TMap,\n handler: AnyHandler,\n ): Unsubscribe {\n let set = bucket.get(event);\n if (!set) {\n set = new Set();\n bucket.set(event, set);\n }\n set.add(handler);\n return () => {\n this.#remove(bucket, event, handler);\n };\n }\n\n #remove(bucket: Map<keyof TMap, Set<AnyHandler>>, event: keyof TMap, handler: AnyHandler): void {\n const set = bucket.get(event);\n if (set === undefined) return;\n set.delete(handler);\n if (set.size === 0) bucket.delete(event);\n }\n\n async #invoke(handler: AnyHandler, payload: unknown, event: keyof TMap): Promise<void> {\n try {\n await handler(payload);\n } catch (err) {\n const label =\n typeof event === 'string' || typeof event === 'number' ? String(event) : '<event>';\n safeConsoleError(`[live-preview] LP0601: handler for \"${label}\" threw:`, err);\n }\n }\n}\n","/**\n * Every diagnostic code the runtime and tools emit, so a consumer can branch\n * on `e.code` instead of matching message text. A code is never reused for a\n * different meaning; a retired one stays reserved.\n *\n * Browser-side reporting sites write the literal (`code: 'LP0603'`) rather than\n * reading it from this record: the frozen table would then ship in the inline\n * runtime for the sake of six characters — it did, 1 287 B in every page, for\n * the one read Z6 left in the strategy runner, and `diagnostic-codes.test.ts`\n * now holds the artifact free of it. Server-side tools may import it.\n */\n\n/**\n * Every diagnostic code the runtime can report, by name.\n *\n * ```ts\n * client.events.on('error', (e) => {\n * if (e.code === DIAGNOSTIC_CODES.TransformThrew) reportToSentry(e.error);\n * });\n * ```\n */\nexport const DIAGNOSTIC_CODES = Object.freeze({\n /** No trusted origin configured in production; nothing will be accepted. */\n NoTrustedOrigin: 'LP0101',\n /** Origin trust rests on `document.referrer`, so any framing site is trusted. */\n ReferrerOnlyTrust: 'LP0102',\n /** A plugin declares a runtime range this runtime does not satisfy; it was refused. */\n PluginIncompatible: 'LP0103',\n /** The page carries the lean runtime and needs a feature that profile leaves out. */\n ProfileFeatureOmitted: 'LP0104',\n\n /** An update named an empty field with no binding anchor on the page; an edit to it has nowhere to land. */\n OrphanField: 'LP0201',\n /** Owner scoping is on and the update names no document it could belong to. */\n UnattributableUpdate: 'LP0202',\n /** An update carried a value for a field the page binds nowhere; editing it changes nothing on this page. */\n UnboundField: 'LP0203',\n /** In development: a bound path covers its group under the `descendant` default, which 3.0 changes. */\n CoverageDefaultChanges: 'LP0204',\n\n /** The visibility gate held offscreen writes back until they scroll into view. */\n VisibilityGateDeferred: 'LP0301',\n\n /** A value was refused because the attribute or the value itself is unsafe. */\n UnsafeAttributeWrite: 'LP0401',\n /** A text element has structured children, so replacing its text was skipped. */\n TextTargetHasChildren: 'LP0402',\n /** A structural container has no array template, so the update was skipped. */\n MissingArrayTemplate: 'LP0403',\n /** A structural item has no `id`; it pairs positionally, so an insert re-renders every row after it. */\n StructuralItemUnkeyed: 'LP0404',\n /** Two structural items share a key; later ones pair positionally. */\n StructuralDuplicateKey: 'LP0405',\n /** Every structural key changed while the length did not; the source generates keys per message. */\n StructuralUnstableKeys: 'LP0406',\n /** A binding asks for a delivery strategy this release does not have; it is left unchanged. */\n UnsupportedStrategy: 'LP0407',\n /** `data-payload-format` names a format the vocabulary does not contain; the default formatting was used instead. */\n UnknownValueFormat: 'LP0408',\n /** The strict sanitizer removed an attribute the 1.x `'compat'` policy kept. */\n SanitizerDroppedAttribute: 'LP0409',\n /** A Lexical block has no renderer; the markup the server rendered for it is kept instead. */\n UnrenderedBlockKept: 'LP0410',\n /** A patch cannot reach what the server would have drawn; `onUnfaithfulPatch` decided what happens next. */\n UnfaithfulPatch: 'LP0411',\n /** The first write to a date, number, checkbox, select or radio binding replaced a different reading of the same value. */\n ServerFormatReplaced: 'LP0412',\n /** A Lexical block has no renderer, and the write could not keep the markup the server rendered for it; it is gone. */\n UnrenderedBlockLost: 'LP0413',\n\n /** A message was rejected before it reached the update pipeline. */\n MessageRejected: 'LP0501',\n /** A preview token was rejected. */\n TokenRejected: 'LP0502',\n /** A trusted origin sent a message this protocol version does not recognise. */\n ProtocolShapeUnknown: 'LP0503',\n\n /** A consumer event handler threw. */\n HandlerThrew: 'LP0601',\n /** A consumer transform threw; the original value was kept. */\n TransformThrew: 'LP0602',\n /** A renderer threw while writing a value. */\n RendererThrew: 'LP0603',\n // LP0604 is reserved and unassigned; codes are never reused or renumbered.\n /** Runtime startup failed. */\n StartupFailed: 'LP0605',\n /** Sending the ready handshake failed. */\n ReadyFailed: 'LP0606',\n /** The page declared hydration, but no React commit, Vue mount, SvelteKit mount or `markHydrated()` call came within the cap; the runtime started without waiting. */\n HydrationWaitTimedOut: 'LP0607',\n\n /** The audit found no runtime in a response that carried preview intent. */\n AuditRuntimeMissing: 'LP0701',\n /** The preview response declares no `frame-ancestors`. */\n AuditNoFrameAncestors: 'LP0702',\n /** `X-Frame-Options` forbids framing on a response that declares no `frame-ancestors`; `SAMEORIGIN` forbids it from another origin only. */\n AuditFrameOptionsBlocks: 'LP0703',\n /** Binding attributes are served to anonymous visitors. */\n AuditBindingsExposed: 'LP0704',\n /** More bindings than the visibility gate will write eagerly. */\n AuditGateThresholdExceeded: 'LP0705',\n /** Owner markers exist, but some bindings are outside all of them. */\n AuditUnownedBindings: 'LP0706',\n /** The preview response carries no bindings and no fragment boundary. */\n AuditNoBindings: 'LP0707',\n /** The URL did not return an HTML page, so nothing else can be judged. */\n AuditNotAPage: 'LP0708',\n /** A fragment request failed (network, timeout, server error); the boundary was patched instead. */\n FragmentRequestFailed: 'LP0801',\n /** The fragment response had the wrong content type or shape; the boundary was patched instead. */\n FragmentResponseInvalid: 'LP0802',\n /** The fragment endpoint refused the preview (not authorized); the boundary was patched instead. */\n FragmentUnauthorized: 'LP0803',\n /** A fragment response arrived for a revision that was already superseded and was discarded. */\n FragmentSuperseded: 'LP0804',\n /** A route refresh was refused: the loop guard, or the strategy's minimum interval. */\n RouteRefreshLoop: 'LP0805',\n /** A boundary asks for the fragment strategy but no fragment handler is configured; it is patched. */\n FragmentStrategyUnavailable: 'LP0806',\n /** A revision changed a field with no binding; `onUnfaithfulPatch` refreshed the route. */\n UnboundChangeRefresh: 'LP0807',\n /** `onUnfaithfulPatch: 'escalate'` found no route or fragment strategy, or no boundary, to hand an unfaithful patch to; the page keeps it. */\n EscalationUnavailable: 'LP0808',\n /** A fragment inserted an Astro island the page cannot start: it never loaded the island element or that client directive. */\n IslandStartUnavailable: 'LP0809',\n /** The host's route refresh returned no promise, so the revision was re-applied before the host committed. */\n RouteRefreshUnconfirmed: 'LP0810',\n /** A readiness row is not yet at its 2.0 value; `pll doctor --v2` reports it. */\n V2ReadinessGap: 'LP0709',\n /** The preview runtime is served to anonymous visitors, not only inside the admin frame. */\n RuntimeOnPublicPage: 'LP0710',\n /** An element carries attributes that only mean something beside `data-payload-field`, and has none. */\n AuditModifierWithoutField: 'LP0711',\n} as const);\n\n/** A diagnostic code, as it appears in log output and on the `error` event. */\nexport type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];\n","/**\n * Per-instance plugin manager. Mutations run through one call-order queue;\n * while a queue-held hook is pending, a requested mutation takes the direct\n * path because that hook may be awaiting it. See ADR 0005.\n */\n\nimport type { FieldRenderer } from '@core/types';\nimport type { PluginInspection } from '@core/inspection/types';\nimport { LIBRARY_PROTOCOL_VERSION } from '@core/protocol-version';\nimport { VERSION } from '@/version';\nimport { incompatibilityOf } from './compat';\nimport { isolateDiagnostic } from '@core/diagnostics';\nimport { observeThenableResult } from '@core/thenable';\nimport type { EventEmitter } from '@events/emitter';\nimport { ResourceScope } from './resource-scope';\nimport { ScopedPluginEvents } from './scoped-events';\nimport type { FieldTransform, LivePreviewPlugin, PluginContext } from './types';\n\nexport interface PluginManagerOptions {\n readonly events: EventEmitter;\n readonly config: Readonly<Record<string, unknown>>;\n /** Add one renderer layer to the host; may return the layer's disposer. */\n readonly registerFieldRenderer: (renderer: FieldRenderer) => void;\n /** Receives transform contract failures for the runtime's `error` event. */\n readonly onTransformError?: (error: Error) => unknown;\n readonly log: (...args: unknown[]) => void;\n}\n\ninterface PluginRegistration {\n readonly plugin: LivePreviewPlugin;\n readonly scope: ResourceScope;\n}\n\ninterface InitializingPluginRegistration {\n readonly scope: ResourceScope;\n cancelled: boolean;\n}\n\ninterface TransformRegistration {\n readonly transform: FieldTransform;\n active: boolean;\n}\n\nfunction isPluginDisposer(value: unknown): value is (() => void) | undefined {\n return typeof value === 'function';\n}\n\nexport class PluginManager {\n readonly #events: EventEmitter;\n readonly #config: Readonly<Record<string, unknown>>;\n // The public callback type is void; the client host returns its layer disposer through it.\n readonly #registerRenderer: (renderer: FieldRenderer) => unknown;\n readonly #onTransformError: ((error: Error) => void) | undefined;\n readonly #log: (...args: unknown[]) => void;\n readonly #plugins = new Map<string, PluginRegistration>();\n readonly #initializing = new Map<string, InitializingPluginRegistration>();\n readonly #teardowns = new Map<string, Promise<void>>();\n readonly #destroying = new Set<string>();\n readonly #transforms = new Map<string, TransformRegistration[]>();\n #mutationQueue: Promise<void> = Promise.resolve();\n // Hooks awaited by the queue entry in flight. Hooks started on the direct\n // path never hold the queue, so they must not open it for others.\n #queuedHooks = 0;\n\n constructor(options: PluginManagerOptions) {\n this.#events = options.events;\n this.#config = options.config;\n this.#registerRenderer = options.registerFieldRenderer;\n this.#log = isolateDiagnostic(options.log);\n const onTransformError = options.onTransformError;\n this.#onTransformError =\n onTransformError === undefined\n ? undefined\n : isolateDiagnostic((...args: unknown[]): unknown => {\n // Private and single-callered: `applyTransforms` normalizes to an\n // Error before it reports one.\n const error = args[0] as Error;\n try {\n return onTransformError(error);\n } catch (reportError) {\n this.#log('transform error reporter failed:', reportError);\n return undefined;\n }\n });\n }\n\n /** Register a plugin transactionally; concurrent mutations run in call order. */\n register(plugin: LivePreviewPlugin): Promise<void> {\n if (this.#queuedHooks > 0) return this.#registerNow(plugin, false);\n return this.#enqueue(() => this.#registerNow(plugin, true));\n }\n\n /** Remove one plugin and every resource its registration created. */\n unregister(name: string): Promise<void> {\n if (this.#queuedHooks > 0) return this.#unregisterNow(name, false);\n return this.#enqueue(async () => {\n await this.#unregisterNow(name, true);\n });\n }\n\n /** Destroy every registration; one failure never strands another. */\n destroyAll(): Promise<void> {\n if (this.#queuedHooks > 0) return this.#destroyAllNow(false);\n return this.#enqueue(async () => {\n await this.#destroyAllNow(true);\n });\n }\n\n /** Apply active transforms in registration order; a failure returns the original value. */\n applyTransforms(\n fieldName: string,\n value: unknown,\n context: { readonly element: Element; readonly allFields: Record<string, unknown> },\n isCurrent?: () => boolean,\n ): unknown {\n const registrations = this.#transforms.get(fieldName);\n if (registrations === undefined || registrations.length === 0) return value;\n\n let result: unknown = value;\n for (const registration of [...registrations]) {\n if (!registration.active) continue;\n const { transform } = registration;\n if (isCurrent?.() === false) return value;\n try {\n result = transform(result, {\n fieldName,\n element: context.element,\n allFields: context.allFields,\n });\n const returnedThenable = observeThenableResult(result);\n // A transform may synchronously let a newer message in; then its\n // result belongs to a superseded revision and is not reported.\n if (isCurrent?.() === false) return value;\n if (returnedThenable) {\n throw new TypeError(\n `Transform for \"${fieldName}\" returned a Promise/thenable; transforms must be synchronous`,\n );\n }\n } catch (error) {\n if (isCurrent?.() === false) return value;\n const normalized = error instanceof Error ? error : new Error(String(error));\n this.#log(`transform for \"${fieldName}\" failed:`, normalized);\n this.#onTransformError?.(normalized);\n return value;\n }\n }\n return result;\n }\n\n list(): readonly string[] {\n return [...this.#plugins.keys()];\n }\n\n /** Every plugin with its state and live registrations (`inspect().plugins`). */\n snapshot(): readonly PluginInspection[] {\n const entries: PluginInspection[] = [];\n const describe = (\n name: string,\n version: string | undefined,\n state: PluginInspection['state'],\n scope: ResourceScope,\n ): PluginInspection => {\n const counts = scope.counts();\n return {\n name,\n version,\n state,\n registrations: {\n transforms: counts.transform,\n renderers: counts.renderer,\n subscriptions: counts.subscription,\n cleanups: counts.cleanup,\n },\n };\n };\n for (const [name, initializing] of this.#initializing) {\n entries.push(describe(name, undefined, 'initializing', initializing.scope));\n }\n for (const [name, registration] of this.#plugins) {\n entries.push(describe(name, registration.plugin.version, 'active', registration.scope));\n }\n // A name with a pending teardown left `#plugins` before the teardown began.\n for (const name of this.#teardowns.keys()) {\n entries.push({\n name,\n version: undefined,\n state: 'tearing-down',\n registrations: { transforms: 0, renderers: 0, subscriptions: 0, cleanups: 0 },\n });\n }\n return entries;\n }\n\n get size(): number {\n return this.#plugins.size;\n }\n\n async #registerNow(plugin: LivePreviewPlugin, queued: boolean): Promise<void> {\n if (\n this.#plugins.has(plugin.name) ||\n this.#initializing.has(plugin.name) ||\n this.#teardowns.has(plugin.name)\n ) {\n this.#log(`plugin \"${plugin.name}\" already registered`);\n return;\n }\n\n const incompatibility = incompatibilityOf(plugin.compat, VERSION, LIBRARY_PROTOCOL_VERSION);\n if (incompatibility !== undefined) {\n this.#refuse(plugin.name, incompatibility);\n return;\n }\n const scope = new ResourceScope(plugin.name, this.#log);\n const context = this.#createContext(plugin.name, scope);\n const initializing: InitializingPluginRegistration = { scope, cancelled: false };\n this.#initializing.set(plugin.name, initializing);\n try {\n await this.#runHook(() => plugin.init(context), queued);\n if (initializing.cancelled) return;\n scope.commit();\n } catch (error) {\n scope.close();\n if (!initializing.cancelled) this.#log(`plugin \"${plugin.name}\" init failed:`, error);\n return;\n } finally {\n if (this.#initializing.get(plugin.name) === initializing) {\n this.#initializing.delete(plugin.name);\n }\n }\n\n this.#plugins.set(plugin.name, { plugin, scope });\n this.#log(`plugin \"${plugin.name}\" registered`);\n }\n\n /** A refused plugin is an integration mistake; it reaches the `error` event, not only the log. */\n #refuse(name: string, reason: string): void {\n const message = `plugin \"${name}\" refused: ${reason}`;\n this.#log(message);\n void this.#events.emit('error', {\n error: new Error(message),\n context: 'plugin',\n code: 'LP0103',\n });\n }\n\n #createContext(pluginName: string, scope: ResourceScope): PluginContext {\n return {\n events: new ScopedPluginEvents(this.#events, scope),\n registerFieldRenderer: (renderer) => {\n scope.stage('renderer', () => {\n const result = this.#registerRenderer(renderer);\n return isPluginDisposer(result) ? result : undefined;\n });\n },\n registerTransform: (fieldName, transform) => {\n const registration: TransformRegistration = { transform, active: false };\n scope.stage('transform', () => {\n registration.active = true;\n const existing = this.#transforms.get(fieldName);\n if (existing === undefined) this.#transforms.set(fieldName, [registration]);\n else existing.push(registration);\n\n return () => {\n registration.active = false;\n const current = this.#transforms.get(fieldName);\n if (current === undefined) return;\n const index = current.indexOf(registration);\n if (index >= 0) current.splice(index, 1);\n if (current.length === 0) this.#transforms.delete(fieldName);\n };\n });\n },\n registerCleanup: (cleanup) => {\n scope.own(cleanup);\n },\n getConfig: () => this.#config,\n log: (...args) => {\n this.#log(`[${pluginName}]`, ...args);\n },\n };\n }\n\n #unregisterNow(name: string, queued: boolean): Promise<void> {\n const initializing = this.#initializing.get(name);\n if (initializing !== undefined) {\n initializing.cancelled = true;\n initializing.scope.close();\n return Promise.resolve();\n }\n\n const existingTeardown = this.#teardowns.get(name);\n if (existingTeardown !== undefined) {\n // A destroy hook removing its own name cannot await the teardown that\n // awaits it; its resources are already revoked, so this is complete.\n if (this.#destroying.has(name)) return Promise.resolve();\n return queued ? this.#holdQueue(existingTeardown) : existingTeardown;\n }\n const registration = this.#plugins.get(name);\n if (registration === undefined) return Promise.resolve();\n\n // Revoke before consumer code runs: a throwing destroy keeps no access,\n // and a same-name registration from inside destroy stays a duplicate.\n this.#plugins.delete(name);\n registration.scope.close();\n const teardown = Promise.resolve().then(() =>\n this.#destroyPlugin(name, registration.plugin, queued),\n );\n this.#teardowns.set(name, teardown);\n void teardown.then(() => {\n if (this.#teardowns.get(name) === teardown) this.#teardowns.delete(name);\n });\n return teardown;\n }\n\n async #destroyPlugin(name: string, plugin: LivePreviewPlugin, queued: boolean): Promise<void> {\n if (plugin.destroy === undefined) return;\n this.#destroying.add(name);\n try {\n await this.#runHook(() => plugin.destroy?.(), queued);\n } catch (error) {\n this.#log(`plugin \"${name}\" destroy failed:`, error);\n } finally {\n this.#destroying.delete(name);\n }\n }\n\n async #destroyAllNow(queued: boolean): Promise<void> {\n for (const initializing of this.#initializing.values()) {\n initializing.cancelled = true;\n initializing.scope.close();\n }\n const names = [...this.#plugins.keys()];\n for (const name of names) await this.#unregisterNow(name, queued);\n }\n\n async #runHook(hook: () => void | Promise<void>, queued: boolean): Promise<void> {\n if (!queued) {\n await hook();\n return;\n }\n await this.#holdQueue(Promise.resolve().then(hook));\n }\n\n async #holdQueue(pending: Promise<void>): Promise<void> {\n this.#queuedHooks += 1;\n try {\n await pending;\n } finally {\n this.#queuedHooks -= 1;\n }\n }\n\n #enqueue(operation: () => void | Promise<void>): Promise<void> {\n const result = this.#mutationQueue.then(operation);\n // Keep the tail usable after an escaped error; the caller still sees it on `result`.\n this.#mutationQueue = result.catch((error: unknown) => {\n this.#log('plugin manager mutation failed:', error);\n });\n return result;\n }\n}\n","/**\n * Plugin compatibility claims. The range grammar is the subset a plugin\n * author writes (`*`, `1.2.3`, `^`, `~`, `>=`, `>`, `<`, `<=`, space-joined\n * conjunctions, `||` alternatives); prerelease tags are ignored.\n */\n\nexport interface PluginCompatibility {\n /** A semver range the runtime's `VERSION` must satisfy, e.g. `>=2.0.0`. */\n readonly runtime?: string;\n /** The highest postMessage protocol version the plugin understands. */\n readonly protocol?: number;\n}\n\ntype Version = readonly [number, number, number];\n\nfunction parseVersion(text: string): Version | undefined {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(text.trim());\n if (match === null) return undefined;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n}\n\nfunction compare(a: Version, b: Version): number {\n for (let index = 0; index < 3; index += 1) {\n const delta = (a[index] ?? 0) - (b[index] ?? 0);\n if (delta !== 0) return delta;\n }\n return 0;\n}\n\nfunction satisfiesComparator(version: Version, comparator: string): boolean {\n const trimmed = comparator.trim();\n if (trimmed === '' || trimmed === '*') return true;\n const match = /^(\\^|~|>=|<=|>|<|=)?\\s*v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(trimmed);\n if (match === null) return false;\n const operator = match[1] ?? '=';\n const target: Version = [Number(match[2]), Number(match[3]), Number(match[4])];\n const order = compare(version, target);\n switch (operator) {\n case '=':\n return order === 0;\n case '>':\n return order > 0;\n case '>=':\n return order >= 0;\n case '<':\n return order < 0;\n case '<=':\n return order <= 0;\n case '~':\n return order >= 0 && version[0] === target[0] && version[1] === target[1];\n case '^':\n if (order < 0) return false;\n if (target[0] > 0) return version[0] === target[0];\n if (target[1] > 0) return version[0] === 0 && version[1] === target[1];\n return version[0] === 0 && version[1] === 0 && version[2] === target[2];\n default:\n return false;\n }\n}\n\n/** Whether `version` satisfies `range`; anything unparsable never satisfies. */\nexport function satisfiesRange(version: string, range: string): boolean {\n const parsed = parseVersion(version);\n if (parsed === undefined) return false;\n const alternatives = range.split('||');\n return alternatives.some((alternative) => {\n const comparators = alternative\n .trim()\n .split(/\\s+/)\n .filter((part) => part.length > 0);\n if (comparators.length === 0) return alternative.trim() === '' && range.trim() === '';\n return comparators.every((comparator) => satisfiesComparator(parsed, comparator));\n });\n}\n\n/** Why a plugin was refused, or `undefined` when it fits. */\nexport function incompatibilityOf(\n compat: PluginCompatibility | undefined,\n runtimeVersion: string,\n protocolVersion: number,\n): string | undefined {\n if (compat === undefined) return undefined;\n if (compat.runtime !== undefined && !satisfiesRange(runtimeVersion, compat.runtime)) {\n return `declares runtime ${compat.runtime}, this runtime is ${runtimeVersion}`;\n }\n if (compat.protocol !== undefined) {\n if (!Number.isInteger(compat.protocol) || compat.protocol < 1) {\n return `declares an invalid protocol version ${String(compat.protocol)}`;\n }\n if (compat.protocol < protocolVersion) {\n return `declares protocol ${String(compat.protocol)}, this runtime speaks ${String(protocolVersion)}`;\n }\n }\n return undefined;\n}\n","/**\n * Protocol negotiation. A capability is granted either by the version a peer\n * announces or by observation, since the stock Payload admin announces none:\n * what it can do is read off the messages it sends. See ADR 0010.\n */\n\n/** Bumped only when this library's understanding of the wire format changes. @internal */\nexport const LIBRARY_PROTOCOL_VERSION = 4;\n\n/** How a capability becomes active. @internal */\nexport type CapabilitySource = 'version' | 'observed';\n\n/** @internal */\nexport interface CapabilityDeclaration {\n /** Enabled once the negotiated version reaches this (for announced peers). */\n readonly since: number;\n /** The wire signal that grants this capability to a peer announcing no version. */\n readonly observed?:\n 'schema' | 'locale' | 'preview-token' | 'document-event' | 'relationship-event';\n}\n\n/** What activates each capability; the prose lives in `CAPABILITY_DOCUMENTATION`. */\nexport const CAPABILITY_DECLARATIONS = {\n basic: { since: 1 },\n 'schema-json': { since: 2, observed: 'schema' },\n locale: { since: 2, observed: 'locale' },\n 'preview-token': { since: 3, observed: 'preview-token' },\n 'nested-arrays': { since: 4 },\n 'recursive-diffs': { since: 4 },\n 'document-events': { since: 4, observed: 'document-event' },\n 'relationship-events': { since: 4, observed: 'relationship-event' },\n} as const satisfies Record<string, CapabilityDeclaration>;\n\nexport type ProtocolCapability = keyof typeof CAPABILITY_DECLARATIONS;\n\n/** Every declared capability, in declaration order. @internal */\nexport const PROTOCOL_CAPABILITIES = Object.keys(\n CAPABILITY_DECLARATIONS,\n) as readonly ProtocolCapability[];\n\nexport interface ProtocolNegotiation {\n /** This library's protocol version. */\n readonly ours: number;\n /** The remote party's version, when it announced one. */\n readonly theirs: number | undefined;\n /** `min(ours, theirs ?? 1)` — the version both sides actually share. */\n readonly negotiated: number;\n /** Capabilities active at the negotiated version or seen on the wire. */\n readonly capabilities: ReadonlySet<ProtocolCapability>;\n /** The subset that was observed on the wire rather than granted by version. */\n readonly observed: ReadonlySet<ProtocolCapability>;\n}\n\n/** Deterministic; the runtime re-runs it whenever either input changes. */\nexport function negotiateProtocol(\n theirs: number | undefined,\n observed: Iterable<ProtocolCapability> = [],\n): ProtocolNegotiation {\n const sanitisedTheirs =\n typeof theirs === 'number' && Number.isFinite(theirs) && theirs >= 1\n ? Math.floor(theirs)\n : undefined;\n const effectiveTheirs = sanitisedTheirs ?? 1;\n const negotiated = Math.min(LIBRARY_PROTOCOL_VERSION, effectiveTheirs);\n const seen = new Set<ProtocolCapability>(observed);\n const capabilities = new Set<ProtocolCapability>();\n for (const capability of PROTOCOL_CAPABILITIES) {\n if (negotiated >= CAPABILITY_DECLARATIONS[capability].since || seen.has(capability)) {\n capabilities.add(capability);\n }\n }\n return {\n ours: LIBRARY_PROTOCOL_VERSION,\n ...(sanitisedTheirs !== undefined ? { theirs: sanitisedTheirs } : { theirs: undefined }),\n negotiated,\n capabilities,\n observed: seen,\n };\n}\n\n/** @internal */\nexport function hasCapability(\n negotiation: ProtocolNegotiation,\n capability: ProtocolCapability,\n): boolean {\n return negotiation.capabilities.has(capability);\n}\n\n/** What a project on Payload 2 hears in development, from the runtime and from a hook. @internal */\nexport const PAYLOAD_2_HINT =\n '[payload-live-preview] This admin sends fieldSchemaJSON, which only Payload 2 does. ' +\n 'Every 2.x release of this package supports Payload 2; 3.0 supports Payload 3 and 4.';\n\n/** The capabilities a single message demonstrates, by its shape alone. */\nexport function observeCapabilities(message: {\n readonly fieldSchemaJSON?: unknown;\n readonly locale?: unknown;\n readonly previewToken?: unknown;\n readonly externallyUpdatedRelationship?: unknown;\n}): readonly ProtocolCapability[] {\n const seen: ProtocolCapability[] = [];\n if (Array.isArray(message.fieldSchemaJSON)) seen.push('schema-json');\n if (typeof message.locale === 'string') seen.push('locale');\n if (typeof message.previewToken === 'string') seen.push('preview-token');\n if (\n typeof message.externallyUpdatedRelationship === 'object' &&\n message.externallyUpdatedRelationship !== null\n ) {\n seen.push('relationship-events');\n }\n return seen;\n}\n","{\n \"name\": \"payload-live-preview\",\n \"version\": \"2.4.0\",\n \"description\": \"Live preview for Payload CMS on server-rendered and static frontends (Astro, Next.js, SvelteKit, Nuxt, plain HTML), with React and Vue hooks for client-rendered apps.\",\n \"author\": \"relative23\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"packageManager\": \"npm@12.0.2\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.cts\",\n \"default\": \"./dist/index.cjs\"\n }\n },\n \"./core\": {\n \"import\": {\n \"types\": \"./dist/core.d.ts\",\n \"default\": \"./dist/core.js\"\n },\n \"require\": {\n \"types\": \"./dist/core.d.cts\",\n \"default\": \"./dist/core.cjs\"\n }\n },\n \"./astro\": {\n \"import\": {\n \"types\": \"./dist/adapters/astro/index.d.ts\",\n \"default\": \"./dist/adapters/astro/index.js\"\n }\n },\n \"./nextjs\": {\n \"import\": {\n \"types\": \"./dist/adapters/nextjs/index.d.ts\",\n \"default\": \"./dist/adapters/nextjs/index.js\"\n },\n \"default\": {\n \"types\": \"./dist/adapters/nextjs/index.d.ts\",\n \"default\": \"./dist/adapters/nextjs/index.js\"\n }\n },\n \"./nextjs/client\": {\n \"import\": {\n \"types\": \"./dist/adapters/nextjs/client.d.ts\",\n \"default\": \"./dist/adapters/nextjs/client.js\"\n }\n },\n \"./sveltekit\": {\n \"import\": {\n \"types\": \"./dist/adapters/sveltekit/index.d.ts\",\n \"default\": \"./dist/adapters/sveltekit/index.js\"\n }\n },\n \"./sveltekit/client\": {\n \"import\": {\n \"types\": \"./dist/adapters/sveltekit/client.d.ts\",\n \"default\": \"./dist/adapters/sveltekit/client.js\"\n }\n },\n \"./nuxt\": {\n \"import\": {\n \"types\": \"./dist/adapters/nuxt/index.d.ts\",\n \"default\": \"./dist/adapters/nuxt/index.js\"\n }\n },\n \"./nuxt/client\": {\n \"import\": {\n \"types\": \"./dist/adapters/nuxt/client.d.ts\",\n \"default\": \"./dist/adapters/nuxt/client.js\"\n }\n },\n \"./nuxt-module\": {\n \"import\": {\n \"types\": \"./dist/adapters/nuxt/module.d.ts\",\n \"default\": \"./dist/adapters/nuxt/module.js\"\n }\n },\n \"./react\": {\n \"import\": {\n \"types\": \"./dist/adapters/react/index.d.ts\",\n \"default\": \"./dist/adapters/react/index.js\"\n }\n },\n \"./vue\": {\n \"import\": {\n \"types\": \"./dist/adapters/vue/index.d.ts\",\n \"default\": \"./dist/adapters/vue/index.js\"\n }\n },\n \"./codegen\": {\n \"import\": {\n \"types\": \"./dist/codegen.d.ts\",\n \"default\": \"./dist/codegen.js\"\n },\n \"require\": {\n \"types\": \"./dist/codegen.d.cts\",\n \"default\": \"./dist/codegen.cjs\"\n }\n },\n \"./codegen/astro\": {\n \"import\": {\n \"types\": \"./dist/codegen-astro.d.ts\",\n \"default\": \"./dist/codegen-astro.js\"\n }\n },\n \"./annotate\": {\n \"import\": {\n \"types\": \"./dist/annotate.d.ts\",\n \"default\": \"./dist/annotate.js\"\n }\n },\n \"./doctor\": {\n \"import\": {\n \"types\": \"./dist/doctor.d.ts\",\n \"default\": \"./dist/doctor.js\"\n }\n },\n \"./migrate\": {\n \"import\": {\n \"types\": \"./dist/migrate.d.ts\",\n \"default\": \"./dist/migrate.js\"\n }\n },\n \"./payload\": {\n \"import\": {\n \"types\": \"./dist/payload.d.ts\",\n \"default\": \"./dist/payload.js\"\n },\n \"require\": {\n \"types\": \"./dist/payload.d.cts\",\n \"default\": \"./dist/payload.cjs\"\n }\n },\n \"./plugin\": {\n \"import\": {\n \"types\": \"./dist/plugin.d.ts\",\n \"default\": \"./dist/plugin.js\"\n },\n \"require\": {\n \"types\": \"./dist/plugin.d.cts\",\n \"default\": \"./dist/plugin.cjs\"\n }\n },\n \"./server\": {\n \"import\": {\n \"types\": \"./dist/server.d.ts\",\n \"default\": \"./dist/server.js\"\n },\n \"require\": {\n \"types\": \"./dist/server.d.cts\",\n \"default\": \"./dist/server.cjs\"\n }\n },\n \"./client\": {\n \"import\": {\n \"types\": \"./dist/client.d.ts\",\n \"default\": \"./dist/client.js\"\n },\n \"require\": {\n \"types\": \"./dist/client.d.cts\",\n \"default\": \"./dist/client.cjs\"\n }\n },\n \"./structural\": {\n \"import\": {\n \"types\": \"./dist/structural.d.ts\",\n \"default\": \"./dist/structural.js\"\n },\n \"require\": {\n \"types\": \"./dist/structural.d.cts\",\n \"default\": \"./dist/structural.cjs\"\n }\n },\n \"./lexical\": {\n \"import\": {\n \"types\": \"./dist/lexical.d.ts\",\n \"default\": \"./dist/lexical.js\"\n },\n \"require\": {\n \"types\": \"./dist/lexical.d.cts\",\n \"default\": \"./dist/lexical.cjs\"\n }\n },\n \"./plugins\": {\n \"import\": {\n \"types\": \"./dist/plugins.d.ts\",\n \"default\": \"./dist/plugins.js\"\n },\n \"require\": {\n \"types\": \"./dist/plugins.d.cts\",\n \"default\": \"./dist/plugins.cjs\"\n }\n },\n \"./lean\": {\n \"import\": {\n \"types\": \"./dist/lean.d.ts\",\n \"default\": \"./dist/lean.js\"\n },\n \"require\": {\n \"types\": \"./dist/lean.d.cts\",\n \"default\": \"./dist/lean.cjs\"\n }\n },\n \"./fragment\": {\n \"import\": {\n \"types\": \"./dist/fragment.d.ts\",\n \"default\": \"./dist/fragment.js\"\n },\n \"require\": {\n \"types\": \"./dist/fragment.d.cts\",\n \"default\": \"./dist/fragment.cjs\"\n }\n },\n \"./astro/RichText.astro\": \"./dist/adapters/astro/RichText.astro\",\n \"./astro/PreviewBoundary.astro\": \"./dist/adapters/astro/PreviewBoundary.astro\",\n \"./astro/middleware-entry\": {\n \"import\": {\n \"types\": \"./dist/adapters/astro/middleware-entry.d.ts\",\n \"default\": \"./dist/adapters/astro/middleware-entry.js\"\n }\n },\n \"./package.json\": \"./package.json\"\n },\n \"bin\": {\n \"pll-codegen\": \"./dist/codegen-cli.js\",\n \"pll\": \"./dist/doctor-cli.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"sideEffects\": false,\n \"scripts\": {\n \"build:runtime\": \"node -e \\\"const c=require('node:child_process'),e={...process.env};if(!e.SOURCE_DATE_EPOCH){const g=c.spawnSync('git',['show','-s','--format=%ct','HEAD'],{encoding:'utf8'});if(g.status===0)e.SOURCE_DATE_EPOCH=g.stdout.trim()}process.exit(c.spawnSync(process.execPath,['--import','tsx',process.argv[1]],{stdio:'inherit',env:e}).status??1)\\\" scripts/build-runtime.ts\",\n \"build\": \"npm run build:runtime && tsx scripts/build-dist.ts && npm run build:assets && npm run test:bundle && npm run test:treeshake && npm run test:edge && npm run test:interaction && npm run test:protocol-semantics\",\n \"build:assets\": \"node -e \\\"const fs=require('node:fs');for(const f of ['RichText','PreviewBoundary','FragmentBridge'])fs.copyFileSync('src/adapters/astro/'+f+'.astro','dist/adapters/astro/'+f+'.astro')\\\"\",\n \"dev\": \"tsup --watch\",\n \"pretest\": \"npm run build:runtime\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:security-corpus\": \"vitest run tests/unit/security/sanitizer-corpus.test.ts tests/unit/property/sanitizer-fuzz.property.test.ts\",\n \"test:unit\": \"vitest run tests/unit\",\n \"test:integration\": \"vitest run tests/integration\",\n \"test:e2e\": \"playwright test\",\n \"test:e2e:next-base-path\": \"playwright test --config playwright.next-base-path.config.ts\",\n \"test:e2e:next-production\": \"playwright test --config playwright.next-production.config.ts\",\n \"test:e2e:next-webpack-production\": \"playwright test --config playwright.next-webpack-production.config.ts\",\n \"test:e2e:next-continuation\": \"playwright test --config playwright.next-continuation.config.ts\",\n \"test:e2e:sveltekit-continuation\": \"playwright test --config playwright.sveltekit-continuation.config.ts\",\n \"test:e2e:nuxt-continuation\": \"playwright test --config playwright.nuxt-continuation.config.ts\",\n \"test:e2e:astro-continuation\": \"playwright test --config playwright.astro-continuation.config.ts\",\n \"test:e2e:astro-resources\": \"playwright test --config playwright.astro-resources.config.ts\",\n \"test:e2e:html-continuation\": \"playwright test --config playwright.html-continuation.config.ts\",\n \"test:e2e:vue-continuation\": \"playwright test --config playwright.vue-continuation.config.ts\",\n \"test:e2e:react-continuation\": \"playwright test --config playwright.react-continuation.config.ts\",\n \"test:e2e:nuxt-production\": \"playwright test --config playwright.nuxt-production.config.ts\",\n \"test:e2e:sveltekit-production\": \"playwright test --config playwright.sveltekit-production.config.ts\",\n \"check:fixtures\": \"tsx scripts/check-fixture-freshness.ts\",\n \"check:generated\": \"tsx scripts/check-generated-runtime.ts\",\n \"test:e2e:real-payload\": \"playwright test --config playwright.real-payload.config.ts\",\n \"test:acl:real-payload\": \"tsx scripts/check-payload-acl.ts\",\n \"test:a11y\": \"playwright test tests/e2e/specs/accessibility.spec.ts\",\n \"test:soak\": \"playwright test --config playwright.soak.config.ts\",\n \"test:browser-bench\": \"playwright test --config playwright.bench.config.ts\",\n \"test:bench\": \"vitest bench tests/benchmarks\",\n \"test:bench:codspeed\": \"vitest bench --run --config vitest.bench.config.ts\",\n \"test:bundle\": \"tsx scripts/check-bundle-size.ts\",\n \"test:interaction\": \"tsx scripts/check-interaction-budgets.ts\",\n \"test:protocol-semantics\": \"tsx scripts/check-protocol-semantics.ts\",\n \"test:upstream-findings\": \"tsx scripts/check-upstream-findings.ts\",\n \"test:treeshake\": \"tsx scripts/check-tree-shaking.ts\",\n \"test:edge\": \"NODE_OPTIONS='--experimental-vm-modules --no-warnings' tsx scripts/check-edge-runtime.ts\",\n \"compat:check\": \"tsx scripts/compat-table.ts --check\",\n \"compat:write\": \"tsx scripts/compat-table.ts --write\",\n \"compat:refresh\": \"tsx scripts/compat-table.ts --refresh\",\n \"compat:record\": \"tsx scripts/record-compat-results.ts && prettier --write quality/compat-matrix.json && tsx scripts/compat-table.ts --write && prettier --write README.md\",\n \"diagnostics:check\": \"tsx scripts/diagnostic-table.ts --check\",\n \"test:package\": \"tsx scripts/check-package.ts\",\n \"audit:gate\": \"tsx scripts/audit-gate.ts\",\n \"test:smoke\": \"tsx scripts/post-publish-smoke.ts\",\n \"test:coverage\": \"vitest run --coverage\",\n \"test:coverage:diff\": \"tsx scripts/coverage-policy.ts\",\n \"test:policy\": \"tsx scripts/test-policy.ts\",\n \"test:architecture\": \"tsx scripts/architecture-policy.ts && tsx scripts/check-complexity.ts && tsx scripts/check-trusted-core.ts && tsx scripts/compare-scope.ts --check && tsx scripts/workflow-contracts.ts && tsx scripts/docs-contracts.ts && tsx scripts/check-resource-inventory.ts && knip --no-progress --treat-config-hints-as-errors\",\n \"test:property\": \"vitest run tests/unit/property\",\n \"test:mutation\": \"stryker run stryker.config.js\",\n \"test:mutation:policy:pr\": \"tsx scripts/mutation-policy.ts --policy quality/mutation-policy-pr.json --report test-results/stryker-pr.json\",\n \"test:mutation:policy:core\": \"tsx scripts/mutation-policy.ts --policy quality/mutation-policy-core.json --report test-results/stryker-core.json\",\n \"test:mutation:policy\": \"tsx scripts/mutation-policy.ts\",\n \"test:leak\": \"node --expose-gc --import tsx scripts/leak-soak.ts\",\n \"test:leak:quick\": \"node --expose-gc --import tsx scripts/leak-soak.ts --quick\",\n \"api:update\": \"npm run build && tsx scripts/check-package.ts --update-api-reports\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"tests/**/*.ts\\\" \\\"scripts/**/*.ts\\\" \\\"*.{js,cjs,mjs,ts,json,jsonc,yml,yaml,md}\\\" \\\"quality/**/*.json\\\" \\\"docs/**/*.md\\\" \\\"type-tests/**/*.md\\\" \\\".prettierrc.json\\\" \\\".changeset/*.{json,md}\\\" \\\".github/**/*.{yml,yaml,json}\\\" \\\"examples/**/*.{ts,tsx,js,cjs,mjs,json}\\\" && prettier --write \\\"type-tests/packed/*.fixture\\\" --parser typescript\",\n \"format:check\": \"prettier --check \\\"src/**/*.ts\\\" \\\"tests/**/*.ts\\\" \\\"scripts/**/*.ts\\\" \\\"*.{js,cjs,mjs,ts,json,jsonc,yml,yaml,md}\\\" \\\"quality/**/*.json\\\" \\\"docs/**/*.md\\\" \\\"type-tests/**/*.md\\\" \\\".prettierrc.json\\\" \\\".changeset/*.{json,md}\\\" \\\".github/**/*.{yml,yaml,json}\\\" \\\"examples/**/*.{ts,tsx,js,cjs,mjs,json}\\\" && prettier --check \\\"type-tests/packed/*.fixture\\\" --parser typescript\",\n \"check\": \"npm run typecheck && npm run lint && npm run format:check && npm run test:policy && npm run test:architecture && npm run compat:check && npm run diagnostics:check && npm run test\",\n \"prepublishOnly\": \"npm run build && npm run check && npm run format:check && npm run test:package\",\n \"changeset\": \"changeset\",\n \"version\": \"changeset version && tsx scripts/sync-lockfile-metadata.ts && npm run build:runtime\",\n \"version:release\": \"npm run version && npm run compat:record\",\n \"release\": \"tsx scripts/publish-artifact.ts\",\n \"test:docs\": \"tsx scripts/docs-contracts.ts\"\n },\n \"devDependencies\": {\n \"@arethetypeswrong/cli\": \"^0.18.5\",\n \"@axe-core/playwright\": \"^4.13.0\",\n \"@changesets/cli\": \"^2.31.1\",\n \"@codspeed/vitest-plugin\": \"^5.7.1\",\n \"@eslint/js\": \"^10.0.1\",\n \"@fast-check/vitest\": \"^0.4.1\",\n \"@microsoft/api-extractor\": \"^7.58.12\",\n \"@payloadcms/live-preview\": \"^3.88.0\",\n \"@playwright/test\": \"^1.62.1\",\n \"@stryker-mutator/core\": \"^9.6.1\",\n \"@stryker-mutator/vitest-runner\": \"^9.6.1\",\n \"@testing-library/react\": \"^16.3.3\",\n \"@types/jsdom\": \"^30.0.0\",\n \"@types/node\": \"^22.20.1\",\n \"@types/react\": \"^19.2.18\",\n \"@types/react-dom\": \"^19.2.7\",\n \"@vitest/coverage-v8\": \"^4.1.12\",\n \"dompurify\": \"^3.4.15\",\n \"esbuild\": \"^0.28.2\",\n \"eslint\": \"^10.8.1\",\n \"fast-check\": \"^4.9.0\",\n \"globals\": \"^17.11.0\",\n \"jsdom\": \"^29.1.1\",\n \"knip\": \"^6.32.2\",\n \"linkedom\": \"^0.18.14\",\n \"prettier\": \"^3.9.6\",\n \"publint\": \"^0.3.23\",\n \"react\": \"^19.3.1\",\n \"react-dom\": \"^19.3.1\",\n \"svelte\": \"^5.57.3\",\n \"terser\": \"^5.46.1\",\n \"ts-morph\": \"^28.0.0\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.23.12\",\n \"typescript\": \"^5.9.3\",\n \"typescript-eslint\": \"^8.67.0\",\n \"vite\": \"^7.3.6\",\n \"vitest\": \"^4.1.12\",\n \"vue\": \"^3.5.44\",\n \"yaml\": \"^2.9.0\"\n },\n \"overrides\": {\n \"qs\": \"6.16.1\",\n \"tsup\": {\n \"esbuild\": \"0.28.2\"\n }\n },\n \"allowScripts\": {\n \"esbuild@0.28.2\": true,\n \"fsevents@2.3.2\": false,\n \"fsevents@2.3.3\": false\n },\n \"keywords\": [\n \"astro\",\n \"astro-payload\",\n \"astro-cms\",\n \"astro-integration\",\n \"astro-live-preview\",\n \"payload\",\n \"payload-cms\",\n \"payload-plugin\",\n \"payload-live-preview\",\n \"live-preview\",\n \"preview\",\n \"cms\",\n \"headless\",\n \"headless-cms\",\n \"lexical\",\n \"sveltekit\",\n \"nuxt\",\n \"nextjs\",\n \"react\",\n \"vue\",\n \"ssr\",\n \"framework-agnostic\"\n ],\n \"peerDependencies\": {\n \"astro\": \">=4.0.0 <8.0.0\",\n \"next\": \"*\",\n \"payload\": \"^2.0.0 || ^3.0.0 || ^4.0.0-0\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\",\n \"svelte\": \">=5\",\n \"ts-morph\": \"^28.0.0\",\n \"vite\": \">=5.4.0 <9.0.0\",\n \"vue\": \">=3.3\"\n },\n \"peerDependenciesMeta\": {\n \"astro\": {\n \"optional\": true\n },\n \"next\": {\n \"optional\": true\n },\n \"payload\": {\n \"optional\": true\n },\n \"react\": {\n \"optional\": true\n },\n \"react-dom\": {\n \"optional\": true\n },\n \"svelte\": {\n \"optional\": true\n },\n \"ts-morph\": {\n \"optional\": true\n },\n \"vue\": {\n \"optional\": true\n },\n \"vite\": {\n \"optional\": true\n }\n },\n \"engines\": {\n \"node\": \">=20.19.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"provenance\": true\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/relative23/payload-live-preview.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/relative23/payload-live-preview/issues\"\n },\n \"homepage\": \"https://github.com/relative23/payload-live-preview#readme\"\n}\n","/** `analytics` plugin: running totals over the update stream, read through `getStats()`. */\n\nimport type { LivePreviewPlugin } from '../types';\n\nexport interface AnalyticsSnapshot {\n readonly updateCount: number;\n readonly totalElements: number;\n readonly totalDurationMs: number;\n readonly averageDurationMs: number;\n}\n\nexport function createAnalyticsPlugin(): LivePreviewPlugin & {\n readonly getStats: () => AnalyticsSnapshot;\n} {\n let updateCount = 0;\n let totalElements = 0;\n let totalDurationMs = 0;\n\n return {\n name: 'analytics',\n version: '1.0.0',\n init: (ctx) => {\n ctx.events.on('afterUpdate', (e) => {\n updateCount += 1;\n totalElements += e.updatedCount;\n totalDurationMs += e.durationMs;\n });\n },\n getStats: (): AnalyticsSnapshot => ({\n updateCount,\n totalElements,\n totalDurationMs,\n averageDurationMs: updateCount === 0 ? 0 : totalDurationMs / updateCount,\n }),\n };\n}\n"],"mappings":"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","ignoreList":[]}