@preprio/toolkit 0.5.0-rc.1 → 0.5.0-rc.10

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 (61) hide show
  1. package/README.md +416 -23
  2. package/dist/astro/index.cjs +1290 -1
  3. package/dist/astro/index.d.cts +47 -1
  4. package/dist/astro/index.d.ts +47 -1
  5. package/dist/astro/index.js +1297 -1
  6. package/dist/chunk-F46GJS6Y.js +26 -0
  7. package/dist/{chunk-4JNKYIEV.js → chunk-IDEC77LZ.js} +1423 -642
  8. package/dist/chunk-IPMB32AZ.js +246 -0
  9. package/dist/chunk-KD3GK6TO.js +1221 -0
  10. package/dist/chunk-S3VT4UWM.js +75 -0
  11. package/dist/chunk-TBBU3LDD.js +184 -0
  12. package/dist/chunk-URXSDJOU.js +356 -0
  13. package/dist/codegen/index.cjs +82 -0
  14. package/dist/codegen/index.d.cts +70 -0
  15. package/dist/codegen/index.d.ts +70 -0
  16. package/dist/codegen/index.js +64 -0
  17. package/dist/index.cjs +3342 -417
  18. package/dist/index.d.cts +276 -5
  19. package/dist/index.d.ts +276 -5
  20. package/dist/index.js +307 -144
  21. package/dist/live-preview-DLXGXRE5.js +18 -0
  22. package/dist/nextjs/components.cjs +1582 -386
  23. package/dist/nextjs/components.d.cts +1 -1
  24. package/dist/nextjs/components.d.ts +1 -1
  25. package/dist/nextjs/components.js +4 -1
  26. package/dist/nextjs/index.cjs +1181 -6
  27. package/dist/nextjs/index.d.cts +83 -3
  28. package/dist/nextjs/index.d.ts +83 -3
  29. package/dist/nextjs/index.js +1179 -7
  30. package/dist/nextjs/live-action.cjs +285 -0
  31. package/dist/nextjs/live-action.d.cts +12 -0
  32. package/dist/nextjs/live-action.d.ts +12 -0
  33. package/dist/nextjs/live-action.js +68 -0
  34. package/dist/nextjs/live.cjs +1899 -0
  35. package/dist/nextjs/live.d.cts +54 -0
  36. package/dist/nextjs/live.d.ts +54 -0
  37. package/dist/nextjs/live.js +268 -0
  38. package/dist/nuxt/chunk-BWPGO25E.js +340 -0
  39. package/dist/nuxt/index.cjs +1 -1
  40. package/dist/nuxt/index.js +1 -1
  41. package/dist/nuxt/live-preview-2RCU35W5.js +1189 -0
  42. package/dist/nuxt/live.cjs +1816 -0
  43. package/dist/nuxt/live.d.cts +43 -0
  44. package/dist/nuxt/live.d.ts +43 -0
  45. package/dist/nuxt/live.js +198 -0
  46. package/dist/{pixel-e1fUWl2Y.d.cts → pixel-CX422dCO.d.cts} +18 -3
  47. package/dist/{pixel-e1fUWl2Y.d.ts → pixel-CX422dCO.d.ts} +18 -3
  48. package/dist/react/components.cjs +1582 -386
  49. package/dist/react/components.d.cts +17 -2
  50. package/dist/react/components.d.ts +17 -2
  51. package/dist/react/components.js +1582 -386
  52. package/dist/sveltekit/chunk-BWPGO25E.js +340 -0
  53. package/dist/sveltekit/index.cjs +1 -1
  54. package/dist/sveltekit/index.js +1 -1
  55. package/dist/sveltekit/live-preview-2RCU35W5.js +1189 -0
  56. package/dist/sveltekit/live.cjs +1830 -0
  57. package/dist/sveltekit/live.d.cts +59 -0
  58. package/dist/sveltekit/live.d.ts +59 -0
  59. package/dist/sveltekit/live.js +204 -0
  60. package/package.json +37 -11
  61. package/src/astro/PreprToolbar.astro +7 -1
package/dist/index.d.cts CHANGED
@@ -1,11 +1,11 @@
1
- import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-e1fUWl2Y.cjs';
2
- export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-e1fUWl2Y.cjs';
1
+ import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-CX422dCO.cjs';
2
+ export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-CX422dCO.cjs';
3
3
 
