payload-live-preview 1.4.0 → 1.5.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.
package/dist/index.d.cts CHANGED
@@ -13,6 +13,144 @@
13
13
  */
14
14
  declare const VERSION: string;
15
15
 
16
+ /**
17
+ * Connection state + heartbeat.
18
+ *
19
+ * Tracks whether the runtime is currently receiving updates from a
20
+ * trusted origin and fires a callback when the heartbeat times out.
21
+ *
22
+ * The heartbeat is reset on every valid message and considered dead
23
+ * after `timeoutMs` of silence. The host typically responds by
24
+ * re-sending the `ready` handshake to attempt reconnection.
25
+ *
26
+ * @module @core/state
27
+ */
28
+ type ConnectionStatus = 'disconnected' | 'connecting' | 'connected';
29
+
30
+ /**
31
+ * The shape of a live-preview inspection snapshot.
32
+ *
33
+ * This module is types only. The snapshot is assembled by
34
+ * `LivePreviewRuntime.inspect()` as a plain object literal, because the inline
35
+ * runtime pays for every byte of indirection and the assembly needs access to
36
+ * internal state the runtime does not otherwise expose.
37
+ *
38
+ * A snapshot is a read of what the runtime already holds. It discloses nothing
39
+ * that is not already observable on the page: the trusted origins are inside
40
+ * the injected script, the field names are `data-payload-field` attributes in
41
+ * the DOM, and the counters are derived from those. It is therefore available
42
+ * in production rather than gated to development builds — a preview that
43
+ * misbehaves only on the deployed site is exactly the case where the
44
+ * information is worth having, and a development-only gate would withhold it
45
+ * there.
46
+ *
47
+ * Nothing here is transmitted anywhere. Reading a snapshot performs no I/O.
48
+ *
49
+ * @module @core/inspection/types
50
+ */
51
+
52
+ /** Origin trust as the runtime currently sees it. */
53
+ interface InspectionOrigins {
54
+ /**
55
+ * Origins the runtime is willing to accept messages from, as configured.
56
+ * An empty list means no explicit allow-list was given, which is the
57
+ * condition under which referrer and localhost heuristics decide instead.
58
+ */
59
+ readonly trusted: readonly string[];
60
+ /**
61
+ * The origin the runtime locked onto after its first accepted update, or
62
+ * `undefined` while still unlocked. Once locked, every other origin is
63
+ * refused for the rest of the session.
64
+ */
65
+ readonly locked: string | undefined;
66
+ }
67
+ /** Protocol versions and the capabilities they enable. */
68
+ interface InspectionProtocol {
69
+ /** This library's protocol version. */
70
+ readonly ours: number;
71
+ /** The remote party's version, or `undefined` if it never announced one. */
72
+ readonly theirs: number | undefined;
73
+ /** `min(ours, theirs ?? 1)` — what both sides actually share. */
74
+ readonly negotiated: number;
75
+ /** Capability flags enabled at the negotiated version. */
76
+ readonly capabilities: readonly string[];
77
+ }
78
+ /** Revision accounting for the update pipeline. */
79
+ interface InspectionRevisions {
80
+ /** Updates accepted since the runtime started. */
81
+ readonly accepted: number;
82
+ /**
83
+ * Updates that were still in flight when a newer one arrived and were
84
+ * therefore abandoned. A number that tracks `accepted` closely means the
85
+ * editor is out-typing the pipeline, which is normal; it is only a problem
86
+ * when the last update is among the abandoned ones.
87
+ */
88
+ readonly superseded: number;
89
+ /** Revision currently in flight, or `undefined` when the pipeline is idle. */
90
+ readonly active: number | undefined;
91
+ }
92
+ /** What the DOM offers the runtime to write into. */
93
+ interface InspectionBindings {
94
+ /** Elements carrying a binding. */
95
+ readonly elements: number;
96
+ /** Distinct field names across those elements. */
97
+ readonly fields: number;
98
+ /** Those field names, sorted. */
99
+ readonly fieldNames: readonly string[];
100
+ /**
101
+ * Field names that arrived in an update but matched no binding, as far as
102
+ * the runtime has observed. This is the list to read when a field refuses
103
+ * to update: a name here is a markup problem, a name absent from here and
104
+ * from `fieldNames` was never sent.
105
+ */
106
+ readonly orphanFields: readonly string[];
107
+ /** Whether `scopeBindingsByOwner` is active. */
108
+ readonly ownerScoped: boolean;
109
+ /** Distinct document owners currently on the page, sorted. */
110
+ readonly owners: readonly string[];
111
+ }
112
+ /** Scheduler work in progress. */
113
+ interface InspectionScheduler {
114
+ /** Writes buffered for the next flush. */
115
+ readonly pending: number;
116
+ /**
117
+ * Writes held back because their element is offscreen and the binding count
118
+ * is above `visibilityGateThreshold`. These are applied when the element
119
+ * scrolls into view — never, on a page nobody scrolls.
120
+ */
121
+ readonly deferred: number;
122
+ /** The binding count above which the visibility gate starts deferring. */
123
+ readonly visibilityGateThreshold: number;
124
+ /** Whether the binding count is above that threshold right now. */
125
+ readonly visibilityGateActive: boolean;
126
+ /** Stats of the most recent flush, or `undefined` if none has run. */
127
+ readonly lastFlush: {
128
+ readonly applied: number;
129
+ readonly deferred: number;
130
+ readonly durationMs: number;
131
+ } | undefined;
132
+ }
133
+ /**
134
+ * A point-in-time read of runtime state, for diagnosing a preview that is not
135
+ * behaving. Every field is a plain value; the snapshot holds no references
136
+ * into runtime internals and does not change after it is returned.
137
+ */
138
+ interface LivePreviewInspection {
139
+ /** Package version that produced this snapshot. */
140
+ readonly version: string;
141
+ /** Whether the runtime is started, and whether it has been destroyed. */
142
+ readonly started: boolean;
143
+ /** Connection status as reported to the `connect`/`disconnect` events. */
144
+ readonly status: ConnectionStatus;
145
+ readonly origins: InspectionOrigins;
146
+ readonly protocol: InspectionProtocol;
147
+ readonly revisions: InspectionRevisions;
148
+ readonly bindings: InspectionBindings;
149
+ readonly scheduler: InspectionScheduler;
150
+ /** Field types with a registered renderer, sorted. */
151
+ readonly renderers: readonly string[];
152
+ }
153
+
16
154
  /**
17
155
  * Payload Live Preview message protocol.
18
156
  *
@@ -128,6 +266,101 @@ type PayloadFieldType = 'text' | 'textarea' | 'richText' | 'email' | 'number' |
128
266
  */
