@marktiderman/genesis-sites 0.2.0 → 0.3.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.
@@ -0,0 +1,526 @@
1
+ import * as React from 'react';
2
+ import { P as PageKind, a as PageDoc, b as PageMeta, R as Release, F as FormsResolver, c as RenderContext, d as ResolvedForm, S as SectionCategory, A as AnySectionDefinition, e as Seo, f as SectionNode, g as SiteDoc } from './registry-HBn1X60x.js';
3
+ import { A as Asset, a as AssetMeta, S as SiteStore, B as BrandInput, b as SiteIssue, P as PublishOptions, R as ReservedPaths, c as SaveResult } from './store-BXiZeZzH.js';
4
+ import { Config, Fields, Overrides } from '@puckeditor/core';
5
+ export { Config as PuckConfig, Data as PuckData, Overrides as PuckOverrides, createUsePuck, usePuck } from '@puckeditor/core';
6
+ import 'zod';
7
+ import '@marktiderman/genesis-design-system';
8
+
9
+ /** The host's asset library, beside the store's `putAsset` uploads. */
10
+ interface EditorAssets {
11
+ /** The images and files a site already has (shown in the picker's Library). */
12
+ list?: (siteId: string) => Promise<Asset[]>;
13
+ /** Upload, instead of the store's `putAsset` (for a host that stores files elsewhere). */
14
+ upload?: (siteId: string, file: File, meta: AssetMeta) => Promise<Asset>;
15
+ /** The largest upload, in bytes. Default 10 MB. */
16
+ maxBytes?: number;
17
+ }
18
+ interface PickedImage {
19
+ src: string;
20
+ alt: string;
21
+ decorative?: boolean;
22
+ width?: number;
23
+ height?: number;
24
+ }
25
+
26
+ /**
27
+ * What the editor's panels do to a site, as plain functions over a
28
+ * `SiteStore`: check and publish, add, move, delete and reorder pages, and
29
+ * the page templates. No React, so each is tested against the memory store.
30
+ */
31
+
32
+ /** A store the editor can drive. `reorderPages` is optional: without it, page order is the store's. */
33
+ type EditorSiteStore = SiteStore & {
34
+ reorderPages?(siteId: string, pageIds: string[]): Promise<void>;
35
+ };
36
+ interface SiteCheck {
37
+ issues: SiteIssue[];
38
+ /** No errors: the site can be published. */
39
+ publishable: boolean;
40
+ }
41
+ /**
42
+ * Run the publish checks on the drafts as they are now (accessibility,
43
+ * contrast, placeholders, paths), without publishing: what the Publish
44
+ * panel lists, errors first.
45
+ *
46
+ * @stability Beta
47
+ */
48
+ declare function checkSite(store: SiteStore, siteId: string, options?: Pick<PublishOptions, "brand" | "reserved">): Promise<SiteCheck>;
49
+ /** Publish after checking: a site with errors is refused before the store is asked. */
50
+ declare function publishSite(store: SiteStore, siteId: string, options: {
51
+ brand: BrandInput;
52
+ note?: string;
53
+ reserved?: ReservedPaths;
54
+ }): Promise<{
55
+ release: Release;
56
+ } | {
57
+ blocked: SiteIssue[];
58
+ }>;
59
+ /** Why a path can't be a page's here (empty when it can): the pattern, reserved paths, and pages already there. */
60
+ declare function pathProblems(path: string, pages: readonly Pick<PageMeta, "id" | "path">[], options?: {
61
+ reserved?: ReservedPaths;
62
+ except?: string;
63
+ }): string[];
64
+ /** A page's title as a path segment: "Our classes" → "/our-classes". */
65
+ declare function slugify(title: string): string;
66
+ /**
67
+ * Move a page to a new address. The store writes a 301 from the old path
68
+ * (and rewrites older redirects, so there are no chains). Refuses the home
69
+ * page, reserved paths and a path another page has, before asking the store.
70
+ */
71
+ declare function renamePage(store: SiteStore, pageId: string, path: string, options?: {
72
+ reserved?: ReservedPaths;
73
+ }): Promise<PageMeta>;
74
+ /** A page a person can start from. */
75
+ interface PageTemplate {
76
+ id: string;
77
+ label: string;
78
+ description: string;
79
+ kind: PageKind;
80
+ doc(input: {
81
+ title: string;
82
+ brand: BrandInput;
83
+ }): PageDoc;
84
+ }
85
+ /**
86
+ * The templates the Add page dialog offers: a blank page, the one-click
87
+ * landing page from the brand, and each page of the starter site (about,
88
+ * contact) after its home page.
89
+ *
90
+ * @stability Beta
91
+ */
92
+ declare function pageTemplates(): PageTemplate[];
93
+ /** Move one page up or down the list (through `reorderPages`, when the store has it). */
94
+ declare function movePageInList(store: EditorSiteStore, siteId: string, pageId: string, by: -1 | 1): Promise<PageMeta[]>;
95
+
96
+ /**
97
+ * `<SiteEditor>`: the visual editor for a genesis-sites site.
98
+ *
99
+ * <SiteEditor siteId="riverside" store={store} brand={brand} />
100
+ *
101
+ * Puck runs the canvas, drag and drop, the fields and the history; every
102
+ * panel around it is Genesis UI. The canvas is an iframe drawn by each
103
+ * section's own renderer with the site's stylesheet and the brand's theme;
104
+ * "Preview" runs the real `/web` request handler. Drafts autosave by
105
+ * compare-and-swap; publishing runs the checks first, and holds the canvas
106
+ * and the autosaves while it runs. `readOnly` opens a site to look at only.
107
+ */
108
+
109
+ interface SiteEditorProps {
110
+ siteId: string;
111
+ /** Any `SiteStore`: the Supabase one signed in as the editor, or the memory store. */
112
+ store: EditorSiteStore;
113
+ /** The site's brand: the canvas theme, and what a publish checks contrast against. */
114
+ brand: BrandInput;
115
+ /** Resolves form embeds' slugs, for the canvas and preview. */
116
+ forms?: FormsResolver;
117
+ /** The asset library and upload, beside the store's `putAsset`. */
118
+ assets?: EditorAssets;
119
+ /** After each publish. */
120
+ onPublish?: (release: Release) => void;
121
+ /**
122
+ * Whether anything isn't saved yet (waiting, saving, a conflict, a failed save, or a change that
123
+ * can't be saved until it's fixed). Block your app's own navigation while it's true: closing the
124
+ * tab is already guarded, and unmounting the editor saves what it can but can't ask.
125
+ */
126
+ onDirtyChange?: (dirty: boolean) => void;
127
+ /** Paths the site can't use (default: the store's own rule). */
128
+ reserved?: ReservedPaths;
129
+ /** A link to the host's preview route for a page path (opens in a new tab). */
130
+ previewUrl?: (path: string) => string;
131
+ /** Milliseconds after the last change before a save (default 800). */
132
+ autosaveDelay?: number;
133
+ /** The page to open first (default: the home page). */
134
+ initialPageId?: string;
135
+ /**
136
+ * The URL of the package's site stylesheet (`@marktiderman/genesis-sites/sites.css`, for example
137
+ * Vite's `?url` import, or `/_gs/sites.<hash>.css` where `handleSiteRequest` is mounted). Without it
138
+ * the canvas loads the stylesheet from the renderer's bundled assets, a larger download.
139
+ */
140
+ siteStylesheet?: string;
141
+ /**
142
+ * View only: the canvas, fields and SEO can't be changed, there is no Add, no
143
+ * page actions, no Publish and no Roll back, and nothing is ever saved. For
144
+ * someone who may see the drafts but not edit them.
145
+ */
146
+ readOnly?: boolean;
147
+ className?: string;
148
+ }
149
+ /**
150
+ * The visual editor.
151
+ *
152
+ * @stability Beta
153
+ */
154
+ declare function SiteEditor({ siteId, store, brand, forms, assets, onPublish, reserved, previewUrl, autosaveDelay, initialPageId, siteStylesheet, readOnly, onDirtyChange, className }: SiteEditorProps): React.JSX.Element;
155
+
156
+ /** What the Add picker and its limits know about one Puck component. */
157
+ interface ComponentInfo {
158
+ type: string;
159
+ /** The preset's name (the Add picker's label). */
160
+ label: string;
161
+ /** The section's own label. */
162
+ sectionLabel: string;
163
+ category: SectionCategory;
164
+ placement: "header" | "body" | "footer";
165
+ limit?: number;
166
+ }
167
+ /** What every section on the canvas is told about the page (Puck metadata). */
168
+ interface CanvasMetadata {
169
+ site: RenderContext["site"];
170
+ pagePath: string;
171
+ /** Plain objects, not Maps: Puck copies its metadata. */
172
+ forms: Readonly<Record<string, ResolvedForm | null>>;
173
+ /** The section that gets the page's h1. */
174
+ h1Id: string | null;
175
+ /** Template placeholders' original props, by section id. */
176
+ placeholders: Readonly<Record<string, string>>;
177
+ }
178
+ interface EditorConfigOptions {
179
+ /** The page kind: sections not `enabledOn` it are left out of the picker. */
180
+ kind?: PageKind;
181
+ /** Sections to offer (default: every registered section). */
182
+ sections?: readonly AnySectionDefinition[];
183
+ /** How many of each type the page holds now; read when Puck asks whether one more may be added. */
184
+ counts?: () => ReadonlyMap<string, number>;
185
+ /**
186
+ * Whether the page can't be changed now (a view-only editor, or a publish
187
+ * running). Read with `counts`: a component's own `insert` overrides the
188
+ * global permissions Puck is given, so it has to say no itself.
189
+ */
190
+ readOnly?: () => boolean;
191
+ }
192
+ interface EditorConfig {
193
+ config: Config;
194
+ /** Puck component name → what it is. */
195
+ components: ReadonlyMap<string, ComponentInfo>;
196
+ /** The props of a section type that hold nested sections. */
197
+ slotKeys: (type: string) => readonly string[];
198
+ }
199
+ /**
200
+ * The Puck config for one page kind, from the registry.
201
+ *
202
+ * @stability Beta
203
+ */
204
+ declare function createEditorConfig(options?: EditorConfigOptions): EditorConfig;
205
+
206
+ /**
207
+ * Editor fields from a section's JSON Schema (`sectionJsonSchema`, the zod
208
+ * schema's input side), so a new section gets its fields with no editor
209
+ * change:
210
+ *
211
+ * - `x-genesis-kind: "image"` (or any object with `src` and `alt`) → the
212
+ * image picker, which asks for alt text;
213
+ * - `x-genesis-kind: "rich-text"` → the Genesis rich text editor;
214
+ * - `x-genesis-kind: "slot"` → a Puck slot (nested sections);
215
+ * - an enum, or a union of constants → a select;
216
+ * - a boolean → a yes/no radio; a number → a number input;
217
+ * - a string → text, or a textarea when it may run past 160 characters;
218
+ * - an object → its fields (a record keyed by an enum, such as
219
+ * `z.partialRecord(Day, …)`, gets one optional field per key); an array of
220
+ * objects → a list of them; an array of strings → one per line.
221
+ *
222
+ * Anything else gets a field that says it can't be edited here, and a
223
+ * warning in the console, so a gap is visible rather than silent.
224
+ */
225
+
226
+ /** `primaryCta` → "Primary CTA"; `hideOn` → "Hide on". */
227
+ declare function humanize(key: string): string;
228
+ interface SectionFields {
229
+ fields: Fields;
230
+ /** Props that hold nested sections (Puck slots). */
231
+ slotKeys: string[];
232
+ /** Props no field could be made for (shown as "can't be edited here"). */
233
+ unsupported: string[];
234
+ }
235
+ /**
236
+ * Every field of a section: its layout (variant) first, then its props from
237
+ * the JSON Schema, then where it shows.
238
+ *
239
+ * @stability Beta
240
+ */
241
+ declare function sectionFields(def: AnySectionDefinition, options?: {
242
+ slotAllow?: string[];
243
+ }): SectionFields;
244
+
245
+ /**
246
+ * Between Genesis documents and Puck's data.
247
+ *
248
+ * A Genesis section node is `{ id, type, v, variant, hidden, hideOn,
249
+ * placeholder, props }`; a Puck item is `{ type, props: { id, ...props } }`.
250
+ * The node's own fields travel in the Puck props under `_` keys (`_variant`,
251
+ * `_hidden`, `_hideOn`, `_v`, `_placeholder`) that no section schema may use,
252
+ * and come back out on save. A page's header and footer (site parts) are
253
+ * slots on Puck's root, so the canvas shows and edits the whole page.
254
+ *
255
+ * The editor's Add picker offers each section's presets: a preset after the
256
+ * first is its own Puck component, `type__n`, and turns back into `type` on
257
+ * save, so stored documents only ever name registered types.
258
+ */
259
+
260
+ /** Puck's item shape, as far as the editor needs it. */
261
+ interface PuckItem {
262
+ type: string;
263
+ props: Record<string, unknown> & {
264
+ id: string;
265
+ };
266
+ }
267
+ /** Puck's page data as the editor builds it. */
268
+ interface EditorData {
269
+ root: {
270
+ props: EditorRootProps;
271
+ };
272
+ content: PuckItem[];
273
+ }
274
+ interface EditorRootProps {
275
+ title: string;
276
+ hideSiteChrome?: boolean;
277
+ seo?: Seo;
278
+ /** The site header's sections (slot). */
279
+ header: PuckItem[];
280
+ /** The site footer's sections (slot). */
281
+ footer: PuckItem[];
282
+ [key: string]: unknown;
283
+ }
284
+ /** Keys a section schema may not use: they carry the node's own fields. */
285
+ declare const NODE_KEYS: readonly ["_variant", "_hidden", "_hideOn", "_v", "_placeholder"];
286
+ /** The Puck component name of a section's preset: `hero` for the first, `hero__1` for the second (`_` never appears in a section type, and Puck builds ids from the name, so it must be id-safe). */
287
+ declare const presetComponentName: (type: string, index: number) => string;
288
+ /** The section type a Puck component name stands for. */
289
+ declare const sectionTypeOf: (componentName: string) => string;
290
+ type Lookup = (type: string) => AnySectionDefinition | undefined;
291
+ type SlotKeys = (type: string) => readonly string[];
292
+ /** A node as a Puck item. Unknown types keep their props, so nothing is lost. */
293
+ declare function nodeToItem(node: SectionNode, slotKeys?: SlotKeys): PuckItem;
294
+ /**
295
+ * Empty optional values out: `""`, and objects left with nothing in them
296
+ * (an optional button whose fields were cleared). A required field that
297
+ * empties is then reported by the section's schema, never saved as `""`.
298
+ * Strings inside arrays stay as they are (an empty one is the schema's to
299
+ * report, not ours to drop).
300
+ */
301
+ declare function pruneEmpty(value: unknown): unknown;
302
+ /**
303
+ * A section id the schema accepts (1–64 letters, digits, `-`, `_`). Puck makes
304
+ * ids for dragged-in and duplicated sections from the component name and a
305
+ * UUID; the same id always maps to the same safe one, so saves stay stable.
306
+ */
307
+ declare function safeSectionId(id: string): string;
308
+ interface FromItemOptions {
309
+ lookup?: Lookup;
310
+ slotKeys?: SlotKeys;
311
+ /**
312
+ * A hash of the props each template placeholder had when the editor
313
+ * opened it (`placeholderSnapshot`), by section id. A placeholder stays one only while its props are unchanged:
314
+ * editing it clears the flag.
315
+ */
316
+ placeholders?: ReadonlyMap<string, string>;
317
+ }
318
+ /** A Puck item as a node. */
319
+ declare function itemToNode(item: PuckItem, options?: FromItemOptions): SectionNode;
320
+ /** A hash of every placeholder node's props, to tell later whether it was edited. */
321
+ declare function placeholderSnapshot(nodes: readonly SectionNode[], into?: Map<string, string>): Map<string, string>;
322
+ /** A page (and its site's header and footer) as the editor's Puck data. */
323
+ declare function toEditorData(page: PageDoc, site: Pick<SiteDoc, "header" | "footer">, slotKeys?: SlotKeys): EditorData;
324
+ interface FromEditorResult {
325
+ page: PageDoc;
326
+ header: SectionNode[];
327
+ footer: SectionNode[];
328
+ }
329
+ /** The editor's Puck data back as a page and the site's header and footer. */
330
+ declare function fromEditorData(data: {
331
+ root?: {
332
+ props?: Record<string, unknown>;
333
+ };
334
+ content?: unknown[];
335
+ }, options?: FromItemOptions): FromEditorResult;
336
+ /** The id of the section that gets the page's `h1`: the first visible one that provides it. */
337
+ declare function h1SectionId(content: readonly PuckItem[], lookup?: Lookup): string | null;
338
+ /** How many sections of each type the page holds, in every zone (for the Add picker's limits). */
339
+ declare function countTypes(data: Pick<EditorData, "content"> & {
340
+ root?: {
341
+ props?: Partial<EditorRootProps>;
342
+ };
343
+ }): Map<string, number>;
344
+
345
+ /**
346
+ * Autosave with compare-and-swap: a document is saved a moment after the
347
+ * last change, naming the revision it started from. When someone else saved
348
+ * first the store answers with their document, and the autosaver stops and
349
+ * waits: the person chooses to load theirs (`reload`) or keep their own
350
+ * (`overwrite`). Nothing is dropped on the way:
351
+ *
352
+ * - a change made while a save is in flight is saved right after it, on the
353
+ * new revision;
354
+ * - during a conflict, edits keep collecting and are what `overwrite` saves;
355
+ * - a failed save (offline, a server error) keeps the change and retries
356
+ * with backoff, and on the next change;
357
+ * - `flush()` saves now and resolves once nothing is waiting (page switch,
358
+ * publish), or rejects when it can't;
359
+ * - `pause()` holds every save (while a publish runs) and `resume()` saves
360
+ * what collected meanwhile, after `rebase` has adopted the new revision.
361
+ *
362
+ * Pure TypeScript with injectable timers, so it is tested without a DOM.
363
+ */
364
+
365
+ type AutosaveStatus = "saved" | "pending" | "saving" | "conflict" | "error";
366
+ interface AutosaveState<T> {
367
+ status: AutosaveStatus;
368
+ /** The revision the next save names. */
369
+ rev: number;
370
+ /** When status is `conflict`: the store's document and revision. */
371
+ conflict: {
372
+ doc: T;
373
+ rev: number;
374
+ } | null;
375
+ error: Error | null;
376
+ /** When the last save landed. */
377
+ savedAt: Date | null;
378
+ }
379
+ interface AutosaverOptions<T> {
380
+ rev: number;
381
+ save: (rev: number, doc: T) => Promise<SaveResult<T>>;
382
+ /** Wait this long after the last change (default 800 ms). */
383
+ delay?: number;
384
+ /** Retry a failed save after this long, doubling up to a minute (default 2 s). */
385
+ retryDelay?: number;
386
+ onState?: (state: AutosaveState<T>) => void;
387
+ /** Two documents are the same save (default: the same content, in any key order). */
388
+ equals?: (a: T, b: T) => boolean;
389
+ setTimer?: (fn: () => void, ms: number) => unknown;
390
+ clearTimer?: (handle: unknown) => void;
391
+ now?: () => Date;
392
+ }
393
+ /** Thrown by `flush` when the document can't be saved yet (a conflict, or a failed save). */
394
+ declare class AutosaveBlockedError extends Error {
395
+ readonly status: AutosaveStatus;
396
+ constructor(status: AutosaveStatus, message: string);
397
+ }
398
+ /**
399
+ * One document's autosave.
400
+ *
401
+ * @stability Beta
402
+ */
403
+ declare class Autosaver<T> {
404
+ private state;
405
+ /** The newest document not yet saved, or null. */
406
+ private pending;
407
+ /** The last document the store accepted (or loaded). */
408
+ private saved;
409
+ private timer;
410
+ private inFlight;
411
+ private retries;
412
+ private waiters;
413
+ private disposed;
414
+ private paused;
415
+ private readonly opts;
416
+ constructor(options: AutosaverOptions<T>, initial?: T);
417
+ get current(): AutosaveState<T>;
418
+ /** Is anything not yet in the store (pending, saving, a conflict or a failed save)? */
419
+ get dirty(): boolean;
420
+ /** The document as the person has it: unsaved changes, or the last save. */
421
+ get latest(): T | null;
422
+ private set;
423
+ /** A change: saved after the delay, unless another change comes first. */
424
+ update(doc: T): void;
425
+ private schedule;
426
+ private run;
427
+ private settle;
428
+ /** Save now; resolves when nothing is waiting, rejects on a conflict or a failed save. */
429
+ flush(): Promise<void>;
430
+ /** Conflict: take the store's document. Returns it; unsaved changes are discarded. */
431
+ reload(): T | null;
432
+ /** Conflict: save this person's document over the store's. */
433
+ overwrite(): Promise<void>;
434
+ /**
435
+ * The store moved on without a conflict (a page move bumped its revision,
436
+ * a publish migrated it): adopt its revision. `doc` replaces the saved
437
+ * copy when given; unsaved changes are kept and saved on the new revision.
438
+ */
439
+ rebase(rev: number, doc?: T): void;
440
+ /** Is saving held (`pause`)? */
441
+ get isPaused(): boolean;
442
+ /**
443
+ * Hold every save, for as long as the store must not change under the
444
+ * caller (a publish). A save already in flight lands; changes keep
445
+ * collecting and are saved on `resume`.
446
+ */
447
+ pause(): void;
448
+ /** Save again: what collected while paused is saved now, on the current revision. */
449
+ resume(): void;
450
+ dispose(): void;
451
+ }
452
+
453
+ /**
454
+ * The editor's view of the real output: the `/web` request handler, run in
455
+ * the browser, renders a page of the drafts (`preview`) or of the live
456
+ * release (`live`) exactly as a visitor gets it. Its stylesheet is inlined
457
+ * so the HTML works as an iframe's `srcdoc`, and its script is left out:
458
+ * the frame is sandboxed with no script and no same-origin access, so
459
+ * nothing an editor typed can run with the editor's privileges.
460
+ *
461
+ * The renderer and its assets load on demand (a separate chunk), so opening
462
+ * the editor doesn't download them until a preview or the canvas needs them.
463
+ */
464
+
465
+ interface PreviewInput {
466
+ store: Pick<SiteStore, "getLive" | "getDraft" | "listPages" | "getPageDraft">;
467
+ siteId: string;
468
+ brand: BrandInput;
469
+ path: string;
470
+ mode: "preview" | "live";
471
+ forms?: FormsResolver;
472
+ }
473
+ interface PreviewResult {
474
+ status: number;
475
+ /** The page as a self-contained document, or null when the address redirects or isn't the site's. */
476
+ html: string | null;
477
+ /** Where a redirect goes. */
478
+ location?: string;
479
+ }
480
+ /**
481
+ * One page through `handleSiteRequest`, as an iframe-ready document.
482
+ *
483
+ * @stability Beta
484
+ */
485
+ declare function renderPreview(input: PreviewInput): Promise<PreviewResult>;
486
+
487
+ /**
488
+ * The image picker: upload (through the store's `putAsset`, or the host's
489
+ * own upload), choose from the site's library, or link an https image.
490
+ * Every choice needs alt text, or to be marked decorative, before it can be
491
+ * used: the publish check would refuse it anyway, so the picker asks first.
492
+ */
493
+
494
+ /** Raster images only: the database refuses SVG (it can carry script). */
495
+ declare const IMAGE_TYPES: readonly ["image/png", "image/jpeg", "image/webp", "image/avif", "image/gif"];
496
+ interface AssetPickerProps {
497
+ open: boolean;
498
+ siteId: string;
499
+ store: Pick<SiteStore, "putAsset">;
500
+ assets?: EditorAssets | undefined;
501
+ current?: PickedImage | undefined;
502
+ /** The field takes only the address; its alt text is a field of its own (a gallery photo). */
503
+ altElsewhere?: boolean | undefined;
504
+ onDone: (image: PickedImage | null) => void;
505
+ }
506
+ /** Why an upload can't be used (or null). */
507
+ declare function uploadProblem(file: {
508
+ type: string;
509
+ size: number;
510
+ } | null, maxBytes?: number): string | null;
511
+ declare function AssetPicker({ open, siteId, store, assets, current, altElsewhere, onDone }: AssetPickerProps): React.JSX.Element;
512
+
513
+ /**
514
+ * Puck's chrome, drawn with Genesis UI: every field type, field labels, and
515
+ * the Add picker's items (which also enforce each section's limit). So the
516
+ * editor reads as part of the host app, not as stock Puck, and every
517
+ * control has a real label.
518
+ */
519
+
520
+ interface GenesisOverrideOptions {
521
+ /** Say what an action did (a section added, moved or removed), for a live region. */
522
+ announce?: (message: string) => void;
523
+ }
524
+ declare function genesisOverrides(info: ReadonlyMap<string, ComponentInfo>, extra?: Partial<Overrides>, options?: GenesisOverrideOptions): Partial<Overrides>;
525
+
526
+ export { AssetPicker, type AssetPickerProps, AutosaveBlockedError, type AutosaveState, type AutosaveStatus, Autosaver, type AutosaverOptions, type CanvasMetadata, type ComponentInfo, type EditorAssets, type EditorConfig, type EditorConfigOptions, type EditorData, type EditorRootProps, type EditorSiteStore, type FromEditorResult, IMAGE_TYPES, NODE_KEYS, type PageTemplate, type PickedImage, type PreviewInput, type PreviewResult, type PuckItem, type SectionFields, type SiteCheck, SiteEditor, type SiteEditorProps, checkSite, countTypes, createEditorConfig, fromEditorData, genesisOverrides, h1SectionId, humanize, itemToNode, movePageInList, nodeToItem, pageTemplates, pathProblems, placeholderSnapshot, presetComponentName, pruneEmpty, publishSite, renamePage, renderPreview, safeSectionId, sectionFields, sectionTypeOf, slugify, toEditorData, uploadProblem };