payload-live-preview 2.0.0-beta.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +60 -775
  2. package/dist/adapters/astro/PreviewBoundary.astro +2 -2
  3. package/dist/adapters/astro/index.d.ts +28 -154
  4. package/dist/adapters/astro/index.js +1 -1
  5. package/dist/adapters/astro/index.js.map +1 -1
  6. package/dist/adapters/astro/middleware-entry.d.ts +3 -2
  7. package/dist/adapters/astro/middleware-entry.js +1 -1
  8. package/dist/adapters/astro/middleware-entry.js.map +1 -1
  9. package/dist/adapters/nextjs/index.d.ts +247 -6
  10. package/dist/adapters/nextjs/index.js +1 -1
  11. package/dist/adapters/nextjs/index.js.map +1 -1
  12. package/dist/adapters/nuxt/index.d.ts +58 -3
  13. package/dist/adapters/nuxt/index.js +1 -1
  14. package/dist/adapters/nuxt/index.js.map +1 -1
  15. package/dist/adapters/nuxt/module.d.ts +82 -0
  16. package/dist/adapters/nuxt/module.js +2 -0
  17. package/dist/adapters/nuxt/module.js.map +1 -0
  18. package/dist/adapters/react/index.d.ts +110 -0
  19. package/dist/adapters/react/index.js +3 -0
  20. package/dist/adapters/react/index.js.map +1 -0
  21. package/dist/adapters/sveltekit/index.d.ts +65 -7
  22. package/dist/adapters/sveltekit/index.js +1 -1
  23. package/dist/adapters/sveltekit/index.js.map +1 -1
  24. package/dist/adapters/vue/index.d.ts +56 -0
  25. package/dist/adapters/vue/index.js +2 -0
  26. package/dist/adapters/vue/index.js.map +1 -0
  27. package/dist/annotate.d.ts +161 -0
  28. package/dist/annotate.js +2 -0
  29. package/dist/annotate.js.map +1 -0
  30. package/dist/client.cjs +1 -1
  31. package/dist/client.cjs.map +1 -1
  32. package/dist/client.d.cts +182 -9
  33. package/dist/client.d.ts +182 -9
  34. package/dist/client.js +1 -1
  35. package/dist/client.js.map +1 -1
  36. package/dist/codegen-astro.js +1 -1
  37. package/dist/codegen-astro.js.map +1 -1
  38. package/dist/codegen-cli.js +1 -1
  39. package/dist/codegen-cli.js.map +1 -1
  40. package/dist/codegen.cjs +1 -1
  41. package/dist/codegen.cjs.map +1 -1
  42. package/dist/codegen.d.cts +129 -4
  43. package/dist/codegen.d.ts +129 -4
  44. package/dist/codegen.js +1 -1
  45. package/dist/codegen.js.map +1 -1
  46. package/dist/core.cjs +1 -1
  47. package/dist/core.cjs.map +1 -1
  48. package/dist/core.d.cts +264 -73
  49. package/dist/core.d.ts +264 -73
  50. package/dist/core.js +1 -1
  51. package/dist/core.js.map +1 -1
  52. package/dist/doctor-cli.d.ts +1 -1
  53. package/dist/doctor-cli.js +1 -1
  54. package/dist/doctor-cli.js.map +1 -1
  55. package/dist/doctor.d.ts +7 -6
  56. package/dist/doctor.js +1 -1
  57. package/dist/doctor.js.map +1 -1
  58. package/dist/document-session-BfBfLVpg.d.ts +53 -0
  59. package/dist/fragment-endpoint-3Mlz7GDz.d.ts +189 -0
  60. package/dist/fragment.cjs +1 -1
  61. package/dist/fragment.cjs.map +1 -1
  62. package/dist/fragment.d.cts +64 -18
  63. package/dist/fragment.d.ts +64 -18
  64. package/dist/fragment.js +1 -1
  65. package/dist/fragment.js.map +1 -1
  66. package/dist/index.cjs +1 -1
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.d.cts +422 -83
  69. package/dist/index.d.ts +422 -83
  70. package/dist/index.js +1 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/lean.cjs +2 -0
  73. package/dist/lean.cjs.map +1 -0
  74. package/dist/lean.d.cts +44 -0
  75. package/dist/lean.d.ts +44 -0
  76. package/dist/lean.js +2 -0
  77. package/dist/lean.js.map +1 -0
  78. package/dist/lexical.cjs +1 -1
  79. package/dist/lexical.cjs.map +1 -1
  80. package/dist/lexical.d.cts +19 -1
  81. package/dist/lexical.d.ts +19 -1
  82. package/dist/lexical.js +1 -1
  83. package/dist/lexical.js.map +1 -1
  84. package/dist/locals-DBXDMxOA.d.ts +45 -0
  85. package/dist/{middleware-CEPsY1P7.d.ts → middleware-Bx9I7PXW.d.ts} +14 -14
  86. package/dist/migrate.d.ts +4 -3
  87. package/dist/migrate.js +1 -1
  88. package/dist/migrate.js.map +1 -1
  89. package/dist/{options-CEzzfHJu.d.ts → options-BW1eqXvc.d.ts} +90 -2
  90. package/dist/plugins.cjs +1 -1
  91. package/dist/plugins.cjs.map +1 -1
  92. package/dist/plugins.d.cts +111 -6
  93. package/dist/plugins.d.ts +111 -6
  94. package/dist/plugins.js +1 -1
  95. package/dist/plugins.js.map +1 -1
  96. package/dist/{probe-CYtvj_Lm.d.ts → probe-CELeUciC.d.ts} +26 -4
  97. package/dist/server.cjs +1 -1
  98. package/dist/server.cjs.map +1 -1
  99. package/dist/server.d.cts +67 -13
  100. package/dist/server.d.ts +67 -13
  101. package/dist/server.js +1 -1
  102. package/dist/server.js.map +1 -1
  103. package/dist/structural.cjs +2 -2
  104. package/dist/structural.cjs.map +1 -1
  105. package/dist/structural.d.cts +47 -4
  106. package/dist/structural.d.ts +47 -4
  107. package/dist/structural.js +2 -2
  108. package/dist/structural.js.map +1 -1
  109. package/package.json +77 -9