129
267
  type PayloadFieldCondition = (data: unknown, siblingData: unknown) => boolean;
130
268
 
269
+ /**
270
+ * Stable identifiers for everything the runtime reports.
271
+ *
272
+ * Prose gets reworded; a code does not. A consumer filtering logs, an alert
273
+ * rule, or a bug report referring to `LP0301` keeps meaning the same thing
274
+ * after the sentence around it is rewritten, and a code is greppable in a way
275
+ * that a sentence fragment is not.
276
+ *
277
+ * Codes are grouped by the question they answer:
278
+ *
279
+ * - `LP01xx` — configuration and origin trust: the runtime is running, but it
280
+ * was set up in a way that will bite.
281
+ * - `LP02xx` — bindings and markup: an update had nowhere to land.
282
+ * - `LP03xx` — updates and scheduling: the update landed somewhere other than
283
+ * the DOM, or not yet.
284
+ * - `LP04xx` — rendering: a value reached an element and was refused.
285
+ * - `LP05xx` — protocol and messages: something arrived that was not accepted.
286
+ * - `LP06xx` — consumer callbacks: code the consumer supplied threw.
287
+ * - `LP07xx` — audit findings from `pll doctor`, which reports on a served
288
+ * response rather than on a running runtime.
289
+ *
290
+ * A code is part of the public contract. Codes are never reused for a
291
+ * different meaning and never renumbered; a retired code stays retired.
292
+ * `LP0604` is unassigned: a throwing token validator is deliberately treated
293
+ * as a rejection and reported as `LP0502`, so there is nothing distinct to
294
+ * report yet. The number stays reserved rather than being handed to something
295
+ * else.
296
+ *
297
+ * The runtime writes these as string literals at each reporting site rather
298
+ * than reading them from this record, so the inline build pays for the six
299
+ * characters it prints and nothing more. This record exists so consumers can
300
+ * refer to a code by name instead of copying a literal.
301
+ *
302
+ * @module @core/diagnostic-codes
303
+ */
304
+ /**
305
+ * Every diagnostic code the runtime can report, by name.
306
+ *
307
+ * ```ts
308
+ * client.events.on('error', (e) => {
309
+ * if (e.code === DIAGNOSTIC_CODES.TransformThrew) reportToSentry(e.error);
310
+ * });
311
+ * ```
312
+ */
313
+ declare const DIAGNOSTIC_CODES: Readonly<{
314
+ /** No trusted origin configured in production; nothing will be accepted. */
315
+ readonly NoTrustedOrigin: "LP0101";
316
+ /** Origin trust rests on `document.referrer`, so any framing site is trusted. */
317
+ readonly ReferrerOnlyTrust: "LP0102";
318
+ /** An update named a field with no binding anchor on the page. */
319
+ readonly OrphanField: "LP0201";
320
+ /** Owner scoping is on and the update names no document it could belong to. */
321
+ readonly UnattributableUpdate: "LP0202";
322
+ /** The visibility gate held offscreen writes back until they scroll into view. */
323
+ readonly VisibilityGateDeferred: "LP0301";
324
+ /** A value was refused because the attribute or the value itself is unsafe. */
325
+ readonly UnsafeAttributeWrite: "LP0401";
326
+ /** A text element has structured children, so replacing its text was skipped. */
327
+ readonly TextTargetHasChildren: "LP0402";
328
+ /** A structural container has no array template, so the update was skipped. */
329
+ readonly MissingArrayTemplate: "LP0403";
330
+ /** A message was rejected before it reached the update pipeline. */
331
+ readonly MessageRejected: "LP0501";
332
+ /** A preview token was rejected. */
333
+ readonly TokenRejected: "LP0502";
334
+ /** A consumer event handler threw. */
335
+ readonly HandlerThrew: "LP0601";
336
+ /** A consumer transform threw; the original value was kept. */
337
+ readonly TransformThrew: "LP0602";
338
+ /** A renderer threw while writing a value. */
339
+ readonly RendererThrew: "LP0603";
340
+ /** Runtime startup failed. */
341
+ readonly StartupFailed: "LP0605";
342
+ /** Sending the ready handshake failed. */
343
+ readonly ReadyFailed: "LP0606";
344
+ /** The audit found no runtime in a response that carried preview intent. */
345
+ readonly AuditRuntimeMissing: "LP0701";
346
+ /** The preview response declares no `frame-ancestors`. */
347
+ readonly AuditNoFrameAncestors: "LP0702";
348
+ /** `X-Frame-Options` forbids framing, which no CSP can undo. */
349
+ readonly AuditFrameOptionsBlocks: "LP0703";
350
+ /** Binding attributes are served to anonymous visitors. */
351
+ readonly AuditBindingsExposed: "LP0704";
352
+ /** More bindings than the default visibility gate will write eagerly. */
353
+ readonly AuditGateThresholdExceeded: "LP0705";
354
+ /** Owner markers exist, but some bindings are outside all of them. */
355
+ readonly AuditUnownedBindings: "LP0706";
356
+ /** The preview response carries no bindings at all. */
357
+ readonly AuditNoBindings: "LP0707";
358
+ /** The URL did not return an HTML page, so nothing else can be judged. */
359
+ readonly AuditNotAPage: "LP0708";
360
+ }>;
361
+ /** A diagnostic code, as it appears in log output and on the `error` event. */
362
+ type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];
363
+
131
364
  /**
132
365
  * Public event payload shapes for the live preview lifecycle.
133
366
  *
@@ -208,11 +441,14 @@ interface LivePreviewEventMap {
208
441
  /**
209
442
  * Fired on errors that the runtime caught but cannot fully recover from.
210
443
  *
211
- * The `context` string identifies where the error originated.
444
+ * The `context` string identifies where the error originated. `code` says
445
+ * the same thing in a form that survives rewording — branch on `code`, read
446
+ * `context` when you want the human-readable origin.
212
447
  */
