payload-live-preview 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/adapters/astro/index.js +1 -1
- package/dist/adapters/astro/index.js.map +1 -1
- package/dist/adapters/astro/middleware-entry.js +1 -1
- package/dist/adapters/astro/middleware-entry.js.map +1 -1
- package/dist/adapters/nextjs/index.js +1 -1
- package/dist/adapters/nextjs/index.js.map +1 -1
- package/dist/adapters/nuxt/index.js +1 -1
- package/dist/adapters/nuxt/index.js.map +1 -1
- package/dist/adapters/sveltekit/index.js +1 -1
- package/dist/adapters/sveltekit/index.js.map +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/fragment.cjs +1 -1
- package/dist/fragment.cjs.map +1 -1
- package/dist/fragment.js +1 -1
- package/dist/fragment.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lean.cjs +1 -1
- package/dist/lean.cjs.map +1 -1
- package/dist/lean.js +1 -1
- package/dist/lean.js.map +1 -1
- package/dist/lexical.cjs +1 -1
- package/dist/lexical.cjs.map +1 -1
- package/dist/lexical.js +1 -1
- package/dist/lexical.js.map +1 -1
- package/dist/plugins.cjs +1 -1
- package/dist/plugins.cjs.map +1 -1
- package/dist/plugins.js +1 -1
- package/dist/plugins.js.map +1 -1
- package/dist/structural.cjs +2 -2
- package/dist/structural.cjs.map +1 -1
- package/dist/structural.js +2 -2
- package/dist/structural.js.map +1 -1
- package/package.json +3 -1
package/dist/plugins.cjs.map
CHANGED
|
@@ -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","FIELD_ATTRIBUTE","GUESSED_ATTRIBUTE","SYSTEM_FIELD_NAMES","ELEMENT_ID","POSITIONS","unboundFieldNames","boundNames","locale","addressable","covers","fieldName","has","prefix","bound","startsWith","base","suffix","endsWith","slice","stripLocaleSuffix","createNameAddressability","sort","left","right","localeCompare","selectInstead","doc","text","field","setAttribute","body","append","select","copyButton","label","button","type","title","addEventListener","clipboard","defaultView","navigator","writeText","copy","DIAGNOSTIC_CODES","freeze","NoTrustedOrigin","ReferrerOnlyTrust","PluginIncompatible","ProfileFeatureOmitted","OrphanField","UnattributableUpdate","UnboundField","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","V2ReadinessGap","RuntimeOnPublicPage","regular","Map","register","emitSequential","invoke","size","snapshot","key","bucket","err","String","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","entries","describe","renderers","cleanups","push","queued","incompatibility","compat","runtimeVersion","runtime","range","parsed","match","exec","trim","Number","parseVersion","split","some","alternative","comparators","part","every","comparator","trimmed","operator","target","order","a","b","index","delta","compare","satisfiesComparator","satisfiesRange","protocol","isInteger","incompatibilityOf","refuse","createContext","cancelled","runHook","code","registerTransform","current","indexOf","splice","getConfig","existingTeardown","holdQueue","teardown","destroyPlugin","destroy","values","hook","pending","operation","updateCount","totalElements","totalDurationMs","getStats","averageDurationMs","root","onlyWithDebug","overlay","position","nodeType","ownerDocument","hostDocument","panel","hidden","heading","unboundTitle","guessedTitle","guessedList","update","guessed","replaceChildren","map","matched","mountOverlay","querySelectorAll","getAttribute","boundNamesIn","guessedBindingsIn","join","g","strategy","controllers","controller","abort","raw","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/cache.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 every lifecycle event 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 * 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, 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';\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 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\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\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/**\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\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 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 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 }\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 * 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';\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\nfunction hasBinding(cache: ElementCache, fieldName: string, ownerKeys: OwnerScope): boolean {\n const bindings = cache.get(fieldName);\n if (bindings === undefined) return false;\n if (ownerKeys === false) return true;\n return bindings.some((binding) => isBindingInScope(binding.owner, ownerKeys));\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\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): FieldAddressability {\n const names = new Set(boundNames);\n const covers = (fieldName: string): boolean => {\n if (names.has(fieldName)) return true;\n const prefix = `${fieldName}.`;\n for (const bound of names) if (bound.startsWith(prefix)) return true;\n return false;\n };\n return (fieldName) => {\n if (covers(fieldName)) return true;\n const base = stripLocaleSuffix(fieldName, locale);\n return base !== fieldName && covers(base);\n };\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): FieldAddressability {\n let localised: Set<string> | undefined;\n return (fieldName) => {\n if (hasBinding(cache, fieldName, ownerKeys)) return true;\n const base = stripLocaleSuffix(fieldName, locale);\n if (base !== fieldName && hasBinding(cache, base, ownerKeys)) return true;\n if (hasBindingBelow(cache, fieldName, ownerKeys)) return true;\n if (base !== fieldName && hasBindingBelow(cache, base, ownerKeys)) return true;\n localised ??= localisedBindingNames(cache, ownerKeys);\n return localised.has(fieldName);\n };\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): string[] {\n const isAddressable = createFieldAddressability(cache, locale, ownerKeys);\n const unbound: string[] = [];\n for (const fieldName of touched) {\n if (!SYSTEM_FIELD_NAMES.has(fieldName) && !isAddressable(fieldName)) unbound.push(fieldName);\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 { FIELD_ATTRIBUTE, GUESSED_ATTRIBUTE } from '@core/cache';\nimport { createNameAddressability, SYSTEM_FIELD_NAMES } 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\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/** The document this update named, minus everything the page can already show. @internal */\nexport function unboundFieldNames(\n fields: Readonly<Record<string, unknown>>,\n boundNames: Iterable<string>,\n locale?: string,\n): readonly string[] {\n const addressable = createNameAddressability(boundNames, locale);\n return Object.keys(fields)\n .filter((name) => !SYSTEM_FIELD_NAMES.has(name) && !addressable(name))\n .sort((left, right) => left.localeCompare(right));\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.setAttribute('style', '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.setAttribute('style', 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.setAttribute('style', 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.setAttribute('style', '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 ctx.events.on('afterUpdate', (e) => {\n const names = unboundFieldNames(e.data.fields, boundNamesIn(root), e.data.locale);\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\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 or checkbox 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 or Vue mount 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, which no CSP can undo; `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 default 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 at all. */\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 to hand an unfaithful patch to; the page keeps it. */\n EscalationUnavailable: 'LP0808',\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} 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/** 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.0.4\",\n \"description\": \"Live preview for Payload CMS on server-rendered and static frontends (Astro, Next.js, SvelteKit, Nuxt, plain HTML): DOM patches, server-rendered fragments, React and Vue hooks. Strict by default, zero dependencies.\",\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 },\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 \"./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'])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:unit\": \"vitest run tests/unit\",\n \"test:integration\": \"vitest run tests/integration\",\n \"test:e2e\": \"playwright test\",\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: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 \"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 && 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 \"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.11\",\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 \"prettier\": \"^3.9.6\",\n \"publint\": \"^0.3.23\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\",\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.11\",\n \"vue\": \"^3.5.42\",\n \"yaml\": \"^2.9.0\"\n },\n \"overrides\": {\n \"qs\": \"6.15.3\",\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-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 \"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 \"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","FIELD_ATTRIBUTE","GUESSED_ATTRIBUTE","SYSTEM_FIELD_NAMES","ELEMENT_ID","POSITIONS","unboundFieldNames","boundNames","locale","addressable","covers","fieldName","has","prefix","bound","startsWith","base","suffix","endsWith","slice","stripLocaleSuffix","createNameAddressability","sort","left","right","localeCompare","selectInstead","doc","text","field","setAttribute","body","append","select","copyButton","label","button","type","title","addEventListener","clipboard","defaultView","navigator","writeText","copy","DIAGNOSTIC_CODES","freeze","NoTrustedOrigin","ReferrerOnlyTrust","PluginIncompatible","ProfileFeatureOmitted","OrphanField","UnattributableUpdate","UnboundField","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","V2ReadinessGap","RuntimeOnPublicPage","regular","Map","register","emitSequential","invoke","size","snapshot","key","bucket","err","String","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","entries","describe","renderers","cleanups","push","queued","incompatibility","compat","runtimeVersion","runtime","range","parsed","match","exec","trim","Number","parseVersion","split","some","alternative","comparators","part","every","comparator","trimmed","operator","target","order","a","b","index","delta","compare","satisfiesComparator","satisfiesRange","protocol","isInteger","incompatibilityOf","refuse","createContext","cancelled","runHook","code","registerTransform","current","indexOf","splice","getConfig","existingTeardown","holdQueue","teardown","destroyPlugin","destroy","values","hook","pending","operation","updateCount","totalElements","totalDurationMs","getStats","averageDurationMs","root","onlyWithDebug","overlay","position","nodeType","ownerDocument","hostDocument","panel","hidden","heading","unboundTitle","guessedTitle","guessedList","update","guessed","replaceChildren","map","matched","mountOverlay","querySelectorAll","getAttribute","boundNamesIn","guessedBindingsIn","join","g","strategy","controllers","controller","abort","raw","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/cache.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 every lifecycle event 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 * 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, 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';\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 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\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\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/**\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\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 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 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 }\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 * 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';\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\nfunction hasBinding(cache: ElementCache, fieldName: string, ownerKeys: OwnerScope): boolean {\n const bindings = cache.get(fieldName);\n if (bindings === undefined) return false;\n if (ownerKeys === false) return true;\n return bindings.some((binding) => isBindingInScope(binding.owner, ownerKeys));\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\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): FieldAddressability {\n const names = new Set(boundNames);\n const covers = (fieldName: string): boolean => {\n if (names.has(fieldName)) return true;\n const prefix = `${fieldName}.`;\n for (const bound of names) if (bound.startsWith(prefix)) return true;\n return false;\n };\n return (fieldName) => {\n if (covers(fieldName)) return true;\n const base = stripLocaleSuffix(fieldName, locale);\n return base !== fieldName && covers(base);\n };\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): FieldAddressability {\n let localised: Set<string> | undefined;\n return (fieldName) => {\n if (hasBinding(cache, fieldName, ownerKeys)) return true;\n const base = stripLocaleSuffix(fieldName, locale);\n if (base !== fieldName && hasBinding(cache, base, ownerKeys)) return true;\n if (hasBindingBelow(cache, fieldName, ownerKeys)) return true;\n if (base !== fieldName && hasBindingBelow(cache, base, ownerKeys)) return true;\n localised ??= localisedBindingNames(cache, ownerKeys);\n return localised.has(fieldName);\n };\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): string[] {\n const isAddressable = createFieldAddressability(cache, locale, ownerKeys);\n const unbound: string[] = [];\n for (const fieldName of touched) {\n if (!SYSTEM_FIELD_NAMES.has(fieldName) && !isAddressable(fieldName)) unbound.push(fieldName);\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 { FIELD_ATTRIBUTE, GUESSED_ATTRIBUTE } from '@core/cache';\nimport { createNameAddressability, SYSTEM_FIELD_NAMES } 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\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/** The document this update named, minus everything the page can already show. @internal */\nexport function unboundFieldNames(\n fields: Readonly<Record<string, unknown>>,\n boundNames: Iterable<string>,\n locale?: string,\n): readonly string[] {\n const addressable = createNameAddressability(boundNames, locale);\n return Object.keys(fields)\n .filter((name) => !SYSTEM_FIELD_NAMES.has(name) && !addressable(name))\n .sort((left, right) => left.localeCompare(right));\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.setAttribute('style', '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.setAttribute('style', 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.setAttribute('style', 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.setAttribute('style', '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 ctx.events.on('afterUpdate', (e) => {\n const names = unboundFieldNames(e.data.fields, boundNamesIn(root), e.data.locale);\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\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 or checkbox 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 or Vue mount 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, which no CSP can undo; `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 default 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 at all. */\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 to hand an unfaithful patch to; the page keeps it. */\n EscalationUnavailable: 'LP0808',\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} 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/** 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.0.6\",\n \"description\": \"Live preview for Payload CMS on server-rendered and static frontends (Astro, Next.js, SvelteKit, Nuxt, plain HTML): DOM patches, server-rendered fragments, React and Vue hooks. Strict by default, zero dependencies.\",\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 },\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 \"./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'])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 \"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: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 \"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 && 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 \"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.11\",\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 \"prettier\": \"^3.9.6\",\n \"publint\": \"^0.3.23\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\",\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.11\",\n \"vue\": \"^3.5.42\",\n \"yaml\": \"^2.9.0\"\n },\n \"overrides\": {\n \"qs\": \"6.15.3\",\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-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 \"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 \"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":[]}
|