package/dist/core.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  /** The package version, read from package.json so the entries and the inline runtime cannot drift. */
2
+ /** @internal */
2
3
  declare const VERSION: string;
3
4
 
4
5
  /** Connection status and the heartbeat that decides a disconnect. */
@@ -83,6 +84,23 @@ interface InspectionBindings {
83
84
  readonly ownerScoped: boolean;
84
85
  /** Distinct document owners currently on the page, sorted. */
85
86
  readonly owners: readonly string[];
87
+ /**
88
+ * Bindings the runtime found by value on the connection's first message
89
+ * (`autoBind: 'unique'`, ADR 0014), sorted by field, each with the value it
90
+ * matched on and the attribute it matched in — `undefined` for a text match.
91
+ * These are the elements that change without a `data-payload-field` in the
92
+ * template; every one of them carries `data-payload-guessed` in the DOM.
93
+ */
94
+ readonly guessed: readonly {
95
+ readonly field: string;
96
+ readonly matched: string;
97
+ readonly attribute: string | undefined;
98
+ }[];
99
+ /** `autoBind` as configured, and what the one search cost; `searchMs` is `undefined` until it ran. */
100
+ readonly autoBind: {
101
+ readonly mode: 'off' | 'unique';
102
+ readonly searchMs: number | undefined;
103
+ };
86
104
  }
87
105
  /** Scheduler work in progress. */
