payload-live-preview 2.0.6 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +141 -38
  2. package/dist/adapters/astro/FragmentBridge.astro +25 -0
  3. package/dist/adapters/astro/PreviewBoundary.astro +2 -4
  4. package/dist/adapters/astro/RichText.astro +26 -5
  5. package/dist/adapters/astro/index.d.ts +41 -9
  6. package/dist/adapters/astro/index.js +1 -1
  7. package/dist/adapters/astro/index.js.map +1 -1
  8. package/dist/adapters/astro/middleware-entry.d.ts +3 -3
  9. package/dist/adapters/astro/middleware-entry.js +1 -1
  10. package/dist/adapters/astro/middleware-entry.js.map +1 -1
  11. package/dist/adapters/nextjs/index.d.ts +17 -12
  12. package/dist/adapters/nextjs/index.js +1 -1
  13. package/dist/adapters/nextjs/index.js.map +1 -1
  14. package/dist/adapters/nuxt/index.d.ts +11 -6
  15. package/dist/adapters/nuxt/index.js +1 -1
  16. package/dist/adapters/nuxt/index.js.map +1 -1
  17. package/dist/adapters/nuxt/module.d.ts +64 -13
  18. package/dist/adapters/nuxt/module.js +1 -1
  19. package/dist/adapters/nuxt/module.js.map +1 -1
  20. package/dist/adapters/react/index.d.ts +11 -7
  21. package/dist/adapters/react/index.js +1 -1
  22. package/dist/adapters/react/index.js.map +1 -1
  23. package/dist/adapters/sveltekit/index.d.ts +10 -5
  24. package/dist/adapters/sveltekit/index.js +1 -1
  25. package/dist/adapters/sveltekit/index.js.map +1 -1
  26. package/dist/adapters/vue/index.d.ts +10 -7
  27. package/dist/adapters/vue/index.js +1 -1
  28. package/dist/adapters/vue/index.js.map +1 -1
  29. package/dist/annotate.d.ts +15 -2
  30. package/dist/annotate.js.map +1 -1
  31. package/dist/client.cjs +1 -1
  32. package/dist/client.cjs.map +1 -1
  33. package/dist/client.d.cts +367 -266
  34. package/dist/client.d.ts +367 -266
  35. package/dist/client.js +1 -1
  36. package/dist/client.js.map +1 -1
  37. package/dist/codegen-cli.js.map +1 -1
  38. package/dist/codegen.cjs.map +1 -1
  39. package/dist/codegen.d.cts +7 -1
  40. package/dist/codegen.d.ts +7 -1
  41. package/dist/codegen.js.map +1 -1
  42. package/dist/core.cjs +1 -1
  43. package/dist/core.cjs.map +1 -1
  44. package/dist/core.d.cts +544 -392
  45. package/dist/core.d.ts +544 -392
  46. package/dist/core.js +1 -1
  47. package/dist/core.js.map +1 -1
  48. package/dist/doctor-cli.d.ts +1 -1
  49. package/dist/doctor-cli.js +1 -1
  50. package/dist/doctor-cli.js.map +1 -1
  51. package/dist/doctor.d.ts +2 -2
  52. package/dist/doctor.js +1 -1
  53. package/dist/doctor.js.map +1 -1
  54. package/dist/{document-session-BfBfLVpg.d.ts → document-session-DWi9H3Qk.d.ts} +7 -0
  55. package/dist/{fragment-endpoint-DATKU183.d.ts → fragment-endpoint-B2qcRw5T.d.ts} +22 -7
  56. package/dist/fragment.cjs +1 -1
  57. package/dist/fragment.cjs.map +1 -1
  58. package/dist/fragment.d.cts +37 -16
  59. package/dist/fragment.d.ts +37 -16
  60. package/dist/fragment.js +1 -1
  61. package/dist/fragment.js.map +1 -1
  62. package/dist/index.cjs +1 -1
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +598 -400
  65. package/dist/index.d.ts +598 -400
  66. package/dist/index.js +1 -1
  67. package/dist/index.js.map +1 -1
  68. package/dist/lean.cjs +1 -1
  69. package/dist/lean.cjs.map +1 -1
  70. package/dist/lean.d.cts +5 -2
  71. package/dist/lean.d.ts +5 -2
  72. package/dist/lean.js +1 -1
  73. package/dist/lean.js.map +1 -1
  74. package/dist/lexical.cjs +1 -1
  75. package/dist/lexical.cjs.map +1 -1
  76. package/dist/lexical.d.cts +32 -11
  77. package/dist/lexical.d.ts +32 -11
  78. package/dist/lexical.js +1 -1
  79. package/dist/lexical.js.map +1 -1
  80. package/dist/{locals-CNUGYbA_.d.ts → locals-B1mF3aTb.d.ts} +1 -1
  81. package/dist/{middleware-CWObDO37.d.ts → middleware-BGobLN9P.d.ts} +11 -5
  82. package/dist/migrate.js +1 -1
  83. package/dist/migrate.js.map +1 -1
  84. package/dist/{options-uHKrDM2U.d.ts → options-Cm8fC7dj.d.ts} +31 -1
  85. package/dist/payload.cjs +1 -1
  86. package/dist/payload.cjs.map +1 -1
  87. package/dist/payload.d.cts +18 -2
  88. package/dist/payload.d.ts +18 -2
  89. package/dist/payload.js +1 -1
  90. package/dist/payload.js.map +1 -1
  91. package/dist/plugin.cjs +2 -0
  92. package/dist/plugin.cjs.map +1 -0
  93. package/dist/plugin.d.cts +30 -0
  94. package/dist/plugin.d.ts +30 -0
  95. package/dist/plugin.js +2 -0
  96. package/dist/plugin.js.map +1 -0
  97. package/dist/plugins.cjs +1 -1
  98. package/dist/plugins.cjs.map +1 -1
  99. package/dist/plugins.d.cts +102 -29
  100. package/dist/plugins.d.ts +102 -29
  101. package/dist/plugins.js +1 -1
  102. package/dist/plugins.js.map +1 -1
  103. package/dist/{probe-Bzm4fYFL.d.ts → probe-DGPDsnbj.d.ts} +6 -2
  104. package/dist/server.cjs +1 -1
  105. package/dist/server.cjs.map +1 -1
  106. package/dist/server.d.cts +43 -4
  107. package/dist/server.d.ts +43 -4
  108. package/dist/server.js +1 -1
  109. package/dist/server.js.map +1 -1
  110. package/dist/structural.cjs +2 -2
  111. package/dist/structural.cjs.map +1 -1
  112. package/dist/structural.d.cts +61 -13
  113. package/dist/structural.d.ts +61 -13
  114. package/dist/structural.js +2 -2
  115. package/dist/structural.js.map +1 -1
  116. package/package.json +33 -4
package/dist/core.d.ts CHANGED
@@ -2,280 +2,6 @@
2
2
  /** @internal */
3
3
  declare const VERSION: string;
4
4
 