4
4
  /**
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.5.0-rc.1";
8
+ declare const VERSION = "0.5.0-rc.10";
9
9
 
10
10
  /**
11
11
  * Resolve a `PreprFeatures` bag to plain booleans, defaulting every omitted key
@@ -141,11 +141,73 @@ declare function definePreprToolbar(): void;
141
141
  interface ScrollToFieldMessage {
142
142
  field: string;
143
143
  id?: string;
144
+ /** Item within a list field value: the n-th `<li>` of a rich text list. */
145
+ block?: number;
146
+ /** The entry's `data-prepr-entry-id`, preferred over `field` when present. */
147
+ entryId?: string;
148
+ /**
149
+ * The same field with stack entries named by id instead of position, as
150
+ * on entries added before save, whose position changes until then.
151
+ */
152
+ fieldById?: string;
153
+ }
154
+ /** A content item the open item links to, and the field that links it. */
155
+ interface EditorReference {
156
+ id: string;
157
+ field: string;
158
+ }
159
+ /**
160
+ * An image asset used by the open item: where its field is, and the part of
161
+ * its CDN URL that identifies it whatever size the page renders it at.
162
+ */
163
+ interface EditorAsset {
164
+ key: string;
165
+ /** Field path in the editor, as stega text carries it. */
166
+ field: string;
167
+ /** The Dynamic Content entry that holds the asset. */
168
+ entryId?: string;
169
+ }
170
+ /** What the editor told the preview when the handshake completed. */
171
+ interface EditorHandshake {
172
+ /**
173
+ * The content item open in the editor. Absent when the editor does not
174
+ * send one, in which case every tagged element counts as part of it.
175
+ */
176
+ itemId?: string;
177
+ /**
178
+ * Items the open item references. Absent when the editor does not send
179
+ * them, in which case other items are not split into linked and unrelated.
180
+ */
181
+ referencedIds?: EditorReference[];
182
+ /**
183
+ * `_id`s of component instances inside the open item. Content tagged with
184
+ * one of them (`previewAttrs` on a component's image) belongs to the open
185
+ * item, not to another one.
186
+ */
187
+ componentIds?: string[];
188
+ /**
189
+ * The language of the editor's own interface. Absent when the editor does
190
+ * not send one or sends a language the toolkit has no translations for.
191
+ */
192
+ uiLocale?: Locale;
193
+ /**
194
+ * The editor asks before the preview leaves the page: navigations are
195
+ * stopped and reported as `navigation_blocked`, and
196
+ * `prepr:allowNavigation` follows one. Absent for editors that do not
197
+ * handle `navigation_blocked`.
198
+ */
199
+ navigationGuard?: boolean;
200
+ /**
201
+ * Image assets of the open item. Absent when the editor does not send
202
+ * them, in which case images are only editable where the page tags them.
203
+ */
204
+ assets?: EditorAsset[];
144
205
  }
