payload-mcp-toolkit 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.
- package/README.md +59 -42
- package/dist/__tests__/introspection.test.js +141 -46
- package/dist/__tests__/introspection.test.js.map +1 -1
- package/dist/draft-workflow.d.ts +24 -19
- package/dist/draft-workflow.js +78 -31
- package/dist/draft-workflow.js.map +1 -1
- package/dist/index.d.ts +10 -15
- package/dist/index.js +43 -70
- package/dist/index.js.map +1 -1
- package/dist/introspection.d.ts +14 -7
- package/dist/introspection.js +92 -68
- package/dist/introspection.js.map +1 -1
- package/dist/prompts.d.ts +4 -4
- package/dist/prompts.js +44 -35
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts +9 -4
- package/dist/resources.js +44 -52
- package/dist/resources.js.map +1 -1
- package/dist/tools/patch-layout.d.ts +15 -79
- package/dist/tools/patch-layout.js +140 -48
- package/dist/tools/patch-layout.js.map +1 -1
- package/dist/types.d.ts +82 -53
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/tools/compose-helpers.d.ts +0 -117
- package/dist/tools/compose-helpers.js +0 -236
- package/dist/tools/compose-helpers.js.map +0 -1
- package/dist/tools/compose-layout.d.ts +0 -139
- package/dist/tools/compose-layout.js +0 -61
- package/dist/tools/compose-layout.js.map +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,44 +1,60 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* payload-mcp-toolkit configuration.
|
|
3
|
+
*
|
|
4
|
+
* The plugin works with zero options — every field below is an escape hatch
|
|
5
|
+
* for the cases where Payload's own config doesn't carry enough signal.
|
|
6
|
+
*/
|
|
4
7
|
export interface ContentToolkitOptions {
|
|
5
|
-
/** Base URL of the site (used for preview URLs). e.g. "https://example.com" */
|
|
6
|
-
siteUrl: string;
|
|
7
|
-
/** Secret used for preview URL authentication */
|
|
8
|
-
previewSecret: string;
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* Example:
|
|
15
|
-
* {
|
|
16
|
-
* posts: '/blog',
|
|
17
|
-
* products: '/shop',
|
|
18
|
-
* pages: '',
|
|
19
|
-
* }
|
|
20
|
-
*
|
|
21
|
-
* Collections without an entry default to `/{slug}`.
|
|
9
|
+
* Preview URL behavior. The toolkit reads `collection.admin.livePreview.url`
|
|
10
|
+
* (or `collection.admin.preview` as a fallback) when generating preview links
|
|
11
|
+
* for draft documents. Provide this object only to override what Payload
|
|
12
|
+
* already knows.
|
|
22
13
|
*/
|
|
23
|
-
|
|
14
|
+
preview?: {
|
|
15
|
+
/**
|
|
16
|
+
* Absolute base URL prepended to relative preview paths. Defaults to
|
|
17
|
+
* `incomingConfig.serverURL`, then `process.env.NEXT_PUBLIC_SERVER_URL`,
|
|
18
|
+
* then `process.env.SITE_URL`. If none of those resolve and your preview
|
|
19
|
+
* URL function returns a relative path, no preview URL is appended.
|
|
20
|
+
*/
|
|
21
|
+
siteUrl?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Disable preview URL injection entirely.
|
|
24
|
+
*/
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
};
|
|
24
27
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
+
* Per-collection draft behavior overrides. The default behavior is inferred
|
|
29
|
+
* from each collection's `versions.drafts` setting:
|
|
30
|
+
* - drafts enabled → `'always-draft'` (raw `update` is locked; clients go
|
|
31
|
+
* through `publishDraft` / `patchLayout` / `updateDocument` which preserve
|
|
32
|
+
* draft semantics)
|
|
33
|
+
* - drafts disabled → `'always-publish'`
|
|
28
34
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
*
|
|
35
|
+
* Override per slug only if you need to allow raw publish on a draftable
|
|
36
|
+
* collection.
|
|
37
|
+
*/
|
|
38
|
+
draftBehavior?: Record<string, 'always-draft' | 'always-publish'>;
|
|
39
|
+
/**
|
|
40
|
+
* Override the auth collection used for API key linkage. By default the
|
|
41
|
+
* toolkit scans `incomingConfig.collections` for the first collection with
|
|
42
|
+
* `auth: true`, preferring one named `'users'`.
|
|
43
|
+
*/
|
|
44
|
+
userCollection?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Hide collections or globals from the MCP surface. Useful for internal
|
|
47
|
+
* bookkeeping collections that should not be exposed to AI clients.
|
|
48
|
+
*/
|
|
49
|
+
exclude?: {
|
|
50
|
+
collections?: string[];
|
|
51
|
+
globals?: string[];
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Site-specific domain prompts that teach the AI business vocabulary.
|
|
55
|
+
* Merged with the auto-generated prompts.
|
|
36
56
|
*/
|
|
37
|
-
sectionBlockSlugs?: string[];
|
|
38
|
-
/** Site-specific domain prompts that teach the AI business vocabulary */
|
|
39
57
|
domainPrompts?: DomainPrompt[];
|
|
40
|
-
/** Per-collection draft behavior overrides (keyed by collection slug) */
|
|
41
|
-
draftBehavior?: Record<string, DraftBehavior>;
|
|
42
58
|
/** Media upload configuration */
|
|
43
59
|
mediaUpload?: {
|
|
44
60
|
/** Maximum file size in bytes (default: 10MB) */
|
|
@@ -46,10 +62,6 @@ export interface ContentToolkitOptions {
|
|
|
46
62
|
/** Media collection slug (default: 'media') */
|
|
47
63
|
collectionSlug?: string;
|
|
48
64
|
};
|
|
49
|
-
/** Collections to exclude from MCP exposure */
|
|
50
|
-
excludeCollections?: string[];
|
|
51
|
-
/** Globals to exclude from MCP exposure */
|
|
52
|
-
excludeGlobals?: string[];
|
|
53
65
|
}
|
|
54
66
|
/** A domain prompt that teaches the AI site-specific vocabulary */
|
|
55
67
|
export interface DomainPrompt {
|
|
@@ -89,26 +101,43 @@ export interface CollectionSchema {
|
|
|
89
101
|
}>;
|
|
90
102
|
searchableFields: string[];
|
|
91
103
|
}
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
acceptedLeafSlugs: string[];
|
|
99
|
-
maxRows?: number;
|
|
100
|
-
fields: FieldSchema[];
|
|
101
|
-
}
|
|
102
|
-
/** Introspected leaf block metadata */
|
|
103
|
-
export interface LeafBlockSchema {
|
|
104
|
+
/**
|
|
105
|
+
* One block in the catalog. Flat — no section/leaf distinction. Whether a
|
|
106
|
+
* block can nest other blocks is encoded in the `BlockNestingMap` keyed by
|
|
107
|
+
* the path to its `blocks` field.
|
|
108
|
+
*/
|
|
109
|
+
export interface BlockSchema {
|
|
104
110
|
slug: string;
|
|
105
111
|
fields: FieldSchema[];
|
|
106
112
|
}
|
|
107
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* Flat catalog of every block referenced by the schema.
|
|
115
|
+
*/
|
|
108
116
|
export interface BlockCatalog {
|
|
109
|
-
|
|
110
|
-
|
|
117
|
+
blocks: BlockSchema[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* One entry per `blocks`-typed field anywhere in the schema.
|
|
121
|
+
*
|
|
122
|
+
* `path` is `<owner>.<dottedFieldPath>` where owner is the collection or
|
|
123
|
+
* block slug that contains the field. Values list the slugs that field
|
|
124
|
+
* accepts. The AI uses this to compose blocks at any nesting depth without
|
|
125
|
+
* us pre-classifying anything as a "section" or "leaf".
|
|
126
|
+
*/
|
|
127
|
+
export interface BlockNestingEdge {
|
|
128
|
+
/** Owner of the blocks field — either a collection slug or a block slug */
|
|
129
|
+
owner: string;
|
|
130
|
+
/** Whether the owner is a collection or a block */
|
|
131
|
+
ownerType: 'collection' | 'block';
|
|
132
|
+
/** Dotted path to the blocks field within the owner (e.g. `layout`, `hero.content`) */
|
|
133
|
+
fieldPath: string;
|
|
134
|
+
/** Block slugs that this field accepts */
|
|
135
|
+
acceptedBlockSlugs: string[];
|
|
136
|
+
/** Optional row cap from the field config */
|
|
137
|
+
maxRows?: number;
|
|
111
138
|
}
|
|
139
|
+
/** Map of every blocks-field in the schema to the slugs it accepts */
|
|
140
|
+
export type BlockNestingMap = BlockNestingEdge[];
|
|
112
141
|
/** Relationship edge in the collection graph */
|
|
113
142
|
export interface RelationshipEdge {
|
|
114
143
|
fromCollection: string;
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* payload-mcp-toolkit configuration.
|
|
3
|
+
*
|
|
4
|
+
* The plugin works with zero options — every field below is an escape hatch
|
|
5
|
+
* for the cases where Payload's own config doesn't carry enough signal.
|
|
6
|
+
*/ /** Relationship edge in the collection graph */ export { };
|
|
2
7
|
|
|
3
8
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * payload-mcp-toolkit configuration.\n *\n * The plugin works with zero options — every field below is an escape hatch\n * for the cases where Payload's own config doesn't carry enough signal.\n */\nexport interface ContentToolkitOptions {\n /**\n * Preview URL behavior. The toolkit reads `collection.admin.livePreview.url`\n * (or `collection.admin.preview` as a fallback) when generating preview links\n * for draft documents. Provide this object only to override what Payload\n * already knows.\n */\n preview?: {\n /**\n * Absolute base URL prepended to relative preview paths. Defaults to\n * `incomingConfig.serverURL`, then `process.env.NEXT_PUBLIC_SERVER_URL`,\n * then `process.env.SITE_URL`. If none of those resolve and your preview\n * URL function returns a relative path, no preview URL is appended.\n */\n siteUrl?: string\n\n /**\n * Disable preview URL injection entirely.\n */\n disabled?: boolean\n }\n\n /**\n * Per-collection draft behavior overrides. The default behavior is inferred\n * from each collection's `versions.drafts` setting:\n * - drafts enabled → `'always-draft'` (raw `update` is locked; clients go\n * through `publishDraft` / `patchLayout` / `updateDocument` which preserve\n * draft semantics)\n * - drafts disabled → `'always-publish'`\n *\n * Override per slug only if you need to allow raw publish on a draftable\n * collection.\n */\n draftBehavior?: Record<string, 'always-draft' | 'always-publish'>\n\n /**\n * Override the auth collection used for API key linkage. By default the\n * toolkit scans `incomingConfig.collections` for the first collection with\n * `auth: true`, preferring one named `'users'`.\n */\n userCollection?: string\n\n /**\n * Hide collections or globals from the MCP surface. Useful for internal\n * bookkeeping collections that should not be exposed to AI clients.\n */\n exclude?: {\n collections?: string[]\n globals?: string[]\n }\n\n /**\n * Site-specific domain prompts that teach the AI business vocabulary.\n * Merged with the auto-generated prompts.\n */\n domainPrompts?: DomainPrompt[]\n\n /** Media upload configuration */\n mediaUpload?: {\n /** Maximum file size in bytes (default: 10MB) */\n maxFileSize?: number\n /** Media collection slug (default: 'media') */\n collectionSlug?: string\n }\n}\n\n/** A domain prompt that teaches the AI site-specific vocabulary */\nexport interface DomainPrompt {\n /** Unique name for the prompt */\n name: string\n /** Display title */\n title: string\n /** Description of what this prompt teaches */\n description: string\n /** The prompt content */\n content: string\n}\n\n/** Introspected field metadata */\nexport interface FieldSchema {\n name: string\n type: string\n required?: boolean\n hasMany?: boolean\n relationTo?: string | string[]\n options?: Array<{ label: string; value: string }>\n fields?: FieldSchema[]\n maxRows?: number\n}\n\n/** Introspected collection metadata */\nexport interface CollectionSchema {\n slug: string\n fields: FieldSchema[]\n hasDrafts: boolean\n hasLivePreview: boolean\n relationships: Array<{ fieldName: string; relationTo: string | string[]; hasMany: boolean }>\n searchableFields: string[]\n}\n\n/**\n * One block in the catalog. Flat — no section/leaf distinction. Whether a\n * block can nest other blocks is encoded in the `BlockNestingMap` keyed by\n * the path to its `blocks` field.\n */\nexport interface BlockSchema {\n slug: string\n fields: FieldSchema[]\n}\n\n/**\n * Flat catalog of every block referenced by the schema.\n */\nexport interface BlockCatalog {\n blocks: BlockSchema[]\n}\n\n/**\n * One entry per `blocks`-typed field anywhere in the schema.\n *\n * `path` is `<owner>.<dottedFieldPath>` where owner is the collection or\n * block slug that contains the field. Values list the slugs that field\n * accepts. The AI uses this to compose blocks at any nesting depth without\n * us pre-classifying anything as a \"section\" or \"leaf\".\n */\nexport interface BlockNestingEdge {\n /** Owner of the blocks field — either a collection slug or a block slug */\n owner: string\n /** Whether the owner is a collection or a block */\n ownerType: 'collection' | 'block'\n /** Dotted path to the blocks field within the owner (e.g. `layout`, `hero.content`) */\n fieldPath: string\n /** Block slugs that this field accepts */\n acceptedBlockSlugs: string[]\n /** Optional row cap from the field config */\n maxRows?: number\n}\n\n/** Map of every blocks-field in the schema to the slugs it accepts */\nexport type BlockNestingMap = BlockNestingEdge[]\n\n/** Relationship edge in the collection graph */\nexport interface RelationshipEdge {\n fromCollection: string\n fieldName: string\n toCollection: string | string[]\n hasMany: boolean\n}\n"],"names":[],"mappings":"AAAA;;;;;CAKC,GA8ID,8CAA8C,GAC9C,WAKC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payload-mcp-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Schema-aware MCP toolkit for Payload CMS — wraps the official @payloadcms/plugin-mcp with introspected prompts, resources, draft workflow, and AI-friendly tools so non-technical editors can manage content via AI chat.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "jon8800",
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { BlockCatalog } from '../types';
|
|
3
|
-
/** Schema for a single leaf block within a section */
|
|
4
|
-
export declare const leafBlockSchema: z.ZodObject<{
|
|
5
|
-
blockType: z.ZodString;
|
|
6
|
-
fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
7
|
-
}, "strip", z.ZodTypeAny, {
|
|
8
|
-
blockType: string;
|
|
9
|
-
fields?: Record<string, unknown> | undefined;
|
|
10
|
-
}, {
|
|
11
|
-
blockType: string;
|
|
12
|
-
fields?: Record<string, unknown> | undefined;
|
|
13
|
-
}>;
|
|
14
|
-
/** Schema for a single section in a layout */
|
|
15
|
-
export declare const sectionSchema: z.ZodObject<{
|
|
16
|
-
sectionType: z.ZodString;
|
|
17
|
-
config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
18
|
-
/** Leaf blocks for single-content sections */
|
|
19
|
-
content: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
20
|
-
blockType: z.ZodString;
|
|
21
|
-
fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
22
|
-
}, "strip", z.ZodTypeAny, {
|
|
23
|
-
blockType: string;
|
|
24
|
-
fields?: Record<string, unknown> | undefined;
|
|
25
|
-
}, {
|
|
26
|
-
blockType: string;
|
|
27
|
-
fields?: Record<string, unknown> | undefined;
|
|
28
|
-
}>, "many">>;
|
|
29
|
-
/** Left column leaf blocks (for two-column sections) */
|
|
30
|
-
leftColumn: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
31
|
-
blockType: z.ZodString;
|
|
32
|
-
fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
33
|
-
}, "strip", z.ZodTypeAny, {
|
|
34
|
-
blockType: string;
|
|
35
|
-
fields?: Record<string, unknown> | undefined;
|
|
36
|
-
}, {
|
|
37
|
-
blockType: string;
|
|
38
|
-
fields?: Record<string, unknown> | undefined;
|
|
39
|
-
}>, "many">>;
|
|
40
|
-
/** Right column leaf blocks (for two-column sections) */
|
|
41
|
-
rightColumn: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
42
|
-
blockType: z.ZodString;
|
|
43
|
-
fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
44
|
-
}, "strip", z.ZodTypeAny, {
|
|
45
|
-
blockType: string;
|
|
46
|
-
fields?: Record<string, unknown> | undefined;
|
|
47
|
-
}, {
|
|
48
|
-
blockType: string;
|
|
49
|
-
fields?: Record<string, unknown> | undefined;
|
|
50
|
-
}>, "many">>;
|
|
51
|
-
/** Flat field values for fixed sections */
|
|
52
|
-
fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
53
|
-
}, "strip", z.ZodTypeAny, {
|
|
54
|
-
sectionType: string;
|
|
55
|
-
fields?: Record<string, unknown> | undefined;
|
|
56
|
-
config?: Record<string, unknown> | undefined;
|
|
57
|
-
content?: {
|
|
58
|
-
blockType: string;
|
|
59
|
-
fields?: Record<string, unknown> | undefined;
|
|
60
|
-
}[] | undefined;
|
|
61
|
-
leftColumn?: {
|
|
62
|
-
blockType: string;
|
|
63
|
-
fields?: Record<string, unknown> | undefined;
|
|
64
|
-
}[] | undefined;
|
|
65
|
-
rightColumn?: {
|
|
66
|
-
blockType: string;
|
|
67
|
-
fields?: Record<string, unknown> | undefined;
|
|
68
|
-
}[] | undefined;
|
|
69
|
-
}, {
|
|
70
|
-
sectionType: string;
|
|
71
|
-
fields?: Record<string, unknown> | undefined;
|
|
72
|
-
config?: Record<string, unknown> | undefined;
|
|
73
|
-
content?: {
|
|
74
|
-
blockType: string;
|
|
75
|
-
fields?: Record<string, unknown> | undefined;
|
|
76
|
-
}[] | undefined;
|
|
77
|
-
leftColumn?: {
|
|
78
|
-
blockType: string;
|
|
79
|
-
fields?: Record<string, unknown> | undefined;
|
|
80
|
-
}[] | undefined;
|
|
81
|
-
rightColumn?: {
|
|
82
|
-
blockType: string;
|
|
83
|
-
fields?: Record<string, unknown> | undefined;
|
|
84
|
-
}[] | undefined;
|
|
85
|
-
}>;
|
|
86
|
-
export type LeafBlockInput = z.infer<typeof leafBlockSchema>;
|
|
87
|
-
export type SectionInput = z.infer<typeof sectionSchema>;
|
|
88
|
-
export interface ValidationError {
|
|
89
|
-
sectionIndex: number;
|
|
90
|
-
message: string;
|
|
91
|
-
validAlternatives?: string[];
|
|
92
|
-
}
|
|
93
|
-
export interface ComposeResult {
|
|
94
|
-
blocks: Record<string, unknown>[];
|
|
95
|
-
errors: ValidationError[];
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Validate and compose an array of section inputs into block JSON.
|
|
99
|
-
* Returns either composed blocks or a list of validation errors.
|
|
100
|
-
*/
|
|
101
|
-
export declare function composeSections(sections: SectionInput[], catalog: BlockCatalog): ComposeResult;
|
|
102
|
-
/** Build a hint payload describing the available section/leaf vocabulary. */
|
|
103
|
-
export declare function buildHint(catalog: BlockCatalog): {
|
|
104
|
-
availableSections: string[];
|
|
105
|
-
availableLeaves: string[];
|
|
106
|
-
sectionDetails: {
|
|
107
|
-
slug: string;
|
|
108
|
-
nestingType: import("../types").BlockNestingType;
|
|
109
|
-
acceptedLeaves: string[];
|
|
110
|
-
maxRows: number | undefined;
|
|
111
|
-
}[];
|
|
112
|
-
};
|
|
113
|
-
/**
|
|
114
|
-
* Apply a list operation against an existing array of blocks.
|
|
115
|
-
* `full` always replaces; the rest preserve the existing array.
|
|
116
|
-
*/
|
|
117
|
-
export declare function applyOperation(composedBlocks: Record<string, unknown>[], operation: 'full' | 'append' | 'prepend' | 'insertAt' | 'replaceAt', insertIndex: number | undefined, existingLayout: Record<string, unknown>[] | undefined): Record<string, unknown>[];
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
/** Schema for a single leaf block within a section */ export const leafBlockSchema = z.object({
|
|
3
|
-
blockType: z.string(),
|
|
4
|
-
fields: z.record(z.string(), z.unknown()).optional()
|
|
5
|
-
});
|
|
6
|
-
/** Schema for a single section in a layout */ export const sectionSchema = z.object({
|
|
7
|
-
sectionType: z.string(),
|
|
8
|
-
config: z.record(z.string(), z.unknown()).optional(),
|
|
9
|
-
/** Leaf blocks for single-content sections */ content: z.array(leafBlockSchema).optional(),
|
|
10
|
-
/** Left column leaf blocks (for two-column sections) */ leftColumn: z.array(leafBlockSchema).optional(),
|
|
11
|
-
/** Right column leaf blocks (for two-column sections) */ rightColumn: z.array(leafBlockSchema).optional(),
|
|
12
|
-
/** Flat field values for fixed sections */ fields: z.record(z.string(), z.unknown()).optional()
|
|
13
|
-
});
|
|
14
|
-
/**
|
|
15
|
-
* Validate and compose an array of section inputs into block JSON.
|
|
16
|
-
* Returns either composed blocks or a list of validation errors.
|
|
17
|
-
*/ export function composeSections(sections, catalog) {
|
|
18
|
-
const sectionMap = new Map(catalog.sections.map((s)=>[
|
|
19
|
-
s.slug,
|
|
20
|
-
s
|
|
21
|
-
]));
|
|
22
|
-
const allLeafSlugs = catalog.leaves.map((l)=>l.slug);
|
|
23
|
-
const blocks = [];
|
|
24
|
-
const errors = [];
|
|
25
|
-
for(let i = 0; i < sections.length; i++){
|
|
26
|
-
const result = composeSingleSection(sections[i], i, sectionMap, allLeafSlugs);
|
|
27
|
-
if (result.errors.length > 0) {
|
|
28
|
-
errors.push(...result.errors);
|
|
29
|
-
} else if (result.block) {
|
|
30
|
-
blocks.push(result.block);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
blocks,
|
|
35
|
-
errors
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
/** Build a hint payload describing the available section/leaf vocabulary. */ export function buildHint(catalog) {
|
|
39
|
-
return {
|
|
40
|
-
availableSections: catalog.sections.map((s)=>s.slug),
|
|
41
|
-
availableLeaves: catalog.leaves.map((l)=>l.slug),
|
|
42
|
-
sectionDetails: catalog.sections.map((s)=>({
|
|
43
|
-
slug: s.slug,
|
|
44
|
-
nestingType: s.nestingType,
|
|
45
|
-
acceptedLeaves: s.acceptedLeafSlugs,
|
|
46
|
-
maxRows: s.maxRows
|
|
47
|
-
}))
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Apply a list operation against an existing array of blocks.
|
|
52
|
-
* `full` always replaces; the rest preserve the existing array.
|
|
53
|
-
*/ export function applyOperation(composedBlocks, operation, insertIndex, existingLayout) {
|
|
54
|
-
if (operation === 'full' || !existingLayout) {
|
|
55
|
-
return composedBlocks;
|
|
56
|
-
}
|
|
57
|
-
const existing = [
|
|
58
|
-
...existingLayout
|
|
59
|
-
];
|
|
60
|
-
if (operation === 'append') {
|
|
61
|
-
return [
|
|
62
|
-
...existing,
|
|
63
|
-
...composedBlocks
|
|
64
|
-
];
|
|
65
|
-
}
|
|
66
|
-
if (operation === 'prepend') {
|
|
67
|
-
return [
|
|
68
|
-
...composedBlocks,
|
|
69
|
-
...existing
|
|
70
|
-
];
|
|
71
|
-
}
|
|
72
|
-
if (operation === 'insertAt') {
|
|
73
|
-
if (insertIndex === undefined || insertIndex < 0 || insertIndex > existing.length) {
|
|
74
|
-
return [
|
|
75
|
-
...existing,
|
|
76
|
-
...composedBlocks
|
|
77
|
-
];
|
|
78
|
-
}
|
|
79
|
-
existing.splice(insertIndex, 0, ...composedBlocks);
|
|
80
|
-
return existing;
|
|
81
|
-
}
|
|
82
|
-
if (operation === 'replaceAt') {
|
|
83
|
-
if (insertIndex === undefined || insertIndex < 0 || insertIndex >= existing.length) {
|
|
84
|
-
return existing;
|
|
85
|
-
}
|
|
86
|
-
existing.splice(insertIndex, composedBlocks.length, ...composedBlocks);
|
|
87
|
-
return existing;
|
|
88
|
-
}
|
|
89
|
-
return composedBlocks;
|
|
90
|
-
}
|
|
91
|
-
function composeSingleSection(section, index, sectionMap, allLeafSlugs) {
|
|
92
|
-
const sectionSchema = sectionMap.get(section.sectionType);
|
|
93
|
-
if (!sectionSchema) {
|
|
94
|
-
return {
|
|
95
|
-
block: null,
|
|
96
|
-
errors: [
|
|
97
|
-
{
|
|
98
|
-
sectionIndex: index,
|
|
99
|
-
message: `Unknown section type: "${section.sectionType}"`,
|
|
100
|
-
validAlternatives: [
|
|
101
|
-
...sectionMap.keys()
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
]
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
if (sectionSchema.nestingType === 'fixed') {
|
|
108
|
-
return composeFixedSection(section, index, sectionSchema);
|
|
109
|
-
}
|
|
110
|
-
// Detect two-column layout by leftColumn block field
|
|
111
|
-
const hasDualColumns = sectionSchema.fields.some((f)=>f.name === 'leftColumn' && f.type === 'blocks');
|
|
112
|
-
if (hasDualColumns) {
|
|
113
|
-
return composeTwoColumnSection(section, index, sectionSchema, allLeafSlugs);
|
|
114
|
-
}
|
|
115
|
-
return composeContentSection(section, index, sectionSchema, allLeafSlugs);
|
|
116
|
-
}
|
|
117
|
-
function composeFixedSection(section, index, schema) {
|
|
118
|
-
const errors = validateRequiredFields(section.fields ?? {}, schema.fields, index);
|
|
119
|
-
if (errors.length > 0) return {
|
|
120
|
-
block: null,
|
|
121
|
-
errors
|
|
122
|
-
};
|
|
123
|
-
return {
|
|
124
|
-
block: {
|
|
125
|
-
blockType: schema.slug,
|
|
126
|
-
...section.fields ?? {},
|
|
127
|
-
...section.config ?? {}
|
|
128
|
-
},
|
|
129
|
-
errors: []
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
function composeContentSection(section, index, schema, allLeafSlugs) {
|
|
133
|
-
const content = section.content ?? [];
|
|
134
|
-
const errors = validateLeafBlocks(content, schema, index, 'content', allLeafSlugs);
|
|
135
|
-
if (schema.maxRows && content.length > schema.maxRows) {
|
|
136
|
-
errors.push({
|
|
137
|
-
sectionIndex: index,
|
|
138
|
-
message: `Section "${schema.slug}" allows at most ${schema.maxRows} content block(s), got ${content.length}`
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
if (errors.length > 0) return {
|
|
142
|
-
block: null,
|
|
143
|
-
errors
|
|
144
|
-
};
|
|
145
|
-
const blockFieldName = findBlockFieldName(schema, 'content');
|
|
146
|
-
const composedLeaves = content.map((leaf)=>({
|
|
147
|
-
blockType: leaf.blockType,
|
|
148
|
-
...leaf.fields ?? {}
|
|
149
|
-
}));
|
|
150
|
-
return {
|
|
151
|
-
block: {
|
|
152
|
-
blockType: schema.slug,
|
|
153
|
-
[blockFieldName]: composedLeaves,
|
|
154
|
-
...section.config ?? {},
|
|
155
|
-
...section.fields ?? {}
|
|
156
|
-
},
|
|
157
|
-
errors: []
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
function composeTwoColumnSection(section, index, schema, allLeafSlugs) {
|
|
161
|
-
const leftColumn = section.leftColumn ?? [];
|
|
162
|
-
const rightColumn = section.rightColumn ?? [];
|
|
163
|
-
const errors = [
|
|
164
|
-
...validateLeafBlocks(leftColumn, schema, index, 'leftColumn', allLeafSlugs),
|
|
165
|
-
...validateLeafBlocks(rightColumn, schema, index, 'rightColumn', allLeafSlugs)
|
|
166
|
-
];
|
|
167
|
-
if (errors.length > 0) return {
|
|
168
|
-
block: null,
|
|
169
|
-
errors
|
|
170
|
-
};
|
|
171
|
-
return {
|
|
172
|
-
block: {
|
|
173
|
-
blockType: schema.slug,
|
|
174
|
-
leftColumn: leftColumn.map((leaf)=>({
|
|
175
|
-
blockType: leaf.blockType,
|
|
176
|
-
...leaf.fields ?? {}
|
|
177
|
-
})),
|
|
178
|
-
rightColumn: rightColumn.map((leaf)=>({
|
|
179
|
-
blockType: leaf.blockType,
|
|
180
|
-
...leaf.fields ?? {}
|
|
181
|
-
})),
|
|
182
|
-
...section.config ?? {}
|
|
183
|
-
},
|
|
184
|
-
errors: []
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
function validateLeafBlocks(leaves, sectionSchema, sectionIndex, columnName, allLeafSlugs) {
|
|
188
|
-
const errors = [];
|
|
189
|
-
for(let i = 0; i < leaves.length; i++){
|
|
190
|
-
const leaf = leaves[i];
|
|
191
|
-
if (!allLeafSlugs.includes(leaf.blockType)) {
|
|
192
|
-
errors.push({
|
|
193
|
-
sectionIndex,
|
|
194
|
-
message: `Unknown leaf block type "${leaf.blockType}" at ${columnName}[${i}]`,
|
|
195
|
-
validAlternatives: allLeafSlugs
|
|
196
|
-
});
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
if (!sectionSchema.acceptedLeafSlugs.includes(leaf.blockType)) {
|
|
200
|
-
errors.push({
|
|
201
|
-
sectionIndex,
|
|
202
|
-
message: `Leaf block "${leaf.blockType}" is not allowed in section "${sectionSchema.slug}" at ${columnName}[${i}]`,
|
|
203
|
-
validAlternatives: sectionSchema.acceptedLeafSlugs
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return errors;
|
|
208
|
-
}
|
|
209
|
-
function validateRequiredFields(values, fieldSchemas, sectionIndex) {
|
|
210
|
-
const errors = [];
|
|
211
|
-
for (const field of fieldSchemas){
|
|
212
|
-
if (!field.required) continue;
|
|
213
|
-
if ([
|
|
214
|
-
'id',
|
|
215
|
-
'blockName',
|
|
216
|
-
'blockType'
|
|
217
|
-
].includes(field.name)) continue;
|
|
218
|
-
const value = values[field.name];
|
|
219
|
-
if (value === undefined || value === null || value === '') {
|
|
220
|
-
errors.push({
|
|
221
|
-
sectionIndex,
|
|
222
|
-
message: `Required field "${field.name}" is missing`
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return errors;
|
|
227
|
-
}
|
|
228
|
-
function findBlockFieldName(schema, defaultName) {
|
|
229
|
-
const hasDefault = schema.fields.some((f)=>f.name === defaultName && f.type === 'blocks');
|
|
230
|
-
if (hasDefault) return defaultName;
|
|
231
|
-
const blocksField = schema.fields.find((f)=>f.type === 'blocks');
|
|
232
|
-
if (blocksField) return blocksField.name;
|
|
233
|
-
return defaultName;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
//# sourceMappingURL=compose-helpers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tools/compose-helpers.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { BlockCatalog, SectionBlockSchema } from '../types'\n\n/** Schema for a single leaf block within a section */\nexport const leafBlockSchema = z.object({\n blockType: z.string(),\n fields: z.record(z.string(), z.unknown()).optional(),\n})\n\n/** Schema for a single section in a layout */\nexport const sectionSchema = z.object({\n sectionType: z.string(),\n config: z.record(z.string(), z.unknown()).optional(),\n /** Leaf blocks for single-content sections */\n content: z.array(leafBlockSchema).optional(),\n /** Left column leaf blocks (for two-column sections) */\n leftColumn: z.array(leafBlockSchema).optional(),\n /** Right column leaf blocks (for two-column sections) */\n rightColumn: z.array(leafBlockSchema).optional(),\n /** Flat field values for fixed sections */\n fields: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport type LeafBlockInput = z.infer<typeof leafBlockSchema>\nexport type SectionInput = z.infer<typeof sectionSchema>\n\nexport interface ValidationError {\n sectionIndex: number\n message: string\n validAlternatives?: string[]\n}\n\nexport interface ComposeResult {\n blocks: Record<string, unknown>[]\n errors: ValidationError[]\n}\n\n/**\n * Validate and compose an array of section inputs into block JSON.\n * Returns either composed blocks or a list of validation errors.\n */\nexport function composeSections(\n sections: SectionInput[],\n catalog: BlockCatalog,\n): ComposeResult {\n const sectionMap = new Map(catalog.sections.map((s) => [s.slug, s]))\n const allLeafSlugs = catalog.leaves.map((l) => l.slug)\n\n const blocks: Record<string, unknown>[] = []\n const errors: ValidationError[] = []\n\n for (let i = 0; i < sections.length; i++) {\n const result = composeSingleSection(sections[i], i, sectionMap, allLeafSlugs)\n if (result.errors.length > 0) {\n errors.push(...result.errors)\n } else if (result.block) {\n blocks.push(result.block)\n }\n }\n\n return { blocks, errors }\n}\n\n/** Build a hint payload describing the available section/leaf vocabulary. */\nexport function buildHint(catalog: BlockCatalog) {\n return {\n availableSections: catalog.sections.map((s) => s.slug),\n availableLeaves: catalog.leaves.map((l) => l.slug),\n sectionDetails: catalog.sections.map((s) => ({\n slug: s.slug,\n nestingType: s.nestingType,\n acceptedLeaves: s.acceptedLeafSlugs,\n maxRows: s.maxRows,\n })),\n }\n}\n\n/**\n * Apply a list operation against an existing array of blocks.\n * `full` always replaces; the rest preserve the existing array.\n */\nexport function applyOperation(\n composedBlocks: Record<string, unknown>[],\n operation: 'full' | 'append' | 'prepend' | 'insertAt' | 'replaceAt',\n insertIndex: number | undefined,\n existingLayout: Record<string, unknown>[] | undefined,\n): Record<string, unknown>[] {\n if (operation === 'full' || !existingLayout) {\n return composedBlocks\n }\n\n const existing = [...existingLayout]\n\n if (operation === 'append') {\n return [...existing, ...composedBlocks]\n }\n\n if (operation === 'prepend') {\n return [...composedBlocks, ...existing]\n }\n\n if (operation === 'insertAt') {\n if (insertIndex === undefined || insertIndex < 0 || insertIndex > existing.length) {\n return [...existing, ...composedBlocks]\n }\n existing.splice(insertIndex, 0, ...composedBlocks)\n return existing\n }\n\n if (operation === 'replaceAt') {\n if (insertIndex === undefined || insertIndex < 0 || insertIndex >= existing.length) {\n return existing\n }\n existing.splice(insertIndex, composedBlocks.length, ...composedBlocks)\n return existing\n }\n\n return composedBlocks\n}\n\n// ─── Internal composition logic ──────────────────────────────────\n\ninterface SingleResult {\n block: Record<string, unknown> | null\n errors: ValidationError[]\n}\n\nfunction composeSingleSection(\n section: SectionInput,\n index: number,\n sectionMap: Map<string, SectionBlockSchema>,\n allLeafSlugs: string[],\n): SingleResult {\n const sectionSchema = sectionMap.get(section.sectionType)\n\n if (!sectionSchema) {\n return {\n block: null,\n errors: [\n {\n sectionIndex: index,\n message: `Unknown section type: \"${section.sectionType}\"`,\n validAlternatives: [...sectionMap.keys()],\n },\n ],\n }\n }\n\n if (sectionSchema.nestingType === 'fixed') {\n return composeFixedSection(section, index, sectionSchema)\n }\n\n // Detect two-column layout by leftColumn block field\n const hasDualColumns = sectionSchema.fields.some(\n (f) => f.name === 'leftColumn' && f.type === 'blocks',\n )\n\n if (hasDualColumns) {\n return composeTwoColumnSection(section, index, sectionSchema, allLeafSlugs)\n }\n\n return composeContentSection(section, index, sectionSchema, allLeafSlugs)\n}\n\nfunction composeFixedSection(\n section: SectionInput,\n index: number,\n schema: SectionBlockSchema,\n): SingleResult {\n const errors = validateRequiredFields(section.fields ?? {}, schema.fields, index)\n if (errors.length > 0) return { block: null, errors }\n\n return {\n block: {\n blockType: schema.slug,\n ...(section.fields ?? {}),\n ...(section.config ?? {}),\n },\n errors: [],\n }\n}\n\nfunction composeContentSection(\n section: SectionInput,\n index: number,\n schema: SectionBlockSchema,\n allLeafSlugs: string[],\n): SingleResult {\n const content = section.content ?? []\n const errors = validateLeafBlocks(content, schema, index, 'content', allLeafSlugs)\n\n if (schema.maxRows && content.length > schema.maxRows) {\n errors.push({\n sectionIndex: index,\n message: `Section \"${schema.slug}\" allows at most ${schema.maxRows} content block(s), got ${content.length}`,\n })\n }\n\n if (errors.length > 0) return { block: null, errors }\n\n const blockFieldName = findBlockFieldName(schema, 'content')\n const composedLeaves = content.map((leaf) => ({\n blockType: leaf.blockType,\n ...(leaf.fields ?? {}),\n }))\n\n return {\n block: {\n blockType: schema.slug,\n [blockFieldName]: composedLeaves,\n ...(section.config ?? {}),\n ...(section.fields ?? {}),\n },\n errors: [],\n }\n}\n\nfunction composeTwoColumnSection(\n section: SectionInput,\n index: number,\n schema: SectionBlockSchema,\n allLeafSlugs: string[],\n): SingleResult {\n const leftColumn = section.leftColumn ?? []\n const rightColumn = section.rightColumn ?? []\n const errors: ValidationError[] = [\n ...validateLeafBlocks(leftColumn, schema, index, 'leftColumn', allLeafSlugs),\n ...validateLeafBlocks(rightColumn, schema, index, 'rightColumn', allLeafSlugs),\n ]\n\n if (errors.length > 0) return { block: null, errors }\n\n return {\n block: {\n blockType: schema.slug,\n leftColumn: leftColumn.map((leaf) => ({\n blockType: leaf.blockType,\n ...(leaf.fields ?? {}),\n })),\n rightColumn: rightColumn.map((leaf) => ({\n blockType: leaf.blockType,\n ...(leaf.fields ?? {}),\n })),\n ...(section.config ?? {}),\n },\n errors: [],\n }\n}\n\nfunction validateLeafBlocks(\n leaves: LeafBlockInput[],\n sectionSchema: SectionBlockSchema,\n sectionIndex: number,\n columnName: string,\n allLeafSlugs: string[],\n): ValidationError[] {\n const errors: ValidationError[] = []\n\n for (let i = 0; i < leaves.length; i++) {\n const leaf = leaves[i]\n\n if (!allLeafSlugs.includes(leaf.blockType)) {\n errors.push({\n sectionIndex,\n message: `Unknown leaf block type \"${leaf.blockType}\" at ${columnName}[${i}]`,\n validAlternatives: allLeafSlugs,\n })\n continue\n }\n\n if (!sectionSchema.acceptedLeafSlugs.includes(leaf.blockType)) {\n errors.push({\n sectionIndex,\n message: `Leaf block \"${leaf.blockType}\" is not allowed in section \"${sectionSchema.slug}\" at ${columnName}[${i}]`,\n validAlternatives: sectionSchema.acceptedLeafSlugs,\n })\n }\n }\n\n return errors\n}\n\nfunction validateRequiredFields(\n values: Record<string, unknown>,\n fieldSchemas: Array<{ name: string; type: string; required?: boolean }>,\n sectionIndex: number,\n): ValidationError[] {\n const errors: ValidationError[] = []\n\n for (const field of fieldSchemas) {\n if (!field.required) continue\n if (['id', 'blockName', 'blockType'].includes(field.name)) continue\n\n const value = values[field.name]\n if (value === undefined || value === null || value === '') {\n errors.push({\n sectionIndex,\n message: `Required field \"${field.name}\" is missing`,\n })\n }\n }\n\n return errors\n}\n\nfunction findBlockFieldName(\n schema: SectionBlockSchema,\n defaultName: string,\n): string {\n const hasDefault = schema.fields.some((f) => f.name === defaultName && f.type === 'blocks')\n if (hasDefault) return defaultName\n\n const blocksField = schema.fields.find((f) => f.type === 'blocks')\n if (blocksField) return blocksField.name\n\n return defaultName\n}\n"],"names":["z","leafBlockSchema","object","blockType","string","fields","record","unknown","optional","sectionSchema","sectionType","config","content","array","leftColumn","rightColumn","composeSections","sections","catalog","sectionMap","Map","map","s","slug","allLeafSlugs","leaves","l","blocks","errors","i","length","result","composeSingleSection","push","block","buildHint","availableSections","availableLeaves","sectionDetails","nestingType","acceptedLeaves","acceptedLeafSlugs","maxRows","applyOperation","composedBlocks","operation","insertIndex","existingLayout","existing","undefined","splice","section","index","get","sectionIndex","message","validAlternatives","keys","composeFixedSection","hasDualColumns","some","f","name","type","composeTwoColumnSection","composeContentSection","schema","validateRequiredFields","validateLeafBlocks","blockFieldName","findBlockFieldName","composedLeaves","leaf","columnName","includes","values","fieldSchemas","field","required","value","defaultName","hasDefault","blocksField","find"],"mappings":"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"}
|