@preprio/toolkit 0.5.0-rc.2 → 0.5.0-rc.3

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 (50) hide show
  1. package/README.md +207 -10
  2. package/dist/astro/index.cjs +1174 -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 +1177 -1
  6. package/dist/chunk-42Z2VW7G.js +1161 -0
  7. package/dist/chunk-6WY3MWCX.js +246 -0
  8. package/dist/chunk-MDAV2FLM.js +26 -0
  9. package/dist/{chunk-FLPNN3CV.js → chunk-PP3O7RB4.js} +1370 -623
  10. package/dist/chunk-S3VT4UWM.js +75 -0
  11. package/dist/chunk-SXUDBGLZ.js +184 -0
  12. package/dist/chunk-URXSDJOU.js +356 -0
  13. package/dist/index.cjs +3108 -392
  14. package/dist/index.d.cts +238 -4
  15. package/dist/index.d.ts +238 -4
  16. package/dist/index.js +189 -149
  17. package/dist/live-preview-EADA3ZL4.js +18 -0
  18. package/dist/nextjs/components.cjs +1522 -359
  19. package/dist/nextjs/components.d.cts +1 -1
  20. package/dist/nextjs/components.d.ts +1 -1
  21. package/dist/nextjs/components.js +4 -1
  22. package/dist/nextjs/index.cjs +1065 -6
  23. package/dist/nextjs/index.d.cts +73 -1
  24. package/dist/nextjs/index.d.ts +73 -1
  25. package/dist/nextjs/index.js +1059 -7
  26. package/dist/nextjs/live-action.cjs +285 -0
  27. package/dist/nextjs/live-action.d.cts +12 -0
  28. package/dist/nextjs/live-action.d.ts +12 -0
  29. package/dist/nextjs/live-action.js +68 -0
  30. package/dist/nextjs/live.cjs +1838 -0
  31. package/dist/nextjs/live.d.cts +52 -0
  32. package/dist/nextjs/live.d.ts +52 -0
  33. package/dist/nextjs/live.js +265 -0
  34. package/dist/nuxt/index.cjs +1 -1
  35. package/dist/nuxt/index.js +1 -1
  36. package/dist/nuxt/live-preview-PTEC3GPC.js +1462 -0
  37. package/dist/nuxt/live.cjs +1662 -0
  38. package/dist/nuxt/live.d.cts +43 -0
  39. package/dist/nuxt/live.d.ts +43 -0
  40. package/dist/nuxt/live.js +94 -0
  41. package/dist/{pixel-B3oQNbZ3.d.cts → pixel-CX422dCO.d.cts} +10 -1
  42. package/dist/{pixel-B3oQNbZ3.d.ts → pixel-CX422dCO.d.ts} +10 -1
  43. package/dist/react/components.cjs +1522 -359
  44. package/dist/react/components.d.cts +9 -0
  45. package/dist/react/components.d.ts +9 -0
  46. package/dist/react/components.js +1522 -359
  47. package/dist/sveltekit/index.cjs +1 -1
  48. package/dist/sveltekit/index.js +1 -1
  49. package/package.json +12 -1
  50. 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-B3oQNbZ3.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-B3oQNbZ3.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.2";
8
+ declare const VERSION = "0.5.0-rc.3";
9
9
 
10
10
  /**
11
11
  * Resolve a `PreprFeatures` bag to plain booleans, defaulting every omitted key
@@ -141,6 +141,67 @@ 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
  /**
@@ -155,7 +216,180 @@ interface IframeBridgeOptions {
155
216
  * stays free of DOM lookups: the preview runtime supplies `scrollToField`.
156
217
  */