145
206
  interface IframeBridgeOptions {
146
207
  /**
147
208
  * Replace the `*.prepr.io` wildcard with an exact origin list. Intended for
148
- * self-hosted editors; when set, the wildcard no longer applies.
209
+ * self-hosted editors; when set, the wildcard no longer applies. `['*']`
210
+ * accepts any editor origin — see `PreprPreviewOptions.allowedEditorOrigins`.
149
211
  */
150
212
  allowedEditorOrigins?: string[];
151
213
  /**
@@ -154,7 +216,216 @@ interface IframeBridgeOptions {
154
216
  * stays free of DOM lookups: the preview runtime supplies `scrollToField`.
155
217
  */
156
218
  onScrollToField?: (message: ScrollToFieldMessage) => void;
219
+ /**
220
+ * Called once the editor handshake is accepted, with the id of the content
221
+ * item open in the editor when the editor sends one. Lets the preview tell
222
+ * that item's fields apart from other items rendered on the same page
223
+ * (navigation, an author card, related posts).
224
+ */
225
+ onHandshake?: (handshake: EditorHandshake) => void;
226
+ /** The editor's reference list changed (`prepr:references`). */
227
+ onReferences?: (referencedIds: EditorReference[], componentIds?: string[]) => void;
228
+ /** The editor's asset list changed (`assets` on `prepr:references`). */
229
+ onAssets?: (assets: EditorAsset[]) => void;
230
+ /**
231
+ * The editor confirmed leaving the page for `href` after a
232
+ * `navigation_blocked` (`prepr:allowNavigation`). `href` is a non-empty
233
+ * string; its scheme is not checked here.
234
+ */
235
+ onAllowNavigation?: (href: string) => void;
236
+ }
237
+
238
+ interface PreviewAttrsTarget {
239
+ /** `_id` of the content item or component that owns the field. */
240
+ id: string | null | undefined;
241
+ /** API field name, or a dotted path below the item (`content.3`). */
242
+ field: string;
243
+ /** Locale of the rendered value, when the site knows it. */
244
+ locale?: string | null;
245
+ /** Site-side id of one entry in a list-like field (`data-prepr-entry-id`). */
246
+ entryId?: string | null;
247
+ }
248
+ interface PreviewAttrsOptions {
249
+ /**
250
+ * Whether to emit the attributes at all. Pass `true` only for preview or
251
+ * draft renders, so production HTML carries no edit metadata.
252
+ */
253
+ enabled: boolean;
254
+ }
255
+ /**
256
+ * Attributes that make an element click-to-edit in the Prepr visual editor,
257
+ * for values that carry no hidden edit link of their own: images, videos,
258
+ * anything rendered from a URL. Spread them onto the element that renders
259
+ * the field:
260
+ *
261
+ * ```tsx
262
+ * <figure {...previewAttrs({ id: post._id, field: 'cover_image' }, { enabled: isPreview })}>
263
+ * ```
264
+ *
265
+ * Returns an empty object when disabled or when there is no target or id, so
266
+ * it is safe to spread unconditionally.
267
+ */
268
+ declare function previewAttrs(target: PreviewAttrsTarget | null | undefined, options: PreviewAttrsOptions): Record<string, string>;
269
+ interface StegaTargetOptions {
270
+ /**
271
+ * A field next to the encoded one, in the same item or component, to target
272
+ * instead: a dotted path that replaces the encoded field's last segment
273
+ * (`products`, or `products.items.2` for one entry of it).
274
+ */
275
+ field?: string;
276
+ }
277
+ /**
278
+ * The edit target behind a text value Prepr returned with a hidden edit link,
279
+ * for {@link previewAttrs}. Reach for it when the field to edit carries no
280
+ * link of its own, such as remote content or a list of references, but a
281
+ * text field of the same component does: the component's title points the
282
+ * way to its `products`.
283
+ *
284
+ * ```tsx
285
+ * const products = stegaTarget(block.title, { field: 'products' });
286
+ * <article {...previewAttrs(products, { enabled: isPreview })}>
287
+ * ```
288
+ *
289
+ * Returns null for a value without an edit link (a production render, or a
290
+ * value Prepr does not encode). Works on the server and in the browser.
291
+ */
292
+ declare function stegaTarget(value: string | null | undefined, options?: StegaTargetOptions): PreviewAttrsTarget | null;
293
+
294
+ /** Values a push may write. Everything else goes through refetch. */
295
+ type LiveScalar = string | number | boolean;
296
+ /** A structured field value, such as an asset. */
297
+ interface LiveObject {
298
+ [key: string]: LiveScalar | null | LiveObject;
157
299
  }
