@bettercms-ai/types 1.7.0 → 1.9.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.ts +440 -5
- package/dist/index.js +1972 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -307,7 +307,27 @@ interface ComponentBlock {
|
|
|
307
307
|
style?: BlockStyle;
|
|
308
308
|
props: ComponentProps;
|
|
309
309
|
}
|
|
310
|
-
|
|
310
|
+
interface CollectionProps {
|
|
311
|
+
/** Component rendered once per entry, interpolated with {{field}} and {{url}}. Omit for a built-in card. */
|
|
312
|
+
cardComponentId?: string;
|
|
313
|
+
/** Component rendered for the single entry on a detail URL. Omit to fall back to the generic field layout. */
|
|
314
|
+
detailComponentId?: string;
|
|
315
|
+
/** Built-in card only. Defaults to "title" / no excerpt. */
|
|
316
|
+
titleField?: string;
|
|
317
|
+
excerptField?: string;
|
|
318
|
+
/** Max cards to render. Defaults to 20. */
|
|
319
|
+
limit?: number;
|
|
320
|
+
/** "newest" (default) reverses the reader's created_at ordering. */
|
|
321
|
+
order?: "newest" | "oldest";
|
|
322
|
+
emptyText?: string;
|
|
323
|
+
}
|
|
324
|
+
interface CollectionBlock {
|
|
325
|
+
type: "collection";
|
|
326
|
+
id: string;
|
|
327
|
+
style?: BlockStyle;
|
|
328
|
+
props: CollectionProps;
|
|
329
|
+
}
|
|
330
|
+
type ContentBlock = CollectionBlock | HeadingBlock | TextBlock | RichTextBlock | ImageBlock | ButtonBlock | SpacerBlock | ColumnsBlock | VideoBlock | FormBlock | SectionBlock | NavbarBlock | FooterBlock | SliderBlock | TabsBlock | ComponentBlock;
|
|
311
331
|
/** Literal union of all block type discriminators. */
|
|
312
332
|
type BlockType = ContentBlock["type"];
|
|
313
333
|
/**
|
|
@@ -340,6 +360,326 @@ declare function getBlockType(value: unknown): BlockType | null;
|
|
|
340
360
|
/** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */
|
|
341
361
|
declare function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined;
|
|
342
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Generated from lucide-react@1.8.0 dynamic icon names.
|
|
365
|
+
* Legacy CamelCase identifiers remain valid for existing Layout documents.
|
|
366
|
+
*/
|
|
367
|
+
declare const LAYOUT_SECTION_ICONS: readonly string[];
|
|
368
|
+
declare const LAYOUT_SECTION_ICON_SET: ReadonlySet<string>;
|
|
369
|
+
type LayoutSectionIcon = string;
|
|
370
|
+
|
|
371
|
+
/** Stable identifiers used by every project and page layout document. */
|
|
372
|
+
declare const PAGE_CONTENT_ANCHOR_ID: "page-content";
|
|
373
|
+
declare const NAVIGATION_SECTION_ID: "navigation";
|
|
374
|
+
declare const FOOTER_SECTION_ID: "footer";
|
|
375
|
+
|
|
376
|
+
type LayoutZone = "above-page-content" | "below-page-content";
|
|
377
|
+
type ReservedLayoutSection = "navigation" | "footer";
|
|
378
|
+
type LayoutScalarFieldType = "text" | "longtext" | "richtext" | "number" | "toggle" | "date" | "image" | "file" | "link" | "email" | "phone" | "select" | "color" | "json" | "reference" | "multi-reference";
|
|
379
|
+
type LayoutFieldType = LayoutScalarFieldType | "group" | "repeater";
|
|
380
|
+
/** A recursive, stable-ID field contract shared by Sections and variant inputs. */
|
|
381
|
+
interface LayoutFieldDefinition {
|
|
382
|
+
id: string;
|
|
383
|
+
slug: string;
|
|
384
|
+
label: string;
|
|
385
|
+
type: LayoutFieldType;
|
|
386
|
+
required?: boolean;
|
|
387
|
+
defaultValue?: unknown;
|
|
388
|
+
config?: {
|
|
389
|
+
options?: Array<{
|
|
390
|
+
label: string;
|
|
391
|
+
value: string;
|
|
392
|
+
}>;
|
|
393
|
+
referenceModelId?: string;
|
|
394
|
+
minItems?: number;
|
|
395
|
+
maxItems?: number;
|
|
396
|
+
} & Record<string, unknown>;
|
|
397
|
+
/** Required for group/repeater; forbidden for scalar fields. */
|
|
398
|
+
fields?: LayoutFieldDefinition[];
|
|
399
|
+
}
|
|
400
|
+
/** The canonical public input contract all variants in a group implement. */
|
|
401
|
+
type CanonicalInputDefinition = LayoutFieldDefinition;
|
|
402
|
+
/** Maps one canonical input onto one or more internal component prop paths. */
|
|
403
|
+
interface VariantInputMapping {
|
|
404
|
+
inputId: string;
|
|
405
|
+
targets: Array<{
|
|
406
|
+
blockId: string;
|
|
407
|
+
path: string;
|
|
408
|
+
}>;
|
|
409
|
+
}
|
|
410
|
+
interface ComponentVariantGroup {
|
|
411
|
+
id: string;
|
|
412
|
+
workspaceId: string;
|
|
413
|
+
projectId?: string | null;
|
|
414
|
+
name: string;
|
|
415
|
+
slug: string;
|
|
416
|
+
canonicalInputs: CanonicalInputDefinition[];
|
|
417
|
+
status: "draft" | "published";
|
|
418
|
+
}
|
|
419
|
+
interface LayoutFieldItem {
|
|
420
|
+
id: string;
|
|
421
|
+
kind: "field";
|
|
422
|
+
fieldId: string;
|
|
423
|
+
}
|
|
424
|
+
interface LayoutComponentItem {
|
|
425
|
+
id: string;
|
|
426
|
+
kind: "component";
|
|
427
|
+
componentId: string;
|
|
428
|
+
variantGroupId?: string;
|
|
429
|
+
bindings: Array<{
|
|
430
|
+
inputId: string;
|
|
431
|
+
fieldId: string;
|
|
432
|
+
}>;
|
|
433
|
+
literalValues?: Record<string, unknown>;
|
|
434
|
+
}
|
|
435
|
+
type LayoutSectionItem = LayoutFieldItem | LayoutComponentItem;
|
|
436
|
+
interface LayoutSection {
|
|
437
|
+
id: string;
|
|
438
|
+
name: string;
|
|
439
|
+
slug: string;
|
|
440
|
+
icon: string;
|
|
441
|
+
zone: LayoutZone;
|
|
442
|
+
orderKey: string;
|
|
443
|
+
reserved?: ReservedLayoutSection;
|
|
444
|
+
fields: LayoutFieldDefinition[];
|
|
445
|
+
items: LayoutSectionItem[];
|
|
446
|
+
}
|
|
447
|
+
interface LayoutStructureDocument {
|
|
448
|
+
version: 1;
|
|
449
|
+
pageContentAnchor: {
|
|
450
|
+
id: typeof PAGE_CONTENT_ANCHOR_ID;
|
|
451
|
+
};
|
|
452
|
+
sections: LayoutSection[];
|
|
453
|
+
}
|
|
454
|
+
interface LayoutDataDocument {
|
|
455
|
+
version: 1;
|
|
456
|
+
sections: Record<string, {
|
|
457
|
+
fields: Record<string, unknown>;
|
|
458
|
+
}>;
|
|
459
|
+
}
|
|
460
|
+
type PageLayoutOverrideState = "inherit" | "override-content" | "customize-structure" | "disable";
|
|
461
|
+
interface PageSectionPlacement {
|
|
462
|
+
zone: LayoutZone;
|
|
463
|
+
afterSectionId?: string;
|
|
464
|
+
beforeSectionId?: string;
|
|
465
|
+
localOrderKey: string;
|
|
466
|
+
}
|
|
467
|
+
type PageLayoutSectionOverride = {
|
|
468
|
+
sectionId: string;
|
|
469
|
+
state: "inherit";
|
|
470
|
+
} | {
|
|
471
|
+
sectionId: string;
|
|
472
|
+
state: "override-content";
|
|
473
|
+
values: Record<string, unknown>;
|
|
474
|
+
} | {
|
|
475
|
+
sectionId: string;
|
|
476
|
+
state: "customize-structure";
|
|
477
|
+
section: LayoutSection;
|
|
478
|
+
data: {
|
|
479
|
+
fields: Record<string, unknown>;
|
|
480
|
+
};
|
|
481
|
+
/** Retained when the inherited Section is later deleted. */
|
|
482
|
+
placement: PageSectionPlacement;
|
|
483
|
+
} | {
|
|
484
|
+
sectionId: string;
|
|
485
|
+
state: "disable";
|
|
486
|
+
};
|
|
487
|
+
interface PageOnlyLayoutSection {
|
|
488
|
+
section: LayoutSection;
|
|
489
|
+
data: {
|
|
490
|
+
fields: Record<string, unknown>;
|
|
491
|
+
};
|
|
492
|
+
placement: PageSectionPlacement;
|
|
493
|
+
}
|
|
494
|
+
type PageLayoutSectionStructureOverride = {
|
|
495
|
+
sectionId: string;
|
|
496
|
+
state: "inherit";
|
|
497
|
+
} | {
|
|
498
|
+
sectionId: string;
|
|
499
|
+
state: "override-content";
|
|
500
|
+
} | {
|
|
501
|
+
sectionId: string;
|
|
502
|
+
state: "customize-structure";
|
|
503
|
+
section: LayoutSection;
|
|
504
|
+
placement: PageSectionPlacement;
|
|
505
|
+
} | {
|
|
506
|
+
sectionId: string;
|
|
507
|
+
state: "disable";
|
|
508
|
+
};
|
|
509
|
+
/** Persisted in pages.layout_override_structure_json. */
|
|
510
|
+
interface PageLayoutOverrideStructureDocument {
|
|
511
|
+
version: 1;
|
|
512
|
+
sections: PageLayoutSectionStructureOverride[];
|
|
513
|
+
pageOnlySections: Array<{
|
|
514
|
+
section: LayoutSection;
|
|
515
|
+
placement: PageSectionPlacement;
|
|
516
|
+
}>;
|
|
517
|
+
}
|
|
518
|
+
/** Persisted independently so values can be patched without rewriting structure. */
|
|
519
|
+
interface PageLayoutOverrideDataDocument {
|
|
520
|
+
version: 1;
|
|
521
|
+
sections: Record<string, {
|
|
522
|
+
fields: Record<string, unknown>;
|
|
523
|
+
}>;
|
|
524
|
+
pageOnlySections: Record<string, {
|
|
525
|
+
fields: Record<string, unknown>;
|
|
526
|
+
}>;
|
|
527
|
+
}
|
|
528
|
+
/** Canonical in-memory form consumed by the pure resolver. */
|
|
529
|
+
interface PageLayoutOverrideDocument {
|
|
530
|
+
version: 1;
|
|
531
|
+
sections: PageLayoutSectionOverride[];
|
|
532
|
+
pageOnlySections: PageOnlyLayoutSection[];
|
|
533
|
+
}
|
|
534
|
+
/** Canonical, discriminated Management/MCP authoring transport. Authority is derived from type. */
|
|
535
|
+
type ManagementLayoutCommand = {
|
|
536
|
+
type: "set-section-values";
|
|
537
|
+
sectionId: string;
|
|
538
|
+
values: Record<string, unknown>;
|
|
539
|
+
} | {
|
|
540
|
+
type: "set-field-value";
|
|
541
|
+
sectionId: string;
|
|
542
|
+
fieldId: string;
|
|
543
|
+
value: unknown;
|
|
544
|
+
} | {
|
|
545
|
+
type: "add-component";
|
|
546
|
+
sectionId: string;
|
|
547
|
+
componentId: string;
|
|
548
|
+
variantGroupId?: string;
|
|
549
|
+
bindings?: LayoutComponentItem["bindings"];
|
|
550
|
+
literalValues?: Record<string, unknown>;
|
|
551
|
+
} | {
|
|
552
|
+
type: "remove-item";
|
|
553
|
+
sectionId: string;
|
|
554
|
+
itemId: string;
|
|
555
|
+
} | {
|
|
556
|
+
type: "move-component";
|
|
557
|
+
sectionId: string;
|
|
558
|
+
itemId: string;
|
|
559
|
+
index: number;
|
|
560
|
+
} | {
|
|
561
|
+
type: "move-item";
|
|
562
|
+
sectionId: string;
|
|
563
|
+
itemId: string;
|
|
564
|
+
index: number;
|
|
565
|
+
} | {
|
|
566
|
+
type: "swap-component-variant";
|
|
567
|
+
sectionId: string;
|
|
568
|
+
itemId: string;
|
|
569
|
+
componentId: string;
|
|
570
|
+
} | {
|
|
571
|
+
type: "set-page-state";
|
|
572
|
+
sectionId: string;
|
|
573
|
+
state: PageLayoutOverrideState | "reset";
|
|
574
|
+
} | {
|
|
575
|
+
type: "set-section-state";
|
|
576
|
+
sectionId: string;
|
|
577
|
+
state: PageLayoutOverrideState | "reset";
|
|
578
|
+
} | {
|
|
579
|
+
type: "add-section";
|
|
580
|
+
name: string;
|
|
581
|
+
icon: LayoutSectionIcon;
|
|
582
|
+
zone: "before_page" | "after_page";
|
|
583
|
+
} | {
|
|
584
|
+
type: "restore-section";
|
|
585
|
+
section: LayoutSection;
|
|
586
|
+
data: {
|
|
587
|
+
fields: Record<string, unknown>;
|
|
588
|
+
};
|
|
589
|
+
placement?: PageSectionPlacement;
|
|
590
|
+
} | {
|
|
591
|
+
type: "update-section";
|
|
592
|
+
sectionId: string;
|
|
593
|
+
name?: string;
|
|
594
|
+
icon?: LayoutSectionIcon;
|
|
595
|
+
slug?: string;
|
|
596
|
+
zone?: LayoutZone;
|
|
597
|
+
orderKey?: string;
|
|
598
|
+
} | {
|
|
599
|
+
type: "remove-section";
|
|
600
|
+
sectionId: string;
|
|
601
|
+
} | {
|
|
602
|
+
type: "move-section";
|
|
603
|
+
sectionId: string;
|
|
604
|
+
afterId?: string | null;
|
|
605
|
+
beforeId?: string | null;
|
|
606
|
+
} | {
|
|
607
|
+
type: "add-field";
|
|
608
|
+
sectionId: string;
|
|
609
|
+
parentFieldId?: string;
|
|
610
|
+
field?: LayoutFieldDefinition;
|
|
611
|
+
fieldType?: LayoutFieldType;
|
|
612
|
+
} | {
|
|
613
|
+
type: "update-field";
|
|
614
|
+
sectionId: string;
|
|
615
|
+
fieldId: string;
|
|
616
|
+
patch: Partial<Omit<LayoutFieldDefinition, "id">>;
|
|
617
|
+
} | {
|
|
618
|
+
type: "remove-field";
|
|
619
|
+
sectionId: string;
|
|
620
|
+
fieldId: string;
|
|
621
|
+
} | {
|
|
622
|
+
type: "move-field";
|
|
623
|
+
sectionId: string;
|
|
624
|
+
itemId: string;
|
|
625
|
+
index: number;
|
|
626
|
+
} | {
|
|
627
|
+
type: "set-bindings";
|
|
628
|
+
sectionId: string;
|
|
629
|
+
itemId: string;
|
|
630
|
+
bindings: LayoutComponentItem["bindings"];
|
|
631
|
+
literalValues?: Record<string, unknown>;
|
|
632
|
+
};
|
|
633
|
+
type ResolvedLayoutNode = {
|
|
634
|
+
kind: "page-content";
|
|
635
|
+
id: typeof PAGE_CONTENT_ANCHOR_ID;
|
|
636
|
+
} | {
|
|
637
|
+
kind: "section";
|
|
638
|
+
id: string;
|
|
639
|
+
section: LayoutSection;
|
|
640
|
+
data: {
|
|
641
|
+
fields: Record<string, unknown>;
|
|
642
|
+
};
|
|
643
|
+
source: "inherit" | "override-content" | "customize-structure" | "page-only" | "detached";
|
|
644
|
+
};
|
|
645
|
+
interface DeliveredLayout {
|
|
646
|
+
version: 1;
|
|
647
|
+
nodes: Array<{
|
|
648
|
+
kind: "page-content";
|
|
649
|
+
id: typeof PAGE_CONTENT_ANCHOR_ID;
|
|
650
|
+
} | {
|
|
651
|
+
kind: "section";
|
|
652
|
+
id: string;
|
|
653
|
+
slug: string;
|
|
654
|
+
name: string;
|
|
655
|
+
source: Extract<ResolvedLayoutNode, {
|
|
656
|
+
kind: "section";
|
|
657
|
+
}>["source"];
|
|
658
|
+
}>;
|
|
659
|
+
sections: Record<string, {
|
|
660
|
+
id: string;
|
|
661
|
+
slug: string;
|
|
662
|
+
name: string;
|
|
663
|
+
fields: Record<string, unknown>;
|
|
664
|
+
items: Array<{
|
|
665
|
+
id: string;
|
|
666
|
+
kind: "field";
|
|
667
|
+
fieldId: string;
|
|
668
|
+
value: unknown;
|
|
669
|
+
} | {
|
|
670
|
+
id: string;
|
|
671
|
+
kind: "component";
|
|
672
|
+
componentId: string;
|
|
673
|
+
variantGroupId?: string;
|
|
674
|
+
canonicalInputs: CanonicalInputDefinition[];
|
|
675
|
+
bindings: LayoutComponentItem["bindings"];
|
|
676
|
+
canonicalValues: Record<string, unknown>;
|
|
677
|
+
resolvedProps: Record<string, unknown>;
|
|
678
|
+
blocks: unknown[];
|
|
679
|
+
}>;
|
|
680
|
+
}>;
|
|
681
|
+
}
|
|
682
|
+
|
|
343
683
|
/**
|
|
344
684
|
* Component — a reusable, Webflow-style block tree (a "symbol").
|
|
345
685
|
*
|
|
@@ -367,9 +707,27 @@ interface ComponentPropDef {
|
|
|
367
707
|
blockId: string;
|
|
368
708
|
path: string;
|
|
369
709
|
};
|
|
370
|
-
|
|
710
|
+
/**
|
|
711
|
+
* `slot` holds ONE nested component instance — the component-level twin of the
|
|
712
|
+
* content-model field type `component-ref` (see content-model.ts), named differently for
|
|
713
|
+
* the same reason that one is: `component` already means a BLOCK type. Its value is
|
|
714
|
+
* `{ componentId, overrides }` and its `target.path` is `props`, so filling a slot writes
|
|
715
|
+
* that object over an empty `component` block's props.
|
|
716
|
+
*
|
|
717
|
+
* On a PAGE a slot fill is a LIVE reference; a published ENTRY freezes it (resolveDeep).
|
|
718
|
+
*/
|
|
719
|
+
type: "text" | "richtext" | "image" | "url" | "boolean" | "slot";
|
|
371
720
|
defaultValue?: unknown;
|
|
721
|
+
/** Per-type settings. `slot` uses `componentIds` as a pick allowlist. */
|
|
722
|
+
config?: {
|
|
723
|
+
componentIds?: string[];
|
|
724
|
+
} & Record<string, unknown>;
|
|
372
725
|
}
|
|
726
|
+
/**
|
|
727
|
+
* A component is a DRAFT until published; only the published copy reaches a visitor.
|
|
728
|
+
* Mirrors pages and entries. See migration 0186_component_draft_live_split.sql.
|
|
729
|
+
*/
|
|
730
|
+
type ComponentStatus = "draft" | "published";
|
|
373
731
|
interface Component {
|
|
374
732
|
id: string;
|
|
375
733
|
workspaceId: string;
|
|
@@ -383,14 +741,41 @@ interface Component {
|
|
|
383
741
|
* of one section. Null/absent = an ordinary component, not shown in the section library.
|
|
384
742
|
*/
|
|
385
743
|
sectionType?: string | null;
|
|
744
|
+
/** First-class variant family membership; exact workspace/project scope is enforced in DB. */
|
|
745
|
+
variantGroupId?: string | null;
|
|
746
|
+
variantInputMappings?: VariantInputMapping[];
|
|
747
|
+
/** Placement governance: `*`, `slug:<page-slug>`, and/or `type:<page-type>`. */
|
|
748
|
+
allowedOn: string[];
|
|
386
749
|
description?: string | null;
|
|
750
|
+
/** The DRAFT definition. Every builder/autosave/import write path targets these two. */
|
|
387
751
|
blockJson: ContentBlock[];
|
|
388
752
|
props: ComponentPropDef[];
|
|
753
|
+
status: ComponentStatus;
|
|
754
|
+
/**
|
|
755
|
+
* The LIVE snapshot get_components_by_handle() serves. Null until the first publish.
|
|
756
|
+
* Returned by GET-one (the Compare view needs it), omitted from list rows for payload.
|
|
757
|
+
*/
|
|
758
|
+
publishedBlockJson?: ContentBlock[] | null;
|
|
759
|
+
publishedProps?: ComponentPropDef[] | null;
|
|
760
|
+
publishedAt?: string | null;
|
|
761
|
+
/**
|
|
762
|
+
* Computed in SQL on list/get, never stored:
|
|
763
|
+
* status='published' AND (blockJson or props has diverged from its published copy).
|
|
764
|
+
* An exact jsonb compare, so it self-clears when an edit is reverted.
|
|
765
|
+
*/
|
|
766
|
+
pendingChanges?: boolean;
|
|
389
767
|
thumbnail?: string | null;
|
|
390
768
|
createdAt: string;
|
|
391
769
|
updatedAt: string;
|
|
392
770
|
}
|
|
393
|
-
/**
|
|
771
|
+
/**
|
|
772
|
+
* Public/delivery projection — the fields a renderer needs to resolve instances.
|
|
773
|
+
*
|
|
774
|
+
* DELIBERATELY UNCHANGED by the 0186 draft/live split: delivery aliases
|
|
775
|
+
* publishedBlockJson -> blockJson, so every already-deployed site and every
|
|
776
|
+
* bcms-content.json on disk keeps a byte-identical wire shape. Do not add `status` here —
|
|
777
|
+
* delivery only ever returns published rows, so it would always be the same constant.
|
|
778
|
+
*/
|
|
394
779
|
interface DeliveryComponent {
|
|
395
780
|
id: string;
|
|
396
781
|
name: string;
|
|
@@ -411,6 +796,7 @@ interface ContentEntry {
|
|
|
411
796
|
slug: string;
|
|
412
797
|
title: string;
|
|
413
798
|
blocks: ContentBlock[];
|
|
799
|
+
layout?: DeliveredLayout | null;
|
|
414
800
|
updatedAt: string;
|
|
415
801
|
}
|
|
416
802
|
|
|
@@ -423,7 +809,11 @@ interface ContentModel {
|
|
|
423
809
|
workspaceId: string;
|
|
424
810
|
name: string;
|
|
425
811
|
description?: string;
|
|
812
|
+
/** 'block' models hold no entries — they are instantiable only inside a `modular` field. */
|
|
813
|
+
kind?: ContentModelKind;
|
|
426
814
|
fields: ContentModelField[];
|
|
815
|
+
/** Authoring-only field grouping for the schema builder. Never affects the API shape. */
|
|
816
|
+
fieldsets?: Fieldset[];
|
|
427
817
|
createdAt: string;
|
|
428
818
|
updatedAt: string;
|
|
429
819
|
}
|
|
@@ -433,7 +823,13 @@ interface ContentModel {
|
|
|
433
823
|
* by the API but normalized to `array` + zones on write, so stored/delivered
|
|
434
824
|
* content never contains them.
|
|
435
825
|
*/
|
|
436
|
-
type ContentModelFieldType = "text" | "richtext" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "multiReference" | "array" | "date" | "datetime" | "longtext" | "slug" | "email" | "phone" | "link" | "color" | "json" | "file" | "component-ref";
|
|
826
|
+
type ContentModelFieldType = "text" | "richtext" | "document" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "multiReference" | "array" | "date" | "datetime" | "longtext" | "slug" | "email" | "phone" | "link" | "color" | "json" | "file" | "component-ref" | "modular" | "sections" | "location";
|
|
827
|
+
type ContentModelKind = "model" | "block";
|
|
828
|
+
/** A named, UI-only grouping of a model's fields. Order is the array index. */
|
|
829
|
+
interface Fieldset {
|
|
830
|
+
id: string;
|
|
831
|
+
name: string;
|
|
832
|
+
}
|
|
437
833
|
/**
|
|
438
834
|
* Nested-content config for an `array` field. A zone holds ordinary fields, and a
|
|
439
835
|
* zone field may itself be an `array` with its own zones, so nesting is recursive
|
|
@@ -462,6 +858,38 @@ interface FieldConfig {
|
|
|
462
858
|
max?: number;
|
|
463
859
|
/** date / datetime */
|
|
464
860
|
includeTime?: boolean;
|
|
861
|
+
/** modular: SLUGS of the kind='block' models this field accepts. Non-empty. */
|
|
862
|
+
blockSlugs?: string[];
|
|
863
|
+
/** modular: bounds on how many block instances the field may hold. */
|
|
864
|
+
minItems?: number;
|
|
865
|
+
maxItems?: number;
|
|
866
|
+
/**
|
|
867
|
+
* sections: SLUGS of the sections an author may insert into this zone.
|
|
868
|
+
*
|
|
869
|
+
* Deliberately NOT named `blockSlugs`. That key means "kind='block' content models" and is
|
|
870
|
+
* read by ModularField; these are section-registry slugs resolved from a different place.
|
|
871
|
+
* One key meaning two things is how `blockModels`/`blockSlugs` already drifted apart in the
|
|
872
|
+
* dashboard — a distinct name costs nothing and cannot be confused at a call site.
|
|
873
|
+
*
|
|
874
|
+
* ⚠ ABSENT ≠ EMPTY:
|
|
875
|
+
* absent → UNRESTRICTED, every registry section may be inserted
|
|
876
|
+
* [] → DENY ALL, a deliberate empty restriction
|
|
877
|
+
* [a, b] → only those
|
|
878
|
+
* `[]` means DENY here to match `components.allowed_on` (migration 0190), so two adjacent
|
|
879
|
+
* allow-lists never disagree about what empty means.
|
|
880
|
+
*
|
|
881
|
+
* Absent rather than "all current slugs" because the registry GROWS — it is fed by repo
|
|
882
|
+
* pushes and project components, so materializing today's slugs at field-creation time would
|
|
883
|
+
* silently exclude every section shipped afterwards.
|
|
884
|
+
*
|
|
885
|
+
* NOT READ DIRECTLY. Insertability is this list INTERSECTED with the component's `allowedOn`
|
|
886
|
+
* (where that section may be placed), computed by one resolver so the two cannot drift.
|
|
887
|
+
*
|
|
888
|
+
* Enforced on NEW picks only. Narrowing the list later must never invalidate sections an
|
|
889
|
+
* author already placed, the same rule modular's blockSlugs and component-ref's allowlist
|
|
890
|
+
* follow.
|
|
891
|
+
*/
|
|
892
|
+
allowedSections?: string[];
|
|
465
893
|
[key: string]: unknown;
|
|
466
894
|
}
|
|
467
895
|
/**
|
|
@@ -498,6 +926,11 @@ interface ContentModelField {
|
|
|
498
926
|
options?: string[];
|
|
499
927
|
/** Per-type config. For `array`: either `itemType` (primitive) or `zones` (nested). */
|
|
500
928
|
config?: FieldConfig | null;
|
|
929
|
+
/**
|
|
930
|
+
* Which fieldset this field renders under in the schema builder. Authoring-only: it is
|
|
931
|
+
* never delivered and cannot move a value — see {@link Fieldset}.
|
|
932
|
+
*/
|
|
933
|
+
fieldsetId?: string;
|
|
501
934
|
/**
|
|
502
935
|
* Authoring-only editor placement. See {@link ContentModelFieldPlacement}.
|
|
503
936
|
* Field ORDER is the array index — there is deliberately no `order` property.
|
|
@@ -618,6 +1051,7 @@ interface SiteSeoDefaults {
|
|
|
618
1051
|
}
|
|
619
1052
|
/** A published page with its rendered block tree. */
|
|
620
1053
|
interface DeliveryPage {
|
|
1054
|
+
projectId?: string | null;
|
|
621
1055
|
slug: string;
|
|
622
1056
|
title: string;
|
|
623
1057
|
metaTitle: string | null;
|
|
@@ -625,6 +1059,7 @@ interface DeliveryPage {
|
|
|
625
1059
|
/** Rich SEO (OG / Twitter / canonical / JSON-LD). Always present; `null` when unset. */
|
|
626
1060
|
metaJson: PageMetaJson | null;
|
|
627
1061
|
blocks: ContentBlock[];
|
|
1062
|
+
layout?: DeliveredLayout | null;
|
|
628
1063
|
updatedAt: string | null;
|
|
629
1064
|
publishedAt: string | null;
|
|
630
1065
|
}
|
|
@@ -811,4 +1246,4 @@ type DeepReadonly<T> = T extends Function ? T : T extends object ? {
|
|
|
811
1246
|
*/
|
|
812
1247
|
type AssertEqual<L, R> = [L] extends [R] ? ([R] extends [L] ? true : false) : false;
|
|
813
1248
|
|
|
814
|
-
export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, type BetterCMSErrorCode, type BlockStyle, type BlockType, type ButtonBlock, type ButtonProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentPropDef, type ComponentProps, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentPageResult, type ContentResponse, type DeepReadonly, type DeliveryComponent, type DeliveryEntry, type DeliveryList, type DeliveryPage, type FieldConfig, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, type MediaAsset, type NavLink, type NavbarBlock, type NavbarProps, type Page, type PageMetaJson, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type RadiusToken, type Redirect, type RichTextBlock, type RichTextProps, type SectionBlock, type SectionProps, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, getBlockType, isBlock };
|
|
1249
|
+
export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, type BetterCMSErrorCode, type BlockStyle, type BlockType, type ButtonBlock, type ButtonProps, type CanonicalInputDefinition, type CollectionBlock, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentPropDef, type ComponentProps, type ComponentVariantGroup, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentPageResult, type ContentResponse, type DeepReadonly, type DeliveredLayout, type DeliveryComponent, type DeliveryEntry, type DeliveryList, type DeliveryPage, FOOTER_SECTION_ID, type FieldConfig, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, type LayoutComponentItem, type LayoutDataDocument, type LayoutFieldDefinition, type LayoutFieldItem, type LayoutFieldType, type LayoutScalarFieldType, type LayoutSection, type LayoutSectionIcon, type LayoutSectionItem, type LayoutStructureDocument, type LayoutZone, type ManagementLayoutCommand, type MediaAsset, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, PAGE_CONTENT_ANCHOR_ID, type Page, type PageLayoutOverrideDataDocument, type PageLayoutOverrideDocument, type PageLayoutOverrideState, type PageLayoutOverrideStructureDocument, type PageLayoutSectionOverride, type PageLayoutSectionStructureOverride, type PageMetaJson, type PageOnlyLayoutSection, type PageSectionPlacement, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type RadiusToken, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, type SectionBlock, type SectionProps, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type VariantInputMapping, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, getBlockType, isBlock };
|