157
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;
158
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 id, so it is safe
266
+ * to spread unconditionally.
267
+ */
268
+ declare function previewAttrs(target: PreviewAttrsTarget, options: PreviewAttrsOptions): Record<string, string>;
269
+
270
+ /** Values a push may write. Everything else goes through refetch. */
271
+ type LiveScalar = string | number | boolean;
272
+ /** A structured field value, such as an asset. */
273
+ interface LiveObject {
274
+ [key: string]: LiveScalar | null | LiveObject;
275
+ }
276
+ /** Anything a `prepr:fieldChange` may carry. */
277
+ type LiveValue = LiveScalar | null | LiveObject | LiveObject[];
278
+ /** One entry of a `prepr:listChange`, in the editor's order. */
279
+ interface LiveListEntry {
280
+ /** Stored id, or a temporary `tmp:` id for an entry added before save. */
281
+ _id: string;
282
+ __typename?: string;
283
+ /** Text entries only. */
284
+ body?: string;
285
+ format?: string | null;
286
+ /** A new entry's type as the editor names it (`Side by side`). */
287
+ typeName?: string;
288
+ /** A new entry's field values, shaped as the API returns them. */
289
+ fields?: Record<string, unknown>;
290
+ }
291
+
292
+ /**
293
+ * What `normalizeQuery` accepts as the query: GraphQL source text, a parsed
294
+ * `DocumentNode` (from `graphql-tag`, Apollo or GraphQL Code Generator), or a
295
+ * string-like object such as codegen's `TypedDocumentString`.
296
+ */
297
+ type QueryInput = string | {
298
+ kind: 'Document';
299
+ } | {
300
+ toString(): string;
301
+ };
302
+
303
+ /** The open item and a field path in the editor's id-based convention. */
304
+ interface LiveEditTarget {
305
+ item: string;
306
+ field: string;
307
+ }
308
+
309
+ /**
310
+ * One unsaved change from the Prepr editor: the `_id` of the item (or stack
311
+ * entry) that owns the field, and the field's API name or a dotted path below
312
+ * it (`content.headline_style`, `content.3.body`).
313
+ */
314
+ type LivePatch = {
315
+ type: 'field';
316
+ itemId: string;
317
+ field: string;
318
+ value: LiveValue;
319
+ /** Edit-link target for text that has none yet (an unsaved entry). */
320
+ edit?: LiveEditTarget;
321
+ } | {
322
+ type: 'list';
323
+ itemId: string;
324
+ field: string;
325
+ entries: LiveListEntry[];
326
+ };
327
+ interface NormalizeQueryOptions {
328
+ /**
329
+ * The editor's unsaved changes, oldest first. Treated as hostile: malformed
330
+ * entries are dropped.
331
+ */
332
+ log?: unknown;
333
+ /** Which operation to use when the document holds more than one. */
334
+ operationName?: string;
335
+ }
336
+ /**
337
+ * Validate a patch log from an untrusted source (a request body, a cookie).
338
+ * Accepts the array or its JSON text, drops malformed entries, never throws.
339
+ */
340
+ declare function parsePatchLog(raw: unknown): LivePatch[];
341
+ /**
342
+ * Apply the Prepr editor's unsaved changes to a GraphQL result, so the page
343
+ * renders them before the editor saves. Pass the query that produced the
344
+ * result (`{ data }` or just `data`):
345
+ *
346
+ * ```ts
347
+ * const page = normalizeQuery(GetPageDocument, data, { log });
348
+ * ```
349
+ *
350
+ * The query maps fields to response keys, so changes land under aliases and
351
+ * on every place the same item appears; fields not in the query are left
352
+ * alone. Select `_id` on every item and component that should update.
353
+ * Without a log the query is not parsed and the result is returned as-is.
354
+ * Never throws.
355
+ */
356
+ declare function normalizeQuery<T>(query: QueryInput, result: T, options?: NormalizeQueryOptions): T;
357
+
358
+ interface HtmlLivePreviewOptions {
359
+ /**
360
+ * Replace the `*.prepr.io` editor-origin wildcard with an exact list, as
361
+ * the toolbar's option of the same name.
362
+ */
363
+ allowedEditorOrigins?: string[];
364
+ /** See the toolbar's `strictMode`. */
365
+ strictMode?: boolean;
366
+ }
367
+ interface HtmlLivePreview {
368
+ stop(): void;
369
+ }
370
+ /**
371
+ * Live preview for server-rendered pages without a client framework (Astro,
372
+ * or any HTML-first site): while an editor types, the page is requested
373
+ * again from the server with the unsaved changes in the request body, and
374
+ * only the parts of the DOM that changed are updated. On save the page is
375
+ * requested without changes. The server applies them with `normalizeQuery`;
376
+ * see `readLiveLogFromRequest`.
377
+ *
378
+ * A no-op outside the Prepr editor's preview iframe.
379
+ */
380
+ declare function startHtmlLivePreview(options?: HtmlLivePreviewOptions): HtmlLivePreview;
381
+
382
+ /**
383
+ * The editor's unsaved changes carried by a live-preview re-render request
384
+ * (sent by `startHtmlLivePreview`), or an empty list for any other request.
385
+ *
386
+ * Accepted only from a same-origin `POST` with the live-preview header and a
387
+ * JSON body, so a link, a form on another site or a cacheable `GET` can never
388
+ * inject changes. Call it only when the site runs in preview, and mark the
389
+ * response uncacheable (`Cache-Control: private, no-store`) whenever it
390
+ * returns changes. Never throws.
391
+ */
392
+ declare function readLiveLogFromRequest(request: Request): Promise<LivePatch[]>;
159
393
 