5
- /** Connection status and the heartbeat that decides a disconnect. */
6
- type ConnectionStatus = 'disconnected' | 'connecting' | 'connected';
7
-
8
- /**
9
- * Shape of the `inspect()` snapshot. It only re-reads what the page already
10
- * shows — origins from the injected script, field names from the DOM,
11
- * counters derived from both — so it stays available in production, where a
12
- * misbehaving preview is exactly the case worth diagnosing. Reading one
13
- * performs no I/O and transmits nothing.
14
- */
15
-
16
- /** Origin trust as the runtime currently sees it. */
17
- interface InspectionOrigins {
18
- /** Configured origins; empty means the referrer and localhost heuristics decide instead. */
19
- readonly trusted: readonly string[];
20
- /** The origin locked onto by the first accepted update; every other is then refused. */
21
- readonly locked: string | undefined;
22
- }
23
- /** Protocol versions and the capabilities they enable. */
24
- interface InspectionProtocol {
25
- /** This library's protocol version. */
26
- readonly ours: number;
27
- /** The remote party's version, or `undefined` if it never announced one. */
28
- readonly theirs: number | undefined;
29
- /** `min(ours, theirs ?? 1)` — what both sides actually share. */
30
- readonly negotiated: number;
31
- /** Capability flags enabled at the negotiated version. */
32
- readonly capabilities: readonly string[];
33
- /** The subset of `capabilities` seen on the wire rather than granted by version. */
34
- readonly observed: readonly string[];
35
- /** The Payload profile the observed capabilities imply: `unknown`, `payload-2` or `payload-3`. */
36
- readonly profile: string;
37
- }
38
- /** Revision accounting for the update pipeline. */
39
- interface InspectionRevisions {
40
- /** Updates accepted since the runtime started. */
41
- readonly accepted: number;
42
- /**
43
- * Updates that were still in flight when a newer one arrived and were
44
- * therefore abandoned. A number that tracks `accepted` closely means the
45
- * editor is out-typing the pipeline, which is normal; it is only a problem
46
- * when the last update is among the abandoned ones.
47
- */
48
- readonly superseded: number;
49
- /**
50
- * Updates whose scheduled writes reached the DOM. What is neither
51
- * superseded nor completed is in flight or was cancelled; a `superseded`
52
- * that tracks `accepted` while `completed` stays low is the editor
53
- * out-typing the pipeline.
54
- */
55
- readonly completed: number;
56
- /**
57
- * Bindings not scheduled because their value was identical to the one last
58
- * applied. Cumulative since start; always `0` unless `skipUnchanged` is on.
59
- * A large number beside a small `accepted` is the optimisation working.
60
- */
61
- readonly skippedUnchanged: number;
62
- /** Revision currently in flight, or `undefined` when the pipeline is idle. */
63
- readonly active: number | undefined;
64
- }
65
- /** What the DOM offers the runtime to write into. */
66
- interface InspectionBindings {
67
- /** Elements carrying a binding. */
68
- readonly elements: number;
69
- /** Distinct field names across those elements. */
70
- readonly fields: number;
71
- /** Those field names, sorted. */
72
- readonly fieldNames: readonly string[];
73
- /**
74
- * Bound fields some update carried no value for, so the binding kept its old
75
- * text — why a binding can stay stale while its siblings update. Cumulative.
76
- */
77
- readonly absentFields: readonly string[];
78
- /**
79
- * Field names that arrived but matched no binding — a markup problem.
80
- * A name in neither this list nor `fieldNames` was never sent. Cumulative.
81
- */
82
- readonly orphanFields: readonly string[];
83
- /** Whether `scopeBindingsByOwner` is active. */
84
- readonly ownerScoped: boolean;
85
- /** Distinct document owners currently on the page, sorted. */
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
- };
104
- }
105
- /** Scheduler work in progress. */
106
- interface InspectionScheduler {
107
- /** Writes buffered for the next flush. */
108
- readonly pending: number;
109
- /** Writes held back offscreen above `visibilityGateThreshold`; applied when scrolled into view. */
110
- readonly deferred: number;
111
- /** The binding count above which the visibility gate starts deferring. */
112
- readonly visibilityGateThreshold: number;
113
- /** Whether the binding count is above that threshold right now. */
114
- readonly visibilityGateActive: boolean;
115
- /** Stats of the most recent flush, or `undefined` if none has run. */
116
- readonly lastFlush: {
117
- readonly applied: number;
118
- /** Which fields the flush wrote; a count alone cannot say a binding was skipped. */
119
- readonly appliedFields: readonly string[];
120
- readonly deferred: number;
121
- readonly durationMs: number;
122
- } | undefined;
123
- }
124
- /** A point-in-time read; plain values only, with no references into runtime internals. */
125
- interface LivePreviewInspection {
126
- /** Package version that produced this snapshot. */
127
- readonly version: string;
128
- /** Whether the runtime is started, and whether it has been destroyed. */
129
- readonly started: boolean;
130
- /** Connection status as reported to the `connect`/`disconnect` events. */
131
- readonly status: ConnectionStatus;
132
- readonly origins: InspectionOrigins;
133
- readonly protocol: InspectionProtocol;
134
- readonly revisions: InspectionRevisions;
135
- readonly bindings: InspectionBindings;
136
- readonly scheduler: InspectionScheduler;
137
- /** Field types with a registered renderer, sorted. */
138
- readonly renderers: readonly string[];
139
- /** Registered plugins and their live registrations; empty on a bare runtime. */
140
- readonly plugins: readonly PluginInspection[];
141
- /** Server-rendered fragment boundaries: whether a handler exists and what happened to renders. */
142
- readonly fragments: InspectionFragments;
143
- /** Route refreshes: whether a strategy exists, how many ran, failed, were paced, or were stopped by the loop guard. */
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 `canEscalate` is false: neither
162
- * `fragments.handler` nor `route.handler` is there to escalate to, which the
163
- * runtime also says once as LP0808 when `mode` is `'escalate'`.
164
- */
165
- interface InspectionFidelity {
166
- /** `onUnfaithfulPatch` as resolved from both of its names. */
167
- readonly mode: 'ignore' | 'warn' | 'escalate';
168
- /** Whether a fragment or route strategy exists for `'escalate'` to hand a patch to. */
169
- readonly canEscalate: boolean;
170
- /** Bindings reported unfaithful since start — once per element, like LP0411, and under every mode. */
171
- readonly unfaithful: number;
172
- /** Of those, how many were handed to the fragment or route strategy. */
173
- readonly escalated: number;
174
- /** The field names behind `unfaithful`, sorted. Cumulative. */
175
- readonly fields: readonly string[];
176
- }
177
- /** The route strategy as `inspect()` reports it. */
178
- interface InspectionRoute {
179
- readonly handler: boolean;
180
- readonly refreshes: number;
181
- /** Refreshes that broke: the request, the answer, or the morph. */
182
- readonly failed: number;
183
- /**
184
- * Refreshes the strategy's own minimum interval held back (LP0805). Each is
185
- * run once the window closes unless a newer revision takes its place, so this
186
- * counts pacing and not loss — and it is deliberately not `failed`.
187
- */
188
- readonly refused: number;
189
- /** Second refresh requests for one revision, refused with LP0805. */
190
- readonly loopStopped: number;
191
- }
192
- /** The fragment strategy as `inspect()` reports it. */
193
- interface InspectionFragments {
194
- /** Whether a fragment handler is configured; without one, boundaries are patched. */
195
- readonly handler: boolean;
196
- readonly inFlight: number;
197
- readonly rendered: number;
198
- readonly failed: number;
199
- readonly superseded: number;
200
- }
201
- /** One plugin as `inspect().plugins` reports it. */
202
- interface PluginInspection {
203
- readonly name: string;
204
- readonly version: string | undefined;
205
- /** `initializing` while `init` runs, `active` afterwards, `tearing-down` while `destroy` runs. */
206
- readonly state: 'initializing' | 'active' | 'tearing-down';
207
- /** Live registrations owned by the plugin's scope, by kind. */
208
- readonly registrations: {
209
- readonly transforms: number;
210
- readonly renderers: number;
211
- readonly subscriptions: number;
212
- readonly cleanups: number;
213
- };
214
- }
215
-
216
- /**
217
- * Payload's live-preview `postMessage` protocol as the shipped admin sends it:
218
- * raw form values on every edit, no schema. `previewToken` and
219
- * `protocolVersion` are extensions of this library for custom senders.
220
- */
221
- interface PayloadLivePreviewMessage {
222
- readonly type: 'payload-live-preview';
223
- readonly data?: Record<string, unknown>;
224
- /** Sent by Payload 2.x and custom senders only. */
225
- readonly fieldSchemaJSON?: readonly PayloadFieldSchema[];
226
- readonly globalSlug?: string;
227
- readonly collectionSlug?: string;
228
- readonly locale?: string;
229
- readonly ready?: boolean;
230
- /** Payload 3.x: the most recent relationship-document event (a drawer save), or `null`. */
231
- readonly externallyUpdatedRelationship?: PayloadDocumentEventDetail | null;
232
- /** Library extension: the token `validateToken` checks. Stock Payload never sends one. */
233
- readonly previewToken?: string;
234
- /** Library extension: the highest protocol version the sender supports; absent means v1. */
235
- readonly protocolVersion?: number;
236
- }
237
- /** Payload's `DocumentEvent` shape (admin `providers/DocumentEvents`). */
238
- interface PayloadDocumentEventDetail {
239
- readonly entitySlug: string;
240
- readonly operation?: 'create' | 'update';
241
- readonly id?: string | number;
242
- readonly updatedAt?: string;
243
- readonly [extra: string]: unknown;
244
- }
245
- /** A validated update as events expose it. */
246
- interface PayloadLivePreviewData {
247
- readonly fields: Record<string, unknown>;
248
- readonly schema?: readonly PayloadFieldSchema[];
249
- readonly globalSlug?: string;
250
- readonly collectionSlug?: string;
251
- readonly locale?: string;
252
- }
253
- /** The subset of Payload's field schema the runtime reads; extra properties are kept opaquely. */
254
- interface PayloadFieldSchema {
255
- readonly name: string;
256
- readonly type: PayloadFieldType;
257
- readonly label?: string;
258
- readonly required?: boolean;
259
- readonly localized?: boolean;
260
- readonly fields?: readonly PayloadFieldSchema[];
261
- readonly blocks?: readonly PayloadBlockSchema[];
262
- readonly relationTo?: string | readonly string[];
263
- readonly hasMany?: boolean;
264
- readonly admin?: {
265
- readonly condition?: PayloadFieldCondition;
266
- };
267
- readonly [extra: string]: unknown;
268
- }
269
- interface PayloadBlockSchema {
270
- readonly slug: string;
271
- readonly fields: readonly PayloadFieldSchema[];
272
- readonly [extra: string]: unknown;
273
- }
274
- /** Payload's core field types. `tabs` is a structural container; `group` flattens. */
275
- type PayloadFieldType = 'text' | 'textarea' | 'richText' | 'email' | 'number' | 'checkbox' | 'date' | 'select' | 'radio' | 'array' | 'blocks' | 'group' | 'tabs' | 'row' | 'collapsible' | 'relationship' | 'upload' | 'point' | 'json' | 'code' | 'ui';
276
- /** `admin.condition` is a function in source and cannot cross `postMessage`; modelled, not consumed. */
277
- type PayloadFieldCondition = (data: unknown, siblingData: unknown) => boolean;
278
-
279
5
  /**
280
6
  * Every diagnostic code the runtime and tools emit, so a consumer can branch
281
7
  * on `e.code` instead of matching message text. A code is never reused for a
@@ -355,13 +81,13 @@ declare const DIAGNOSTIC_CODES: Readonly<{
355
81
  readonly StartupFailed: "LP0605";
356
82
  /** Sending the ready handshake failed. */
357
83
  readonly ReadyFailed: "LP0606";
358
- /** The page declared hydration, but no React commit or Vue mount came within the cap; the runtime started without waiting. */
84
+ /** The page declared hydration, but no React commit, Vue mount or SvelteKit mount came within the cap; the runtime started without waiting. */
359
85
  readonly HydrationWaitTimedOut: "LP0607";
360
86
  /** The audit found no runtime in a response that carried preview intent. */
361
87
  readonly AuditRuntimeMissing: "LP0701";
362
88
  /** The preview response declares no `frame-ancestors`. */
363
89
  readonly AuditNoFrameAncestors: "LP0702";
364
- /** `X-Frame-Options` forbids framing, which no CSP can undo; `SAMEORIGIN` forbids it from another origin only. */
90
+ /** `X-Frame-Options` forbids framing on a response that declares no `frame-ancestors`; `SAMEORIGIN` forbids it from another origin only. */
365
91
  readonly AuditFrameOptionsBlocks: "LP0703";
366
92
  /** Binding attributes are served to anonymous visitors. */
367
93
  readonly AuditBindingsExposed: "LP0704";
@@ -389,6 +115,10 @@ declare const DIAGNOSTIC_CODES: Readonly<{
389
115
  readonly UnboundChangeRefresh: "LP0807";
390
116
  /** `onUnfaithfulPatch: 'escalate'` found no route or fragment strategy to hand an unfaithful patch to; the page keeps it. */
391
117
  readonly EscalationUnavailable: "LP0808";
118
+ /** A fragment inserted an Astro island the page cannot start: it never loaded the island element or that client directive. */
119
+ readonly IslandStartUnavailable: "LP0809";
120
+ /** The host's route refresh returned no promise, so the revision was re-applied before the host committed. */
121
+ readonly RouteRefreshUnconfirmed: "LP0810";
392
122
  /** A readiness row is not yet at its 2.0 value; `pll doctor --v2` reports it. */
393
123
  readonly V2ReadinessGap: "LP0709";
394
124
  /** The preview runtime is served to anonymous visitors, not only inside the admin frame. */
@@ -397,6 +127,69 @@ declare const DIAGNOSTIC_CODES: Readonly<{
397
127
  /** A diagnostic code, as it appears in log output and on the `error` event. */
398
128
  type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];
399
129
 
130
+ /**
131
+ * Payload's live-preview `postMessage` protocol as the shipped admin sends it:
132
+ * raw form values on every edit, no schema. `previewToken` and
133
+ * `protocolVersion` are extensions of this library for custom senders.
134
+ */
135
+ interface PayloadLivePreviewMessage {
136
+ readonly type: 'payload-live-preview';
137
+ readonly data?: Record<string, unknown>;
138
+ /** Sent by Payload 2.x and custom senders only. */
139
+ readonly fieldSchemaJSON?: readonly PayloadFieldSchema[];
140
+ readonly globalSlug?: string;
141
+ readonly collectionSlug?: string;
142
+ readonly locale?: string;
143
+ readonly ready?: boolean;
144
+ /** Payload 3.x: the most recent relationship-document event (a drawer save), or `null`. */
145
+ readonly externallyUpdatedRelationship?: PayloadDocumentEventDetail | null;
146
+ /** Library extension: the token `validateToken` checks. Stock Payload never sends one. */
147
+ readonly previewToken?: string;
148
+ /** Library extension: the highest protocol version the sender supports; absent means v1. */
149
+ readonly protocolVersion?: number;
150
+ }
151
+ /** Payload's `DocumentEvent` shape (admin `providers/DocumentEvents`). */
152
+ interface PayloadDocumentEventDetail {
153
+ readonly entitySlug: string;
154
+ readonly operation?: 'create' | 'update';
155
+ readonly id?: string | number;
156
+ readonly updatedAt?: string;
157
+ readonly [extra: string]: unknown;
158
+ }
159
+ /** A validated update as events expose it. */
160
+ interface PayloadLivePreviewData {
161
+ readonly fields: Record<string, unknown>;
162
+ readonly schema?: readonly PayloadFieldSchema[];
163
+ readonly globalSlug?: string;
164
+ readonly collectionSlug?: string;
165
+ readonly locale?: string;
166
+ }
167
+ /** The subset of Payload's field schema the runtime reads; extra properties are kept opaquely. */
168
+ interface PayloadFieldSchema {
169
+ readonly name: string;
170
+ readonly type: PayloadFieldType;
171
+ readonly label?: string;
172
+ readonly required?: boolean;
173
+ readonly localized?: boolean;
174
+ readonly fields?: readonly PayloadFieldSchema[];
175
+ readonly blocks?: readonly PayloadBlockSchema[];
176
+ readonly relationTo?: string | readonly string[];
177
+ readonly hasMany?: boolean;
178
+ readonly admin?: {
179
+ readonly condition?: PayloadFieldCondition;
180
+ };
181
+ readonly [extra: string]: unknown;
182
+ }
183
+ interface PayloadBlockSchema {
184
+ readonly slug: string;
185
+ readonly fields: readonly PayloadFieldSchema[];
186
+ readonly [extra: string]: unknown;
187
+ }
188
+ /** Payload's core field types. `tabs` is a structural container; `group` flattens. */
189
+ type PayloadFieldType = 'text' | 'textarea' | 'richText' | 'email' | 'number' | 'checkbox' | 'date' | 'select' | 'radio' | 'array' | 'blocks' | 'group' | 'tabs' | 'row' | 'collapsible' | 'relationship' | 'upload' | 'point' | 'json' | 'code' | 'ui';
190
+ /** `admin.condition` is a function in source and cannot cross `postMessage`; modelled, not consumed. */
191
+ type PayloadFieldCondition = (data: unknown, siblingData: unknown) => boolean;
192
+
400
193
  /**
401
194
  * How a bound region is brought up to date: the runtime patches it, a server
402
195
  * renders a `data-payload-fragment` boundary from the unsaved form state, or
@@ -420,9 +213,9 @@ interface FragmentContext {
420
213
  readonly signal: AbortSignal;
421
214
  /** Whether this revision is still the current one. */
422
215
  readonly isCurrent: () => boolean;
423
- /** Morph server-rendered HTML into a boundary (Trusted Types and the keyed morph apply). */
216
+ /** Morph server-rendered HTML into a boundary; no-op after supersession (Trusted Types and the keyed morph apply). */
424
217
  readonly morph: (boundary: Element, html: string) => void;
425
- /** Patch the boundary's own bindings from this revision — the deterministic fallback. */
218
+ /** Patch the boundary's owned bindings from this revision; no-op after supersession. */
426
219
  readonly patch: (boundary: Element) => void;
427
220
  /** Debug log through the runtime's logger, with the diagnostic code. */
428
221
  readonly log: (code: DiagnosticCode, detail: string) => void;
@@ -447,8 +240,13 @@ interface FragmentStrategy {
447
240
  interface RouteContext {
448
241
  readonly revision: number;
449
242
  readonly receivedAt: number;
450
- /** Aborted when a newer revision arrives or the runtime stops. */
243
+ /** Aborted when a newer revision asks for a refresh of its own, a navigation commits, or the runtime stops. */
451
244
  readonly signal: AbortSignal;
245
+ /**
246
+ * Whether the refresh may still land. A newer revision that asks for no
247
+ * refresh of its own does not end it: the route is the server's, so the
248
+ * refresh lands for that revision, which the runtime then re-applies.
249
+ */
452
250
  readonly isCurrent: () => boolean;
453
251
  readonly log: (code: DiagnosticCode, detail: string) => void;
454
252
  /**
@@ -461,18 +259,30 @@ interface RouteContext {
461
259
  readonly retryAfter?: (delayMs: number) => void;
462
260
  }
463
261
  /**
464
- * What one refresh did. `refused` is the strategy's own brake and not a
465
- * failure — it is counted separately, because a number that mixes a planned
466
- * pause with a broken request cannot be read.
262
+ * What one refresh did. `refreshed` asserts that the strategy rendered the
263
+ * current unsaved revision. `partial` completed a render whose data source was
264
+ * not proven current; the runtime still reapplies every binding it can reach.
265
+ * `refused` is the strategy's own brake and not a failure.
467
266
  */
468
- type RouteOutcome = 'refreshed' | 'failed' | 'refused' | 'superseded';
267
+ type RouteOutcome = 'refreshed' | 'partial' | 'failed' | 'refused' | 'superseded';
268
+ /** What the runtime tells a route planner about the update it plans for. */
269
+ interface RoutePlanContext {
270
+ /**
271
+ * Whether an element belongs to the update: always `true` without
272
+ * `scopeBindingsByOwner`, otherwise only inside the document the update
273
+ * names. A marker outside it asks for nothing.
274
+ */
275
+ readonly inScope: (element: Element) => boolean;
276
+ }
469
277
  /**
470
278
  * Whether a revision needs the whole route re-rendered, and how. After a
471
- * refresh the runtime rescans and re-applies the revision, so the unsaved
472
- * state lands on the fresh markup.
279
+ * refresh the runtime rescans and re-applies the revision, so reachable
280
+ * unsaved bindings land on the fresh markup. The runtime always passes
281
+ * `context`; a planner written before it existed still works, but plans for
282
+ * markers of every document.
473
283
  */
474
284
  interface RouteStrategy {
475
- readonly plan: (root: ParentNode, changedFields: ReadonlySet<string>) => boolean;
285
+ readonly plan: (root: ParentNode, changedFields: ReadonlySet<string>, context?: RoutePlanContext) => boolean;
476
286
  readonly refresh: (context: RouteContext) => Promise<RouteOutcome>;
477
287
  }
478
288
  interface StrategyHandlers {
@@ -542,6 +352,12 @@ interface LivePreviewEventMap {
542
352
  readonly revision: number;
543
353
  readonly receivedAt: number;
544
354
  };
355
+ /**
356
+ * A revision left `pending`: it is current, partial (with the shortfalls
357
+ * that kept it from being current), unconfirmed by an island, or superseded.
358
+ * Fires again when an unconfirmed revision is confirmed (ADR 0023).
359
+ */
360
+ readonly revisionDisplay: RevisionDisplay;
545
361
  /** A `payload-document-event` message arrived (document save). */
546
362
  readonly documentSave: {
547
363
  readonly timestamp: number;
@@ -630,6 +446,12 @@ interface SanitizeOptions {
630
446
  * never add a binding.
631
447
  */
632
448
  readonly templateMode?: boolean;
449
+ /**
450
+ * The DOM to parse with, for this call: an SSR document such as linkedom's
451
+ * or jsdom's. Wins over `setSanitizerDocument()` and over the global
452
+ * `document`, and two callers with two documents never share one.
453
+ */
454
+ readonly document?: SanitizerDocument;
633
455
  }
634
456
  /** The `Document` surface the sanitizer needs; jsdom, linkedom and happy-dom all provide it. */
635
457
  interface SanitizerDocument {
@@ -638,10 +460,19 @@ interface SanitizerDocument {
638
460
  readonly content: ParentNode;
639
461
  };
640
462
  }
641
- /** Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`; `null` clears it, for every entry. */
463
+ /**
464
+ * Supply a `Document` for SSR, e.g. linkedom's `parseHTML(...).document`;
465
+ * `null` clears it, for every entry. The fallback for a call that names no
466
+ * document of its own.
467
+ *
468
+ * @deprecated Since 2.1 a call names its document: `sanitizeHtml(html, { document })`,
469
+ * `lexicalToHtml(content, { document })`. The process-wide slot stays until 3.0
470
+ * (ADR 0007 ledger).
471
+ */
642
472
  declare function setSanitizerDocument(doc: SanitizerDocument | null): void;
643
473
  /**
644
- * Sanitize `html`; malformed input is recovered by the parser first.
474
+ * Sanitize `html`; malformed input is recovered by the parser first. The
475
+ * result is a fixed point: sanitising it again changes nothing.
645
476
  *
646
477
  * @throws {SanitizerEnvironmentError} when no DOM is available.
647
478
  */
@@ -703,45 +534,385 @@ interface CachedElement {
703
534
  /** The document this binding belongs to, from the nearest `data-payload-owner`. */
704
535
  readonly owner?: string;
705
536
  /**
706
- * The value an auto-binding matched on (`data-payload-guessed`), for a
707
- * binding the runtime found by value rather than one the template declared.
708
- * Absent for a declared binding.
537
+ * The value an auto-binding matched on (`data-payload-guessed`), for a
538
+ * binding the runtime found by value rather than one the template declared.
539
+ * Absent for a declared binding.
540
+ */
541
+ readonly guessed?: string;
542
+ }
543
+ /** What a renderer is given; `allFields` lets it resolve a sibling field. */
544
+ interface RenderContext {
545
+ /** Full field map for the current update — used for sibling lookups. */
546
+ readonly allFields: Record<string, unknown>;
547
+ /** Active locale, or `undefined` when none is established. */
548
+ readonly locale: string | undefined;
549
+ /** Optional schema descriptor for the field, when available. */
550
+ readonly schema: PayloadFieldSchema | undefined;
551
+ /** The project's rich-text renderer, when the client was configured with one. */
552
+ readonly renderRichText?: RichTextRenderer;
553
+ /**
554
+ * The Payload server the runtime reads populated documents from (`serverURL`),
555
+ * absent without one. A renderer that writes a URL out of a media document
556
+ * resolves a path against it, as Payload's admin does; the built-in `upload`
557
+ * and `image` renderers do.
558
+ */
559
+ readonly serverURL?: string;
560
+ /**
561
+ * This instance's sanitizer policy, for every HTML write the renderer makes.
562
+ * Absent, the process default set by `setSanitizerPolicy()` applies.
563
+ */
564
+ readonly sanitizerPolicy?: SanitizerPolicyMode;
565
+ /**
566
+ * Say that this write cannot reproduce what the server drew, so
567
+ * `onUnfaithfulPatch` can have a strategy render the region instead of
568
+ * leaving a degraded patch on the page. The built-in rich-text renderer
569
+ * calls it for a Lexical block whose markup it had to drop; a project
570
+ * renderer may call it for any value it can only approximate. `reason`
571
+ * completes the sentence 'field "x" …' in LP0411.
572
+ */
573
+ readonly reportUnfaithful?: (target: CachedElement, reason: string) => void;
574
+ }
575
+ /**
576
+ * A renderer writes one value into its element. It must not throw: one bad
577
+ * field may not stop an update. The result stays `void` — the internal
578
+ * no-write sentinel is not part of the contract.
579
+ */
580
+ interface FieldRenderer {
581
+ readonly name: RendererKey;
582
+ render(target: CachedElement, value: unknown, context: RenderContext): void;
583
+ }
584
+
585
+ /**
586
+ * Protocol negotiation. A capability is granted either by the version a peer
587
+ * announces or by observation, since the stock Payload admin announces none:
588
+ * what it can do is read off the messages it sends. See ADR 0010.
589
+ */
590
+ /** Bumped only when this library's understanding of the wire format changes. @internal */
591
+ declare const LIBRARY_PROTOCOL_VERSION = 4;
592
+ /** How a capability becomes active. @internal */
593
+ type CapabilitySource = 'version' | 'observed';
594
+ /** @internal */
595
+ interface CapabilityDeclaration {
596
+ /** Enabled once the negotiated version reaches this (for announced peers). */
597
+ readonly since: number;
598
+ /** The wire signal that grants this capability to a peer announcing no version. */
599
+ readonly observed?: 'schema' | 'locale' | 'preview-token' | 'document-event' | 'relationship-event';
600
+ }
601
+ /** What activates each capability; the prose lives in `CAPABILITY_DOCUMENTATION`. */
602
+ declare const CAPABILITY_DECLARATIONS: {
603
+ readonly basic: {
604
+ readonly since: 1;
605
+ };
606
+ readonly 'schema-json': {
607
+ readonly since: 2;
608
+ readonly observed: "schema";
609
+ };
610
+ readonly locale: {
611
+ readonly since: 2;
612
+ readonly observed: "locale";
613
+ };
614
+ readonly 'preview-token': {
615
+ readonly since: 3;
616
+ readonly observed: "preview-token";
617
+ };
618
+ readonly 'nested-arrays': {
619
+ readonly since: 4;
620
+ };
621
+ readonly 'recursive-diffs': {
622
+ readonly since: 4;
623
+ };
624
+ readonly 'document-events': {
625
+ readonly since: 4;
626
+ readonly observed: "document-event";
627
+ };
628
+ readonly 'relationship-events': {
629
+ readonly since: 4;
630
+ readonly observed: "relationship-event";
631
+ };
632
+ };
633
+ type ProtocolCapability = keyof typeof CAPABILITY_DECLARATIONS;
634
+ /** Every declared capability, in declaration order. @internal */
635
+ declare const PROTOCOL_CAPABILITIES: readonly ProtocolCapability[];
636
+ interface ProtocolNegotiation {
637
+ /** This library's protocol version. */
638
+ readonly ours: number;
639
+ /** The remote party's version, when it announced one. */
640
+ readonly theirs: number | undefined;
641
+ /** `min(ours, theirs ?? 1)` — the version both sides actually share. */
642
+ readonly negotiated: number;
643
+ /** Capabilities active at the negotiated version or seen on the wire. */
644
+ readonly capabilities: ReadonlySet<ProtocolCapability>;
645
+ /** The subset that was observed on the wire rather than granted by version. */
646
+ readonly observed: ReadonlySet<ProtocolCapability>;
647
+ }
648
+ /** Deterministic; the runtime re-runs it whenever either input changes. */
649
+ declare function negotiateProtocol(theirs: number | undefined, observed?: Iterable<ProtocolCapability>): ProtocolNegotiation;
650
+ /** @internal */
651
+ declare function hasCapability(negotiation: ProtocolNegotiation, capability: ProtocolCapability): boolean;
652
+
653
+ /** Connection status and the heartbeat that decides a disconnect. */
654
+ type ConnectionStatus = 'disconnected' | 'connecting' | 'connected';
655
+
656
+ /**
657
+ * How completely the page shows one revision (ADR 0023). The session counters
658
+ * say what happened over a session; this says, for the revision in flight,
659
+ * whether work is outstanding and which step fell short, so a host does not
660
+ * have to attribute route outcomes and fragment fallbacks itself.
661
+ */
662
+
663
+ /** Where a revision stands: work left, shown, shown with shortfalls, awaiting an island, or replaced (ADR 0023). */
664
+ type RevisionDisplayState = 'pending' | 'current' | 'partial' | 'unconfirmed' | 'superseded';
665
+ /** One step that kept a settled revision from being current. */
666
+ type RevisionShortfall = {
667
+ readonly kind: 'fragment';
668
+ readonly id: string;
669
+ readonly key: string | undefined;
670
+ readonly code: DiagnosticCode;
671
+ } | {
672
+ readonly kind: 'route-saved';
673
+ } | {
674
+ readonly kind: 'route-failed';
675
+ readonly outcome: RouteOutcome;
676
+ } | {
677
+ readonly kind: 'unfaithful' | 'unbound';
678
+ readonly field: string;
679
+ } | {
680
+ readonly kind: 'write';
681
+ readonly field: string;
682
+ readonly code: DiagnosticCode;
683
+ } | {
684
+ readonly kind: 'merge';
685
+ };
686
+ /** How completely the page shows one accepted revision (ADR 0023). */
687
+ interface RevisionDisplay {
688
+ /** The message revision this record is about. */
689
+ readonly revision: number;
690
+ /** `pending` while work is left; the other states once it settled. */
691
+ readonly state: RevisionDisplayState;
692
+ /** What kept a settled revision from being current; empty unless `state` is `partial`. */
693
+ readonly shortfalls: readonly RevisionShortfall[];
694
+ /** Writes the visibility gate holds until their element is seen; they count as landed. */
695
+ readonly deferred: number;
696
+ /** Islands the revision was handed to that have not called `displayed()`. */
697
+ readonly awaitingIslands: number;
698
+ }
699
+
700
+ /**
701
+ * Shape of the `inspect()` snapshot. It only re-reads what the page already
702
+ * shows — origins from the injected script, field names from the DOM,
703
+ * counters derived from both — so it stays available in production, where a
704
+ * misbehaving preview is exactly the case worth diagnosing. Reading one
705
+ * performs no I/O and transmits nothing.
706
+ */
707
+
708
+ /** Origin trust as the runtime currently sees it. */
709
+ interface InspectionOrigins {
710
+ /** Configured origins; empty means the referrer and localhost heuristics decide instead. */
711
+ readonly trusted: readonly string[];
712
+ /** The origin locked onto by the first accepted update; every other is then refused. */
713
+ readonly locked: string | undefined;
714
+ }
715
+ /** Protocol versions and the capabilities they enable. */
716
+ interface InspectionProtocol {
717
+ /** This library's protocol version. */
718
+ readonly ours: number;
719
+ /** The remote party's version, or `undefined` if it never announced one. */
720
+ readonly theirs: number | undefined;
721
+ /** `min(ours, theirs ?? 1)` — what both sides actually share. */
722
+ readonly negotiated: number;
723
+ /** Capability flags enabled at the negotiated version. */
724
+ readonly capabilities: readonly string[];
725
+ /** The subset of `capabilities` seen on the wire rather than granted by version. */
726
+ readonly observed: readonly string[];
727
+ /** The Payload profile the observed capabilities imply: `unknown`, `payload-2` or `payload-3`. */
728
+ readonly profile: string;
729
+ }
730
+ /** Revision accounting for the update pipeline. */
731
+ interface InspectionRevisions {
732
+ /** Updates accepted since the runtime started. */
733
+ readonly accepted: number;
734
+ /**
735
+ * Updates that were still in flight when a newer one arrived and were
736
+ * therefore abandoned. A number that tracks `accepted` closely means the
737
+ * editor is out-typing the pipeline, which is normal; it is only a problem
738
+ * when the last update is among the abandoned ones.
739
+ */
740
+ readonly superseded: number;
741
+ /**
742
+ * Updates whose scheduled writes reached the DOM. What is neither
743
+ * superseded nor completed is in flight or was cancelled; a `superseded`
744
+ * that tracks `accepted` while `completed` stays low is the editor
745
+ * out-typing the pipeline.
746
+ */
747
+ readonly completed: number;
748
+ /**
749
+ * Bindings not scheduled because their value was identical to the one last
750
+ * applied. Cumulative since start; always `0` unless `skipUnchanged` is on.
751
+ * A large number beside a small `accepted` is the optimisation working.
709
752
  */
710
- readonly guessed?: string;
753
+ readonly skippedUnchanged: number;
754
+ /** Revision currently in flight, or `undefined` when the pipeline is idle. */
755
+ readonly active: number | undefined;
756
+ /**
757
+ * How completely the page shows the latest accepted revision (ADR 0023):
758
+ * `pending`, `current`, `partial` with its shortfalls, or `unconfirmed` while
759
+ * an island it was handed has not called `displayed()`. `undefined` before
760
+ * the first message.
761
+ */
762
+ readonly display: RevisionDisplay | undefined;
711
763
  }
712
- /** What a renderer is given; `allFields` lets it resolve a sibling field. */
713
- interface RenderContext {
714
- /** Full field map for the current update — used for sibling lookups. */
715
- readonly allFields: Record<string, unknown>;
716
- /** Active locale, or `undefined` when none is established. */
717
- readonly locale: string | undefined;
718
- /** Optional schema descriptor for the field, when available. */
719
- readonly schema: PayloadFieldSchema | undefined;
720
- /** The project's rich-text renderer, when the client was configured with one. */
721
- readonly renderRichText?: RichTextRenderer;
764
+ /** What the DOM offers the runtime to write into. */
765
+ interface InspectionBindings {
766
+ /** Elements carrying a binding. */
767
+ readonly elements: number;
768
+ /** Distinct field names across those elements. */
769
+ readonly fields: number;
770
+ /** Those field names, sorted. */
771
+ readonly fieldNames: readonly string[];
722
772
  /**
723
- * This instance's sanitizer policy, for every HTML write the renderer makes.
724
- * Absent, the process default set by `setSanitizerPolicy()` applies.
773
+ * Bound fields some update carried no value for, so the binding kept its old
774
+ * text — why a binding can stay stale while its siblings update. Cumulative.
725
775
  */
726
- readonly sanitizerPolicy?: SanitizerPolicyMode;
776
+ readonly absentFields: readonly string[];
727
777
  /**
728
- * Say that this write cannot reproduce what the server drew, so
729
- * `onUnfaithfulPatch` can have a strategy render the region instead of
730
- * leaving a degraded patch on the page. The built-in rich-text renderer
731
- * calls it for a Lexical block whose markup it had to drop; a project
732
- * renderer may call it for any value it can only approximate. `reason`
733
- * completes the sentence 'field "x" …' in LP0411.
778
+ * Scalar fields (and one group level) that arrived but matched no binding.
779
+ * Arrays, relationships, rich text, `null` and the fields Payload sends with
780
+ * every update are never listed. Cumulative.
734
781
  */
735
- readonly reportUnfaithful?: (target: CachedElement, reason: string) => void;
782
+ readonly orphanFields: readonly string[];
783
+ /** Whether `scopeBindingsByOwner` is active. */
784
+ readonly ownerScoped: boolean;
785
+ /** Distinct document owners currently on the page, sorted. */
786
+ readonly owners: readonly string[];
787
+ /**
788
+ * Bindings the runtime found by value on the connection's first message
789
+ * (`autoBind: 'unique'`, ADR 0014), sorted by field, each with the value it
790
+ * matched on and the attribute it matched in — `undefined` for a text match.
791
+ * These are the elements that change without a `data-payload-field` in the
792
+ * template; every one of them carries `data-payload-guessed` in the DOM.
793
+ */
794
+ readonly guessed: readonly {
795
+ readonly field: string;
796
+ readonly matched: string;
797
+ readonly attribute: string | undefined;
798
+ }[];
799
+ /** `autoBind` as configured, and what the one search cost; `searchMs` is `undefined` until it ran. */
800
+ readonly autoBind: {
801
+ readonly mode: 'off' | 'unique';
802
+ readonly searchMs: number | undefined;
803
+ };
804
+ }
805
+ /** Scheduler work in progress. */
806
+ interface InspectionScheduler {
807
+ /** Writes buffered for the next flush. */
808
+ readonly pending: number;
809
+ /** Writes held back offscreen above `visibilityGateThreshold`; applied when scrolled into view. */
810
+ readonly deferred: number;
811
+ /** The binding count above which the visibility gate starts deferring. */
812
+ readonly visibilityGateThreshold: number;
813
+ /** Whether the binding count is above that threshold right now. */
814
+ readonly visibilityGateActive: boolean;
815
+ /** Stats of the most recent flush, or `undefined` if none has run. */
816
+ readonly lastFlush: {
817
+ readonly applied: number;
818
+ /** Which fields the flush wrote; a count alone cannot say a binding was skipped. */
819
+ readonly appliedFields: readonly string[];
820
+ readonly deferred: number;
821
+ readonly durationMs: number;
822
+ } | undefined;
823
+ }
824
+ /** A point-in-time read; plain values only, with no references into runtime internals. */
825
+ interface LivePreviewInspection {
826
+ /** Package version that produced this snapshot. */
827
+ readonly version: string;
828
+ /** Whether the runtime is started, and whether it has been destroyed. */
829
+ readonly started: boolean;
830
+ /** Connection status as reported to the `connect`/`disconnect` events. */
831
+ readonly status: ConnectionStatus;
832
+ readonly origins: InspectionOrigins;
833
+ readonly protocol: InspectionProtocol;
834
+ readonly revisions: InspectionRevisions;
835
+ readonly bindings: InspectionBindings;
836
+ readonly scheduler: InspectionScheduler;
837
+ /** Field types with a registered renderer, sorted. */
838
+ readonly renderers: readonly string[];
839
+ /** Registered plugins and their live registrations; empty on a bare runtime. */
840
+ readonly plugins: readonly PluginInspection[];
841
+ /** Server-rendered fragment boundaries: whether a handler exists and what happened to renders. */
842
+ readonly fragments: InspectionFragments;
843
+ /** Route refreshes: whether a strategy exists, how many ran, failed, were paced, or were stopped by the loop guard. */
844
+ readonly route: InspectionRoute;
845
+ /** Patches the runtime knew could not match the server's render, and what became of them. */
846
+ readonly fidelity: InspectionFidelity;
847
+ /**
848
+ * Whether the page declared a framework that hydrates it, and how far the
849
+ * wait for its first commit — React's, Vue's mount, or SvelteKit's root
850
+ * mounting — got (ADR 0015). `waiting` is why a preview on a Next, Nuxt or
851
+ * SvelteKit page is not connected yet; `timed-out` is LP0607.
852
+ */
853
+ readonly hydration: {
854
+ readonly mode: 'off' | 'react' | 'vue' | 'sveltekit';
855
+ readonly state: 'idle' | 'waiting' | 'committed' | 'timed-out';
856
+ };
736
857
  }
737
858
  /**
738
- * A renderer writes one value into its element. It must not throw: one bad
739
- * field may not stop an update. The result stays `void` — the internal
740
- * no-write sentinel is not part of the contract.
859
+ * The fidelity verdicts as `inspect()` reports them (LP0411). A positive
860
+ * `unfaithful` beside `escalated: 0` is a page that keeps a degraded patch —
861
+ * because `mode` says so, or because `canEscalate` is false: neither
862
+ * `fragments.handler` nor `route.handler` is there to escalate to, which the
863
+ * runtime also says once as LP0808 when `mode` is `'escalate'`.
741
864
  */
742
- interface FieldRenderer {
743
- readonly name: RendererKey;
744
- render(target: CachedElement, value: unknown, context: RenderContext): void;
865
+ interface InspectionFidelity {
866
+ /** `onUnfaithfulPatch` as resolved from both of its names. */
867
+ readonly mode: 'ignore' | 'warn' | 'escalate';
868
+ /** Whether a fragment or route strategy exists for `'escalate'` to hand a patch to. */
869
+ readonly canEscalate: boolean;
870
+ /** Bindings reported unfaithful since start — once per element, like LP0411, and under every mode. */
871
+ readonly unfaithful: number;
872
+ /** Of those, how many were handed to the fragment or route strategy. */
873
+ readonly escalated: number;
874
+ /** The field names behind `unfaithful`, sorted. Cumulative. */
875
+ readonly fields: readonly string[];
876
+ }
877
+ /** The route strategy as `inspect()` reports it. */
878
+ interface InspectionRoute {
879
+ readonly handler: boolean;
880
+ readonly refreshes: number;
881
+ /** Successful refreshes whose server render was not proven to contain the current unsaved revision. */
882
+ readonly partial: number;
883
+ /** Refreshes that broke: the request, the answer, or the morph. */
884
+ readonly failed: number;
885
+ /**
886
+ * Refreshes the strategy's own minimum interval held back (LP0805). Each is
887
+ * run once the window closes unless a newer revision takes its place, so this
888
+ * counts pacing and not loss — and it is deliberately not `failed`.
889
+ */
890
+ readonly refused: number;
891
+ /** Second refresh requests for one revision, refused with LP0805. */
892
+ readonly loopStopped: number;
893
+ }
894
+ /** The fragment strategy as `inspect()` reports it. */
895
+ interface InspectionFragments {
896
+ /** Whether a fragment handler is configured; without one, boundaries are patched. */
897
+ readonly handler: boolean;
898
+ readonly inFlight: number;
899
+ readonly rendered: number;
900
+ readonly failed: number;
901
+ readonly superseded: number;
902
+ }
903
+ /** One plugin as `inspect().plugins` reports it. */
904
+ interface PluginInspection {
905
+ readonly name: string;
906
+ readonly version: string | undefined;
907
+ /** `initializing` while `init` runs, `active` afterwards, `tearing-down` while `destroy` runs. */
908
+ readonly state: 'initializing' | 'active' | 'tearing-down';
909
+ /** Live registrations owned by the plugin's scope, by kind. */
910
+ readonly registrations: {
911
+ readonly transforms: number;
912
+ readonly renderers: number;
913
+ readonly subscriptions: number;
914
+ readonly cleanups: number;
915
+ };
745
916
  }
746
917
 
747
918
  /**
@@ -856,6 +1027,13 @@ interface LivePreviewClientConfig {
856
1027
  * and listed in `inspect().bindings.guessed`. Default `'off'`.
857
1028
  */
858
1029
  readonly autoBind?: 'off' | 'unique';
1030
+ /**
1031
+ * How a group counts as covered (ADR 0022). `'descendant'` (default): one
1032
+ * bound path inside it covers all of it. `'declared'`: each changed path
1033
+ * inside such a group needs its own binding or a `data-payload-covers`
1034
+ * declaration; an uncovered one is an unbound change.
1035
+ */
1036
+ readonly subfieldCoverage?: 'descendant' | 'declared';
859
1037
  /** Fields whose change re-applies other bindings regardless of their own value: `{ price: ['priceLabel'] }`. Used with `skipUnchanged`. */
860
1038
  readonly dependencies?: Readonly<Record<string, readonly string[]>>;
861
1039
  /** Strategy handlers beyond patching; `createFragmentStrategy()` from `payload-live-preview/fragment` builds one. */
@@ -921,7 +1099,10 @@ declare class LivePreviewClient {
921
1099
  use(plugin: LivePreviewPlugin): Promise<void>;
922
1100
  /** Unregister a plugin and release everything its registration owned. Still allowed from a destroy hook during teardown. */
923
1101
  unuse(name: string): Promise<void>;
1102
+ /** Re-scan bindings after replacing markup without crossing a navigation boundary. */
924
1103
  refreshCache(): void;
1104
+ /** Re-scan bindings and locally replay the last accepted document after a router commit. */
1105
+ refreshAfterNavigation(): void;
925
1106
  get events(): EventEmitter;
926
1107
  /** Names of the registered plugins. */
927
1108
  get plugins(): readonly string[];
@@ -1011,6 +1192,25 @@ declare function buildScriptSrcWithNonce(nonce: string, options?: {
1011
1192
  */
1012
1193
  declare const AUTHORIZED_PREVIEW_BRAND_KEY = "payload-live-preview.authorized-preview-context";
1013
1194
  type PreviewAuthorizationStrategyName = 'payload-session' | 'signed-token' | 'verifier';
1195
+ /** One server-authorized Payload document, not a query selected by the browser. */
1196
+ type AuthorizedPreviewDocument = {
1197
+ readonly kind: 'collection';
1198
+ readonly slug: string;
1199
+ readonly id: string | number;
1200
+ } | {
1201
+ readonly kind: 'global';
1202
+ readonly slug: string;
1203
+ };
1204
+ /** Opt-in data capability, enforced by the fragment endpoint and `definePreview`. */
1205
+ interface AuthorizedPreviewPayloadScope {
1206
+ /** Payload base URL, distinct from the preview site's audience. */
1207
+ readonly serverURL: string;
1208
+ /** REST prefix, default `/api`. */
1209
+ readonly apiRoute?: string;
1210
+ readonly document: AuthorizedPreviewDocument;
1211
+ /** Maximum requested population depth, not a field-level ACL. */
1212
+ readonly maxDepth: number;
1213
+ }
1014
1214
  /** What a context is bound to; every field is optional because every strategy binds differently. */
1015
1215
  interface AuthorizedPreviewScope {
1016
1216
  /** The site origin the credential was issued for. */
@@ -1018,6 +1218,8 @@ interface AuthorizedPreviewScope {
1018
1218
  /** The request pathname the credential is valid for. */
1019
1219
  readonly path?: string;
1020
1220
  readonly locale?: string;
1221
+ /** Requires a finite context expiry. Unscoped contexts keep their existing behavior. */
1222
+ readonly payload?: AuthorizedPreviewPayloadScope;
1021
1223
  }
1022
1224
  /** The verdict of a successful `authorizePreviewRequest()`: frozen, branded, produced only there. Carry it, do not rebuild it. */
1023
1225
  interface AuthorizedPreviewContext {
@@ -1092,74 +1294,6 @@ declare class OriginDetector {
1092
1294
  /** @internal */
1093
1295
  declare function detectInitialLocale(): string;
1094
1296
 
1095
- /**
1096
- * Protocol negotiation. A capability is granted either by the version a peer
1097
- * announces or by observation, since the stock Payload admin announces none:
1098
- * what it can do is read off the messages it sends. See ADR 0010.
1099
- */
1100
- /** Bumped only when this library's understanding of the wire format changes. @internal */
1101
- declare const LIBRARY_PROTOCOL_VERSION = 4;
1102
- /** How a capability becomes active. @internal */
1103
- type CapabilitySource = 'version' | 'observed';
1104
- /** @internal */
1105
- interface CapabilityDeclaration {
1106
- /** Enabled once the negotiated version reaches this (for announced peers). */
1107
- readonly since: number;
1108
- /** The wire signal that grants this capability to a peer announcing no version. */
1109
- readonly observed?: 'schema' | 'locale' | 'preview-token' | 'document-event' | 'relationship-event';
1110
- }
1111
- /** What activates each capability; the prose lives in `CAPABILITY_DOCUMENTATION`. */
1112
- declare const CAPABILITY_DECLARATIONS: {
1113
- readonly basic: {
1114
- readonly since: 1;
1115
- };
1116
- readonly 'schema-json': {
1117
- readonly since: 2;
1118
- readonly observed: "schema";
1119
- };
1120
- readonly locale: {
1121
- readonly since: 2;
1122
- readonly observed: "locale";
1123
- };
1124
- readonly 'preview-token': {
1125
- readonly since: 3;
1126
- readonly observed: "preview-token";
1127
- };
1128
- readonly 'nested-arrays': {
1129
- readonly since: 4;
1130
- };
1131
- readonly 'recursive-diffs': {
1132
- readonly since: 4;
1133
- };
1134
- readonly 'document-events': {
1135
- readonly since: 4;
1136
- readonly observed: "document-event";
1137
- };
1138
- readonly 'relationship-events': {
1139
- readonly since: 4;
1140
- readonly observed: "relationship-event";
1141
- };
1142
- };
1143
- type ProtocolCapability = keyof typeof CAPABILITY_DECLARATIONS;
1144
- /** Every declared capability, in declaration order. @internal */
1145
- declare const PROTOCOL_CAPABILITIES: readonly ProtocolCapability[];
1146
- interface ProtocolNegotiation {
1147
- /** This library's protocol version. */
1148
- readonly ours: number;
1149
- /** The remote party's version, when it announced one. */
1150
- readonly theirs: number | undefined;
1151
- /** `min(ours, theirs ?? 1)` — the version both sides actually share. */
1152
- readonly negotiated: number;
1153
- /** Capabilities active at the negotiated version or seen on the wire. */
1154
- readonly capabilities: ReadonlySet<ProtocolCapability>;
1155
- /** The subset that was observed on the wire rather than granted by version. */
1156
- readonly observed: ReadonlySet<ProtocolCapability>;
1157
- }
1158
- /** Deterministic; the runtime re-runs it whenever either input changes. */
1159
- declare function negotiateProtocol(theirs: number | undefined, observed?: Iterable<ProtocolCapability>): ProtocolNegotiation;
1160
- /** @internal */
1161
- declare function hasCapability(negotiation: ProtocolNegotiation, capability: ProtocolCapability): boolean;
1162
-
1163
1297
  /**
1164
1298
  * What each capability tells the runtime, for `inspect()` and consumer
1165
1299
  * diagnostics. Kept out of the runtime module so the inline bundle ships the
@@ -1186,9 +1320,10 @@ interface ProtocolProfile {
1186
1320
  /** Where field types come from. */
1187
1321
  readonly fieldTyping: 'schema' | 'heuristic';
1188
1322
  /**
1189
- * Who populates relationships. Payload 2.x's admin posts populated data
1190
- * (it merges client-side with `fieldSchemaJSON`); Payload 3.x posts raw
1191
- * form values and the runtime asks the REST API when `serverURL` is set.
1323
+ * Legacy transport label, retained for 2.x compatibility. `admin` identifies
1324
+ * Payload 2's schema-based path; observed messages can contain raw relation IDs,
1325
+ * which the shared merger populates with collection GETs. `server` identifies
1326
+ * the Payload 3 merge path. This label alone does not describe population state.
1192
1327
  */
1193
1328
  readonly populatesRelationships: 'admin' | 'server';
1194
1329
  /** Whether the peer reports document saves and relationship edits. */
@@ -1226,6 +1361,9 @@ declare function detectProtocolProfile(observed: ReadonlySet<ProtocolCapability>
1226
1361
  * A host's own route refresh. It must settle once the fresh markup is
1227
1362
  * committed: the runtime re-applies the revision on top of it, and doing that
1228
1363
  * against the markup being replaced would write into nodes about to be dropped.
1364
+ * A function that returns nothing is taken as already committed; the route
1365
+ * strategy says once that it could not wait (LP0810), and 3.0 requires the
1366
+ * promise (ADR 0028).
1229
1367
  */
1230
1368
  type RouteRefresh = () => void | Promise<void>;
1231
1369
  /**
@@ -1269,7 +1407,7 @@ interface BindOptions {
1269
1407
  readonly attribute?: string;
1270
1408
  /** Explicit field type, bypassing schema detection. */
1271
1409
  readonly type?: string;
1272
- /** Mark the binding as Lexical rich text; needed only when the initial render is empty. */
1410
+ /** Mark the binding as Lexical rich text; needed for an element that can hold uploads or relationships, or when the initial render is empty. */
1273
1411
  readonly richtext?: boolean;
1274
1412
  /** Render the value as sanitised HTML rather than text. */
1275
1413
  readonly html?: boolean;
@@ -1331,6 +1469,12 @@ interface PreviewBindings {
1331
1469
  * The registry behind `id` is the endpoint's (docs/hybrid.md).
1332
1470
  */
1333
1471
  boundary: (id: string, options?: FragmentBoundaryOptions) => FragmentBoundaryAttributes | SuppressedBinding;
1472
+ /**
1473
+ * Field paths the page accounts for without binding them, and everything
1474
+ * below them (`data-payload-covers`, ADR 0022), or nothing while
1475
+ * unauthorized.
1476
+ */
1477
+ covers: (...paths: readonly string[]) => Readonly<Record<'data-payload-covers', string>> | SuppressedBinding;
1334
1478
  }
1335
1479
  /** Request-scoped `bind`, `bindByPath` and `owner`, all suppressed unless `authorization` is a real context. */
1336
1480
  declare function createPreviewBindings(options: PreviewBindingsOptions): PreviewBindings;
@@ -1340,7 +1484,8 @@ declare function createPreviewBindings(options: PreviewBindingsOptions): Preview
1340
1484
  * Instead every flush that carried a change dispatches `payload-live-preview:update`
1341
1485
  * on each island root with the update in `detail`, whether or not a binding
1342
1486
  * outside the islands was written. `data-payload-island="patch"` opts back in.
1343
- * @internal
1487
+ * Server HTML reaches an Astro island only through Astro's own props handoff
1488
+ * (ADR 0021). @internal
1344
1489
  */
1345
1490
  declare const ISLAND_EVENT = "payload-live-preview:update";
1346
1491
  interface IslandUpdateDetail {
@@ -1348,6 +1493,13 @@ interface IslandUpdateDetail {
1348
1493
  readonly revision: number;
1349
1494
  readonly receivedAt: number;
1350
1495
  readonly locale: string | undefined;
1496
+ /**
1497
+ * Call once the island has rendered this revision, for instance from an
1498
+ * effect after its framework committed. Until every island handed the
1499
+ * revision has called it, `inspect().revisions.display` says `unconfirmed`
1500
+ * (ADR 0023). Repeated, late or superseded calls do nothing.
1501
+ */
1502
+ readonly displayed: () => void;
1351
1503
  }
1352
1504
  /** Whether `element` (or an ancestor) is an island that did not opt into patching. @internal */
1353
1505
  declare function isInsideIsland(element: Element): boolean;
@@ -1374,4 +1526,4 @@ declare function isInsideIsland(element: Element): boolean;
1374
1526
  /** @internal */
1375
1527
  declare const CORE_ENTRY = true;
1376
1528
 
1377
- 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 };
1529
+ export { AUTHORIZED_PREVIEW_BRAND_KEY, type AuthorizedPreviewContext, type AuthorizedPreviewDocument, type AuthorizedPreviewPayloadScope, 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 RevisionDisplay, type RevisionDisplayState, type RevisionShortfall, type RichTextRenderer, type RouteContext, type RouteOutcome, type RoutePlanContext, 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 };