88
106
  interface InspectionScheduler {
@@ -122,14 +140,49 @@ interface LivePreviewInspection {
122
140
  readonly plugins: readonly PluginInspection[];
123
141
  /** Server-rendered fragment boundaries: whether a handler exists and what happened to renders. */
124
142
  readonly fragments: InspectionFragments;
125
- /** Route refreshes: whether a strategy exists, how many ran, failed, or were stopped by the loop guard. */
143
+ /** Route refreshes: whether a strategy exists, how many ran, failed, were paced, or were stopped by the loop guard. */
126
144
  readonly route: InspectionRoute;
145
+ /** Patches the runtime knew could not match the server's render, and what became of them. */
146
+ readonly fidelity: InspectionFidelity;
147
+ /**
148
+ * Whether the page declared a framework that hydrates it, and how far the
149
+ * wait for its first commit — React's, or Vue's mount — got (ADR 0015).
150
+ * `waiting` is why a preview on a Next or Nuxt page is not connected yet;
151
+ * `timed-out` is LP0607.
152
+ */
153
+ readonly hydration: {
154
+ readonly mode: 'off' | 'react' | 'vue';
155
+ readonly state: 'idle' | 'waiting' | 'committed' | 'timed-out';
156
+ };
157
+ }
158
+ /**
159
+ * The fidelity verdicts as `inspect()` reports them (LP0411). A positive
160
+ * `unfaithful` beside `escalated: 0` is a page that keeps a degraded patch —
161
+ * because `mode` says so, or because neither `fragments.handler` nor
162
+ * `route.handler` is there to escalate to.
163
+ */
164
+ interface InspectionFidelity {
165
+ /** `onUnfaithfulPatch` as resolved from both of its names. */
166
+ readonly mode: 'ignore' | 'warn' | 'escalate';
167
+ /** Bindings reported unfaithful since start — once per element, like LP0411, and under every mode. */
168
+ readonly unfaithful: number;
169
+ /** Of those, how many were handed to the fragment or route strategy. */
170
+ readonly escalated: number;
171
+ /** The field names behind `unfaithful`, sorted. Cumulative. */
172
+ readonly fields: readonly string[];
127
173
  }
128
174
  /** The route strategy as `inspect()` reports it. */
129
175
  interface InspectionRoute {
130
176
  readonly handler: boolean;
131
177
  readonly refreshes: number;
178
+ /** Refreshes that broke: the request, the answer, or the morph. */
132
179
  readonly failed: number;
180
+ /**
181
+ * Refreshes the strategy's own minimum interval held back (LP0805). Each is
182
+ * run once the window closes unless a newer revision takes its place, so this
183
+ * counts pacing and not loss — and it is deliberately not `failed`.
184
+ */
185
+ readonly refused: number;
133
186
  /** Second refresh requests for one revision, refused with LP0805. */
134
187
  readonly loopStopped: number;
135
188
  }
@@ -227,7 +280,9 @@ type PayloadFieldCondition = (data: unknown, siblingData: unknown) => boolean;
227
280
  *
228
281
  * Browser-side reporting sites write the literal (`code: 'LP0603'`) rather than
229
282
  * reading it from this record: the frozen table would then ship in the inline
230
- * runtime for the sake of six characters. Server-side tools may import it.
283
+ * runtime for the sake of six characters — it did, 1 287 B in every page, for
284
+ * the one read Z6 left in the strategy runner, and `diagnostic-codes.test.ts`
285
+ * now holds the artifact free of it. Server-side tools may import it.
231
286
  */
232
287
  /**
233
288
  * Every diagnostic code the runtime can report, by name.
@@ -245,6 +300,8 @@ declare const DIAGNOSTIC_CODES: Readonly<{
245
300
  readonly ReferrerOnlyTrust: "LP0102";
246
301
  /** A plugin declares a runtime range this runtime does not satisfy; it was refused. */
247
302
  readonly PluginIncompatible: "LP0103";
303
+ /** The page carries the lean runtime and needs a feature that profile leaves out. */
304
+ readonly ProfileFeatureOmitted: "LP0104";
248
305
  /** An update named a field with no binding anchor on the page. */
249
306
  readonly OrphanField: "LP0201";
250
307
  /** Owner scoping is on and the update names no document it could belong to. */
@@ -265,10 +322,24 @@ declare const DIAGNOSTIC_CODES: Readonly<{
265
322
  readonly StructuralUnstableKeys: "LP0406";
266
323
  /** A binding asks for a delivery strategy this release does not have; it is left unchanged. */
267
324
  readonly UnsupportedStrategy: "LP0407";
325
+ /** `data-payload-format` names a format the vocabulary does not contain; the default formatting was used instead. */
326
+ readonly UnknownValueFormat: "LP0408";
327
+ /** The strict sanitizer removed an attribute the 1.x `'compat'` policy kept. */
328
+ readonly SanitizerDroppedAttribute: "LP0409";
329
+ /** A Lexical block has no renderer; the markup the server rendered for it is kept instead. */
330
+ readonly UnrenderedBlockKept: "LP0410";
331
+ /** A patch cannot reach what the server would have drawn; `onUnfaithfulPatch` decided what happens next. */
332
+ readonly UnfaithfulPatch: "LP0411";
333
+ /** The first write to a date, number or checkbox binding replaced a different reading of the same value. */
334
+ readonly ServerFormatReplaced: "LP0412";
335
+ /** A Lexical block has no renderer, and the write could not keep the markup the server rendered for it; it is gone. */
336
+ readonly UnrenderedBlockLost: "LP0413";
268
337
  /** A message was rejected before it reached the update pipeline. */
269
338
  readonly MessageRejected: "LP0501";
270
339
  /** A preview token was rejected. */
271
340
  readonly TokenRejected: "LP0502";
341
+ /** A trusted origin sent a message this protocol version does not recognise. */
342
+ readonly ProtocolShapeUnknown: "LP0503";
272
343
  /** A consumer event handler threw. */
273
344
  readonly HandlerThrew: "LP0601";
274
345
  /** A consumer transform threw; the original value was kept. */
@@ -279,11 +350,13 @@ declare const DIAGNOSTIC_CODES: Readonly<{
279
350
  readonly StartupFailed: "LP0605";
280
351
  /** Sending the ready handshake failed. */
281
352
  readonly ReadyFailed: "LP0606";
353
+ /** The page declared hydration, but no React commit or Vue mount came within the cap; the runtime started without waiting. */
354
+ readonly HydrationWaitTimedOut: "LP0607";
282
355
  /** The audit found no runtime in a response that carried preview intent. */
283
356
  readonly AuditRuntimeMissing: "LP0701";
284
357
  /** The preview response declares no `frame-ancestors`. */
285
358
  readonly AuditNoFrameAncestors: "LP0702";
286
- /** `X-Frame-Options` forbids framing, which no CSP can undo. */
359
+ /** `X-Frame-Options` forbids framing, which no CSP can undo; `SAMEORIGIN` forbids it from another origin only. */
287
360
  readonly AuditFrameOptionsBlocks: "LP0703";
288
361
  /** Binding attributes are served to anonymous visitors. */
289
362
  readonly AuditBindingsExposed: "LP0704";
@@ -303,10 +376,12 @@ declare const DIAGNOSTIC_CODES: Readonly<{
303
376
  readonly FragmentUnauthorized: "LP0803";
304
377
  /** A fragment response arrived for a revision that was already superseded and was discarded. */
305
378
  readonly FragmentSuperseded: "LP0804";
306
- /** A route refresh was requested again for the same revision; the loop guard stopped it. */
379
+ /** A route refresh was refused: the loop guard, or the strategy's minimum interval. */
307
380
  readonly RouteRefreshLoop: "LP0805";
308
381
  /** A boundary asks for the fragment strategy but no fragment handler is configured; it is patched. */
309
382
  readonly FragmentStrategyUnavailable: "LP0806";
383
+ /** A revision changed a field with no binding; `onUnfaithfulPatch` refreshed the route. */
384
+ readonly UnboundChangeRefresh: "LP0807";
310
385
  /** A readiness row is not yet at its 2.0 value; `pll doctor --v2` reports it. */
311
386
  readonly V2ReadinessGap: "LP0709";
312
387
  /** The preview runtime is served to anonymous visitors, not only inside the admin frame. */
@@ -369,7 +444,21 @@ interface RouteContext {
369
444
  readonly signal: AbortSignal;
370
445
  readonly isCurrent: () => boolean;
371
446
  readonly log: (code: DiagnosticCode, detail: string) => void;
447
+ /**
448
+ * Ask to be run again in `delayMs`, once. A strategy that refuses a refresh
449
+ * because it is rate-limiting itself uses this: the window is a rate limit
450
+ * and not a filter, so what falls inside it still has to reach the preview.
451
+ * The runtime runs at most one such request, and only while the revision that
452
+ * asked is still the current one.
453
+ */
454
+ readonly retryAfter?: (delayMs: number) => void;
372
455
  }
456
+ /**
457
+ * What one refresh did. `refused` is the strategy's own brake and not a
458
+ * failure — it is counted separately, because a number that mixes a planned
459
+ * pause with a broken request cannot be read.
460
+ */
461
+ type RouteOutcome = 'refreshed' | 'failed' | 'refused' | 'superseded';
373
462
  /**
374
463
  * Whether a revision needs the whole route re-rendered, and how. After a
375
464
  * refresh the runtime rescans and re-applies the revision, so the unsaved
@@ -377,7 +466,7 @@ interface RouteContext {
377
466
  */
378
467
  interface RouteStrategy {
379
468
  readonly plan: (root: ParentNode, changedFields: ReadonlySet<string>) => boolean;
380
- readonly refresh: (context: RouteContext) => Promise<'refreshed' | 'failed' | 'superseded'>;
469
+ readonly refresh: (context: RouteContext) => Promise<RouteOutcome>;
381
470
  }
382
471
  interface StrategyHandlers {
383
472
  readonly fragment?: FragmentStrategy;
@@ -450,7 +539,15 @@ interface LivePreviewEventMap {
450
539
  readonly documentSave: {
451
540
  readonly timestamp: number;
452
541
  };
453
- /** A data update carried `externallyUpdatedRelationship`: a related document changed in an admin drawer, so the update re-renders unconditionally. */
542
+ /**
543
+ * A save in another document reached the page through
544
+ * `externallyUpdatedRelationship` — an admin-drawer edit. Fires once per
545
+ * such save, not once per message: the panel repeats its last document
546
+ * event in every later message, including its own saves of the previewed
547
+ * document, and neither of those is news. That update re-renders every
548
+ * bound field even under `skipUnchanged`, because a drawer edit changes
549
+ * populated values while the form values stay put.
550
+ */
454
551
  readonly relationshipUpdate: {
455
552
  readonly detail: PayloadDocumentEventDetail;
456
553
  readonly timestamp: number;
@@ -496,6 +593,53 @@ declare class EventEmitter<TMap extends object = LivePreviewEventMap> {
496
593
  eventNames(): (keyof TMap)[];
497
594
  }
498
595
 
596
+ /**
597
+ * `'strict'` (default) strips `id`, `name` and `data-payload-*` and passes
598
+ * other `data-*` only via `allowedDataAttributes`; `'compat'` keeps them.
599
+ */
600
+ type SanitizerPolicyMode = 'compat' | 'strict';
601
+ interface SanitizeOptions {
602
+ /** Overrides the module default set by `setSanitizerPolicy()`. */
603
+ readonly policy?: SanitizerPolicyMode;
604
+ /** `data-*` attributes (full names) that pass under `'strict'`; `data-payload-*` never does. */
605
+ readonly allowedDataAttributes?: readonly string[];
606
+ /**
607
+ * Keep `input`, `button`, `textarea`, `select`, `option` and `label` — only
608
+ * for markup the page author wrote, never for CMS content. `form`,
609
+ * handlers, `style` and unsafe URLs stay dropped.
610
+ */
611
+ readonly allowFormControls?: boolean;
612
+ /** Extra tags to allow. Lower-case, untrimmed. */
613
+ readonly additionalAllowedTags?: readonly string[];
614
+ /**
615
+ * Extra per-tag attributes, lower-case. Cannot re-admit handlers, `style`,
616
+ * or — under `'strict'` — `id`, `name` and `data-payload-*`.
617
+ */
618
+ readonly additionalAllowedAttributes?: Readonly<Record<string, readonly string[]>>;
619
+ /**
620
+ * The input is a page-author item template, so `'strict'` keeps the
621
+ * applier's reconciliation attributes (`TEMPLATE_ATTRIBUTES`) and nothing
622
+ * else — every other `data-payload-*` is still stripped, so a template can
623
+ * never add a binding.
624
+ */
625
+ readonly templateMode?: boolean;
626
+ }
627
+ /** The `Document` surface the sanitizer needs; jsdom, linkedom and happy-dom all provide it. */
628
+ interface SanitizerDocument {
629
+ createElement: (tagName: string) => {
630
+ innerHTML: string;
631
+ readonly content: ParentNode;
632
+ };
633
+ }
634
+ /** Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`; `null` clears it. */
635
+ declare function setSanitizerDocument(doc: SanitizerDocument | null): void;
636
+ /**
637
+ * Sanitize `html`; malformed input is recovered by the parser first.
638
+ *
639
+ * @throws {SanitizerEnvironmentError} when no DOM is available.
640
+ */
641
+ declare function sanitizeHtml(html: string, options?: SanitizeOptions): string;
642
+
499
643
  /** Types shared by the runtime primitives. */
500
644
 
501
645
  /** Payload's field set plus the DOM-binding categories `html`, `url`, `image` and `structural-array`. */
@@ -532,7 +676,7 @@ interface CachedElement {
532
676
  /** Nearest enclosing `data-payload-fragment` boundary. Resolved by the cache. */
533
677
  readonly fragmentBoundary?: Element;
534
678
  /** `data-payload-boundary`: an anchor that hides itself while its field is empty. */
535
- readonly boundary?: boolean;
679
+ readonly hidesWhenEmpty?: boolean;
536
680
  /** Write the value into this attribute instead of the content; policed writes. */
537
681
  readonly targetAttribute?: string;
538
682
  /** Optional sibling-field path bound to the element's `href` attribute. */
@@ -547,8 +691,16 @@ interface CachedElement {
547
691
  readonly arraySeparator?: string;
548
692
  /** Optional locale code locked onto this element (overrides the global locale). */
549
693
  readonly locale?: string;
694
+ /** Raw `data-payload-format`; the date and number renderers read the vocabulary. */
695
+ readonly format?: string;
550
696
  /** The document this binding belongs to, from the nearest `data-payload-owner`. */
551
697
  readonly owner?: string;
698
+ /**
699
+ * The value an auto-binding matched on (`data-payload-guessed`), for a
700
+ * binding the runtime found by value rather than one the template declared.
701
+ * Absent for a declared binding.
702
+ */
703
+ readonly guessed?: string;
552
704
  }
553
705
  /** What a renderer is given; `allFields` lets it resolve a sibling field. */
554
706
  interface RenderContext {
@@ -560,6 +712,20 @@ interface RenderContext {
560
712
  readonly schema: PayloadFieldSchema | undefined;
561
713
  /** The project's rich-text renderer, when the client was configured with one. */
562
714
  readonly renderRichText?: RichTextRenderer;
715
+ /**
716
+ * This instance's sanitizer policy, for every HTML write the renderer makes.
717
+ * Absent, the process default set by `setSanitizerPolicy()` applies.
718
+ */
719
+ readonly sanitizerPolicy?: SanitizerPolicyMode;
720
+ /**
721
+ * Say that this write cannot reproduce what the server drew, so
722
+ * `onUnfaithfulPatch` can have a strategy render the region instead of
723
+ * leaving a degraded patch on the page. The built-in rich-text renderer
724
+ * calls it for a Lexical block whose markup it had to drop; a project
725
+ * renderer may call it for any value it can only approximate. `reason`
726
+ * completes the sentence 'field "x" …' in LP0411.
727
+ */
728
+ readonly reportUnfaithful?: (target: CachedElement, reason: string) => void;
563
729
  }
564
730
  /**
565
731
  * A renderer writes one value into its element. It must not throw: one bad
@@ -636,6 +802,10 @@ interface LivePreviewPlugin {
636
802
  * one side — the adapter's request decision or the browser runtime — and a
637
803
  * test asserts the profile assigns every readiness row that has an option, so
638
804
  * a row added later cannot be forgotten. See ADR 0007.
805
+ *
806
+ * It lives in the leaf `types` domain, like `merge-depth.ts`, because the
807
+ * inline generator resolves the profile too, and the generator is server-side
808
+ * code that may not reach the browser runtime in `core`.
639
809
  */
640
810
  /** `'v2'` is the 2.0 default; `'v1'` is the 1.x table. */
641
811
  type DefaultsProfile = 'v1' | 'v2';
@@ -672,6 +842,13 @@ interface LivePreviewClientConfig {
672
842
  readonly skipUnchanged?: boolean;
673
843
  /** Scroll the preview to the field being edited when its value changes. Default `false`. */
674
844
  readonly revealEditedField?: boolean;
845
+ /**
846
+ * Find bindings by value on the connection's first message: a scalar whose
847
+ * value is the whole content of exactly one element is bound to it as if
848
+ * `data-payload-field` stood there; every guess is stamped `data-payload-guessed`
849
+ * and listed in `inspect().bindings.guessed`. Default `'off'`.
850
+ */
851
+ readonly autoBind?: 'off' | 'unique';
675
852
  /** Fields whose change re-applies other bindings regardless of their own value: `{ price: ['priceLabel'] }`. Used with `skipUnchanged`. */
676
853
  readonly dependencies?: Readonly<Record<string, readonly string[]>>;
677
854
  /** Strategy handlers beyond patching; `createFragmentStrategy()` from `payload-live-preview/fragment` builds one. */
@@ -696,7 +873,11 @@ interface LivePreviewClientConfig {
696
873
  readonly disableLocalhostMatching?: boolean;
697
874
  /** Which windows may post updates. Default `'parent-or-opener'`; `defaults: 'v1'` sets `'any'`. */
698
875
  readonly eventSourcePolicy?: EventSourcePolicy;
699
- /** Sanitizer policy for rich text and HTML writes. Default `'strict'`; `defaults: 'v1'` sets `'compat'`. */
876
+ /**
877
+ * Sanitizer policy for this client's rich text and HTML writes. Default
878
+ * `'strict'`; `defaults: 'v1'` sets `'compat'`. Per instance: it leaves the
879
+ * process default that `setSanitizerPolicy()` sets for direct `sanitizeHtml()` calls alone.
880
+ */
700
881
  readonly sanitizerPolicy?: 'compat' | 'strict';
701
882
  /** `'v2'` (default) is the 2.0 table; `'v1'` restores every 1.x row at once. Explicit options win. */
702
883
  readonly defaults?: DefaultsProfile;
@@ -754,7 +935,7 @@ declare function initLivePreview(config?: LivePreviewClientConfig): LivePreviewC
754
935
  /** HTML and CSS escaping primitives (OWASP XSS Prevention Cheat Sheet). DOM-free. */
755
936
  /** Escape `text` for an element body or a *quoted* attribute value; strings only, and unquoted attributes are not covered. */
756
937
  declare function escapeHtml(text: string): string;
757
- /** Escape a value for a *quoted* HTML attribute, leaving URL characters intact; it validates no scheme, so run `isSafeUrl()` on `href`/`src` first. */
938
+ /** Escape a value for a *quoted* HTML attribute, leaving URL characters intact; it validates no scheme, so run `isSafeUrl()` on `href`/`src` first. @internal */
758
939
  declare function escapeHtmlAttribute(value: string): string;
759
940
 
760
941
  /**
@@ -763,56 +944,9 @@ declare function escapeHtmlAttribute(value: string): string;
763
944
  */
764
945
  /** `true` only for absolute `http`/`https`/`mailto`/`tel` URLs, protocol-relative URLs, paths, `#`/`?` fragments and relative paths. */
765
946
  declare function isSafeUrl(url: unknown): boolean;
766
- /** Whether a safe URL points at another HTTP(S) origin, protocol-relative forms included, and so needs `noopener` hardening. */
947
+ /** Whether a URL points at another HTTP(S) origin, protocol-relative forms included, and so needs `noopener` hardening; every URL these two patterns match is one `isSafeUrl` admits. */
767
948
  declare function isExternalHttpUrl(url: string): boolean;
768
949
 
769
- /**
770
- * `'strict'` (default) strips `id`, `name` and `data-payload-*` and passes
771
- * other `data-*` only via `allowedDataAttributes`; `'compat'` keeps them.
772
- */
773
- type SanitizerPolicyMode = 'compat' | 'strict';
774
- interface SanitizeOptions {
775
- /** Overrides the module default set by `setSanitizerPolicy()`. */
776
- readonly policy?: SanitizerPolicyMode;
777
- /** `data-*` attributes (full names) that pass under `'strict'`; `data-payload-*` never does. */
778
- readonly allowedDataAttributes?: readonly string[];
779
- /**
780
- * Keep `input`, `button`, `textarea`, `select`, `option` and `label` — only
781
- * for markup the page author wrote, never for CMS content. `form`,
782
- * handlers, `style` and unsafe URLs stay dropped.
783
- */
784
- readonly allowFormControls?: boolean;
785
- /** Extra tags to allow. Lower-case, untrimmed. */
786
- readonly additionalAllowedTags?: readonly string[];
787
- /**
788
- * Extra per-tag attributes, lower-case. Cannot re-admit handlers, `style`,
789
- * or — under `'strict'` — `id`, `name` and `data-payload-*`.
790
- */
791
- readonly additionalAllowedAttributes?: Readonly<Record<string, readonly string[]>>;
792
- /**
793
- * The input is a page-author item template, so `'strict'` keeps the
794
- * applier's reconciliation attributes (`TEMPLATE_ATTRIBUTES`) and nothing
795
- * else — every other `data-payload-*` is still stripped, so a template can
796
- * never add a binding.
797
- */
798
- readonly templateMode?: boolean;
799
- }
800
- /** The `Document` surface the sanitizer needs; jsdom, linkedom and happy-dom all provide it. */
801
- interface SanitizerDocument {
802
- createElement: (tagName: string) => {
803
- innerHTML: string;
804
- readonly content: ParentNode;
805
- };
806
- }
807
- /** Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`; `null` clears it. */
808
- declare function setSanitizerDocument(doc: SanitizerDocument | null): void;
809
- /**
810
- * Sanitize `html`; malformed input is recovered by the parser first.
811
- *
812
- * @throws {SanitizerEnvironmentError} when no DOM is available.
813
- */
814
- declare function sanitizeHtml(html: string, options?: SanitizeOptions): string;
815
-
816
950
  /**
817
951
  * Content-Security-Policy helpers: nonce generation, directive builders and
818
952
  * the header merge every adapter uses. Isomorphic; needs only Web Crypto.
@@ -821,9 +955,9 @@ declare function sanitizeHtml(html: string, options?: SanitizeOptions): string;
821
955
  interface WebCryptoLike {
822
956
  getRandomValues: <T extends ArrayBufferView | null>(array: T) => T;
823
957
  }
824
- /** Supply a Web Crypto implementation for runtimes without `globalThis.crypto`; `null` clears it. */
958
+ /** Supply a Web Crypto implementation for runtimes without `globalThis.crypto`; `null` clears it. @internal */
825
959
  declare function setCspCrypto(crypto: WebCryptoLike | null): void;
826
- /** A base64url nonce of `bytes` random bytes (default 16); throws without Web Crypto, since a predictable nonce silently defeats the CSP. */
960
+ /** A base64url nonce of `bytes` random bytes (default 16); throws without Web Crypto, since a predictable nonce silently defeats the CSP. @internal */
827
961
  declare function generateCspNonce(bytes?: number): string;
828
962
  interface FrameAncestorsOptions {
829
963
  readonly self?: boolean;
@@ -836,6 +970,7 @@ declare function buildFrameAncestors(options?: FrameAncestorsOptions): string;
836
970
  * A `script-src` value permitting one nonce plus optional extra sources.
837
971
  * `'strict-dynamic'` is opt-in: it makes CSP 3 browsers ignore `'self'` and
838
972
  * host sources, so every script on the page must then carry the nonce.
973
+ * @internal
839
974
  */
840
975
  declare function buildScriptSrcWithNonce(nonce: string, options?: {
841
976
  readonly self?: boolean;
@@ -898,12 +1033,14 @@ declare function isAuthorizedPreviewContext(value: unknown): value is Authorized
898
1033
  * Where the runtime is running: framed, opened, or on a developer's machine.
899
1034
  * Nothing reads bundler-injected variables; a Vite consumer passes
900
1035
  * `import.meta.env.X` explicitly (docs/astro.md).
1036
+ * @internal
901
1037
  */
902
1038
  declare function isInIframe(): boolean;
1039
+ /** @internal */
903
1040
  declare function isInPopup(): boolean;
904
- /** An iframe or a popup; top-level navigation never starts the preview. */
1041
+ /** An iframe or a popup; top-level navigation never starts the preview. @internal */
905
1042
  declare function isInPreviewContext(): boolean;
906
- /** Under Node, `NODE_ENV !== 'production'`; in a browser the hostname, which is the only signal a bundle has. */
1043
+ /** Under Node, `NODE_ENV !== 'production'`; in a browser the hostname, which is the only signal a bundle has. @internal */
907
1044
  declare function isDevMode(): boolean;
908
1045
 
909
1046
  /**
@@ -945,6 +1082,7 @@ declare class OriginDetector {
945
1082
  }
946
1083
 
947
1084
  /** The locale for `Intl` renders before Payload names one: `<html lang>`, then `navigator.language`, then `'en'`. */
1085
+ /** @internal */
948
1086
  declare function detectInitialLocale(): string;
949
1087
 
950
1088
  /**
@@ -952,10 +1090,11 @@ declare function detectInitialLocale(): string;
952
1090
  * announces or by observation, since the stock Payload admin announces none:
953
1091
  * what it can do is read off the messages it sends. See ADR 0010.
954
1092
  */
955
- /** Bumped only when this library's understanding of the wire format changes. */
1093
+ /** Bumped only when this library's understanding of the wire format changes. @internal */
956
1094
  declare const LIBRARY_PROTOCOL_VERSION = 4;
957
- /** How a capability becomes active. */
1095
+ /** How a capability becomes active. @internal */
958
1096
  type CapabilitySource = 'version' | 'observed';
1097
+ /** @internal */
959
1098
  interface CapabilityDeclaration {
960
1099
  /** Enabled once the negotiated version reaches this (for announced peers). */
961
1100
  readonly since: number;
@@ -995,7 +1134,7 @@ declare const CAPABILITY_DECLARATIONS: {
995
1134
  };
996
1135
  };
997
1136
  type ProtocolCapability = keyof typeof CAPABILITY_DECLARATIONS;
998
- /** Every declared capability, in declaration order. */
1137
+ /** Every declared capability, in declaration order. @internal */
999
1138
  declare const PROTOCOL_CAPABILITIES: readonly ProtocolCapability[];
1000
1139
  interface ProtocolNegotiation {
1001
1140
  /** This library's protocol version. */
@@ -1011,6 +1150,7 @@ interface ProtocolNegotiation {
1011
1150
  }
1012
1151
  /** Deterministic; the runtime re-runs it whenever either input changes. */
1013
1152
  declare function negotiateProtocol(theirs: number | undefined, observed?: Iterable<ProtocolCapability>): ProtocolNegotiation;
1153
+ /** @internal */
1014
1154
  declare function hasCapability(negotiation: ProtocolNegotiation, capability: ProtocolCapability): boolean;
1015
1155
 
1016
1156
  /**
@@ -1056,15 +1196,48 @@ interface ProtocolProfile {
1056
1196
  */
1057
1197
  declare function detectProtocolProfile(observed: ReadonlySet<ProtocolCapability>): ProtocolProfile;
1058
1198
 
1199
+ /**
1200
+ * The seam between a host framework's own router and the route strategy.
1201
+ *
1202
+ * The route strategy answers a revision by fetching the route and morphing it
1203
+ * into the living page. On a page whose DOM belongs to a reconciler that is
1204
+ * working against the framework, and it was seen to break once: `removeChild`
1205
+ * on `null` inside React's commit phase, over markup this package had patched.
1206
+ * A host that re-renders the route itself does the same job without the morph
1207
+ * and without the second HTML request, so it is given the chance to.
1208
+ *
1209
+ * Why a named slot on `window` and not a reference: the runtime is an inline
1210
+ * script that builds its strategy before any application code has hydrated, so
1211
+ * there is nothing to hand a component; `window.__livePreview`, the only other
1212
+ * public surface, is created later and not at all outside a preview; and the
1213
+ * two richer extension points — plugins and events — are reachable only through
1214
+ * the programmatic client, which a page using an adapter does not have. One
1215
+ * slot, written by whoever mounts and read at the moment of a refresh, is the
1216
+ * smallest thing that survives both orders of arrival.
1217
+ */
1218
+ /**
1219
+ * A host's own route refresh. It must settle once the fresh markup is
1220
+ * committed: the runtime re-applies the revision on top of it, and doing that
1221
+ * against the markup being replaced would write into nodes about to be dropped.
1222
+ */
1223
+ type RouteRefresh = () => void | Promise<void>;
1224
+ /**
1225
+ * Lend the runtime the host's route refresh; the return value undoes it, for a
1226
+ * component's cleanup. A later registration wins, and undoing one that has
1227
+ * already been replaced does nothing — two components on one page would
1228
+ * otherwise take the slot from each other on unmount.
1229
+ */
1230
+ declare function registerRouteRefresh(refresh: RouteRefresh): () => void;
1231
+
1059
1232
  /** Type-level field paths, so a binding name is checked at compile time against the codegen schema. */
1060
1233
  /** String keys of `T`. */
1061
1234
  type FieldName<T> = Extract<keyof T, string>;
1062
- /** Dotted paths into `T`, capped at three levels so IntelliSense stays usable. */
1235
+ /** Dotted paths into `T`, capped at three levels so IntelliSense stays usable. @internal */
1063
1236
  type FieldPath<T, Depth extends 0 | 1 | 2 | 3 = 3> = Depth extends 0 ? never : T extends readonly (infer U)[] ? FieldPath<U, Prev<Depth>> : T extends object ? {
1064
1237
  [K in Extract<keyof T, string>]: K | (T[K] extends object ? `${K}.${FieldPath<T[K], Prev<Depth>>}` : never);
1065
1238
  }[Extract<keyof T, string>] : never;
1066
1239
  type Prev<N extends 0 | 1 | 2 | 3> = N extends 3 ? 2 : N extends 2 ? 1 : N extends 1 ? 0 : 0;
1067
- /** The value type at a dotted path, or `unknown` when the path does not exist. */
1240
+ /** The value type at a dotted path, or `unknown` when the path does not exist. @internal */
1068
1241
  type ValueAt<T, P extends string> = P extends `${infer Head}.${infer Rest}` ? Head extends keyof T ? T[Head] extends readonly (infer U)[] ? ValueAt<U, Rest> : T[Head] extends object ? ValueAt<T[Head], Rest> : unknown : unknown : P extends keyof T ? T[P] : unknown;
1069
1242
 
1070
1243
  /**
@@ -1116,15 +1289,25 @@ declare function bindByPath<T = Record<string, unknown>>(picker: (data: T) => un
1116
1289
  interface OwnerBindingAttributes {
1117
1290
  readonly 'data-payload-owner': string;
1118
1291
  }
1292
+ /** The attributes marking a server-rendered boundary (ADR 0011, docs/hybrid.md). */
1293
+ interface FragmentBoundaryAttributes {
1294
+ readonly 'data-payload-fragment': string;
1295
+ readonly 'data-payload-fragment-key'?: string;
1296
+ readonly 'data-payload-depends'?: string;
1297
+ }
1298
+ interface FragmentBoundaryOptions {
1299
+ /** Distinguishes boundaries when one registry id renders several on a page. */
1300
+ readonly key?: string;
1301
+ /** The fields that re-render the boundary. Without it, every update does. */
1302
+ readonly dependsOn?: readonly string[];
1303
+ }
1119
1304
  /** No attributes at all: an unauthorized response is byte-identical to one that never knew about live preview. */
1120
1305
  type SuppressedBinding = Readonly<Record<string, never>>;
1121
- interface PreviewBindingsCommonOptions {
1122
- /** Document this subtree belongs to, emitted as `data-payload-owner`; needed with `scopeBindingsByOwner`. */
1123
- readonly owner?: string;
1124
- }
1125
1306
  /** The verdict from `authorizePreviewRequest()`, or `null` for a public response. Only a branded context authorizes emission. */
1126
- interface PreviewBindingsOptions extends PreviewBindingsCommonOptions {
1307
+ interface PreviewBindingsOptions {
1127
1308
  readonly authorization: AuthorizedPreviewContext | null;
1309
+ /** Document this subtree belongs to, emitted as `data-payload-owner`; needed with `scopeBindingsByOwner`. */
1310
+ readonly owner?: string;
1128
1311
  }
1129
1312
  /** Request-scoped binding helpers carrying one authorization decision. */
1130
1313
  interface PreviewBindings {
@@ -1135,6 +1318,12 @@ interface PreviewBindings {
1135
1318
  bindByPath: <T = Record<string, unknown>>(picker: (data: T) => unknown, options?: BindOptions) => FieldBindingAttributes | SuppressedBinding;
1136
1319
  /** Owner marker for this subtree, or nothing while unauthorized or without an owner. */
1137
1320
  owner: () => OwnerBindingAttributes | SuppressedBinding;
1321
+ /**
1322
+ * A server-rendered boundary, or nothing while unauthorized — the id and the
1323
+ * fields it depends on describe the content model as much as a binding does.
1324
+ * The registry behind `id` is the endpoint's (docs/hybrid.md).
1325
+ */
1326
+ boundary: (id: string, options?: FragmentBoundaryOptions) => FragmentBoundaryAttributes | SuppressedBinding;
1138
1327
  }
1139
1328
  /** Request-scoped `bind`, `bindByPath` and `owner`, all suppressed unless `authorization` is a real context. */
1140
1329
  declare function createPreviewBindings(options: PreviewBindingsOptions): PreviewBindings;
@@ -1143,6 +1332,7 @@ declare function createPreviewBindings(options: PreviewBindingsOptions): Preview
1143
1332
  * Hydrated islands own their subtree, so the runtime never patches inside one.
1144
1333
  * Instead every flush dispatches `payload-live-preview:update` on each island
1145
1334
  * root with the update in `detail`. `data-payload-island="patch"` opts back in.
1335
+ * @internal
1146
1336
  */
1147
1337
  declare const ISLAND_EVENT = "payload-live-preview:update";
1148
1338
  interface IslandUpdateDetail {
@@ -1151,7 +1341,7 @@ interface IslandUpdateDetail {
1151
1341
  readonly receivedAt: number;
1152
1342
  readonly locale: string | undefined;
1153
1343
  }
1154
- /** Whether `element` (or an ancestor) is an island that did not opt into patching. */
1344
+ /** Whether `element` (or an ancestor) is an island that did not opt into patching. @internal */
1155
1345
  declare function isInsideIsland(element: Element): boolean;
1156
1346
 
1157
1347
  /**
@@ -1173,6 +1363,7 @@ declare function isInsideIsland(element: Element): boolean;
1173
1363
  * @packageDocumentation
1174
1364
  */
1175
1365
 
1366
+ /** @internal */
1176
1367
  declare const CORE_ENTRY = true;
1177
1368
 
1178
- export { AUTHORIZED_PREVIEW_BRAND_KEY, type AuthorizedPreviewContext, type AuthorizedPreviewScope, type BindOptions, CAPABILITY_DECLARATIONS, CAPABILITY_DOCUMENTATION, CORE_ENTRY, type CachedElement, type CapabilityDeclaration, type CapabilityDocumentation, type CapabilitySource, type ConnectionStatus, type CustomRendererKey, DIAGNOSTIC_CODES, type DefaultsProfile, type DiagnosticCode, EventEmitter, type EventHandler, type EventSourcePolicy, type FieldBindingAttributes, type FieldName, type FieldPath, type FieldRenderer, type FieldType, type FragmentContext, type FragmentReport, type FragmentStrategy, type FrameAncestorsOptions, ISLAND_EVENT, type InspectionBindings, type InspectionFragments, type InspectionOrigins, type InspectionProtocol, type InspectionRevisions, type InspectionRoute, type InspectionScheduler, type IslandUpdateDetail, LIBRARY_PROTOCOL_VERSION, LivePreviewClient, type LivePreviewClientConfig, type LivePreviewEventMap, type LivePreviewInspection, OriginDetector, type OwnerBindingAttributes, PROTOCOL_CAPABILITIES, type PayloadDocumentEventDetail, type PayloadFieldCondition, type PayloadFieldSchema, type PayloadFieldType, type PayloadLivePreviewData, type PayloadLivePreviewMessage, type PluginCompatibility, type PluginInspection, type PreviewAuthorizationStrategyName, type PreviewBindings, type PreviewBindingsCommonOptions, type PreviewBindingsOptions, type ProtocolCapability, type ProtocolNegotiation, type ProtocolProfile, type ProtocolProfileName, type RenderContext, type RendererKey, type RichTextRenderer, type RouteContext, type RouteStrategy, type SanitizerDocument, type SanitizerPolicyMode, type StrategyHandlers, type SuppressedBinding, type Unsubscribe, type UpdateSource, VERSION, type ValueAt, bind, bindByPath, buildFrameAncestors, buildScriptSrcWithNonce, createPreviewBindings, detectInitialLocale, detectProtocolProfile, escapeHtml, escapeHtmlAttribute, generateCspNonce, hasCapability, initLivePreview, isAuthorizedPreviewContext, isDevMode, isExternalHttpUrl, isInIframe, isInPopup, isInPreviewContext, isInsideIsland, isSafeUrl, negotiateProtocol, sanitizeHtml, setCspCrypto, setSanitizerDocument };
1369
+ export { AUTHORIZED_PREVIEW_BRAND_KEY, type AuthorizedPreviewContext, type AuthorizedPreviewScope, type BindOptions, CAPABILITY_DECLARATIONS, CAPABILITY_DOCUMENTATION, CORE_ENTRY, type CachedElement, type CapabilityDeclaration, type CapabilityDocumentation, type CapabilitySource, type ConnectionStatus, type CustomRendererKey, DIAGNOSTIC_CODES, type DefaultsProfile, type DiagnosticCode, EventEmitter, type EventHandler, type EventSourcePolicy, type FieldBindingAttributes, type FieldName, type FieldPath, type FieldRenderer, type FieldType, type FragmentBoundaryAttributes, type FragmentBoundaryOptions, type FragmentContext, type FragmentReport, type FragmentStrategy, type FrameAncestorsOptions, ISLAND_EVENT, type InspectionBindings, type InspectionFidelity, type InspectionFragments, type InspectionOrigins, type InspectionProtocol, type InspectionRevisions, type InspectionRoute, type InspectionScheduler, type IslandUpdateDetail, LIBRARY_PROTOCOL_VERSION, LivePreviewClient, type LivePreviewClientConfig, type LivePreviewEventMap, type LivePreviewInspection, OriginDetector, type OwnerBindingAttributes, PROTOCOL_CAPABILITIES, type PayloadDocumentEventDetail, type PayloadFieldCondition, type PayloadFieldSchema, type PayloadFieldType, type PayloadLivePreviewData, type PayloadLivePreviewMessage, type PluginCompatibility, type PluginInspection, type PreviewAuthorizationStrategyName, type PreviewBindings, type PreviewBindingsOptions, type ProtocolCapability, type ProtocolNegotiation, type ProtocolProfile, type ProtocolProfileName, type RenderContext, type RendererKey, type RichTextRenderer, type RouteContext, type RouteOutcome, type RouteRefresh, type RouteStrategy, type SanitizerDocument, type SanitizerPolicyMode, type StrategyHandlers, type SuppressedBinding, type Unsubscribe, type UpdateSource, VERSION, type ValueAt, bind, bindByPath, buildFrameAncestors, buildScriptSrcWithNonce, createPreviewBindings, detectInitialLocale, detectProtocolProfile, escapeHtml, escapeHtmlAttribute, generateCspNonce, hasCapability, initLivePreview, isAuthorizedPreviewContext, isDevMode, isExternalHttpUrl, isInIframe, isInPopup, isInPreviewContext, isInsideIsland, isSafeUrl, negotiateProtocol, registerRouteRefresh, sanitizeHtml, setCspCrypto, setSanitizerDocument };