213
448
  readonly error: {
214
449
  readonly error: Error;
215
450
  readonly context: string;
451
+ readonly code: DiagnosticCode;
216
452
  };
217
453
  /**
218
454
  * Fired during destroy after browser observers and the message listener are
@@ -672,6 +908,15 @@ declare class LivePreviewClient {
672
908
  /** Current connection status. */
673
909
  get status(): 'disconnected' | 'connecting' | 'connected';
674
910
  /** Number of valid updates received so far. */
911
+ /**
912
+ * Point-in-time read of runtime state, for diagnosing a preview that is not
913
+ * updating. Performs no I/O and transmits nothing.
914
+ *
915
+ * Read `bindings.orphanFields` when a field refuses to update, and
916
+ * `scheduler.deferred` together with `scheduler.visibilityGateActive` when
917
+ * updates stop below the fold.
918
+ */
919
+ inspect(): LivePreviewInspection;
675
920
  get updateCount(): number;
676
921
  /** `true` once `destroy()` has been called. */
677
922
  get destroyed(): boolean;
@@ -700,7 +945,7 @@ declare function initLivePreview(config?: LivePreviewClientConfig): LivePreviewC
700
945
  * instead of re-deriving it — which is what every integration has had to do so
701
946
  * far.
702
947
  *
703
- * @module @client/navigation-lifecycle
948
+ * @module @core/navigation-lifecycle
704
949
  */
705
950
  /** The part of the client this owner drives. */