160
394
  /** Error thrown by the token helpers and the segments fetch. */
161
395
  declare class PreprError extends Error {
@@ -242,4 +476,4 @@ interface PreprMiddlewareOptions {
242
476
  */
243
477
  declare function processPreprRequest(request: Request, opts?: PreprMiddlewareOptions): PreprMiddlewareResult;
244
478
 
245
- 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 };
479
+ 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 ToolbarState, type ToolbarStore, VERSION, createPreprPreview, createToolbarStore, definePreprToolbar, extractAccessToken, getActiveSegmentFromHeaders, getActiveVariantFromHeaders, getPreprEnvironmentSegments, getPreprHeadersFromHeaders, getPreprUUIDFromHeaders, getToolbarPropsFromHeaders, normalizeQuery, parsePatchLog, previewAttrs, processPreprRequest, readLiveLogFromRequest, resolveFeatures, startHtmlLivePreview, stegaClean, 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-B3oQNbZ3.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-B3oQNbZ3.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.2";
8
+ declare const VERSION = "0.5.0-rc.3";
9
9
 
10
10
  /**
11
11
  * Resolve a `PreprFeatures` bag to plain booleans, defaulting every omitted key
@@ -141,6 +141,67 @@ 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
  /**
@@ -155,7 +216,180 @@ interface IframeBridgeOptions {
155
216
  * stays free of DOM lookups: the preview runtime supplies `scrollToField`.
156
217
  */
157
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;
158
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 id, so it is safe
266
+ * to spread unconditionally.
267
+ */
268
+ declare function previewAttrs(target: PreviewAttrsTarget, options: PreviewAttrsOptions): Record<string, string>;
269
+
270
+ /** Values a push may write. Everything else goes through refetch. */
271
+ type LiveScalar = string | number | boolean;
272
+ /** A structured field value, such as an asset. */
273
+ interface LiveObject {
274
+ [key: string]: LiveScalar | null | LiveObject;
275
+ }
276
+ /** Anything a `prepr:fieldChange` may carry. */
277
+ type LiveValue = LiveScalar | null | LiveObject | LiveObject[];
278
+ /** One entry of a `prepr:listChange`, in the editor's order. */
279
+ interface LiveListEntry {
280
+ /** Stored id, or a temporary `tmp:` id for an entry added before save. */
281
+ _id: string;
282
+ __typename?: string;
283
+ /** Text entries only. */
284
+ body?: string;
285
+ format?: string | null;
286
+ /** A new entry's type as the editor names it (`Side by side`). */
287
+ typeName?: string;
288
+ /** A new entry's field values, shaped as the API returns them. */
289
+ fields?: Record<string, unknown>;
290
+ }
291
+
292
+ /**
293
+ * What `normalizeQuery` accepts as the query: GraphQL source text, a parsed
294
+ * `DocumentNode` (from `graphql-tag`, Apollo or GraphQL Code Generator), or a
295
+ * string-like object such as codegen's `TypedDocumentString`.
296
+ */
297
+ type QueryInput = string | {
298
+ kind: 'Document';
299
+ } | {
300
+ toString(): string;
301
+ };
302
+
303
+ /** The open item and a field path in the editor's id-based convention. */
304
+ interface LiveEditTarget {
305
+ item: string;
306
+ field: string;
307
+ }
308
+
309
+ /**
310
+ * One unsaved change from the Prepr editor: the `_id` of the item (or stack
311
+ * entry) that owns the field, and the field's API name or a dotted path below
312
+ * it (`content.headline_style`, `content.3.body`).
313
+ */
314
+ type LivePatch = {
315
+ type: 'field';
316
+ itemId: string;
317
+ field: string;
318
+ value: LiveValue;
319
+ /** Edit-link target for text that has none yet (an unsaved entry). */
320
+ edit?: LiveEditTarget;
321
+ } | {
322
+ type: 'list';
323
+ itemId: string;
324
+ field: string;
325
+ entries: LiveListEntry[];
326
+ };
327
+ interface NormalizeQueryOptions {
328
+ /**
329
+ * The editor's unsaved changes, oldest first. Treated as hostile: malformed
330
+ * entries are dropped.
331
+ */
332
+ log?: unknown;
333
+ /** Which operation to use when the document holds more than one. */
334
+ operationName?: string;
335
+ }
336
+ /**
337
+ * Validate a patch log from an untrusted source (a request body, a cookie).
338
+ * Accepts the array or its JSON text, drops malformed entries, never throws.
339
+ */
340
+ declare function parsePatchLog(raw: unknown): LivePatch[];
341
+ /**
342
+ * Apply the Prepr editor's unsaved changes to a GraphQL result, so the page
343
+ * renders them before the editor saves. Pass the query that produced the
344
+ * result (`{ data }` or just `data`):
345
+ *
346
+ * ```ts
347
+ * const page = normalizeQuery(GetPageDocument, data, { log });
348
+ * ```
349
+ *
350
+ * The query maps fields to response keys, so changes land under aliases and
351
+ * on every place the same item appears; fields not in the query are left
352
+ * alone. Select `_id` on every item and component that should update.
353
+ * Without a log the query is not parsed and the result is returned as-is.
354
+ * Never throws.
355
+ */
356
+ declare function normalizeQuery<T>(query: QueryInput, result: T, options?: NormalizeQueryOptions): T;
357
+
358
+ interface HtmlLivePreviewOptions {
359
+ /**
360
+ * Replace the `*.prepr.io` editor-origin wildcard with an exact list, as
361
+ * the toolbar's option of the same name.
362
+ */
363
+ allowedEditorOrigins?: string[];
364
+ /** See the toolbar's `strictMode`. */
365
+ strictMode?: boolean;
366
+ }
367
+ interface HtmlLivePreview {
368
+ stop(): void;
369
+ }
370
+ /**
371
+ * Live preview for server-rendered pages without a client framework (Astro,
372
+ * or any HTML-first site): while an editor types, the page is requested
373
+ * again from the server with the unsaved changes in the request body, and
374
+ * only the parts of the DOM that changed are updated. On save the page is
375
+ * requested without changes. The server applies them with `normalizeQuery`;
376
+ * see `readLiveLogFromRequest`.
377
+ *
378
+ * A no-op outside the Prepr editor's preview iframe.
379
+ */
380
+ declare function startHtmlLivePreview(options?: HtmlLivePreviewOptions): HtmlLivePreview;
381
+
382
+ /**
383
+ * The editor's unsaved changes carried by a live-preview re-render request
384
+ * (sent by `startHtmlLivePreview`), or an empty list for any other request.
385
+ *
386
+ * Accepted only from a same-origin `POST` with the live-preview header and a
387
+ * JSON body, so a link, a form on another site or a cacheable `GET` can never
388
+ * inject changes. Call it only when the site runs in preview, and mark the
389
+ * response uncacheable (`Cache-Control: private, no-store`) whenever it
390
+ * returns changes. Never throws.
391
+ */
392
+ declare function readLiveLogFromRequest(request: Request): Promise<LivePatch[]>;
159
393
 
160
394
  /** Error thrown by the token helpers and the segments fetch. */
161
395
  declare class PreprError extends Error {
@@ -242,4 +476,4 @@ interface PreprMiddlewareOptions {
242
476
  */
243
477
  declare function processPreprRequest(request: Request, opts?: PreprMiddlewareOptions): PreprMiddlewareResult;
244
478
 
245
- 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 };
479
+ 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 ToolbarState, type ToolbarStore, VERSION, createPreprPreview, createToolbarStore, definePreprToolbar, extractAccessToken, getActiveSegmentFromHeaders, getActiveVariantFromHeaders, getPreprEnvironmentSegments, getPreprHeadersFromHeaders, getPreprUUIDFromHeaders, getToolbarPropsFromHeaders, normalizeQuery, parsePatchLog, previewAttrs, processPreprRequest, readLiveLogFromRequest, resolveFeatures, startHtmlLivePreview, stegaClean, validatePreprToken };