300
+ /** Anything a `prepr:fieldChange` may carry. */
301
+ type LiveValue = LiveScalar | null | LiveObject | LiveObject[];
302
+ /** One entry of a `prepr:listChange`, in the editor's order. */
303
+ interface LiveListEntry {
304
+ /** Stored id, or a temporary `tmp:` id for an entry added before save. */
305
+ _id: string;
306
+ __typename?: string;
307
+ /** Text entries only. */
308
+ body?: string;
309
+ format?: string | null;
310
+ /** A new entry's type as the editor names it (`Side by side`). */
311
+ typeName?: string;
312
+ /** A new entry's field values, shaped as the API returns them. */
313
+ fields?: Record<string, unknown>;
314
+ }
315
+
316
+ /**
317
+ * What `normalizeQuery` accepts as the query: GraphQL source text, a parsed
318
+ * `DocumentNode` (from `graphql-tag`, Apollo or GraphQL Code Generator), or a
319
+ * string-like object such as codegen's `TypedDocumentString`.
320
+ */
321
+ type QueryInput = string | {
322
+ kind: 'Document';
323
+ } | {
324
+ toString(): string;
325
+ };
326
+
327
+ /** The open item and a field path in the editor's id-based convention. */
328
+ interface LiveEditTarget {
329
+ item: string;
330
+ field: string;
331
+ }
332
+
333
+ /**
334
+ * One unsaved change from the Prepr editor: the `_id` of the item (or stack
335
+ * entry) that owns the field, and the field's API name or a dotted path below
336
+ * it (`content.headline_style`, `content.3.body`).
337
+ */
338
+ type LivePatch = {
339
+ type: 'field';
340
+ itemId: string;
341
+ field: string;
342
+ value: LiveValue;
343
+ /** Edit-link target for text that has none yet (an unsaved entry). */
344
+ edit?: LiveEditTarget;
345
+ } | {
346
+ type: 'list';
347
+ itemId: string;
348
+ field: string;
349
+ entries: LiveListEntry[];
350
+ };
351
+ interface NormalizeQueryOptions {
352
+ /**
353
+ * The editor's unsaved changes, oldest first. Treated as hostile: malformed
354
+ * entries are dropped.
355
+ */
356
+ log?: unknown;
357
+ /** Which operation to use when the document holds more than one. */
358
+ operationName?: string;
359
+ }
360
+ /**
361
+ * Validate a patch log from an untrusted source (a request body, a cookie).
362
+ * Accepts the array or its JSON text, drops malformed entries, never throws.
363
+ */
364
+ declare function parsePatchLog(raw: unknown): LivePatch[];
365
+ /**
366
+ * Apply the Prepr editor's unsaved changes to a GraphQL result, so the page
367
+ * renders them before the editor saves. Pass the query that produced the
368
+ * result (`{ data }` or just `data`):
369
+ *
370
+ * ```ts
371
+ * const page = normalizeQuery(GetPageDocument, data, { log });
372
+ * ```
373
+ *
374
+ * The query maps fields to response keys, so changes land under aliases and
375
+ * on every place the same item appears; fields not in the query are left
376
+ * alone. Select `_id` on every item and component that should update.
377
+ * Without a log the query is not parsed and the result is returned as-is.
378
+ * Never throws.
379
+ */
380
+ declare function normalizeQuery<T>(query: QueryInput, result: T, options?: NormalizeQueryOptions): T;
381
+
382
+ /**
383
+ * Adds the list entry each piece of text belongs to (a dynamic content
384
+ * entry, a repeated component) to its hidden edit link, so the visual editor
385
+ * can find the entry by id without `data-prepr-entry-id` on the page. A
386
+ * `Text` entry's link, which names no field, also gets the entry's field
387
+ * path, so `data-prepr-edit-target` is not needed to name it.
388
+ *
389
+ * Needs `_id` on the entries. Returns the result itself when nothing
390
+ * changed. Pass the query to name fields by their API name under aliases.
391
+ */
392
+ declare function annotateEditLinks<T>(result: T, query?: QueryInput, operationName?: string): T;
393
+
394
+ interface HtmlLivePreviewOptions {
395
+ /**
396
+ * Replace the `*.prepr.io` editor-origin wildcard with an exact list, as
397
+ * the toolbar's option of the same name.
398
+ */
399
+ allowedEditorOrigins?: string[];
400
+ /** See the toolbar's `strictMode`. */
401
+ strictMode?: boolean;
402
+ }
403
+ interface HtmlLivePreview {
404
+ stop(): void;
405
+ }
406
+ /**
407
+ * Live preview for server-rendered pages without a client framework (Astro,
408
+ * or any HTML-first site): while an editor types, the page is requested
409
+ * again from the server with the unsaved changes in the request body, and
410
+ * only the parts of the DOM that changed are updated. On save the page is
411
+ * requested without changes. The server applies them with `normalizeQuery`;
412
+ * see `readLiveLogFromRequest`.
413
+ *
414
+ * A no-op outside the Prepr editor's preview iframe.
415
+ */
416
+ declare function startHtmlLivePreview(options?: HtmlLivePreviewOptions): HtmlLivePreview;
417
+
418
+ /**
419
+ * The editor's unsaved changes carried by a live-preview re-render request
420
+ * (sent by `startHtmlLivePreview`), or an empty list for any other request.
421
+ *
422
+ * Accepted only from a same-origin `POST` with the live-preview header and a
423
+ * JSON body, so a link, a form on another site or a cacheable `GET` can never
424
+ * inject changes. Call it only when the site runs in preview, and mark the
425
+ * response uncacheable (`Cache-Control: private, no-store`) whenever it
426
+ * returns changes. Never throws.
427
+ */
428
+ declare function readLiveLogFromRequest(request: Request): Promise<LivePatch[]>;
158
429
 
159
430
  /** Error thrown by the token helpers and the segments fetch. */
