multisite-cms-mcp 1.0.20 → 1.0.22
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/tools/get-conversion-guide.d.ts.map +1 -1
- package/dist/tools/get-conversion-guide.js +20 -19
- package/dist/tools/get-example.js +14 -14
- package/dist/tools/get-schema.d.ts.map +1 -1
- package/dist/tools/get-schema.js +43 -22
- package/dist/tools/validate-manifest.d.ts.map +1 -1
- package/dist/tools/validate-manifest.js +90 -3
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-conversion-guide.d.ts","sourceRoot":"","sources":["../../src/tools/get-conversion-guide.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"get-conversion-guide.d.ts","sourceRoot":"","sources":["../../src/tools/get-conversion-guide.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AA4tB1H;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAkD1E"}
|
|
@@ -193,34 +193,35 @@ The editor automatically detects when you're viewing a CMS path (like /blog or /
|
|
|
193
193
|
|
|
194
194
|
## Custom Collection Templates
|
|
195
195
|
|
|
196
|
-
For custom collections (beyond the built-in blog, team, downloads, authors)
|
|
196
|
+
For custom collections (beyond the built-in blog, team, downloads, authors), use the **flat format**:
|
|
197
197
|
|
|
198
198
|
\`\`\`json
|
|
199
199
|
{
|
|
200
200
|
"cmsTemplates": {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
"detailTemplate": "templates/product_detail.html"
|
|
213
|
-
}
|
|
214
|
-
}
|
|
201
|
+
// Custom collection: video
|
|
202
|
+
"videoIndex": "pages/videos.html",
|
|
203
|
+
"videoIndexPath": "/videos",
|
|
204
|
+
"videoDetail": "templates/video-detail.html",
|
|
205
|
+
"videoDetailPath": "/videos",
|
|
206
|
+
|
|
207
|
+
// Custom collection: product
|
|
208
|
+
"productIndex": "pages/shop.html",
|
|
209
|
+
"productIndexPath": "/shop",
|
|
210
|
+
"productDetail": "templates/product-detail.html",
|
|
211
|
+
"productDetailPath": "/product"
|
|
215
212
|
}
|
|
216
213
|
}
|
|
217
214
|
\`\`\`
|
|
218
215
|
|
|
219
|
-
**Path Configuration:**
|
|
220
|
-
- \`
|
|
221
|
-
- \`
|
|
216
|
+
**Path Configuration (flat format):**
|
|
217
|
+
- \`{slug}Index\` - Template file for the index/listing page
|
|
218
|
+
- \`{slug}IndexPath\` - URL for the collection list page (e.g., /videos)
|
|
219
|
+
- \`{slug}Detail\` - Template file for the detail page
|
|
220
|
+
- \`{slug}DetailPath\` - Base URL for individual item pages (e.g., /videos → /videos/item-slug)
|
|
221
|
+
|
|
222
|
+
**IMPORTANT:** The collection's internal slug is for database only. URL paths come EXCLUSIVELY from the manifest.
|
|
222
223
|
|
|
223
|
-
This allows different paths for list vs detail pages (e.g., /videos for
|
|
224
|
+
This allows same or different paths for list vs detail pages (e.g., /videos for both, or /shop for list and /product for detail).`,
|
|
224
225
|
templates: `# Template Creation Guide
|
|
225
226
|
|
|
226
227
|
## Template Types
|
|
@@ -441,30 +441,30 @@ Every custom collection item automatically has:
|
|
|
441
441
|
- \`{{url}}\` - Full URL to detail page
|
|
442
442
|
- \`{{publishedAt}}\` - Publish date (REQUIRED)
|
|
443
443
|
|
|
444
|
-
## In manifest.json
|
|
444
|
+
## In manifest.json (Flat Format)
|
|
445
445
|
|
|
446
446
|
\`\`\`json
|
|
447
447
|
{
|
|
448
448
|
"cmsTemplates": {
|
|
449
|
-
"
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
"indexTemplate": "templates/products_index.html",
|
|
454
|
-
"detailTemplate": "templates/product_detail.html"
|
|
455
|
-
}
|
|
456
|
-
}
|
|
449
|
+
"productIndex": "pages/shop.html",
|
|
450
|
+
"productIndexPath": "/shop",
|
|
451
|
+
"productDetail": "templates/product-detail.html",
|
|
452
|
+
"productDetailPath": "/product"
|
|
457
453
|
}
|
|
458
454
|
}
|
|
459
455
|
\`\`\`
|
|
460
456
|
|
|
461
|
-
**Path Configuration:**
|
|
462
|
-
- \`
|
|
463
|
-
- \`
|
|
457
|
+
**Path Configuration (flat format):**
|
|
458
|
+
- \`{slug}Index\` - Template file for the list page
|
|
459
|
+
- \`{slug}IndexPath\` - URL for the list page (e.g., /shop → lists all products)
|
|
460
|
+
- \`{slug}Detail\` - Template file for the detail page
|
|
461
|
+
- \`{slug}DetailPath\` - Base URL for detail pages (e.g., /product → /product/my-product-slug)
|
|
464
462
|
|
|
465
463
|
This serves:
|
|
466
|
-
- Collection index at \`/shop\` (lists all products)
|
|
467
|
-
- Detail pages at \`/product/product-slug\` (individual product)
|
|
464
|
+
- Collection index at \`/shop\` (lists all products using productIndex template)
|
|
465
|
+
- Detail pages at \`/product/product-slug\` (individual product using productDetail template)
|
|
466
|
+
|
|
467
|
+
**IMPORTANT:** The manifest's paths are the SINGLE SOURCE OF TRUTH. Collection slug is for database only.`,
|
|
468
468
|
form_handling: `# Form Handling
|
|
469
469
|
|
|
470
470
|
Forms are automatically captured by the CMS:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-schema.d.ts","sourceRoot":"","sources":["../../src/tools/get-schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"get-schema.d.ts","sourceRoot":"","sources":["../../src/tools/get-schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CA4ajD"}
|
package/dist/tools/get-schema.js
CHANGED
|
@@ -325,39 +325,60 @@ For HTML content that should NOT be escaped:
|
|
|
325
325
|
|
|
326
326
|
## CMS Template Configuration
|
|
327
327
|
|
|
328
|
-
Templates
|
|
328
|
+
Templates are configured in manifest.json using a **flat format** that is the SINGLE SOURCE OF TRUTH for URL paths.
|
|
329
329
|
|
|
330
|
-
###
|
|
330
|
+
### manifest.json Format
|
|
331
331
|
\`\`\`json
|
|
332
332
|
{
|
|
333
333
|
"cmsTemplates": {
|
|
334
|
-
|
|
334
|
+
// Built-in: Blog
|
|
335
|
+
"blogIndex": "pages/blog.html",
|
|
335
336
|
"blogIndexPath": "/blog",
|
|
336
|
-
"blogPost": "templates/
|
|
337
|
+
"blogPost": "templates/blog-post.html",
|
|
337
338
|
"blogPostPath": "/blog",
|
|
338
|
-
|
|
339
|
+
|
|
340
|
+
// Built-in: Team, Downloads, Authors
|
|
341
|
+
"team": "pages/team.html",
|
|
339
342
|
"teamPath": "/team",
|
|
340
|
-
"downloads": "
|
|
341
|
-
"downloadsPath": "/resources"
|
|
343
|
+
"downloads": "pages/downloads.html",
|
|
344
|
+
"downloadsPath": "/resources",
|
|
345
|
+
"authorsIndex": "pages/authors.html",
|
|
346
|
+
"authorsIndexPath": "/authors",
|
|
347
|
+
|
|
348
|
+
// Custom Collections: Use {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath
|
|
349
|
+
"videoIndex": "pages/videos.html",
|
|
350
|
+
"videoIndexPath": "/videos",
|
|
351
|
+
"videoDetail": "templates/video-detail.html",
|
|
352
|
+
"videoDetailPath": "/videos",
|
|
353
|
+
|
|
354
|
+
"serviceIndex": "pages/services.html",
|
|
355
|
+
"serviceIndexPath": "/services",
|
|
356
|
+
"serviceDetail": "templates/service-detail.html",
|
|
357
|
+
"serviceDetailPath": "/service"
|
|
342
358
|
}
|
|
343
359
|
}
|
|
344
360
|
\`\`\`
|
|
345
361
|
|
|
346
|
-
###
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
-
|
|
357
|
-
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
**
|
|
362
|
+
### Custom Collection URL Routing
|
|
363
|
+
|
|
364
|
+
**IMPORTANT:** The collection's internal slug (set in CMS) is for database only, NOT for URLs.
|
|
365
|
+
URL paths come EXCLUSIVELY from the manifest's \`{slug}IndexPath\` and \`{slug}DetailPath\`.
|
|
366
|
+
|
|
367
|
+
**Example:** Collection with slug \`video\` but paths \`/videos\` and \`/videos/:itemSlug\`:
|
|
368
|
+
- \`videoIndexPath: "/videos"\` → Index page at \`/videos\`
|
|
369
|
+
- \`videoDetailPath: "/videos"\` → Detail pages at \`/videos/my-video\`
|
|
370
|
+
|
|
371
|
+
**Different paths for index and detail:**
|
|
372
|
+
- \`serviceIndexPath: "/services"\` → Index at \`/services\`
|
|
373
|
+
- \`serviceDetailPath: "/service"\` → Detail at \`/service/my-service\`
|
|
374
|
+
|
|
375
|
+
### Template Types
|
|
376
|
+
- **{slug}Index** - Template file for the index/listing page
|
|
377
|
+
- **{slug}IndexPath** - URL path for the index page
|
|
378
|
+
- **{slug}Detail** - Template file for the detail page
|
|
379
|
+
- **{slug}DetailPath** - URL path base for detail pages (item slug appended)
|
|
380
|
+
|
|
381
|
+
**Note:** The CMS settings UI can also configure these, but manifest.json takes precedence for AI conversions.
|
|
361
382
|
|
|
362
383
|
---
|
|
363
384
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-manifest.d.ts","sourceRoot":"","sources":["../../src/tools/validate-manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate-manifest.d.ts","sourceRoot":"","sources":["../../src/tools/validate-manifest.ts"],"names":[],"mappings":"AAyCA;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4N5E"}
|
|
@@ -8,7 +8,8 @@ const pageSchema = zod_1.z.object({
|
|
|
8
8
|
title: zod_1.z.string(),
|
|
9
9
|
editable: zod_1.z.boolean().optional(),
|
|
10
10
|
});
|
|
11
|
-
|
|
11
|
+
// Built-in collection templates
|
|
12
|
+
const builtInTemplatesSchema = zod_1.z.object({
|
|
12
13
|
blogIndex: zod_1.z.string().optional(),
|
|
13
14
|
blogIndexPath: zod_1.z.string().startsWith('/').optional(),
|
|
14
15
|
blogPost: zod_1.z.string().optional(),
|
|
@@ -20,8 +21,17 @@ const cmsTemplatesSchema = zod_1.z.object({
|
|
|
20
21
|
authorsIndex: zod_1.z.string().optional(),
|
|
21
22
|
authorDetail: zod_1.z.string().optional(),
|
|
22
23
|
authorsIndexPath: zod_1.z.string().startsWith('/').optional(),
|
|
24
|
+
// Legacy format - deprecated
|
|
23
25
|
collectionPaths: zod_1.z.record(zod_1.z.string().startsWith('/')).optional(),
|
|
24
|
-
|
|
26
|
+
collectionTemplates: zod_1.z.record(zod_1.z.object({
|
|
27
|
+
path: zod_1.z.string().startsWith('/').optional(),
|
|
28
|
+
indexTemplate: zod_1.z.string().optional(),
|
|
29
|
+
detailTemplate: zod_1.z.string().optional(),
|
|
30
|
+
})).optional(),
|
|
31
|
+
});
|
|
32
|
+
// Custom collection templates use flat format: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath
|
|
33
|
+
// This schema allows any additional string keys for custom collections
|
|
34
|
+
const cmsTemplatesSchema = builtInTemplatesSchema.catchall(zod_1.z.string()).optional();
|
|
25
35
|
const manifestSchema = zod_1.z.object({
|
|
26
36
|
pages: zod_1.z.array(pageSchema),
|
|
27
37
|
cmsTemplates: cmsTemplatesSchema,
|
|
@@ -85,6 +95,7 @@ The manifest.json file is not valid JSON. Check for:
|
|
|
85
95
|
}
|
|
86
96
|
// Check cmsTemplates
|
|
87
97
|
const templates = m.cmsTemplates;
|
|
98
|
+
const customCollections = new Set();
|
|
88
99
|
if (templates) {
|
|
89
100
|
// Check template file paths
|
|
90
101
|
const templateFields = ['blogIndex', 'blogPost', 'team', 'downloads', 'authorsIndex', 'authorDetail'];
|
|
@@ -120,9 +131,85 @@ The manifest.json file is not valid JSON. Check for:
|
|
|
120
131
|
if (templates.authorDetail && !templates.authorsIndex) {
|
|
121
132
|
warnings.push('- authorDetail template defined but no authorsIndex - authors need both templates');
|
|
122
133
|
}
|
|
134
|
+
// Detect and validate custom collection templates (flat format)
|
|
135
|
+
// Pattern: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath
|
|
136
|
+
const allKeys = Object.keys(templates);
|
|
137
|
+
for (const key of allKeys) {
|
|
138
|
+
// Skip built-in keys
|
|
139
|
+
if (['blogIndex', 'blogIndexPath', 'blogPost', 'blogPostPath', 'team', 'teamPath',
|
|
140
|
+
'downloads', 'downloadsPath', 'authorsIndex', 'authorDetail', 'authorsIndexPath',
|
|
141
|
+
'collectionPaths', 'collectionTemplates'].includes(key)) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
// Extract collection slug from key pattern
|
|
145
|
+
let slug = null;
|
|
146
|
+
if (key.endsWith('Index') && !key.endsWith('IndexPath')) {
|
|
147
|
+
slug = key.slice(0, -5); // Remove 'Index'
|
|
148
|
+
}
|
|
149
|
+
else if (key.endsWith('Detail') && !key.endsWith('DetailPath')) {
|
|
150
|
+
slug = key.slice(0, -6); // Remove 'Detail'
|
|
151
|
+
}
|
|
152
|
+
else if (key.endsWith('IndexPath')) {
|
|
153
|
+
slug = key.slice(0, -9); // Remove 'IndexPath'
|
|
154
|
+
}
|
|
155
|
+
else if (key.endsWith('DetailPath')) {
|
|
156
|
+
slug = key.slice(0, -10); // Remove 'DetailPath'
|
|
157
|
+
}
|
|
158
|
+
if (slug && slug.length > 0) {
|
|
159
|
+
customCollections.add(slug);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Validate each custom collection
|
|
163
|
+
for (const slug of customCollections) {
|
|
164
|
+
const indexTemplate = templates[`${slug}Index`];
|
|
165
|
+
const detailTemplate = templates[`${slug}Detail`];
|
|
166
|
+
const indexPath = templates[`${slug}IndexPath`];
|
|
167
|
+
const detailPath = templates[`${slug}DetailPath`];
|
|
168
|
+
// Check template file paths
|
|
169
|
+
if (typeof indexTemplate === 'string') {
|
|
170
|
+
if (!indexTemplate.endsWith('.html')) {
|
|
171
|
+
warnings.push(`- cmsTemplates.${slug}Index: should end with .html (got: ${indexTemplate})`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (typeof detailTemplate === 'string') {
|
|
175
|
+
if (!detailTemplate.endsWith('.html')) {
|
|
176
|
+
warnings.push(`- cmsTemplates.${slug}Detail: should end with .html (got: ${detailTemplate})`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Check path format
|
|
180
|
+
if (typeof indexPath === 'string' && !indexPath.startsWith('/')) {
|
|
181
|
+
errors.push(`- cmsTemplates.${slug}IndexPath: must start with "/" (got: ${indexPath})`);
|
|
182
|
+
}
|
|
183
|
+
if (typeof detailPath === 'string' && !detailPath.startsWith('/')) {
|
|
184
|
+
errors.push(`- cmsTemplates.${slug}DetailPath: must start with "/" (got: ${detailPath})`);
|
|
185
|
+
}
|
|
186
|
+
// Check consistency - if you have one, you should have the others
|
|
187
|
+
if (indexTemplate && !indexPath) {
|
|
188
|
+
warnings.push(`- Custom collection "${slug}": has ${slug}Index but no ${slug}IndexPath`);
|
|
189
|
+
}
|
|
190
|
+
if (detailTemplate && !detailPath) {
|
|
191
|
+
warnings.push(`- Custom collection "${slug}": has ${slug}Detail but no ${slug}DetailPath`);
|
|
192
|
+
}
|
|
193
|
+
if (indexPath && !indexTemplate) {
|
|
194
|
+
warnings.push(`- Custom collection "${slug}": has ${slug}IndexPath but no ${slug}Index template`);
|
|
195
|
+
}
|
|
196
|
+
if (detailPath && !detailTemplate) {
|
|
197
|
+
warnings.push(`- Custom collection "${slug}": has ${slug}DetailPath but no ${slug}Detail template`);
|
|
198
|
+
}
|
|
199
|
+
// Note: indexPath and detailPath can be the same (e.g., both "/videos")
|
|
200
|
+
// The system distinguishes by whether a slug segment exists after the path
|
|
201
|
+
}
|
|
202
|
+
// Warn about deprecated collectionTemplates format
|
|
203
|
+
if (templates.collectionTemplates) {
|
|
204
|
+
warnings.push('- cmsTemplates.collectionTemplates: This nested format is deprecated. Use flat format instead: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath');
|
|
205
|
+
}
|
|
123
206
|
}
|
|
124
207
|
// Build result
|
|
125
208
|
let output = '';
|
|
209
|
+
// Build custom collections summary
|
|
210
|
+
const customCollectionsSummary = customCollections.size > 0
|
|
211
|
+
? `\n- Custom collections: ${Array.from(customCollections).join(', ')} (using flat format: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath)`
|
|
212
|
+
: '';
|
|
126
213
|
if (errors.length === 0 && warnings.length === 0) {
|
|
127
214
|
output = `✅ MANIFEST VALID
|
|
128
215
|
|
|
@@ -130,7 +217,7 @@ The manifest.json structure is correct.
|
|
|
130
217
|
|
|
131
218
|
Summary:
|
|
132
219
|
- ${m.pages?.length || 0} static page(s) defined
|
|
133
|
-
- CMS templates: ${templates ? 'configured in manifest' : 'not configured (can be set via Settings → CMS Templates after upload)'}
|
|
220
|
+
- CMS templates: ${templates ? 'configured in manifest' : 'not configured (can be set via Settings → CMS Templates after upload)'}${customCollectionsSummary}
|
|
134
221
|
- Head HTML: ${m.defaultHeadHtml ? 'configured' : 'not configured'}`;
|
|
135
222
|
}
|
|
136
223
|
else if (errors.length === 0) {
|
package/package.json
CHANGED