706
951
  interface NavigationLifecycleTarget {
@@ -1996,4 +2241,4 @@ interface PreviewBindings {
1996
2241
  */
1997
2242
  declare function createPreviewBindings(options: PreviewBindingsOptions): PreviewBindings;
1998
2243
 
1999
- export { type AnalyticsSnapshot, type BindOptions, type BlockRenderContext, type BlockRenderer, type CachedElement, type CspDirectiveMerge, type DocumentSaveHandler, type DocumentSavePluginOptions, type DocumentSaveStrategy, EventEmitter, type EventHandler, type FetchPreviewDocumentOptions, type FetchPreviewGlobalOptions, type FieldBindingAttributes, type FieldName, type FieldPath, type FieldRenderer, type FieldTransform, type FieldType, type FrameAncestorsOptions, type InlineScriptConfig, LIBRARY_PROTOCOL_VERSION, type LexicalNode, type LexicalRoot, LivePreviewClient, type LivePreviewClientConfig, type LivePreviewEventMap, type LivePreviewPlugin, type NavigationLifecycleOptions, type NavigationLifecycleTarget, OriginDetector, type OwnerBindingAttributes, type PayloadFieldSchema, type PayloadFieldType, type PayloadLivePreviewData, type PayloadLivePreviewMessage, type PayloadMedia, type PayloadRelationship, type PluginContext, type PluginDisposer, type PluginEvents, type PreviewBindings, type PreviewBindingsOptions, type PreviewFetchBaseOptions, type PreviewRequestLike, type PreviewRequestOptions, type PreviewWhere, type ProtocolCapability, type ProtocolNegotiation, type RenderContext, type SanitizerDocument, type SuppressedBinding, type Unsubscribe, VERSION, type ValueAt, bind, bindByPath, bindNavigationLifecycle, buildBuiltinRenderers, buildFrameAncestors, buildScriptSrcWithNonce, createAnalyticsPlugin, createPreviewBindings, debugPlugin, detectInitialLocale, documentSavePlugin, escapeHtml, escapeHtmlAttribute, fetchPreviewDocument, fetchPreviewGlobal, generateCspNonce, generateInlineScript, hasCapability, highlightPlugin, initLivePreview, isDevMode, isExternalHttpUrl, isInIframe, isInPopup, isInPreviewContext, isLexicalContent, isPreviewRequest, isSafeUrl, lexicalToHtml, lexicalToPlainText, mergeCspHeader, negotiateProtocol, registerBlockRenderer, registerBuiltinRenderer, runtimeBuildInfo, sanitizeHtml, setCspCrypto, setSanitizerDocument, wrapWithScriptTag };
2244
+ export { type AnalyticsSnapshot, type BindOptions, type BlockRenderContext, type BlockRenderer, type CachedElement, type ConnectionStatus, type CspDirectiveMerge, DIAGNOSTIC_CODES, type DiagnosticCode, type DocumentSaveHandler, type DocumentSavePluginOptions, type DocumentSaveStrategy, EventEmitter, type EventHandler, type FetchPreviewDocumentOptions, type FetchPreviewGlobalOptions, type FieldBindingAttributes, type FieldName, type FieldPath, type FieldRenderer, type FieldTransform, type FieldType, type FrameAncestorsOptions, type InlineScriptConfig, type InspectionBindings, type InspectionOrigins, type InspectionProtocol, type InspectionRevisions, type InspectionScheduler, LIBRARY_PROTOCOL_VERSION, type LexicalNode, type LexicalRoot, LivePreviewClient, type LivePreviewClientConfig, type LivePreviewEventMap, type LivePreviewInspection, type LivePreviewPlugin, type NavigationLifecycleOptions, type NavigationLifecycleTarget, OriginDetector, type OwnerBindingAttributes, type PayloadFieldSchema, type PayloadFieldType, type PayloadLivePreviewData, type PayloadLivePreviewMessage, type PayloadMedia, type PayloadRelationship, type PluginContext, type PluginDisposer, type PluginEvents, type PreviewBindings, type PreviewBindingsOptions, type PreviewFetchBaseOptions, type PreviewRequestLike, type PreviewRequestOptions, type PreviewWhere, type ProtocolCapability, type ProtocolNegotiation, type RenderContext, type SanitizerDocument, type SuppressedBinding, type Unsubscribe, VERSION, type ValueAt, bind, bindByPath, bindNavigationLifecycle, buildBuiltinRenderers, buildFrameAncestors, buildScriptSrcWithNonce, createAnalyticsPlugin, createPreviewBindings, debugPlugin, detectInitialLocale, documentSavePlugin, escapeHtml, escapeHtmlAttribute, fetchPreviewDocument, fetchPreviewGlobal, generateCspNonce, generateInlineScript, hasCapability, highlightPlugin, initLivePreview, isDevMode, isExternalHttpUrl, isInIframe, isInPopup, isInPreviewContext, isLexicalContent, isPreviewRequest, isSafeUrl, lexicalToHtml, lexicalToPlainText, mergeCspHeader, negotiateProtocol, registerBlockRenderer, registerBuiltinRenderer, runtimeBuildInfo, sanitizeHtml, setCspCrypto, setSanitizerDocument, wrapWithScriptTag };
package/dist/index.d.ts CHANGED
@@ -13,6 +13,144 @@
13
13
  */
14
14
  declare const VERSION: string;
15
15
 
16
+ /**
17
+ * Connection state + heartbeat.
18
+ *
19
+ * Tracks whether the runtime is currently receiving updates from a
20
+ * trusted origin and fires a callback when the heartbeat times out.
21
+ *
22
+ * The heartbeat is reset on every valid message and considered dead
23
+ * after `timeoutMs` of silence. The host typically responds by
24
+ * re-sending the `ready` handshake to attempt reconnection.
25
+ *
26
+ * @module @core/state
27
+ */
28
+ type ConnectionStatus = 'disconnected' | 'connecting' | 'connected';
29
+
30
+ /**
31
+ * The shape of a live-preview inspection snapshot.
32
+ *
33
+ * This module is types only. The snapshot is assembled by
34
+ * `LivePreviewRuntime.inspect()` as a plain object literal, because the inline
35
+ * runtime pays for every byte of indirection and the assembly needs access to
36
+ * internal state the runtime does not otherwise expose.
37
+ *
38
+ * A snapshot is a read of what the runtime already holds. It discloses nothing
39
+ * that is not already observable on the page: the trusted origins are inside
40
+ * the injected script, the field names are `data-payload-field` attributes in
41
+ * the DOM, and the counters are derived from those. It is therefore available
42
+ * in production rather than gated to development builds — a preview that
43
+ * misbehaves only on the deployed site is exactly the case where the
44
+ * information is worth having, and a development-only gate would withhold it
45
+ * there.
46
+ *
47
+ * Nothing here is transmitted anywhere. Reading a snapshot performs no I/O.
48
+ *
49
+ * @module @core/inspection/types
50
+ */
51
+
52
+ /** Origin trust as the runtime currently sees it. */
53
+ interface InspectionOrigins {
54
+ /**
55
+ * Origins the runtime is willing to accept messages from, as configured.
56
+ * An empty list means no explicit allow-list was given, which is the
57
+ * condition under which referrer and localhost heuristics decide instead.
58
+ */
59
+ readonly trusted: readonly string[];
60
+ /**
61
+ * The origin the runtime locked onto after its first accepted update, or
62
+ * `undefined` while still unlocked. Once locked, every other origin is
63
+ * refused for the rest of the session.
64
+ */
65
+ readonly locked: string | undefined;
66
+ }
67
+ /** Protocol versions and the capabilities they enable. */
68
+ interface InspectionProtocol {
69
+ /** This library's protocol version. */
70
+ readonly ours: number;
71
+ /** The remote party's version, or `undefined` if it never announced one. */
72
+ readonly theirs: number | undefined;
73
+ /** `min(ours, theirs ?? 1)` — what both sides actually share. */
74
+ readonly negotiated: number;
75
+ /** Capability flags enabled at the negotiated version. */
76
+ readonly capabilities: readonly string[];
77
+ }
78
+ /** Revision accounting for the update pipeline. */
79
+ interface InspectionRevisions {
80
+ /** Updates accepted since the runtime started. */
81
+ readonly accepted: number;
82
+ /**
83
+ * Updates that were still in flight when a newer one arrived and were
84
+ * therefore abandoned. A number that tracks `accepted` closely means the
85
+ * editor is out-typing the pipeline, which is normal; it is only a problem
86
+ * when the last update is among the abandoned ones.
87
+ */
88
+ readonly superseded: number;
89
+ /** Revision currently in flight, or `undefined` when the pipeline is idle. */
90
+ readonly active: number | undefined;
91
+ }
92
+ /** What the DOM offers the runtime to write into. */
93
+ interface InspectionBindings {
94
+ /** Elements carrying a binding. */
95
+ readonly elements: number;
96
+ /** Distinct field names across those elements. */
97
+ readonly fields: number;
98
+ /** Those field names, sorted. */
99
+ readonly fieldNames: readonly string[];
100
+ /**
101
+ * Field names that arrived in an update but matched no binding, as far as
102
+ * the runtime has observed. This is the list to read when a field refuses
103
+ * to update: a name here is a markup problem, a name absent from here and
104
+ * from `fieldNames` was never sent.
105
+ */
106
+ readonly orphanFields: readonly string[];
107
+ /** Whether `scopeBindingsByOwner` is active. */
108
+ readonly ownerScoped: boolean;
109
+ /** Distinct document owners currently on the page, sorted. */
110
+ readonly owners: readonly string[];
111
+ }
112
+ /** Scheduler work in progress. */
113
+ interface InspectionScheduler {
114
+ /** Writes buffered for the next flush. */
115
+ readonly pending: number;
116
+ /**
117
+ * Writes held back because their element is offscreen and the binding count
118
+ * is above `visibilityGateThreshold`. These are applied when the element
119
+ * scrolls into view — never, on a page nobody scrolls.
120
+ */
121
+ readonly deferred: number;
122
+ /** The binding count above which the visibility gate starts deferring. */
123
+ readonly visibilityGateThreshold: number;
124
+ /** Whether the binding count is above that threshold right now. */
125
+ readonly visibilityGateActive: boolean;
126
+ /** Stats of the most recent flush, or `undefined` if none has run. */
127
+ readonly lastFlush: {
128
+ readonly applied: number;
129
+ readonly deferred: number;
130
+ readonly durationMs: number;
131
+ } | undefined;
132
+ }
133
+ /**
134
+ * A point-in-time read of runtime state, for diagnosing a preview that is not
135
+ * behaving. Every field is a plain value; the snapshot holds no references
136
+ * into runtime internals and does not change after it is returned.
137
+ */
138
+ interface LivePreviewInspection {
139
+ /** Package version that produced this snapshot. */
140
+ readonly version: string;
141
+ /** Whether the runtime is started, and whether it has been destroyed. */
142
+ readonly started: boolean;
143
+ /** Connection status as reported to the `connect`/`disconnect` events. */
144
+ readonly status: ConnectionStatus;
145
+ readonly origins: InspectionOrigins;
146
+ readonly protocol: InspectionProtocol;
147
+ readonly revisions: InspectionRevisions;
148
+ readonly bindings: InspectionBindings;
149
+ readonly scheduler: InspectionScheduler;
150
+ /** Field types with a registered renderer, sorted. */
151
+ readonly renderers: readonly string[];
152
+ }
153
+
16
154
  /**
17
155
  * Payload Live Preview message protocol.
18
156
  *
@@ -128,6 +266,101 @@ type PayloadFieldType = 'text' | 'textarea' | 'richText' | 'email' | 'number' |
128
266
  */
129
267
  type PayloadFieldCondition = (data: unknown, siblingData: unknown) => boolean;
130
268
 
269
+ /**
270
+ * Stable identifiers for everything the runtime reports.
271
+ *
272
+ * Prose gets reworded; a code does not. A consumer filtering logs, an alert
273
+ * rule, or a bug report referring to `LP0301` keeps meaning the same thing
274
+ * after the sentence around it is rewritten, and a code is greppable in a way
275
+ * that a sentence fragment is not.
276
+ *
277
+ * Codes are grouped by the question they answer:
278
+ *
279
+ * - `LP01xx` — configuration and origin trust: the runtime is running, but it
280
+ * was set up in a way that will bite.
281
+ * - `LP02xx` — bindings and markup: an update had nowhere to land.
282
+ * - `LP03xx` — updates and scheduling: the update landed somewhere other than
283
+ * the DOM, or not yet.
284
+ * - `LP04xx` — rendering: a value reached an element and was refused.
285
+ * - `LP05xx` — protocol and messages: something arrived that was not accepted.
286
+ * - `LP06xx` — consumer callbacks: code the consumer supplied threw.
287
+ * - `LP07xx` — audit findings from `pll doctor`, which reports on a served
288
+ * response rather than on a running runtime.
289
+ *
290
+ * A code is part of the public contract. Codes are never reused for a
291
+ * different meaning and never renumbered; a retired code stays retired.
292
+ * `LP0604` is unassigned: a throwing token validator is deliberately treated
293
+ * as a rejection and reported as `LP0502`, so there is nothing distinct to
294
+ * report yet. The number stays reserved rather than being handed to something
295
+ * else.
296
+ *
297
+ * The runtime writes these as string literals at each reporting site rather
298
+ * than reading them from this record, so the inline build pays for the six
299
+ * characters it prints and nothing more. This record exists so consumers can
300
+ * refer to a code by name instead of copying a literal.
301
+ *
302
+ * @module @core/diagnostic-codes
303
+ */
304
+ /**
305
+ * Every diagnostic code the runtime can report, by name.
306
+ *
307
+ * ```ts
308
+ * client.events.on('error', (e) => {
309
+ * if (e.code === DIAGNOSTIC_CODES.TransformThrew) reportToSentry(e.error);
310
+ * });
311
+ * ```
312
+ */
313
+ declare const DIAGNOSTIC_CODES: Readonly<{
314
+ /** No trusted origin configured in production; nothing will be accepted. */
315
+ readonly NoTrustedOrigin: "LP0101";
316
+ /** Origin trust rests on `document.referrer`, so any framing site is trusted. */
317
+ readonly ReferrerOnlyTrust: "LP0102";
318
+ /** An update named a field with no binding anchor on the page. */
319
+ readonly OrphanField: "LP0201";
320
+ /** Owner scoping is on and the update names no document it could belong to. */
321
+ readonly UnattributableUpdate: "LP0202";
322
+ /** The visibility gate held offscreen writes back until they scroll into view. */
323
+ readonly VisibilityGateDeferred: "LP0301";
324
+ /** A value was refused because the attribute or the value itself is unsafe. */
325
+ readonly UnsafeAttributeWrite: "LP0401";
326
+ /** A text element has structured children, so replacing its text was skipped. */
327
+ readonly TextTargetHasChildren: "LP0402";
328
+ /** A structural container has no array template, so the update was skipped. */
329
+ readonly MissingArrayTemplate: "LP0403";
330
+ /** A message was rejected before it reached the update pipeline. */
331
+ readonly MessageRejected: "LP0501";
332
+ /** A preview token was rejected. */
333
+ readonly TokenRejected: "LP0502";
334
+ /** A consumer event handler threw. */
335
+ readonly HandlerThrew: "LP0601";
336
+ /** A consumer transform threw; the original value was kept. */
337
+ readonly TransformThrew: "LP0602";
338
+ /** A renderer threw while writing a value. */
339
+ readonly RendererThrew: "LP0603";
340
+ /** Runtime startup failed. */
341
+ readonly StartupFailed: "LP0605";
342
+ /** Sending the ready handshake failed. */
343
+ readonly ReadyFailed: "LP0606";
344
+ /** The audit found no runtime in a response that carried preview intent. */
345
+ readonly AuditRuntimeMissing: "LP0701";
346
+ /** The preview response declares no `frame-ancestors`. */
347
+ readonly AuditNoFrameAncestors: "LP0702";
348
+ /** `X-Frame-Options` forbids framing, which no CSP can undo. */
349
+ readonly AuditFrameOptionsBlocks: "LP0703";
350
+ /** Binding attributes are served to anonymous visitors. */
351
+ readonly AuditBindingsExposed: "LP0704";
352
+ /** More bindings than the default visibility gate will write eagerly. */
353
+ readonly AuditGateThresholdExceeded: "LP0705";
354
+ /** Owner markers exist, but some bindings are outside all of them. */
355
+ readonly AuditUnownedBindings: "LP0706";
356
+ /** The preview response carries no bindings at all. */
357
+ readonly AuditNoBindings: "LP0707";
358
+ /** The URL did not return an HTML page, so nothing else can be judged. */
359
+ readonly AuditNotAPage: "LP0708";
360
+ }>;
361
+ /** A diagnostic code, as it appears in log output and on the `error` event. */
362
+ type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];
363
+
131
364
  /**
132
365
  * Public event payload shapes for the live preview lifecycle.
133
366
  *
@@ -208,11 +441,14 @@ interface LivePreviewEventMap {
208
441
  /**
209
442
  * Fired on errors that the runtime caught but cannot fully recover from.
210
443
  *
211
- * The `context` string identifies where the error originated.
444
+ * The `context` string identifies where the error originated. `code` says
445
+ * the same thing in a form that survives rewording — branch on `code`, read
446
+ * `context` when you want the human-readable origin.
212
447
  */
213
448
  readonly error: {
214
449
  readonly error: Error;
215
450
  readonly context: string;
451
+ readonly code: DiagnosticCode;
216
452
  };
217
453
  /**
218
454
  * Fired during destroy after browser observers and the message listener are
@@ -672,6 +908,15 @@ declare class LivePreviewClient {
672
908
  /** Current connection status. */
673
909
  get status(): 'disconnected' | 'connecting' | 'connected';
674
910
  /** Number of valid updates received so far. */
911
+ /**
912
+ * Point-in-time read of runtime state, for diagnosing a preview that is not
913
+ * updating. Performs no I/O and transmits nothing.
914
+ *
915
+ * Read `bindings.orphanFields` when a field refuses to update, and
916
+ * `scheduler.deferred` together with `scheduler.visibilityGateActive` when
917
+ * updates stop below the fold.
918
+ */
919
+ inspect(): LivePreviewInspection;
675
920
  get updateCount(): number;
676
921
  /** `true` once `destroy()` has been called. */
677
922
  get destroyed(): boolean;
@@ -700,7 +945,7 @@ declare function initLivePreview(config?: LivePreviewClientConfig): LivePreviewC
700
945
  * instead of re-deriving it — which is what every integration has had to do so
701
946
  * far.
702
947
  *
703
- * @module @client/navigation-lifecycle
948
+ * @module @core/navigation-lifecycle
704
949
  */
705
950
  /** The part of the client this owner drives. */
706
951
  interface NavigationLifecycleTarget {
@@ -1996,4 +2241,4 @@ interface PreviewBindings {
1996
2241
  */
1997
2242
  declare function createPreviewBindings(options: PreviewBindingsOptions): PreviewBindings;
1998
2243
 
1999
- export { type AnalyticsSnapshot, type BindOptions, type BlockRenderContext, type BlockRenderer, type CachedElement, type CspDirectiveMerge, type DocumentSaveHandler, type DocumentSavePluginOptions, type DocumentSaveStrategy, EventEmitter, type EventHandler, type FetchPreviewDocumentOptions, type FetchPreviewGlobalOptions, type FieldBindingAttributes, type FieldName, type FieldPath, type FieldRenderer, type FieldTransform, type FieldType, type FrameAncestorsOptions, type InlineScriptConfig, LIBRARY_PROTOCOL_VERSION, type LexicalNode, type LexicalRoot, LivePreviewClient, type LivePreviewClientConfig, type LivePreviewEventMap, type LivePreviewPlugin, type NavigationLifecycleOptions, type NavigationLifecycleTarget, OriginDetector, type OwnerBindingAttributes, type PayloadFieldSchema, type PayloadFieldType, type PayloadLivePreviewData, type PayloadLivePreviewMessage, type PayloadMedia, type PayloadRelationship, type PluginContext, type PluginDisposer, type PluginEvents, type PreviewBindings, type PreviewBindingsOptions, type PreviewFetchBaseOptions, type PreviewRequestLike, type PreviewRequestOptions, type PreviewWhere, type ProtocolCapability, type ProtocolNegotiation, type RenderContext, type SanitizerDocument, type SuppressedBinding, type Unsubscribe, VERSION, type ValueAt, bind, bindByPath, bindNavigationLifecycle, buildBuiltinRenderers, buildFrameAncestors, buildScriptSrcWithNonce, createAnalyticsPlugin, createPreviewBindings, debugPlugin, detectInitialLocale, documentSavePlugin, escapeHtml, escapeHtmlAttribute, fetchPreviewDocument, fetchPreviewGlobal, generateCspNonce, generateInlineScript, hasCapability, highlightPlugin, initLivePreview, isDevMode, isExternalHttpUrl, isInIframe, isInPopup, isInPreviewContext, isLexicalContent, isPreviewRequest, isSafeUrl, lexicalToHtml, lexicalToPlainText, mergeCspHeader, negotiateProtocol, registerBlockRenderer, registerBuiltinRenderer, runtimeBuildInfo, sanitizeHtml, setCspCrypto, setSanitizerDocument, wrapWithScriptTag };
2244
+ export { type AnalyticsSnapshot, type BindOptions, type BlockRenderContext, type BlockRenderer, type CachedElement, type ConnectionStatus, type CspDirectiveMerge, DIAGNOSTIC_CODES, type DiagnosticCode, type DocumentSaveHandler, type DocumentSavePluginOptions, type DocumentSaveStrategy, EventEmitter, type EventHandler, type FetchPreviewDocumentOptions, type FetchPreviewGlobalOptions, type FieldBindingAttributes, type FieldName, type FieldPath, type FieldRenderer, type FieldTransform, type FieldType, type FrameAncestorsOptions, type InlineScriptConfig, type InspectionBindings, type InspectionOrigins, type InspectionProtocol, type InspectionRevisions, type InspectionScheduler, LIBRARY_PROTOCOL_VERSION, type LexicalNode, type LexicalRoot, LivePreviewClient, type LivePreviewClientConfig, type LivePreviewEventMap, type LivePreviewInspection, type LivePreviewPlugin, type NavigationLifecycleOptions, type NavigationLifecycleTarget, OriginDetector, type OwnerBindingAttributes, type PayloadFieldSchema, type PayloadFieldType, type PayloadLivePreviewData, type PayloadLivePreviewMessage, type PayloadMedia, type PayloadRelationship, type PluginContext, type PluginDisposer, type PluginEvents, type PreviewBindings, type PreviewBindingsOptions, type PreviewFetchBaseOptions, type PreviewRequestLike, type PreviewRequestOptions, type PreviewWhere, type ProtocolCapability, type ProtocolNegotiation, type RenderContext, type SanitizerDocument, type SuppressedBinding, type Unsubscribe, VERSION, type ValueAt, bind, bindByPath, bindNavigationLifecycle, buildBuiltinRenderers, buildFrameAncestors, buildScriptSrcWithNonce, createAnalyticsPlugin, createPreviewBindings, debugPlugin, detectInitialLocale, documentSavePlugin, escapeHtml, escapeHtmlAttribute, fetchPreviewDocument, fetchPreviewGlobal, generateCspNonce, generateInlineScript, hasCapability, highlightPlugin, initLivePreview, isDevMode, isExternalHttpUrl, isInIframe, isInPopup, isInPreviewContext, isLexicalContent, isPreviewRequest, isSafeUrl, lexicalToHtml, lexicalToPlainText, mergeCspHeader, negotiateProtocol, registerBlockRenderer, registerBuiltinRenderer, runtimeBuildInfo, sanitizeHtml, setCspCrypto, setSanitizerDocument, wrapWithScriptTag };