camox 0.47.0 → 0.51.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/core/createApp.d.ts +19 -6
- package/dist/core/createApp.js +7 -2
- package/dist/core/createBlock.js +54 -43
- package/dist/core/createCollection.d.ts +25 -7
- package/dist/core/createCollection.js +28 -9
- package/dist/core/createLayout.d.ts +98 -71
- package/dist/core/createLayout.js +10 -16
- package/dist/core/derivedRoutes.js +1 -1
- package/dist/core/editing/BlockEditingRuntime.d.ts +3 -2
- package/dist/core/editing/CompleteBlockEditingRuntime.js +2 -1
- package/dist/core/editing/createEditableBlock.d.ts +59 -19
- package/dist/core/editing/createEditableBlock.js +162 -151
- package/dist/core/editing/useLatestRecord.js +7 -7
- package/dist/core/layoutContext.d.ts +55 -0
- package/dist/core/layoutContext.js +66 -0
- package/dist/core/lib/contentType.d.ts +91 -4
- package/dist/core/lib/contentType.js +84 -7
- package/dist/core/lib/recordScope.js +19 -17
- package/dist/core/lib/reference.d.ts +6 -2
- package/dist/core/recordItem.js +55 -2
- package/dist/core/requestContext.d.ts +18 -0
- package/dist/core/structuredData.d.ts +126 -0
- package/dist/core/structuredData.js +40 -0
- package/dist/features/canvas/canvasCamera.js +1 -1
- package/dist/features/canvas/sidebar/CanvasInspector.js +1 -1
- package/dist/features/canvas/sidebar/CanvasSidebarFrame.js +1 -1
- package/dist/features/content/ContentAssets.js +84 -88
- package/dist/features/content/ContentCollection.js +13 -7
- package/dist/features/content/collection-form.js +6 -2
- package/dist/features/content/components/MissingFromLocale.js +1 -1
- package/dist/features/og/pageImage.js +89 -0
- package/dist/features/page/CuratedPageContent.js +45 -32
- package/dist/features/page/DerivedPageContent.js +49 -22
- package/dist/features/page/SharedLayoutContent.js +26 -22
- package/dist/features/preview/CamoxPreview.js +41 -27
- package/dist/features/preview/EditablePageExperience.js +17 -9
- package/dist/features/preview/components/AddBlockSheet.js +1 -0
- package/dist/features/preview/components/BlockActionsPopover.js +19 -41
- package/dist/features/preview/components/FieldToolbar.js +1 -1
- package/dist/features/preview/components/MobilePreviewDrawer.js +6 -9
- package/dist/features/preview/components/PageInfo.js +244 -264
- package/dist/features/preview/components/PageTree.js +63 -53
- package/dist/features/preview/components/PreviewPanel.js +10 -64
- package/dist/features/preview/components/PreviewToolbar.js +1 -1
- package/dist/features/preview/components/RecordCard.js +50 -34
- package/dist/features/preview/components/RecordCombobox.js +12 -5
- package/dist/features/preview/components/ReferenceFieldEditor.js +4 -2
- package/dist/features/preview/components/ReferenceListFieldEditor.js +24 -19
- package/dist/features/preview/components/RepeatableItemsList.js +62 -46
- package/dist/features/preview/components/SelectionEditor.js +3 -2
- package/dist/features/preview/components/useFieldWriter.js +2 -4
- package/dist/features/preview/components/useRecordView.js +2 -2
- package/dist/features/preview/entityName.js +11 -0
- package/dist/features/preview/pageRecord.js +17 -18
- package/dist/features/preview/previewConstants.js +2 -8
- package/dist/features/preview/usePreviewViewportActions.js +1 -1
- package/dist/features/provider/AuthenticatedCamoxProvider.js +1 -1
- package/dist/features/provider/components/CommandPalette.js +2 -5
- package/dist/features/provider/signInShortcut.js +1 -2
- package/dist/features/provider/useAdminShortcuts.js +47 -53
- package/dist/features/routes/pageRuntime.d.ts +17 -2
- package/dist/features/routes/pageRuntime.js +61 -57
- package/dist/features/runtime/RuntimeChrome.js +1 -1
- package/dist/features/runtime/breadcrumbs.js +68 -0
- package/dist/features/runtime/livePages.js +3 -2
- package/dist/features/runtime/pageGraph.js +92 -0
- package/dist/features/runtime/projectLogo.js +110 -0
- package/dist/features/runtime/publicCache.js +83 -0
- package/dist/features/runtime/runtime.d.ts +24 -9
- package/dist/features/runtime/runtime.js +447 -130
- package/dist/features/runtime/runtimeRoutes.d.ts +1 -0
- package/dist/features/runtime/runtimeRoutes.js +1 -0
- package/dist/features/runtime/structuredData.js +213 -0
- package/dist/features/runtime/worker.d.ts +5 -1
- package/dist/features/runtime/worker.js +20 -3
- package/dist/features/settings/AnalyticsSettings.js +622 -0
- package/dist/features/settings/CamoxSettings.js +95 -0
- package/dist/features/settings/FaviconSettings.js +254 -0
- package/dist/features/settings/ProjectNameSettings.js +145 -0
- package/dist/features/settings/SettingsPart.js +73 -0
- package/dist/features/settings/SocialProfilesSettings.js +245 -0
- package/dist/features/settings/useProjectMutation.js +61 -0
- package/dist/features/studio/components/ChatSidebar.js +5 -5
- package/dist/features/studio/components/DraftsControl.js +136 -131
- package/dist/features/studio/components/LocalePicker.js +178 -174
- package/dist/features/studio/components/Navbar.js +107 -66
- package/dist/features/studio/components/ProjectMenu.js +85 -110
- package/dist/features/studio/components/ReviewDraftSheet.js +1046 -990
- package/dist/features/studio/components/ThreadMessages.js +2 -2
- package/dist/features/studio/components/UserButton.js +1 -1
- package/dist/features/studio/routes.js +3 -1
- package/dist/features/studio/showInCanvas.js +129 -0
- package/dist/features/vite/blockBoilerplate.js +3 -2
- package/dist/features/vite/definitionsSync.js +4 -5
- package/dist/features/vite/layoutGeneration.js +3 -2
- package/dist/features/vite/runtimeDev.js +32 -17
- package/dist/features/vite/staticAssetHeaders.js +52 -0
- package/dist/features/vite/vite.d.ts +1 -1
- package/dist/features/vite/vite.js +17 -4
- package/dist/lib/api-client-server.d.ts +1 -1
- package/dist/lib/api-client.d.ts +2 -1
- package/dist/lib/draft-scope.d.ts +1 -0
- package/dist/lib/locale-path.d.ts +3 -11
- package/dist/lib/locale-path.js +3 -27
- package/dist/lib/queries.d.ts +4 -0
- package/dist/lib/queries.js +8 -1
- package/dist/lib/shortcuts.js +29 -0
- package/dist/lib/studio-reads.d.ts +1 -0
- package/dist/lib/studio-reads.js +3 -1
- package/dist/lib/utils.js +1 -104
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +6 -4
- package/skills/camox/references/block-definitions.md +105 -25
- package/skills/camox/references/layout-definitions.md +53 -17
- package/skills/camox/references/routed-layouts.md +17 -14
- package/dist/features/studio/components/FaviconDialog.js +0 -318
package/dist/core/createApp.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { CamoxDocument } from "./defineDocument.js";
|
|
|
3
3
|
import { ArtifactRenderProps } from "./lib/artifact.js";
|
|
4
4
|
import { InlineTextStyles } from "./lib/textStyles.js";
|
|
5
5
|
import { ReferenceContent, ReferenceScope } from "./lib/reference.js";
|
|
6
|
-
import { Layout
|
|
6
|
+
import { Layout } from "./createLayout.js";
|
|
7
7
|
import { Collection } from "./createCollection.js";
|
|
8
8
|
import { IconValue } from "./lib/iconTypes.js";
|
|
9
9
|
import { ArtifactSource, EmbedURL, FileValue, ImageValue, LinkValue } from "./lib/contentType.js";
|
|
@@ -416,17 +416,19 @@ export declare function createApp({ blocks, lazyBlocks, layouts, collections, do
|
|
|
416
416
|
Component: ({ blockData, mode, isFirstBlock, showAddBlockTop, showAddBlockBottom, addBlockAfterPosition }: BlockComponentProps<{
|
|
417
417
|
[x: string]: unknown;
|
|
418
418
|
}>) => import("react").JSX.Element;
|
|
419
|
-
LayoutItem: ({ collectionId,
|
|
419
|
+
LayoutItem: ({ collectionId, collection, properties, record, children, fallback }: LayoutItemProps) => string | number | bigint | boolean | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
|
|
420
420
|
id: string;
|
|
421
421
|
title: string;
|
|
422
422
|
description: string;
|
|
423
423
|
contentSchema: {
|
|
424
|
+
toStructuredData?: unknown;
|
|
424
425
|
type: "object";
|
|
425
426
|
title: string;
|
|
426
427
|
description: string;
|
|
427
428
|
properties: Record<string, import("@sinclair/typebox").TSchema>;
|
|
428
429
|
required: string[];
|
|
429
430
|
toMarkdown: string[];
|
|
431
|
+
toTitle: string;
|
|
430
432
|
};
|
|
431
433
|
settingsSchema: {
|
|
432
434
|
type: "object";
|
|
@@ -458,6 +460,7 @@ export declare function createApp({ blocks, lazyBlocks, layouts, collections, do
|
|
|
458
460
|
settings: Record<string, unknown>;
|
|
459
461
|
slot: null;
|
|
460
462
|
summary: string;
|
|
463
|
+
title: string;
|
|
461
464
|
position: string;
|
|
462
465
|
createdAt: number;
|
|
463
466
|
updatedAt: number;
|
|
@@ -855,17 +858,19 @@ export declare function createApp({ blocks, lazyBlocks, layouts, collections, do
|
|
|
855
858
|
Component: ({ blockData, mode, isFirstBlock, showAddBlockTop, showAddBlockBottom, addBlockAfterPosition }: BlockComponentProps<{
|
|
856
859
|
[x: string]: unknown;
|
|
857
860
|
}>) => import("react").JSX.Element;
|
|
858
|
-
LayoutItem: ({ collectionId,
|
|
861
|
+
LayoutItem: ({ collectionId, collection, properties, record, children, fallback }: LayoutItemProps) => string | number | bigint | boolean | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
|
|
859
862
|
id: string;
|
|
860
863
|
title: string;
|
|
861
864
|
description: string;
|
|
862
865
|
contentSchema: {
|
|
866
|
+
toStructuredData?: unknown;
|
|
863
867
|
type: "object";
|
|
864
868
|
title: string;
|
|
865
869
|
description: string;
|
|
866
870
|
properties: Record<string, import("@sinclair/typebox").TSchema>;
|
|
867
871
|
required: string[];
|
|
868
872
|
toMarkdown: string[];
|
|
873
|
+
toTitle: string;
|
|
869
874
|
};
|
|
870
875
|
settingsSchema: {
|
|
871
876
|
type: "object";
|
|
@@ -897,6 +902,7 @@ export declare function createApp({ blocks, lazyBlocks, layouts, collections, do
|
|
|
897
902
|
settings: Record<string, unknown>;
|
|
898
903
|
slot: null;
|
|
899
904
|
summary: string;
|
|
905
|
+
title: string;
|
|
900
906
|
position: string;
|
|
901
907
|
createdAt: number;
|
|
902
908
|
updatedAt: number;
|
|
@@ -925,12 +931,14 @@ export declare function createApp({ blocks, lazyBlocks, layouts, collections, do
|
|
|
925
931
|
title: string;
|
|
926
932
|
description: string;
|
|
927
933
|
contentSchema: {
|
|
934
|
+
toStructuredData?: unknown;
|
|
928
935
|
type: "object";
|
|
929
936
|
title: string;
|
|
930
937
|
description: string;
|
|
931
938
|
properties: Record<string, import("@sinclair/typebox").TSchema>;
|
|
932
939
|
required: string[];
|
|
933
940
|
toMarkdown: string[];
|
|
941
|
+
toTitle: string;
|
|
934
942
|
};
|
|
935
943
|
settingsSchema: {
|
|
936
944
|
type: "object";
|
|
@@ -947,7 +955,10 @@ export declare function createApp({ blocks, lazyBlocks, layouts, collections, do
|
|
|
947
955
|
synced: boolean;
|
|
948
956
|
}[];
|
|
949
957
|
layouts: {
|
|
950
|
-
recordPages?:
|
|
958
|
+
recordPages?: {
|
|
959
|
+
collectionId: string;
|
|
960
|
+
field: string;
|
|
961
|
+
} | undefined;
|
|
951
962
|
layoutId: string;
|
|
952
963
|
kind: "curated" | "derived" | "singleton";
|
|
953
964
|
description: string;
|
|
@@ -978,11 +989,13 @@ export declare function createApp({ blocks, lazyBlocks, layouts, collections, do
|
|
|
978
989
|
})[];
|
|
979
990
|
}[];
|
|
980
991
|
collections: {
|
|
992
|
+
contentSchema: any;
|
|
993
|
+
toStructuredData?: Record<string, unknown> | undefined;
|
|
981
994
|
collectionId: string;
|
|
982
995
|
title: string;
|
|
983
996
|
description: string;
|
|
984
|
-
|
|
985
|
-
|
|
997
|
+
toTitle: string;
|
|
998
|
+
toDescription: string | null;
|
|
986
999
|
}[];
|
|
987
1000
|
homepage: {
|
|
988
1001
|
layoutId: string;
|
package/dist/core/createApp.js
CHANGED
|
@@ -134,7 +134,10 @@ function createApp({ blocks, lazyBlocks = {}, layouts = [], collections = [], do
|
|
|
134
134
|
kind: layout._internal.kind,
|
|
135
135
|
description: layout._internal.description,
|
|
136
136
|
blocks: layout._internal.blockDefinitions,
|
|
137
|
-
...layout._internal.recordPages && { recordPages:
|
|
137
|
+
...layout._internal.recordPages && { recordPages: {
|
|
138
|
+
collectionId: layout._internal.recordPages.collectionId,
|
|
139
|
+
field: layout._internal.recordPages.field
|
|
140
|
+
} }
|
|
138
141
|
}));
|
|
139
142
|
const typesUsedInLayouts = new Set(layoutDefinitions.flatMap((layout) => layout.blocks.map((block) => block.type)));
|
|
140
143
|
return {
|
|
@@ -154,7 +157,9 @@ function createApp({ blocks, lazyBlocks = {}, layouts = [], collections = [], do
|
|
|
154
157
|
collectionId: _internal.id,
|
|
155
158
|
title: _internal.title,
|
|
156
159
|
description: _internal.description,
|
|
157
|
-
|
|
160
|
+
toTitle: _internal.toTitle,
|
|
161
|
+
toDescription: _internal.toDescription,
|
|
162
|
+
..._internal.toStructuredData && { toStructuredData: _internal.toStructuredData },
|
|
158
163
|
contentSchema: JSON.parse(JSON.stringify(_internal.contentSchema))
|
|
159
164
|
})),
|
|
160
165
|
homepage: await getHomepage()
|
package/dist/core/createBlock.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { artifactFrameProps, artifactStandInProps, isArtifactSource } from "./lib/artifact.js";
|
|
2
2
|
import { artifactData } from "./lib/artifactData.js";
|
|
3
|
-
import { resolveBlockFields, resolveToMarkdown } from "./lib/contentType.js";
|
|
3
|
+
import { resolveBlockFields, resolveToMarkdown, resolveToStructuredData, resolveToTitle } from "./lib/contentType.js";
|
|
4
4
|
import { useProjectUuid } from "../lib/auth.js";
|
|
5
5
|
import { useLocation, useNavigate } from "../features/navigation/navigation.js";
|
|
6
6
|
import { useOptionalCamoxApp } from "../features/provider/components/CamoxAppContext.js";
|
|
@@ -96,6 +96,7 @@ function buildPeekItems(properties, blockId, parentItemId, content, items, count
|
|
|
96
96
|
content: itemContent,
|
|
97
97
|
settings: property.defaultItemSettings ? { ...property.defaultItemSettings } : null,
|
|
98
98
|
summary: "",
|
|
99
|
+
title: "",
|
|
99
100
|
position,
|
|
100
101
|
createdAt: 0,
|
|
101
102
|
updatedAt: 0,
|
|
@@ -434,7 +435,7 @@ function createViewBlock(options) {
|
|
|
434
435
|
}, record.id));
|
|
435
436
|
};
|
|
436
437
|
const RecordScope = (t0) => {
|
|
437
|
-
const $ = c(
|
|
438
|
+
const $ = c(14);
|
|
438
439
|
const { block, schema, record, children } = t0;
|
|
439
440
|
const hop = block.recordHop ? 2 : 1;
|
|
440
441
|
let t1;
|
|
@@ -452,10 +453,11 @@ function createViewBlock(options) {
|
|
|
452
453
|
$[4] = t1;
|
|
453
454
|
} else t1 = $[4];
|
|
454
455
|
let t2;
|
|
455
|
-
if ($[5] !== children || $[6] !== hop || $[7] !== record.
|
|
456
|
+
if ($[5] !== children || $[6] !== hop || $[7] !== record.description || $[8] !== record.id || $[9] !== record.title) {
|
|
456
457
|
t2 = children({
|
|
457
458
|
id: record.id,
|
|
458
|
-
|
|
459
|
+
title: record.title,
|
|
460
|
+
description: record.description,
|
|
459
461
|
Field,
|
|
460
462
|
Image: ReferenceImage,
|
|
461
463
|
File: ReferenceFile,
|
|
@@ -469,12 +471,13 @@ function createViewBlock(options) {
|
|
|
469
471
|
});
|
|
470
472
|
$[5] = children;
|
|
471
473
|
$[6] = hop;
|
|
472
|
-
$[7] = record.
|
|
473
|
-
$[8] = record.
|
|
474
|
-
$[9] =
|
|
475
|
-
|
|
474
|
+
$[7] = record.description;
|
|
475
|
+
$[8] = record.id;
|
|
476
|
+
$[9] = record.title;
|
|
477
|
+
$[10] = t2;
|
|
478
|
+
} else t2 = $[10];
|
|
476
479
|
let t3;
|
|
477
|
-
if ($[
|
|
480
|
+
if ($[11] !== t1 || $[12] !== t2) {
|
|
478
481
|
t3 = /* @__PURE__ */ jsx(RepeaterContext.Provider, {
|
|
479
482
|
value: null,
|
|
480
483
|
children: /* @__PURE__ */ jsx(Context.Provider, {
|
|
@@ -482,10 +485,10 @@ function createViewBlock(options) {
|
|
|
482
485
|
children: t2
|
|
483
486
|
})
|
|
484
487
|
});
|
|
485
|
-
$[
|
|
486
|
-
$[
|
|
487
|
-
$[
|
|
488
|
-
} else t3 = $[
|
|
488
|
+
$[11] = t1;
|
|
489
|
+
$[12] = t2;
|
|
490
|
+
$[13] = t3;
|
|
491
|
+
} else t3 = $[13];
|
|
489
492
|
return t3;
|
|
490
493
|
};
|
|
491
494
|
const AssetList = ({ name, children, primitive }) => {
|
|
@@ -634,7 +637,7 @@ function createViewBlock(options) {
|
|
|
634
637
|
return t1;
|
|
635
638
|
};
|
|
636
639
|
const Component = (props) => {
|
|
637
|
-
const $ = c(
|
|
640
|
+
const $ = c(23);
|
|
638
641
|
const editingRuntime = useBlockEditingRuntime();
|
|
639
642
|
if (editingRuntime) {
|
|
640
643
|
let t0;
|
|
@@ -663,66 +666,71 @@ function createViewBlock(options) {
|
|
|
663
666
|
mergedContent = $[4];
|
|
664
667
|
normalizedContent = $[5];
|
|
665
668
|
}
|
|
666
|
-
const
|
|
669
|
+
const ToReact = options.toReact;
|
|
667
670
|
let t0;
|
|
668
|
-
if ($[6]
|
|
671
|
+
if ($[6] !== blockData.settings) {
|
|
669
672
|
t0 = {
|
|
670
|
-
|
|
671
|
-
|
|
673
|
+
...settingsDefaults,
|
|
674
|
+
...blockData.settings
|
|
672
675
|
};
|
|
673
|
-
$[6] =
|
|
674
|
-
|
|
676
|
+
$[6] = blockData.settings;
|
|
677
|
+
$[7] = t0;
|
|
678
|
+
} else t0 = $[7];
|
|
679
|
+
const settings = t0;
|
|
675
680
|
let t1;
|
|
676
|
-
if ($[
|
|
681
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
677
682
|
t1 = {
|
|
678
|
-
|
|
679
|
-
|
|
683
|
+
position: "relative",
|
|
684
|
+
scrollMargin: "5rem"
|
|
680
685
|
};
|
|
681
|
-
$[7] = blockData.settings;
|
|
682
686
|
$[8] = t1;
|
|
683
687
|
} else t1 = $[8];
|
|
684
688
|
let t2;
|
|
685
|
-
if ($[9] !== blockData._id || $[10] !== mergedContent || $[11] !== mode || $[12] !==
|
|
689
|
+
if ($[9] !== blockData._id || $[10] !== mergedContent || $[11] !== mode || $[12] !== settings) {
|
|
686
690
|
t2 = {
|
|
687
691
|
blockId: blockData._id,
|
|
688
692
|
content: mergedContent,
|
|
689
|
-
settings
|
|
693
|
+
settings,
|
|
690
694
|
mode
|
|
691
695
|
};
|
|
692
696
|
$[9] = blockData._id;
|
|
693
697
|
$[10] = mergedContent;
|
|
694
698
|
$[11] = mode;
|
|
695
|
-
$[12] =
|
|
699
|
+
$[12] = settings;
|
|
696
700
|
$[13] = t2;
|
|
697
701
|
} else t2 = $[13];
|
|
698
702
|
let t3;
|
|
699
|
-
if ($[14] !== normalizedContent) {
|
|
700
|
-
t3 = /* @__PURE__ */ jsx(
|
|
703
|
+
if ($[14] !== normalizedContent || $[15] !== settings) {
|
|
704
|
+
t3 = /* @__PURE__ */ jsx(ToReact, {
|
|
705
|
+
content: normalizedContent,
|
|
706
|
+
settings
|
|
707
|
+
});
|
|
701
708
|
$[14] = normalizedContent;
|
|
702
|
-
$[15] =
|
|
703
|
-
|
|
709
|
+
$[15] = settings;
|
|
710
|
+
$[16] = t3;
|
|
711
|
+
} else t3 = $[16];
|
|
704
712
|
let t4;
|
|
705
|
-
if ($[
|
|
713
|
+
if ($[17] !== t2 || $[18] !== t3) {
|
|
706
714
|
t4 = /* @__PURE__ */ jsx(Context.Provider, {
|
|
707
715
|
value: t2,
|
|
708
716
|
children: t3
|
|
709
717
|
});
|
|
710
|
-
$[
|
|
711
|
-
$[
|
|
712
|
-
$[
|
|
713
|
-
} else t4 = $[
|
|
718
|
+
$[17] = t2;
|
|
719
|
+
$[18] = t3;
|
|
720
|
+
$[19] = t4;
|
|
721
|
+
} else t4 = $[19];
|
|
714
722
|
let t5;
|
|
715
|
-
if ($[
|
|
723
|
+
if ($[20] !== blockData._id || $[21] !== t4) {
|
|
716
724
|
t5 = /* @__PURE__ */ jsx("div", {
|
|
717
725
|
className: "group visual-editing-block",
|
|
718
726
|
"data-camox-viewport-block": blockData._id,
|
|
719
|
-
style:
|
|
727
|
+
style: t1,
|
|
720
728
|
children: t4
|
|
721
729
|
});
|
|
722
|
-
$[
|
|
723
|
-
$[
|
|
724
|
-
$[
|
|
725
|
-
} else t5 = $[
|
|
730
|
+
$[20] = blockData._id;
|
|
731
|
+
$[21] = t4;
|
|
732
|
+
$[22] = t5;
|
|
733
|
+
} else t5 = $[22];
|
|
726
734
|
return t5;
|
|
727
735
|
};
|
|
728
736
|
const contentSchema = {
|
|
@@ -731,7 +739,9 @@ function createViewBlock(options) {
|
|
|
731
739
|
description: options.description,
|
|
732
740
|
properties: typeboxSchema.properties,
|
|
733
741
|
required: Object.keys(fields.content),
|
|
734
|
-
toMarkdown: resolveToMarkdown(options.toMarkdown, fields.settings, "block", fields.content)
|
|
742
|
+
toMarkdown: resolveToMarkdown(options.toMarkdown, fields.settings, "block", fields.content),
|
|
743
|
+
toTitle: resolveToTitle(options.toTitle, fields.settings, "block", fields.content),
|
|
744
|
+
...options.toStructuredData && { toStructuredData: resolveToStructuredData(options.toStructuredData, fields.settings, "block", fields.content) }
|
|
735
745
|
};
|
|
736
746
|
const settingsSchema = settingsTypeboxSchema ? {
|
|
737
747
|
type: "object",
|
|
@@ -810,6 +820,7 @@ function createViewBlock(options) {
|
|
|
810
820
|
settings: settingsDefaults,
|
|
811
821
|
slot: null,
|
|
812
822
|
summary: "",
|
|
823
|
+
title: "",
|
|
813
824
|
position: "",
|
|
814
825
|
createdAt: 0,
|
|
815
826
|
updatedAt: 0
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LayoutRequestContext } from "./requestContext.js";
|
|
2
|
+
import { KnownPropertiesOnly, RecordNode } from "./structuredData.js";
|
|
2
3
|
import { LayoutCollectionItemResult, LayoutRoutesResult, RecordPages } from "./createLayout.js";
|
|
3
|
-
import { CollectionFieldBuilder,
|
|
4
|
+
import { CollectionFieldBuilder, RecordStructuredDataContext, RecordTemplateContext } from "./lib/contentType.js";
|
|
4
5
|
import { SystemOrderKey } from "@camox/api-contract";
|
|
5
6
|
import { Static, TObject, TSchema } from "@sinclair/typebox";
|
|
6
7
|
//#region src/core/createCollection.d.ts
|
|
@@ -11,15 +12,27 @@ type TextKey<T extends Record<string, TSchema>> = { [K in keyof T & string]: T[K
|
|
|
11
12
|
} ? K : never; }[keyof T & string];
|
|
12
13
|
/**
|
|
13
14
|
* A definition only: record authoring and querying are not public SDK APIs.
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
15
|
+
*
|
|
16
|
+
* `toTitle` and `toDescription` are templates of the record's String fields, such as
|
|
17
|
+
* `` ({ content }) => `${content.firstName} ${content.lastName}` ``. The API fills them with each
|
|
18
|
+
* record's plain text wherever records are named: studio lists and pickers, record pages,
|
|
19
|
+
* `llms.txt` and agents. `toDescription` may return nothing, and records then have no description.
|
|
16
20
|
*/
|
|
17
|
-
export declare function createCollection<const T extends Record<string, TSchema> & ReservedFieldNames,
|
|
21
|
+
export declare function createCollection<const T extends Record<string, TSchema> & ReservedFieldNames, Node extends RecordNode = RecordNode>(options: {
|
|
18
22
|
id: string;
|
|
19
23
|
title: string;
|
|
20
24
|
description: string;
|
|
21
|
-
content: (field: CollectionFieldBuilder) => T
|
|
22
|
-
|
|
25
|
+
content: (field: CollectionFieldBuilder) => T;
|
|
26
|
+
toTitle: (context: RecordTemplateContext<NoInfer<T>>) => string;
|
|
27
|
+
toDescription: (context: RecordTemplateContext<NoInfer<T>>) => string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Each record's Structured Data node, from tokens of its fields, such as
|
|
30
|
+
* `({ content }) => ({ "@type": "Person", jobTitle: content.role })`. Camox fills its name and
|
|
31
|
+
* description from the record's title and description, and gives it an `@id` per record and
|
|
32
|
+
* locale. Every page referencing the record links this one node, and on the record's own page
|
|
33
|
+
* it's the main entity unless the layout declares one. A reference links the record's node.
|
|
34
|
+
*/
|
|
35
|
+
toStructuredData?: (context: RecordStructuredDataContext<NoInfer<T>>) => Node & KnownPropertiesOnly<Node, RecordNode>;
|
|
23
36
|
}): Collection<T>;
|
|
24
37
|
/** The pages of a derived layout, one per record, found by the record's `by` field. */
|
|
25
38
|
export interface CollectionPages<T extends Record<string, TSchema>, Param extends string> {
|
|
@@ -47,7 +60,12 @@ export type Collection<T extends Record<string, TSchema> = any> = {
|
|
|
47
60
|
id: string;
|
|
48
61
|
title: string;
|
|
49
62
|
description: string;
|
|
50
|
-
|
|
63
|
+
/** The token template titling each record, such as `{{firstName}} {{lastName}}`. */
|
|
64
|
+
toTitle: string;
|
|
65
|
+
/** The token template describing each record, or null when records have no description. */
|
|
66
|
+
toDescription: string | null;
|
|
67
|
+
/** The JSON template of each record's Structured Data node, or null when records have none. */
|
|
68
|
+
toStructuredData: Record<string, unknown> | null;
|
|
51
69
|
contentSchema: TObject<T>;
|
|
52
70
|
};
|
|
53
71
|
};
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { collectionFieldBuilder } from "./lib/contentType.js";
|
|
1
|
+
import { collectionFieldBuilder, resolveRecordStructuredData, resolveRecordTemplate } from "./lib/contentType.js";
|
|
2
2
|
import { notFound } from "./notFound.js";
|
|
3
3
|
import { getRecordLookup } from "./requestContext.js";
|
|
4
|
-
import { SYSTEM_ORDER_KEYS } from "@camox/api-contract";
|
|
4
|
+
import { SYSTEM_ORDER_KEYS, nonStringTemplateFields } from "@camox/api-contract";
|
|
5
5
|
import { Type } from "@sinclair/typebox";
|
|
6
6
|
|
|
7
7
|
//#region src/core/createCollection.ts
|
|
8
8
|
/**
|
|
9
9
|
* A definition only: record authoring and querying are not public SDK APIs.
|
|
10
|
-
*
|
|
11
|
-
* `
|
|
10
|
+
*
|
|
11
|
+
* `toTitle` and `toDescription` are templates of the record's String fields, such as
|
|
12
|
+
* `` ({ content }) => `${content.firstName} ${content.lastName}` ``. The API fills them with each
|
|
13
|
+
* record's plain text wherever records are named: studio lists and pickers, record pages,
|
|
14
|
+
* `llms.txt` and agents. `toDescription` may return nothing, and records then have no description.
|
|
12
15
|
*/
|
|
13
16
|
function createCollection(options) {
|
|
14
17
|
if (!options.id.trim()) throw new Error("Collection id is required");
|
|
@@ -27,7 +30,13 @@ function createCollection(options) {
|
|
|
27
30
|
"ReferenceList"
|
|
28
31
|
]);
|
|
29
32
|
for (const [key, field] of Object.entries(content)) if (!supported.has(field.fieldType)) throw new Error(`Collection "${options.id}" field "${key}": ${String(field.fieldType)} storage is not supported yet`);
|
|
30
|
-
|
|
33
|
+
const toTitle = resolveRecordTemplate(options.toTitle, content);
|
|
34
|
+
if (toTitle === null) throw new Error(`Collection "${options.id}": toTitle returned nothing`);
|
|
35
|
+
const toDescription = resolveRecordTemplate(options.toDescription, content);
|
|
36
|
+
for (const template of [toTitle, toDescription]) {
|
|
37
|
+
const [name] = nonStringTemplateFields(template ?? "", content);
|
|
38
|
+
if (name !== void 0) throw new Error(`Collection "${options.id}": "${name}" names no String field`);
|
|
39
|
+
}
|
|
31
40
|
const id = options.id;
|
|
32
41
|
return {
|
|
33
42
|
pages({ by, param }) {
|
|
@@ -49,10 +58,17 @@ function createCollection(options) {
|
|
|
49
58
|
collectionId: id,
|
|
50
59
|
data: {
|
|
51
60
|
id: record.id,
|
|
61
|
+
...record.title !== void 0 && { title: record.title },
|
|
62
|
+
...record.description !== void 0 && { description: record.description },
|
|
52
63
|
content: record.content,
|
|
53
64
|
...record.references && { references: record.references },
|
|
54
65
|
...record.updatedAt != null && { updatedAt: record.updatedAt }
|
|
55
|
-
}
|
|
66
|
+
},
|
|
67
|
+
...record.structuredData && { structuredData: record.structuredData },
|
|
68
|
+
...record.firstPublishedAt !== void 0 && { published: {
|
|
69
|
+
first: record.firstPublishedAt,
|
|
70
|
+
last: record.publishedAt ?? null
|
|
71
|
+
} }
|
|
56
72
|
};
|
|
57
73
|
},
|
|
58
74
|
async routes({ context }) {
|
|
@@ -69,13 +85,14 @@ function createCollection(options) {
|
|
|
69
85
|
kind: "collection-item",
|
|
70
86
|
collectionId: id,
|
|
71
87
|
id: record.id,
|
|
72
|
-
|
|
88
|
+
title: record.title
|
|
73
89
|
}
|
|
74
90
|
})) };
|
|
75
91
|
},
|
|
76
92
|
recordPages: {
|
|
77
93
|
collectionId: id,
|
|
78
|
-
field: by
|
|
94
|
+
field: by,
|
|
95
|
+
param
|
|
79
96
|
}
|
|
80
97
|
};
|
|
81
98
|
},
|
|
@@ -83,7 +100,9 @@ function createCollection(options) {
|
|
|
83
100
|
id,
|
|
84
101
|
title: options.title,
|
|
85
102
|
description: options.description,
|
|
86
|
-
|
|
103
|
+
toTitle,
|
|
104
|
+
toDescription,
|
|
105
|
+
toStructuredData: options.toStructuredData ? resolveRecordStructuredData(options.toStructuredData, content) : null,
|
|
87
106
|
contentSchema: Type.Object(content, { additionalProperties: false })
|
|
88
107
|
}
|
|
89
108
|
};
|