160
431
  declare class PreprError extends Error {
@@ -241,4 +512,4 @@ interface PreprMiddlewareOptions {
241
512
  */
242
513
  declare function processPreprRequest(request: Request, opts?: PreprMiddlewareOptions): PreprMiddlewareResult;
243
514
 
244
- export { type CookieSpec, type CreatePreprPreviewOptions, type IframeBridgeOptions, PreprError, PreprErrorCode, PreprFeatures, PreprHeaders, type PreprMiddlewareOptions, type PreprMiddlewareResult, type PreprNavigationAdapter, type PreprPreviewController, PreprPreviewOptions, PreprSegment, PreprToolbarElement, PreprToolbarProps, PreprVariant, ResolvedPreprFeatures, type ToolbarState, type ToolbarStore, VERSION, createPreprPreview, createToolbarStore, definePreprToolbar, extractAccessToken, getActiveSegmentFromHeaders, getActiveVariantFromHeaders, getPreprEnvironmentSegments, getPreprHeadersFromHeaders, getPreprUUIDFromHeaders, getToolbarPropsFromHeaders, processPreprRequest, resolveFeatures, stegaClean, validatePreprToken };
515
+ export { type CookieSpec, type CreatePreprPreviewOptions, type HtmlLivePreview, type HtmlLivePreviewOptions, type IframeBridgeOptions, type LivePatch, type NormalizeQueryOptions, PreprError, PreprErrorCode, PreprFeatures, PreprHeaders, type PreprMiddlewareOptions, type PreprMiddlewareResult, type PreprNavigationAdapter, type PreprPreviewController, PreprPreviewOptions, PreprSegment, PreprToolbarElement, PreprToolbarProps, PreprVariant, type PreviewAttrsOptions, type PreviewAttrsTarget, type QueryInput, ResolvedPreprFeatures, type StegaTargetOptions, type ToolbarState, type ToolbarStore, VERSION, annotateEditLinks, createPreprPreview, createToolbarStore, definePreprToolbar, extractAccessToken, getActiveSegmentFromHeaders, getActiveVariantFromHeaders, getPreprEnvironmentSegments, getPreprHeadersFromHeaders, getPreprUUIDFromHeaders, getToolbarPropsFromHeaders, normalizeQuery, parsePatchLog, previewAttrs, processPreprRequest, readLiveLogFromRequest, resolveFeatures, startHtmlLivePreview, stegaClean, stegaTarget, validatePreprToken };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-e1fUWl2Y.js';
2
- export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-e1fUWl2Y.js';
1
+ import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-CX422dCO.js';
2
+ export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-CX422dCO.js';
3
3
 
4
4
  /**
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.5.0-rc.1";
8
+ declare const VERSION = "0.5.0-rc.10";
9
9
 
10
10
  /**
11
11
  * Resolve a `PreprFeatures` bag to plain booleans, defaulting every omitted key
@@ -141,11 +141,73 @@ declare function definePreprToolbar(): void;
141
141
  interface ScrollToFieldMessage {
142
142
  field: string;
143
143
  id?: string;
144
+ /** Item within a list field value: the n-th `<li>` of a rich text list. */
145
+ block?: number;
146
+ /** The entry's `data-prepr-entry-id`, preferred over `field` when present. */
147
+ entryId?: string;
148
+ /**
149
+ * The same field with stack entries named by id instead of position, as
150
+ * on entries added before save, whose position changes until then.
151
+ */
152
+ fieldById?: string;
153
+ }
154
+ /** A content item the open item links to, and the field that links it. */
155
+ interface EditorReference {
156
+ id: string;
157
+ field: string;
158
+ }
159
+ /**
160
+ * An image asset used by the open item: where its field is, and the part of
161
+ * its CDN URL that identifies it whatever size the page renders it at.
162
+ */
163
+ interface EditorAsset {
164
+ key: string;
165
+ /** Field path in the editor, as stega text carries it. */
166
+ field: string;
167
+ /** The Dynamic Content entry that holds the asset. */
168
+ entryId?: string;
169
+ }
170
+ /** What the editor told the preview when the handshake completed. */
171
+ interface EditorHandshake {
172
+ /**
173
+ * The content item open in the editor. Absent when the editor does not
174
+ * send one, in which case every tagged element counts as part of it.
175
+ */
176
+ itemId?: string;
177
+ /**
178
+ * Items the open item references. Absent when the editor does not send
179
+ * them, in which case other items are not split into linked and unrelated.
180
+ */
181
+ referencedIds?: EditorReference[];
182
+ /**
183
+ * `_id`s of component instances inside the open item. Content tagged with
184
+ * one of them (`previewAttrs` on a component's image) belongs to the open
185
+ * item, not to another one.
186
+ */
187
+ componentIds?: string[];
188
+ /**
189
+ * The language of the editor's own interface. Absent when the editor does
190
+ * not send one or sends a language the toolkit has no translations for.
191
+ */
192
+ uiLocale?: Locale;
193
+ /**
194
+ * The editor asks before the preview leaves the page: navigations are
195
+ * stopped and reported as `navigation_blocked`, and
196
+ * `prepr:allowNavigation` follows one. Absent for editors that do not
197
+ * handle `navigation_blocked`.
198
+ */
199
+ navigationGuard?: boolean;
200
+ /**
201
+ * Image assets of the open item. Absent when the editor does not send
202
+ * them, in which case images are only editable where the page tags them.
203
+ */
204
+ assets?: EditorAsset[];
144
205
  }
145
206
  interface IframeBridgeOptions {
146
207
  /**
147
208
  * Replace the `*.prepr.io` wildcard with an exact origin list. Intended for
148
- * self-hosted editors; when set, the wildcard no longer applies.
209
+ * self-hosted editors; when set, the wildcard no longer applies. `['*']`
210
+ * accepts any editor origin — see `PreprPreviewOptions.allowedEditorOrigins`.
149
211
  */
150
212
  allowedEditorOrigins?: string[];
151
213
  /**
@@ -154,7 +216,216 @@ interface IframeBridgeOptions {
154
216
  * stays free of DOM lookups: the preview runtime supplies `scrollToField`.
155
217
  */
156
218
  onScrollToField?: (message: ScrollToFieldMessage) => void;
219
+ /**
220
+ * Called once the editor handshake is accepted, with the id of the content
221
+ * item open in the editor when the editor sends one. Lets the preview tell
222
+ * that item's fields apart from other items rendered on the same page
223
+ * (navigation, an author card, related posts).
224
+ */
225
+ onHandshake?: (handshake: EditorHandshake) => void;
226
+ /** The editor's reference list changed (`prepr:references`). */
227
+ onReferences?: (referencedIds: EditorReference[], componentIds?: string[]) => void;
228
+ /** The editor's asset list changed (`assets` on `prepr:references`). */
229
+ onAssets?: (assets: EditorAsset[]) => void;
230
+ /**
231
+ * The editor confirmed leaving the page for `href` after a
232
+ * `navigation_blocked` (`prepr:allowNavigation`). `href` is a non-empty
233
+ * string; its scheme is not checked here.
234
+ */
235
+ onAllowNavigation?: (href: string) => void;
236
+ }
237
+
238
+ interface PreviewAttrsTarget {
239
+ /** `_id` of the content item or component that owns the field. */
240
+ id: string | null | undefined;
241
+ /** API field name, or a dotted path below the item (`content.3`). */
242
+ field: string;
243
+ /** Locale of the rendered value, when the site knows it. */
244
+ locale?: string | null;
245
+ /** Site-side id of one entry in a list-like field (`data-prepr-entry-id`). */
246
+ entryId?: string | null;
247
+ }
248
+ interface PreviewAttrsOptions {
249
+ /**
250
+ * Whether to emit the attributes at all. Pass `true` only for preview or
251
+ * draft renders, so production HTML carries no edit metadata.
252
+ */
253
+ enabled: boolean;
254
+ }
255
+ /**
256
+ * Attributes that make an element click-to-edit in the Prepr visual editor,
257
+ * for values that carry no hidden edit link of their own: images, videos,
258
+ * anything rendered from a URL. Spread them onto the element that renders
259
+ * the field:
260
+ *
261
+ * ```tsx
262
+ * <figure {...previewAttrs({ id: post._id, field: 'cover_image' }, { enabled: isPreview })}>
263
+ * ```
264
+ *
265
+ * Returns an empty object when disabled or when there is no target or id, so
266
+ * it is safe to spread unconditionally.
267
+ */
268
+ declare function previewAttrs(target: PreviewAttrsTarget | null | undefined, options: PreviewAttrsOptions): Record<string, string>;
269
+ interface StegaTargetOptions {
270
+ /**
271
+ * A field next to the encoded one, in the same item or component, to target
272
+ * instead: a dotted path that replaces the encoded field's last segment
273
+ * (`products`, or `products.items.2` for one entry of it).
274
+ */
275
+ field?: string;
276
+ }
277
+ /**
278
+ * The edit target behind a text value Prepr returned with a hidden edit link,
279
+ * for {@link previewAttrs}. Reach for it when the field to edit carries no
280
+ * link of its own, such as remote content or a list of references, but a
281
+ * text field of the same component does: the component's title points the
282
+ * way to its `products`.
283
+ *
284
+ * ```tsx
285
+ * const products = stegaTarget(block.title, { field: 'products' });
286
+ * <article {...previewAttrs(products, { enabled: isPreview })}>
287
+ * ```
288
+ *
289
+ * Returns null for a value without an edit link (a production render, or a
290
+ * value Prepr does not encode). Works on the server and in the browser.
291
+ */
292
+ declare function stegaTarget(value: string | null | undefined, options?: StegaTargetOptions): PreviewAttrsTarget | null;
293
+
294
+ /** Values a push may write. Everything else goes through refetch. */
295
+ type LiveScalar = string | number | boolean;
296
+ /** A structured field value, such as an asset. */
297
+ interface LiveObject {
298
+ [key: string]: LiveScalar | null | LiveObject;
157
299
  }
300
+ /** Anything a `prepr:fieldChange` may carry. */
301
+ type LiveValue = LiveScalar | null | LiveObject | LiveObject[];
302
+ /** One entry of a `prepr:listChange`, in the editor's order. */
303
+ interface LiveListEntry {
304
+ /** Stored id, or a temporary `tmp:` id for an entry added before save. */
305
+ _id: string;
306
+ __typename?: string;
307
+ /** Text entries only. */
308
+ body?: string;
309
+ format?: string | null;
310
+ /** A new entry's type as the editor names it (`Side by side`). */
311
+ typeName?: string;
312
+ /** A new entry's field values, shaped as the API returns them. */
313
+ fields?: Record<string, unknown>;
314
+ }
315
+
316
+ /**
317
+ * What `normalizeQuery` accepts as the query: GraphQL source text, a parsed
318
+ * `DocumentNode` (from `graphql-tag`, Apollo or GraphQL Code Generator), or a
319
+ * string-like object such as codegen's `TypedDocumentString`.
320
+ */
321
+ type QueryInput = string | {
322
+ kind: 'Document';
323
+ } | {
324
+ toString(): string;
325
+ };
326
+
327
+ /** The open item and a field path in the editor's id-based convention. */
328
+ interface LiveEditTarget {
329
+ item: string;
330
+ field: string;
331
+ }
332
+
333
+ /**
334
+ * One unsaved change from the Prepr editor: the `_id` of the item (or stack
335
+ * entry) that owns the field, and the field's API name or a dotted path below
336
+ * it (`content.headline_style`, `content.3.body`).
337
+ */
338
+ type LivePatch = {
339
+ type: 'field';
340
+ itemId: string;
341
+ field: string;
342
+ value: LiveValue;
343
+ /** Edit-link target for text that has none yet (an unsaved entry). */
344
+ edit?: LiveEditTarget;
345
+ } | {
346
+ type: 'list';
347
+ itemId: string;
348
+ field: string;
349
+ entries: LiveListEntry[];
350
+ };
351
+ interface NormalizeQueryOptions {
352
+ /**
353
+ * The editor's unsaved changes, oldest first. Treated as hostile: malformed
354
+ * entries are dropped.
355
+ */
356
+ log?: unknown;
357
+ /** Which operation to use when the document holds more than one. */
358
+ operationName?: string;
359
+ }
360
+ /**
361
+ * Validate a patch log from an untrusted source (a request body, a cookie).
362
+ * Accepts the array or its JSON text, drops malformed entries, never throws.
363
+ */
364
+ declare function parsePatchLog(raw: unknown): LivePatch[];
365
+ /**
366
+ * Apply the Prepr editor's unsaved changes to a GraphQL result, so the page
367
+ * renders them before the editor saves. Pass the query that produced the
368
+ * result (`{ data }` or just `data`):
369
+ *
370
+ * ```ts
371
+ * const page = normalizeQuery(GetPageDocument, data, { log });
372
+ * ```
373
+ *
374
+ * The query maps fields to response keys, so changes land under aliases and
375
+ * on every place the same item appears; fields not in the query are left
376
+ * alone. Select `_id` on every item and component that should update.
377
+ * Without a log the query is not parsed and the result is returned as-is.
378
+ * Never throws.
379
+ */
380
+ declare function normalizeQuery<T>(query: QueryInput, result: T, options?: NormalizeQueryOptions): T;
381
+
382
+ /**
383
+ * Adds the list entry each piece of text belongs to (a dynamic content
384
+ * entry, a repeated component) to its hidden edit link, so the visual editor
385
+ * can find the entry by id without `data-prepr-entry-id` on the page. A
386
+ * `Text` entry's link, which names no field, also gets the entry's field
387
+ * path, so `data-prepr-edit-target` is not needed to name it.
388
+ *
389
+ * Needs `_id` on the entries. Returns the result itself when nothing
390
+ * changed. Pass the query to name fields by their API name under aliases.
391
+ */
392
+ declare function annotateEditLinks<T>(result: T, query?: QueryInput, operationName?: string): T;
393
+
394
+ interface HtmlLivePreviewOptions {
395
+ /**
396
+ * Replace the `*.prepr.io` editor-origin wildcard with an exact list, as
397
+ * the toolbar's option of the same name.
398
+ */
399
+ allowedEditorOrigins?: string[];
400
+ /** See the toolbar's `strictMode`. */
401
+ strictMode?: boolean;
402
+ }
403
+ interface HtmlLivePreview {
404
+ stop(): void;
405
+ }
406
+ /**
407
+ * Live preview for server-rendered pages without a client framework (Astro,
408
+ * or any HTML-first site): while an editor types, the page is requested
409
+ * again from the server with the unsaved changes in the request body, and
410
+ * only the parts of the DOM that changed are updated. On save the page is
411
+ * requested without changes. The server applies them with `normalizeQuery`;
412
+ * see `readLiveLogFromRequest`.
413
+ *
414
+ * A no-op outside the Prepr editor's preview iframe.
415
+ */
416
+ declare function startHtmlLivePreview(options?: HtmlLivePreviewOptions): HtmlLivePreview;
417
+
418
+ /**
419
+ * The editor's unsaved changes carried by a live-preview re-render request
420
+ * (sent by `startHtmlLivePreview`), or an empty list for any other request.
421
+ *
422
+ * Accepted only from a same-origin `POST` with the live-preview header and a
423
+ * JSON body, so a link, a form on another site or a cacheable `GET` can never
424
+ * inject changes. Call it only when the site runs in preview, and mark the
425
+ * response uncacheable (`Cache-Control: private, no-store`) whenever it
426
+ * returns changes. Never throws.
427
+ */
428
+ declare function readLiveLogFromRequest(request: Request): Promise<LivePatch[]>;
158
429
 
159
430
  /** Error thrown by the token helpers and the segments fetch. */
160
431
  declare class PreprError extends Error {
@@ -241,4 +512,4 @@ interface PreprMiddlewareOptions {
241
512
  */
242
513
  declare function processPreprRequest(request: Request, opts?: PreprMiddlewareOptions): PreprMiddlewareResult;
243
514
 
244
- export { type CookieSpec, type CreatePreprPreviewOptions, type IframeBridgeOptions, PreprError, PreprErrorCode, PreprFeatures, PreprHeaders, type PreprMiddlewareOptions, type PreprMiddlewareResult, type PreprNavigationAdapter, type PreprPreviewController, PreprPreviewOptions, PreprSegment, PreprToolbarElement, PreprToolbarProps, PreprVariant, ResolvedPreprFeatures, type ToolbarState, type ToolbarStore, VERSION, createPreprPreview, createToolbarStore, definePreprToolbar, extractAccessToken, getActiveSegmentFromHeaders, getActiveVariantFromHeaders, getPreprEnvironmentSegments, getPreprHeadersFromHeaders, getPreprUUIDFromHeaders, getToolbarPropsFromHeaders, processPreprRequest, resolveFeatures, stegaClean, validatePreprToken };
515
+ export { type CookieSpec, type CreatePreprPreviewOptions, type HtmlLivePreview, type HtmlLivePreviewOptions, type IframeBridgeOptions, type LivePatch, type NormalizeQueryOptions, PreprError, PreprErrorCode, PreprFeatures, PreprHeaders, type PreprMiddlewareOptions, type PreprMiddlewareResult, type PreprNavigationAdapter, type PreprPreviewController, PreprPreviewOptions, PreprSegment, PreprToolbarElement, PreprToolbarProps, PreprVariant, type PreviewAttrsOptions, type PreviewAttrsTarget, type QueryInput, ResolvedPreprFeatures, type StegaTargetOptions, type ToolbarState, type ToolbarStore, VERSION, annotateEditLinks, createPreprPreview, createToolbarStore, definePreprToolbar, extractAccessToken, getActiveSegmentFromHeaders, getActiveVariantFromHeaders, getPreprEnvironmentSegments, getPreprHeadersFromHeaders, getPreprUUIDFromHeaders, getToolbarPropsFromHeaders, normalizeQuery, parsePatchLog, previewAttrs, processPreprRequest, readLiveLogFromRequest, resolveFeatures, startHtmlLivePreview, stegaClean, stegaTarget, validatePreprToken };