@strapi/content-manager 5.46.0 → 5.47.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/admin/constants/hooks.js +5 -0
- package/dist/admin/constants/hooks.js.map +1 -1
- package/dist/admin/constants/hooks.mjs +5 -0
- package/dist/admin/constants/hooks.mjs.map +1 -1
- package/dist/admin/history/components/VersionInputRenderer.js +64 -26
- package/dist/admin/history/components/VersionInputRenderer.js.map +1 -1
- package/dist/admin/history/components/VersionInputRenderer.mjs +63 -27
- package/dist/admin/history/components/VersionInputRenderer.mjs.map +1 -1
- package/dist/admin/pages/ComponentConfigurationPage.js +2 -45
- package/dist/admin/pages/ComponentConfigurationPage.js.map +1 -1
- package/dist/admin/pages/ComponentConfigurationPage.mjs +3 -46
- package/dist/admin/pages/ComponentConfigurationPage.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +4 -4
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +4 -4
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
- package/dist/admin/pages/ListConfiguration/ListConfigurationPage.js +11 -3
- package/dist/admin/pages/ListConfiguration/ListConfigurationPage.js.map +1 -1
- package/dist/admin/pages/ListConfiguration/ListConfigurationPage.mjs +11 -3
- package/dist/admin/pages/ListConfiguration/ListConfigurationPage.mjs.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.js +1 -0
- package/dist/admin/pages/ListView/ListViewPage.js.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.mjs +1 -0
- package/dist/admin/pages/ListView/ListViewPage.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.js +38 -4
- package/dist/admin/pages/ListView/components/Filters.js.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.mjs +39 -5
- package/dist/admin/pages/ListView/components/Filters.mjs.map +1 -1
- package/dist/admin/pages/formatComponentConfigurationEditLayout.js +58 -0
- package/dist/admin/pages/formatComponentConfigurationEditLayout.js.map +1 -0
- package/dist/admin/pages/formatComponentConfigurationEditLayout.mjs +56 -0
- package/dist/admin/pages/formatComponentConfigurationEditLayout.mjs.map +1 -0
- package/dist/admin/src/constants/hooks.d.ts +23 -0
- package/dist/admin/src/exports.d.ts +1 -0
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +27 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations/Relations.d.ts +9 -5
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +4 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +38 -6
- package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -5
- package/dist/admin/src/pages/ListView/components/Filters.d.ts +3 -4
- package/dist/admin/src/pages/formatComponentConfigurationEditLayout.d.ts +15 -0
- package/dist/admin/translations/cs.json.js +0 -1
- package/dist/admin/translations/cs.json.js.map +1 -1
- package/dist/admin/translations/cs.json.mjs +0 -1
- package/dist/admin/translations/cs.json.mjs.map +1 -1
- package/dist/admin/translations/de.json.js +0 -1
- package/dist/admin/translations/de.json.js.map +1 -1
- package/dist/admin/translations/de.json.mjs +0 -1
- package/dist/admin/translations/de.json.mjs.map +1 -1
- package/dist/admin/translations/en.json.js +0 -1
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +0 -1
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +0 -1
- package/dist/admin/translations/es.json.js.map +1 -1
- package/dist/admin/translations/es.json.mjs +0 -1
- package/dist/admin/translations/es.json.mjs.map +1 -1
- package/dist/admin/translations/fr.json.js +0 -1
- package/dist/admin/translations/fr.json.js.map +1 -1
- package/dist/admin/translations/fr.json.mjs +0 -1
- package/dist/admin/translations/fr.json.mjs.map +1 -1
- package/dist/admin/translations/nl.json.js +0 -1
- package/dist/admin/translations/nl.json.js.map +1 -1
- package/dist/admin/translations/nl.json.mjs +0 -1
- package/dist/admin/translations/nl.json.mjs.map +1 -1
- package/dist/admin/translations/pl.json.js +0 -1
- package/dist/admin/translations/pl.json.js.map +1 -1
- package/dist/admin/translations/pl.json.mjs +0 -1
- package/dist/admin/translations/pl.json.mjs.map +1 -1
- package/dist/admin/translations/ru.json.js +0 -1
- package/dist/admin/translations/ru.json.js.map +1 -1
- package/dist/admin/translations/ru.json.mjs +0 -1
- package/dist/admin/translations/ru.json.mjs.map +1 -1
- package/dist/admin/translations/sk.json.js +175 -9
- package/dist/admin/translations/sk.json.js.map +1 -1
- package/dist/admin/translations/sk.json.mjs +175 -9
- package/dist/admin/translations/sk.json.mjs.map +1 -1
- package/dist/admin/translations/uk.json.js +0 -1
- package/dist/admin/translations/uk.json.js.map +1 -1
- package/dist/admin/translations/uk.json.mjs +0 -1
- package/dist/admin/translations/uk.json.mjs.map +1 -1
- package/dist/admin/translations/zh-Hans.json.js +0 -1
- package/dist/admin/translations/zh-Hans.json.js.map +1 -1
- package/dist/admin/translations/zh-Hans.json.mjs +0 -1
- package/dist/admin/translations/zh-Hans.json.mjs.map +1 -1
- package/dist/server/bootstrap.js +4 -0
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/bootstrap.mjs +4 -0
- package/dist/server/bootstrap.mjs.map +1 -1
- package/dist/server/controllers/collection-types.js +9 -5
- package/dist/server/controllers/collection-types.js.map +1 -1
- package/dist/server/controllers/collection-types.mjs +10 -6
- package/dist/server/controllers/collection-types.mjs.map +1 -1
- package/dist/server/mcp/derive-content-type-mcp-tools.js +524 -0
- package/dist/server/mcp/derive-content-type-mcp-tools.js.map +1 -0
- package/dist/server/mcp/derive-content-type-mcp-tools.mjs +518 -0
- package/dist/server/mcp/derive-content-type-mcp-tools.mjs.map +1 -0
- package/dist/server/mcp/handlers/collection-handlers.js +404 -0
- package/dist/server/mcp/handlers/collection-handlers.js.map +1 -0
- package/dist/server/mcp/handlers/collection-handlers.mjs +395 -0
- package/dist/server/mcp/handlers/collection-handlers.mjs.map +1 -0
- package/dist/server/mcp/handlers/constants.js +10 -0
- package/dist/server/mcp/handlers/constants.js.map +1 -0
- package/dist/server/mcp/handlers/constants.mjs +6 -0
- package/dist/server/mcp/handlers/constants.mjs.map +1 -0
- package/dist/server/mcp/handlers/single-type-handlers.js +344 -0
- package/dist/server/mcp/handlers/single-type-handlers.js.map +1 -0
- package/dist/server/mcp/handlers/single-type-handlers.mjs +336 -0
- package/dist/server/mcp/handlers/single-type-handlers.mjs.map +1 -0
- package/dist/server/mcp/permissions.js +138 -0
- package/dist/server/mcp/permissions.js.map +1 -0
- package/dist/server/mcp/permissions.mjs +131 -0
- package/dist/server/mcp/permissions.mjs.map +1 -0
- package/dist/server/mcp/register-content-manager-mcp-tools.js +30 -0
- package/dist/server/mcp/register-content-manager-mcp-tools.js.map +1 -0
- package/dist/server/mcp/register-content-manager-mcp-tools.mjs +28 -0
- package/dist/server/mcp/register-content-manager-mcp-tools.mjs.map +1 -0
- package/dist/server/mcp/schemas/blocks-schema.js +124 -0
- package/dist/server/mcp/schemas/blocks-schema.js.map +1 -0
- package/dist/server/mcp/schemas/blocks-schema.mjs +122 -0
- package/dist/server/mcp/schemas/blocks-schema.mjs.map +1 -0
- package/dist/server/mcp/schemas/data-schema.js +252 -0
- package/dist/server/mcp/schemas/data-schema.js.map +1 -0
- package/dist/server/mcp/schemas/data-schema.mjs +248 -0
- package/dist/server/mcp/schemas/data-schema.mjs.map +1 -0
- package/dist/server/mcp/schemas/filters-schema.js +111 -0
- package/dist/server/mcp/schemas/filters-schema.js.map +1 -0
- package/dist/server/mcp/schemas/filters-schema.mjs +107 -0
- package/dist/server/mcp/schemas/filters-schema.mjs.map +1 -0
- package/dist/server/mcp/schemas/input-schemas.js +18 -0
- package/dist/server/mcp/schemas/input-schemas.js.map +1 -0
- package/dist/server/mcp/schemas/input-schemas.mjs +13 -0
- package/dist/server/mcp/schemas/input-schemas.mjs.map +1 -0
- package/dist/server/mcp/schemas/output-schemas.js +48 -0
- package/dist/server/mcp/schemas/output-schemas.js.map +1 -0
- package/dist/server/mcp/schemas/output-schemas.mjs +44 -0
- package/dist/server/mcp/schemas/output-schemas.mjs.map +1 -0
- package/dist/server/mcp/schemas/sort-schema.js +80 -0
- package/dist/server/mcp/schemas/sort-schema.js.map +1 -0
- package/dist/server/mcp/schemas/sort-schema.mjs +76 -0
- package/dist/server/mcp/schemas/sort-schema.mjs.map +1 -0
- package/dist/server/mcp/utils.js +43 -0
- package/dist/server/mcp/utils.js.map +1 -0
- package/dist/server/mcp/utils.mjs +39 -0
- package/dist/server/mcp/utils.mjs.map +1 -0
- package/dist/server/services/index.js +1 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/permission-checker.js +4 -1
- package/dist/server/services/permission-checker.js.map +1 -1
- package/dist/server/services/permission-checker.mjs +1 -1
- package/dist/server/services/permission-checker.mjs.map +1 -1
- package/dist/server/services/utils/populate.js +3 -3
- package/dist/server/services/utils/populate.js.map +1 -1
- package/dist/server/services/utils/populate.mjs +3 -3
- package/dist/server/services/utils/populate.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -3
- package/dist/server/src/mcp/derive-content-type-mcp-tools.d.ts +12 -0
- package/dist/server/src/mcp/derive-content-type-mcp-tools.d.ts.map +1 -0
- package/dist/server/src/mcp/handlers/collection-handlers.d.ts +69 -0
- package/dist/server/src/mcp/handlers/collection-handlers.d.ts.map +1 -0
- package/dist/server/src/mcp/handlers/constants.d.ts +4 -0
- package/dist/server/src/mcp/handlers/constants.d.ts.map +1 -0
- package/dist/server/src/mcp/handlers/index.d.ts +3 -0
- package/dist/server/src/mcp/handlers/index.d.ts.map +1 -0
- package/dist/server/src/mcp/handlers/single-type-handlers.d.ts +66 -0
- package/dist/server/src/mcp/handlers/single-type-handlers.d.ts.map +1 -0
- package/dist/server/src/mcp/permissions.d.ts +49 -0
- package/dist/server/src/mcp/permissions.d.ts.map +1 -0
- package/dist/server/src/mcp/register-content-manager-mcp-tools.d.ts +8 -0
- package/dist/server/src/mcp/register-content-manager-mcp-tools.d.ts.map +1 -0
- package/dist/server/src/mcp/schemas/blocks-schema.d.ts +8 -0
- package/dist/server/src/mcp/schemas/blocks-schema.d.ts.map +1 -0
- package/dist/server/src/mcp/schemas/data-schema.d.ts +36 -0
- package/dist/server/src/mcp/schemas/data-schema.d.ts.map +1 -0
- package/dist/server/src/mcp/schemas/filters-schema.d.ts +22 -0
- package/dist/server/src/mcp/schemas/filters-schema.d.ts.map +1 -0
- package/dist/server/src/mcp/schemas/index.d.ts +7 -0
- package/dist/server/src/mcp/schemas/index.d.ts.map +1 -0
- package/dist/server/src/mcp/schemas/input-schemas.d.ts +10 -0
- package/dist/server/src/mcp/schemas/input-schemas.d.ts.map +1 -0
- package/dist/server/src/mcp/schemas/output-schemas.d.ts +18 -0
- package/dist/server/src/mcp/schemas/output-schemas.d.ts.map +1 -0
- package/dist/server/src/mcp/schemas/sort-schema.d.ts +24 -0
- package/dist/server/src/mcp/schemas/sort-schema.d.ts.map +1 -0
- package/dist/server/src/mcp/types.d.ts +31 -0
- package/dist/server/src/mcp/types.d.ts.map +1 -0
- package/dist/server/src/mcp/utils.d.ts +21 -0
- package/dist/server/src/mcp/utils.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +3 -3
- package/dist/server/src/services/permission-checker.d.ts +13 -3
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
- package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/package.json +10 -8
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { z } from '@strapi/utils';
|
|
2
|
+
import { getService } from '../utils/index.mjs';
|
|
3
|
+
|
|
4
|
+
/** Returns true if the content type identified by `uid` has the i18n `localized` plugin option enabled. */ const isContentTypeLocalized = (strapi, uid)=>{
|
|
5
|
+
const ct = strapi.contentTypes?.[uid];
|
|
6
|
+
if (ct === undefined) return false;
|
|
7
|
+
return ct.pluginOptions?.i18n?.localized === true;
|
|
8
|
+
};
|
|
9
|
+
const localeDefaultDescription = (defaultLocale, allowedLocales)=>{
|
|
10
|
+
if (defaultLocale !== null && allowedLocales.includes(defaultLocale)) {
|
|
11
|
+
return `Defaults to "${defaultLocale}".`;
|
|
12
|
+
}
|
|
13
|
+
return 'Defaults to the default locale.';
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Builds the base locale Zod schema for a derived MCP tool input.
|
|
17
|
+
* When `localeCodes` is provided, constrains the field to a `z.enum` of available codes
|
|
18
|
+
* with an optional default; otherwise falls back to a plain optional string.
|
|
19
|
+
*/ const buildLocaleSchema = (localeCodes, defaultLocale)=>{
|
|
20
|
+
if (localeCodes !== null && localeCodes.length > 0) {
|
|
21
|
+
let schema = z.enum(localeCodes).optional();
|
|
22
|
+
if (defaultLocale !== null && localeCodes.includes(defaultLocale)) {
|
|
23
|
+
schema = schema.default(defaultLocale);
|
|
24
|
+
}
|
|
25
|
+
return schema.describe(`Locale code. Available: ${localeCodes.join(', ')}. ${localeDefaultDescription(defaultLocale, localeCodes)}`);
|
|
26
|
+
}
|
|
27
|
+
return z.string().optional().describe('Locale code (e.g. "en", "fr"). Defaults to the default locale.');
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Narrows the base locale schema to only locales the session is permitted to access
|
|
31
|
+
* for the given action + uid combination.
|
|
32
|
+
*
|
|
33
|
+
* Returns the base schema unchanged when:
|
|
34
|
+
* - localeCodes is null (i18n not installed)
|
|
35
|
+
* - the content type is not localized
|
|
36
|
+
* - all installed locales are permitted for this action
|
|
37
|
+
*
|
|
38
|
+
* Returns z.never().optional() when no locales are permitted, keeping the tool
|
|
39
|
+
* registered but signalling no valid locale input.
|
|
40
|
+
*/ const resolvePermittedLocaleSchema = (strapi, context, action, uid, localeCodes, defaultLocale, baseLocaleSchema)=>{
|
|
41
|
+
if (localeCodes === null) return baseLocaleSchema;
|
|
42
|
+
const isLocalized = isContentTypeLocalized(strapi, uid);
|
|
43
|
+
if (isLocalized === false) {
|
|
44
|
+
return z.string().optional().describe('This content type is not localized. Locale is ignored.');
|
|
45
|
+
}
|
|
46
|
+
const permissionChecker = getService('permission-checker').create({
|
|
47
|
+
userAbility: context.userAbility,
|
|
48
|
+
model: uid
|
|
49
|
+
});
|
|
50
|
+
const permitted = getPermittedLocales(permissionChecker, action, localeCodes);
|
|
51
|
+
if (permitted === null) return baseLocaleSchema;
|
|
52
|
+
if (permitted.length === 0) {
|
|
53
|
+
return z.never().optional().describe('No locale access for this action.');
|
|
54
|
+
}
|
|
55
|
+
let schema = z.enum(permitted).optional();
|
|
56
|
+
if (defaultLocale !== null && permitted.includes(defaultLocale)) {
|
|
57
|
+
schema = schema.default(defaultLocale);
|
|
58
|
+
}
|
|
59
|
+
return schema.describe(`Locale code. Permitted: ${permitted.join(', ')}. ${localeDefaultDescription(defaultLocale, permitted)}`);
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Recursively resolves leaf field paths for a component, matching the nested
|
|
63
|
+
* path format used by CASL rules (e.g. 'SEO.title', 'SEO.og.image').
|
|
64
|
+
*
|
|
65
|
+
* The admin RBAC system decomposes component attrs into nested paths and removes
|
|
66
|
+
* the parent key — so checking `ability.can(action, uid, 'SEO')` returns false
|
|
67
|
+
* even when the user has full access to the component's sub-fields.
|
|
68
|
+
*/ const getComponentLeafPaths = (strapi, componentUid, prefix, visited = new Set())=>{
|
|
69
|
+
if (visited.has(componentUid) === true) return [
|
|
70
|
+
prefix
|
|
71
|
+
];
|
|
72
|
+
const component = strapi.components[componentUid];
|
|
73
|
+
if (component === undefined) return [
|
|
74
|
+
prefix
|
|
75
|
+
];
|
|
76
|
+
visited.add(componentUid);
|
|
77
|
+
const paths = [];
|
|
78
|
+
for (const [key, attr] of Object.entries(component.attributes)){
|
|
79
|
+
if (key === 'id') {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const fieldPath = `${prefix}.${key}`;
|
|
83
|
+
if (attr.type === 'component' && attr.component !== undefined) {
|
|
84
|
+
paths.push(...getComponentLeafPaths(strapi, attr.component, fieldPath, visited));
|
|
85
|
+
} else {
|
|
86
|
+
paths.push(fieldPath);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
visited.delete(componentUid);
|
|
90
|
+
return paths.length > 0 ? paths : [
|
|
91
|
+
prefix
|
|
92
|
+
];
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Returns the subset of attribute keys the session may access for `action` on `uid`.
|
|
96
|
+
* Returns `null` when all fields are permitted (caller should skip field filtering).
|
|
97
|
+
* Component attributes are resolved to their nested leaf paths before checking CASL rules.
|
|
98
|
+
*/ const getPermittedFields = (strapi, userAbility, action, uid, attributes)=>{
|
|
99
|
+
const allKeys = Object.keys(attributes);
|
|
100
|
+
const permitted = allKeys.filter((key)=>{
|
|
101
|
+
if (userAbility.can(action, uid, key) === true) return true;
|
|
102
|
+
// Component attrs: CASL rules use nested paths (e.g. 'SEO.title').
|
|
103
|
+
// Check if at least one sub-field path is permitted.
|
|
104
|
+
const attr = attributes[key];
|
|
105
|
+
if (attr.type === 'component' && attr.component !== undefined) {
|
|
106
|
+
const leafPaths = getComponentLeafPaths(strapi, attr.component, key);
|
|
107
|
+
return leafPaths.some((path)=>userAbility.can(action, uid, path) === true);
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
});
|
|
111
|
+
if (permitted.length === allKeys.length) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return new Set(permitted);
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Filters `localeCodes` to only those the session may access for `action`.
|
|
118
|
+
* Returns `null` when all locales are permitted (caller should use the unfiltered base schema).
|
|
119
|
+
* Returns an empty tuple-like array when no locale is permitted.
|
|
120
|
+
*/ const getPermittedLocales = (permissionChecker, action, localeCodes)=>{
|
|
121
|
+
const permitted = localeCodes.filter((code)=>permissionChecker.cannot(action, {
|
|
122
|
+
locale: code
|
|
123
|
+
}) === false);
|
|
124
|
+
if (permitted.length === localeCodes.length) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
return permitted.length > 0 ? permitted : [];
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export { buildLocaleSchema, getComponentLeafPaths, getPermittedFields, getPermittedLocales, isContentTypeLocalized, resolvePermittedLocaleSchema };
|
|
131
|
+
//# sourceMappingURL=permissions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.mjs","sources":["../../../server/src/mcp/permissions.ts"],"sourcesContent":["import { z } from '@strapi/utils';\nimport type { Core, Modules, Struct, UID } from '@strapi/types';\n\nimport { getService } from '../utils';\nimport type { ContentManagerModelForMcp } from './types';\n\n/** Returns true if the content type identified by `uid` has the i18n `localized` plugin option enabled. */\nexport const isContentTypeLocalized = (strapi: Core.Strapi, uid: string): boolean => {\n const ct = strapi.contentTypes?.[uid as UID.ContentType];\n if (ct === undefined) return false;\n return (\n (ct as { pluginOptions?: { i18n?: { localized?: boolean } } }).pluginOptions?.i18n\n ?.localized === true\n );\n};\n\nconst localeDefaultDescription = (\n defaultLocale: string | null,\n allowedLocales: readonly string[]\n): string => {\n if (defaultLocale !== null && allowedLocales.includes(defaultLocale)) {\n return `Defaults to \"${defaultLocale}\".`;\n }\n\n return 'Defaults to the default locale.';\n};\n\n/**\n * Builds the base locale Zod schema for a derived MCP tool input.\n * When `localeCodes` is provided, constrains the field to a `z.enum` of available codes\n * with an optional default; otherwise falls back to a plain optional string.\n */\nexport const buildLocaleSchema = (\n localeCodes: [string, ...string[]] | null,\n defaultLocale: string | null\n): z.ZodTypeAny => {\n if (localeCodes !== null && localeCodes.length > 0) {\n let schema: z.ZodTypeAny = z.enum(localeCodes).optional();\n\n if (defaultLocale !== null && localeCodes.includes(defaultLocale)) {\n schema = schema.default(defaultLocale);\n }\n\n return schema.describe(\n `Locale code. Available: ${localeCodes.join(', ')}. ${localeDefaultDescription(defaultLocale, localeCodes)}`\n );\n }\n\n return z\n .string()\n .optional()\n .describe('Locale code (e.g. \"en\", \"fr\"). Defaults to the default locale.');\n};\n\n/**\n * Narrows the base locale schema to only locales the session is permitted to access\n * for the given action + uid combination.\n *\n * Returns the base schema unchanged when:\n * - localeCodes is null (i18n not installed)\n * - the content type is not localized\n * - all installed locales are permitted for this action\n *\n * Returns z.never().optional() when no locales are permitted, keeping the tool\n * registered but signalling no valid locale input.\n */\nexport const resolvePermittedLocaleSchema = (\n strapi: Core.Strapi,\n context: Modules.MCP.McpHandlerContext,\n action: string,\n uid: string,\n localeCodes: [string, ...string[]] | null,\n defaultLocale: string | null,\n baseLocaleSchema: z.ZodTypeAny\n): z.ZodTypeAny => {\n if (localeCodes === null) return baseLocaleSchema;\n\n const isLocalized = isContentTypeLocalized(strapi, uid);\n if (isLocalized === false) {\n return z.string().optional().describe('This content type is not localized. Locale is ignored.');\n }\n\n const permissionChecker = getService('permission-checker').create({\n userAbility: context.userAbility,\n model: uid,\n });\n const permitted = getPermittedLocales(permissionChecker, action, localeCodes);\n if (permitted === null) return baseLocaleSchema;\n if (permitted.length === 0) {\n return z.never().optional().describe('No locale access for this action.');\n }\n\n let schema: z.ZodTypeAny = z.enum(permitted).optional();\n\n if (defaultLocale !== null && permitted.includes(defaultLocale)) {\n schema = schema.default(defaultLocale);\n }\n\n return schema.describe(\n `Locale code. Permitted: ${permitted.join(', ')}. ${localeDefaultDescription(defaultLocale, permitted)}`\n );\n};\n\n/**\n * Recursively resolves leaf field paths for a component, matching the nested\n * path format used by CASL rules (e.g. 'SEO.title', 'SEO.og.image').\n *\n * The admin RBAC system decomposes component attrs into nested paths and removes\n * the parent key — so checking `ability.can(action, uid, 'SEO')` returns false\n * even when the user has full access to the component's sub-fields.\n */\nexport const getComponentLeafPaths = (\n strapi: Core.Strapi,\n componentUid: string,\n prefix: string,\n visited: Set<string> = new Set()\n): string[] => {\n if (visited.has(componentUid) === true) return [prefix];\n\n type ComponentEntry = { attributes: Record<string, { type: string; component?: string }> };\n const component = (strapi.components as unknown as Record<string, ComponentEntry | undefined>)[\n componentUid\n ];\n if (component === undefined) return [prefix];\n\n visited.add(componentUid);\n const paths: string[] = [];\n\n for (const [key, attr] of Object.entries(component.attributes)) {\n if (key === 'id') {\n // skip system id field — it is not a user-facing permission path\n // eslint-disable-next-line no-continue\n continue;\n }\n const fieldPath = `${prefix}.${key}`;\n\n if (attr.type === 'component' && attr.component !== undefined) {\n paths.push(...getComponentLeafPaths(strapi, attr.component, fieldPath, visited));\n } else {\n paths.push(fieldPath);\n }\n }\n\n visited.delete(componentUid);\n\n return paths.length > 0 ? paths : [prefix];\n};\n\n/**\n * Returns the subset of attribute keys the session may access for `action` on `uid`.\n * Returns `null` when all fields are permitted (caller should skip field filtering).\n * Component attributes are resolved to their nested leaf paths before checking CASL rules.\n */\nexport const getPermittedFields = (\n strapi: Core.Strapi,\n userAbility: Modules.MCP.McpHandlerContext['userAbility'],\n action: string,\n uid: string,\n attributes: Struct.SchemaAttributes\n): Set<string> | null => {\n const allKeys = Object.keys(attributes);\n const permitted = allKeys.filter((key) => {\n if (userAbility.can(action, uid, key) === true) return true;\n\n // Component attrs: CASL rules use nested paths (e.g. 'SEO.title').\n // Check if at least one sub-field path is permitted.\n const attr = attributes[key] as { type: string; component?: string };\n if (attr.type === 'component' && attr.component !== undefined) {\n const leafPaths = getComponentLeafPaths(strapi, attr.component, key);\n return leafPaths.some((path) => userAbility.can(action, uid, path) === true);\n }\n\n return false;\n });\n\n if (permitted.length === allKeys.length) {\n return null;\n }\n\n return new Set(permitted);\n};\n\n/**\n * Filters `localeCodes` to only those the session may access for `action`.\n * Returns `null` when all locales are permitted (caller should use the unfiltered base schema).\n * Returns an empty tuple-like array when no locale is permitted.\n */\nexport const getPermittedLocales = (\n permissionChecker: { cannot: (action: string, entity?: unknown) => boolean },\n action: string,\n localeCodes: [string, ...string[]]\n): [string, ...string[]] | null => {\n const permitted = localeCodes.filter(\n (code) => permissionChecker.cannot(action, { locale: code }) === false\n );\n\n if (permitted.length === localeCodes.length) {\n return null;\n }\n\n return permitted.length > 0\n ? (permitted as [string, ...string[]])\n : ([] as unknown as [string, ...string[]]);\n};\n\n// Re-export for use in handler files (avoids needing to import from permissions in each handler)\nexport type { ContentManagerModelForMcp };\n"],"names":["isContentTypeLocalized","strapi","uid","ct","contentTypes","undefined","pluginOptions","i18n","localized","localeDefaultDescription","defaultLocale","allowedLocales","includes","buildLocaleSchema","localeCodes","length","schema","z","enum","optional","default","describe","join","string","resolvePermittedLocaleSchema","context","action","baseLocaleSchema","isLocalized","permissionChecker","getService","create","userAbility","model","permitted","getPermittedLocales","never","getComponentLeafPaths","componentUid","prefix","visited","Set","has","component","components","add","paths","key","attr","Object","entries","attributes","fieldPath","type","push","delete","getPermittedFields","allKeys","keys","filter","can","leafPaths","some","path","code","cannot","locale"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var deriveContentTypeMcpTools = require('./derive-content-type-mcp-tools.js');
|
|
4
|
+
var index = require('../utils/index.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Registers derived content-type MCP tools during plugin bootstrap, before the MCP HTTP server starts.
|
|
8
|
+
*/ const registerContentManagerMcpTools = async ({ strapi })=>{
|
|
9
|
+
if (strapi.ai.mcp.isEnabled() !== true) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const i18nPlugin = strapi.plugin('i18n');
|
|
13
|
+
let localeCodes = null;
|
|
14
|
+
let defaultLocale = null;
|
|
15
|
+
if (i18nPlugin !== undefined) {
|
|
16
|
+
localeCodes = (await i18nPlugin.service('locales').find()).map((locale)=>locale.code);
|
|
17
|
+
defaultLocale = await i18nPlugin.service('locales').getDefaultLocale();
|
|
18
|
+
}
|
|
19
|
+
const models = index.getService('content-types').findDisplayedContentTypes();
|
|
20
|
+
const tools = deriveContentTypeMcpTools.deriveDisplayedContentTypeMcpToolDefinitions(strapi, models, {
|
|
21
|
+
localeCodes,
|
|
22
|
+
defaultLocale
|
|
23
|
+
});
|
|
24
|
+
for (const tool of tools){
|
|
25
|
+
strapi.ai.mcp.registerTool(tool);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
exports.registerContentManagerMcpTools = registerContentManagerMcpTools;
|
|
30
|
+
//# sourceMappingURL=register-content-manager-mcp-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-content-manager-mcp-tools.js","sources":["../../../server/src/mcp/register-content-manager-mcp-tools.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { deriveDisplayedContentTypeMcpToolDefinitions } from './derive-content-type-mcp-tools';\nimport { getService } from '../utils';\n\n/**\n * Registers derived content-type MCP tools during plugin bootstrap, before the MCP HTTP server starts.\n */\nexport const registerContentManagerMcpTools = async ({\n strapi,\n}: {\n strapi: Core.Strapi;\n}): Promise<void> => {\n if (strapi.ai.mcp.isEnabled() !== true) {\n return;\n }\n\n const i18nPlugin = strapi.plugin('i18n');\n\n let localeCodes = null;\n let defaultLocale: string | null = null;\n if (i18nPlugin !== undefined) {\n localeCodes = (await i18nPlugin.service('locales').find()).map(\n (locale: { code: string }) => locale.code\n ) as [string, ...string[]];\n defaultLocale = await i18nPlugin.service('locales').getDefaultLocale();\n }\n\n const models = getService('content-types').findDisplayedContentTypes();\n const tools = deriveDisplayedContentTypeMcpToolDefinitions(strapi, models, {\n localeCodes,\n defaultLocale,\n });\n\n for (const tool of tools) {\n strapi.ai.mcp.registerTool(tool);\n }\n};\n"],"names":["registerContentManagerMcpTools","strapi","ai","mcp","isEnabled","i18nPlugin","plugin","localeCodes","defaultLocale","undefined","service","find","map","locale","code","getDefaultLocale","models","getService","findDisplayedContentTypes","tools","deriveDisplayedContentTypeMcpToolDefinitions","tool","registerTool"],"mappings":";;;;;AAKA;;AAEC,IACM,MAAMA,8BAAAA,GAAiC,OAAO,EACnDC,MAAM,EAGP,GAAA;AACC,IAAA,IAAIA,OAAOC,EAAE,CAACC,GAAG,CAACC,SAAS,OAAO,IAAA,EAAM;AACtC,QAAA;AACF,IAAA;IAEA,MAAMC,UAAAA,GAAaJ,MAAAA,CAAOK,MAAM,CAAC,MAAA,CAAA;AAEjC,IAAA,IAAIC,WAAAA,GAAc,IAAA;AAClB,IAAA,IAAIC,aAAAA,GAA+B,IAAA;AACnC,IAAA,IAAIH,eAAeI,SAAAA,EAAW;AAC5BF,QAAAA,WAAAA,GAAc,CAAC,MAAMF,UAAAA,CAAWK,OAAO,CAAC,SAAA,CAAA,CAAWC,IAAI,EAAC,EAAGC,GAAG,CAC5D,CAACC,MAAAA,GAA6BA,OAAOC,IAAI,CAAA;AAE3CN,QAAAA,aAAAA,GAAgB,MAAMH,UAAAA,CAAWK,OAAO,CAAC,WAAWK,gBAAgB,EAAA;AACtE,IAAA;IAEA,MAAMC,MAAAA,GAASC,gBAAAA,CAAW,eAAA,CAAA,CAAiBC,yBAAyB,EAAA;IACpE,MAAMC,KAAAA,GAAQC,sEAAAA,CAA6CnB,MAAAA,EAAQe,MAAAA,EAAQ;AACzET,QAAAA,WAAAA;AACAC,QAAAA;AACF,KAAA,CAAA;IAEA,KAAK,MAAMa,QAAQF,KAAAA,CAAO;AACxBlB,QAAAA,MAAAA,CAAOC,EAAE,CAACC,GAAG,CAACmB,YAAY,CAACD,IAAAA,CAAAA;AAC7B,IAAA;AACF;;;;"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { deriveDisplayedContentTypeMcpToolDefinitions } from './derive-content-type-mcp-tools.mjs';
|
|
2
|
+
import { getService } from '../utils/index.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Registers derived content-type MCP tools during plugin bootstrap, before the MCP HTTP server starts.
|
|
6
|
+
*/ const registerContentManagerMcpTools = async ({ strapi })=>{
|
|
7
|
+
if (strapi.ai.mcp.isEnabled() !== true) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const i18nPlugin = strapi.plugin('i18n');
|
|
11
|
+
let localeCodes = null;
|
|
12
|
+
let defaultLocale = null;
|
|
13
|
+
if (i18nPlugin !== undefined) {
|
|
14
|
+
localeCodes = (await i18nPlugin.service('locales').find()).map((locale)=>locale.code);
|
|
15
|
+
defaultLocale = await i18nPlugin.service('locales').getDefaultLocale();
|
|
16
|
+
}
|
|
17
|
+
const models = getService('content-types').findDisplayedContentTypes();
|
|
18
|
+
const tools = deriveDisplayedContentTypeMcpToolDefinitions(strapi, models, {
|
|
19
|
+
localeCodes,
|
|
20
|
+
defaultLocale
|
|
21
|
+
});
|
|
22
|
+
for (const tool of tools){
|
|
23
|
+
strapi.ai.mcp.registerTool(tool);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export { registerContentManagerMcpTools };
|
|
28
|
+
//# sourceMappingURL=register-content-manager-mcp-tools.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-content-manager-mcp-tools.mjs","sources":["../../../server/src/mcp/register-content-manager-mcp-tools.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { deriveDisplayedContentTypeMcpToolDefinitions } from './derive-content-type-mcp-tools';\nimport { getService } from '../utils';\n\n/**\n * Registers derived content-type MCP tools during plugin bootstrap, before the MCP HTTP server starts.\n */\nexport const registerContentManagerMcpTools = async ({\n strapi,\n}: {\n strapi: Core.Strapi;\n}): Promise<void> => {\n if (strapi.ai.mcp.isEnabled() !== true) {\n return;\n }\n\n const i18nPlugin = strapi.plugin('i18n');\n\n let localeCodes = null;\n let defaultLocale: string | null = null;\n if (i18nPlugin !== undefined) {\n localeCodes = (await i18nPlugin.service('locales').find()).map(\n (locale: { code: string }) => locale.code\n ) as [string, ...string[]];\n defaultLocale = await i18nPlugin.service('locales').getDefaultLocale();\n }\n\n const models = getService('content-types').findDisplayedContentTypes();\n const tools = deriveDisplayedContentTypeMcpToolDefinitions(strapi, models, {\n localeCodes,\n defaultLocale,\n });\n\n for (const tool of tools) {\n strapi.ai.mcp.registerTool(tool);\n }\n};\n"],"names":["registerContentManagerMcpTools","strapi","ai","mcp","isEnabled","i18nPlugin","plugin","localeCodes","defaultLocale","undefined","service","find","map","locale","code","getDefaultLocale","models","getService","findDisplayedContentTypes","tools","deriveDisplayedContentTypeMcpToolDefinitions","tool","registerTool"],"mappings":";;;AAKA;;AAEC,IACM,MAAMA,8BAAAA,GAAiC,OAAO,EACnDC,MAAM,EAGP,GAAA;AACC,IAAA,IAAIA,OAAOC,EAAE,CAACC,GAAG,CAACC,SAAS,OAAO,IAAA,EAAM;AACtC,QAAA;AACF,IAAA;IAEA,MAAMC,UAAAA,GAAaJ,MAAAA,CAAOK,MAAM,CAAC,MAAA,CAAA;AAEjC,IAAA,IAAIC,WAAAA,GAAc,IAAA;AAClB,IAAA,IAAIC,aAAAA,GAA+B,IAAA;AACnC,IAAA,IAAIH,eAAeI,SAAAA,EAAW;AAC5BF,QAAAA,WAAAA,GAAc,CAAC,MAAMF,UAAAA,CAAWK,OAAO,CAAC,SAAA,CAAA,CAAWC,IAAI,EAAC,EAAGC,GAAG,CAC5D,CAACC,MAAAA,GAA6BA,OAAOC,IAAI,CAAA;AAE3CN,QAAAA,aAAAA,GAAgB,MAAMH,UAAAA,CAAWK,OAAO,CAAC,WAAWK,gBAAgB,EAAA;AACtE,IAAA;IAEA,MAAMC,MAAAA,GAASC,UAAAA,CAAW,eAAA,CAAA,CAAiBC,yBAAyB,EAAA;IACpE,MAAMC,KAAAA,GAAQC,4CAAAA,CAA6CnB,MAAAA,EAAQe,MAAAA,EAAQ;AACzET,QAAAA,WAAAA;AACAC,QAAAA;AACF,KAAA,CAAA;IAEA,KAAK,MAAMa,QAAQF,KAAAA,CAAO;AACxBlB,QAAAA,MAAAA,CAAOC,EAAE,CAACC,GAAG,CAACmB,YAAY,CAACD,IAAAA,CAAAA;AAC7B,IAAA;AACF;;;;"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var strapiUtils = require('@strapi/utils');
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Inline nodes
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const textNodeSchema = strapiUtils.z.object({
|
|
9
|
+
type: strapiUtils.z.literal('text'),
|
|
10
|
+
text: strapiUtils.z.string().describe('The text content.'),
|
|
11
|
+
bold: strapiUtils.z.boolean().optional(),
|
|
12
|
+
italic: strapiUtils.z.boolean().optional(),
|
|
13
|
+
underline: strapiUtils.z.boolean().optional(),
|
|
14
|
+
strikethrough: strapiUtils.z.boolean().optional(),
|
|
15
|
+
code: strapiUtils.z.boolean().optional()
|
|
16
|
+
}).describe('A text node with optional formatting marks.');
|
|
17
|
+
const linkNodeSchema = strapiUtils.z.object({
|
|
18
|
+
type: strapiUtils.z.literal('link'),
|
|
19
|
+
url: strapiUtils.z.string().describe('The URL the link points to.'),
|
|
20
|
+
children: strapiUtils.z.array(textNodeSchema).min(1)
|
|
21
|
+
}).describe('An inline link node. Children must be text nodes.');
|
|
22
|
+
const inlineNodeSchema = strapiUtils.z.discriminatedUnion('type', [
|
|
23
|
+
textNodeSchema,
|
|
24
|
+
linkNodeSchema
|
|
25
|
+
]);
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Root block nodes
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
const paragraphSchema = strapiUtils.z.object({
|
|
30
|
+
type: strapiUtils.z.literal('paragraph'),
|
|
31
|
+
children: strapiUtils.z.array(inlineNodeSchema).min(1)
|
|
32
|
+
});
|
|
33
|
+
const headingSchema = strapiUtils.z.object({
|
|
34
|
+
type: strapiUtils.z.literal('heading'),
|
|
35
|
+
level: strapiUtils.z.union([
|
|
36
|
+
strapiUtils.z.literal(1),
|
|
37
|
+
strapiUtils.z.literal(2),
|
|
38
|
+
strapiUtils.z.literal(3),
|
|
39
|
+
strapiUtils.z.literal(4),
|
|
40
|
+
strapiUtils.z.literal(5),
|
|
41
|
+
strapiUtils.z.literal(6)
|
|
42
|
+
]),
|
|
43
|
+
children: strapiUtils.z.array(inlineNodeSchema).min(1)
|
|
44
|
+
});
|
|
45
|
+
const quoteSchema = strapiUtils.z.object({
|
|
46
|
+
type: strapiUtils.z.literal('quote'),
|
|
47
|
+
children: strapiUtils.z.array(inlineNodeSchema).min(1)
|
|
48
|
+
});
|
|
49
|
+
const codeSchema = strapiUtils.z.object({
|
|
50
|
+
type: strapiUtils.z.literal('code'),
|
|
51
|
+
language: strapiUtils.z.string().nullable().optional().describe('Programming language identifier (e.g. "javascript", "python").'),
|
|
52
|
+
children: strapiUtils.z.array(textNodeSchema).min(1)
|
|
53
|
+
});
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// List nodes (recursive via z.lazy — mirrors yup.lazy in blocks-validator.ts)
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
const listItemSchema = strapiUtils.z.object({
|
|
58
|
+
type: strapiUtils.z.literal('list-item'),
|
|
59
|
+
children: strapiUtils.z.array(inlineNodeSchema).min(1)
|
|
60
|
+
});
|
|
61
|
+
// ZodType annotation is required because of the self-reference via z.lazy
|
|
62
|
+
const listSchema = strapiUtils.z.object({
|
|
63
|
+
type: strapiUtils.z.literal('list'),
|
|
64
|
+
format: strapiUtils.z.enum([
|
|
65
|
+
'ordered',
|
|
66
|
+
'unordered'
|
|
67
|
+
]),
|
|
68
|
+
indentLevel: strapiUtils.z.number().optional(),
|
|
69
|
+
children: strapiUtils.z.array(strapiUtils.z.lazy(()=>strapiUtils.z.union([
|
|
70
|
+
listItemSchema,
|
|
71
|
+
listSchema
|
|
72
|
+
]))).min(1).describe('Children must be list-item or nested list nodes.')
|
|
73
|
+
});
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Image block
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
const imageSchema = strapiUtils.z.object({
|
|
78
|
+
type: strapiUtils.z.literal('image'),
|
|
79
|
+
image: strapiUtils.z.object({
|
|
80
|
+
name: strapiUtils.z.string(),
|
|
81
|
+
alternativeText: strapiUtils.z.string().nullable().optional(),
|
|
82
|
+
url: strapiUtils.z.string(),
|
|
83
|
+
caption: strapiUtils.z.string().nullable().optional(),
|
|
84
|
+
width: strapiUtils.z.number(),
|
|
85
|
+
height: strapiUtils.z.number(),
|
|
86
|
+
formats: strapiUtils.z.record(strapiUtils.z.string(), strapiUtils.z.unknown()).nullable().optional(),
|
|
87
|
+
hash: strapiUtils.z.string(),
|
|
88
|
+
ext: strapiUtils.z.string(),
|
|
89
|
+
mime: strapiUtils.z.string(),
|
|
90
|
+
size: strapiUtils.z.number(),
|
|
91
|
+
previewUrl: strapiUtils.z.string().nullable().optional(),
|
|
92
|
+
provider: strapiUtils.z.string(),
|
|
93
|
+
provider_metadata: strapiUtils.z.unknown().nullable().optional(),
|
|
94
|
+
createdAt: strapiUtils.z.string(),
|
|
95
|
+
updatedAt: strapiUtils.z.string()
|
|
96
|
+
}).describe('An existing media asset. Use media tools to retrieve this data — MCP cannot upload files.'),
|
|
97
|
+
children: strapiUtils.z.array(strapiUtils.z.object({
|
|
98
|
+
type: strapiUtils.z.literal('text'),
|
|
99
|
+
text: strapiUtils.z.literal('')
|
|
100
|
+
})).length(1)
|
|
101
|
+
});
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Top-level schema
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
const blockNodeSchema = strapiUtils.z.discriminatedUnion('type', [
|
|
106
|
+
paragraphSchema,
|
|
107
|
+
headingSchema,
|
|
108
|
+
quoteSchema,
|
|
109
|
+
codeSchema,
|
|
110
|
+
imageSchema
|
|
111
|
+
]);
|
|
112
|
+
/**
|
|
113
|
+
* Returns the Zod schema for a Strapi Blocks (rich-text) field input.
|
|
114
|
+
* Accepts an array of block nodes — paragraph, heading, quote, code, image, and list —
|
|
115
|
+
* matching Strapi's internal blocks data model.
|
|
116
|
+
*/ const buildBlocksInputSchema = ()=>strapiUtils.z.array(// listSchema uses z.lazy so it cannot participate in discriminatedUnion;
|
|
117
|
+
// use a regular union to merge it back in.
|
|
118
|
+
strapiUtils.z.union([
|
|
119
|
+
blockNodeSchema,
|
|
120
|
+
listSchema
|
|
121
|
+
])).describe('An array of block nodes representing structured rich text content.');
|
|
122
|
+
|
|
123
|
+
exports.buildBlocksInputSchema = buildBlocksInputSchema;
|
|
124
|
+
//# sourceMappingURL=blocks-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks-schema.js","sources":["../../../../server/src/mcp/schemas/blocks-schema.ts"],"sourcesContent":["import { z } from '@strapi/utils';\n\n// ---------------------------------------------------------------------------\n// Inline nodes\n// ---------------------------------------------------------------------------\n\nconst textNodeSchema = z\n .object({\n type: z.literal('text'),\n text: z.string().describe('The text content.'),\n bold: z.boolean().optional(),\n italic: z.boolean().optional(),\n underline: z.boolean().optional(),\n strikethrough: z.boolean().optional(),\n code: z.boolean().optional(),\n })\n .describe('A text node with optional formatting marks.');\n\nconst linkNodeSchema = z\n .object({\n type: z.literal('link'),\n url: z.string().describe('The URL the link points to.'),\n children: z.array(textNodeSchema).min(1),\n })\n .describe('An inline link node. Children must be text nodes.');\n\nconst inlineNodeSchema = z.discriminatedUnion('type', [textNodeSchema, linkNodeSchema]);\n\n// ---------------------------------------------------------------------------\n// Root block nodes\n// ---------------------------------------------------------------------------\n\nconst paragraphSchema = z.object({\n type: z.literal('paragraph'),\n children: z.array(inlineNodeSchema).min(1),\n});\n\nconst headingSchema = z.object({\n type: z.literal('heading'),\n level: z.union([\n z.literal(1),\n z.literal(2),\n z.literal(3),\n z.literal(4),\n z.literal(5),\n z.literal(6),\n ]),\n children: z.array(inlineNodeSchema).min(1),\n});\n\nconst quoteSchema = z.object({\n type: z.literal('quote'),\n children: z.array(inlineNodeSchema).min(1),\n});\n\nconst codeSchema = z.object({\n type: z.literal('code'),\n language: z\n .string()\n .nullable()\n .optional()\n .describe('Programming language identifier (e.g. \"javascript\", \"python\").'),\n children: z.array(textNodeSchema).min(1),\n});\n\n// ---------------------------------------------------------------------------\n// List nodes (recursive via z.lazy — mirrors yup.lazy in blocks-validator.ts)\n// ---------------------------------------------------------------------------\n\nconst listItemSchema = z.object({\n type: z.literal('list-item'),\n children: z.array(inlineNodeSchema).min(1),\n});\n\n// ZodType annotation is required because of the self-reference via z.lazy\nconst listSchema: z.ZodType = z.object({\n type: z.literal('list'),\n format: z.enum(['ordered', 'unordered']),\n indentLevel: z.number().optional(),\n children: z\n .array(z.lazy(() => z.union([listItemSchema, listSchema])))\n .min(1)\n .describe('Children must be list-item or nested list nodes.'),\n});\n\n// ---------------------------------------------------------------------------\n// Image block\n// ---------------------------------------------------------------------------\n\nconst imageSchema = z.object({\n type: z.literal('image'),\n image: z\n .object({\n name: z.string(),\n alternativeText: z.string().nullable().optional(),\n url: z.string(),\n caption: z.string().nullable().optional(),\n width: z.number(),\n height: z.number(),\n formats: z.record(z.string(), z.unknown()).nullable().optional(),\n hash: z.string(),\n ext: z.string(),\n mime: z.string(),\n size: z.number(),\n previewUrl: z.string().nullable().optional(),\n provider: z.string(),\n provider_metadata: z.unknown().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .describe(\n 'An existing media asset. Use media tools to retrieve this data — MCP cannot upload files.'\n ),\n children: z.array(z.object({ type: z.literal('text'), text: z.literal('') })).length(1),\n});\n\n// ---------------------------------------------------------------------------\n// Top-level schema\n// ---------------------------------------------------------------------------\n\nconst blockNodeSchema = z.discriminatedUnion('type', [\n paragraphSchema,\n headingSchema,\n quoteSchema,\n codeSchema,\n imageSchema,\n]);\n\n/**\n * Returns the Zod schema for a Strapi Blocks (rich-text) field input.\n * Accepts an array of block nodes — paragraph, heading, quote, code, image, and list —\n * matching Strapi's internal blocks data model.\n */\nexport const buildBlocksInputSchema = (): z.ZodArray<z.ZodTypeAny> =>\n z\n .array(\n // listSchema uses z.lazy so it cannot participate in discriminatedUnion;\n // use a regular union to merge it back in.\n z.union([blockNodeSchema, listSchema])\n )\n .describe('An array of block nodes representing structured rich text content.');\n"],"names":["textNodeSchema","z","object","type","literal","text","string","describe","bold","boolean","optional","italic","underline","strikethrough","code","linkNodeSchema","url","children","array","min","inlineNodeSchema","discriminatedUnion","paragraphSchema","headingSchema","level","union","quoteSchema","codeSchema","language","nullable","listItemSchema","listSchema","format","enum","indentLevel","number","lazy","imageSchema","image","name","alternativeText","caption","width","height","formats","record","unknown","hash","ext","mime","size","previewUrl","provider","provider_metadata","createdAt","updatedAt","length","blockNodeSchema","buildBlocksInputSchema"],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { z } from '@strapi/utils';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Inline nodes
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const textNodeSchema = z.object({
|
|
7
|
+
type: z.literal('text'),
|
|
8
|
+
text: z.string().describe('The text content.'),
|
|
9
|
+
bold: z.boolean().optional(),
|
|
10
|
+
italic: z.boolean().optional(),
|
|
11
|
+
underline: z.boolean().optional(),
|
|
12
|
+
strikethrough: z.boolean().optional(),
|
|
13
|
+
code: z.boolean().optional()
|
|
14
|
+
}).describe('A text node with optional formatting marks.');
|
|
15
|
+
const linkNodeSchema = z.object({
|
|
16
|
+
type: z.literal('link'),
|
|
17
|
+
url: z.string().describe('The URL the link points to.'),
|
|
18
|
+
children: z.array(textNodeSchema).min(1)
|
|
19
|
+
}).describe('An inline link node. Children must be text nodes.');
|
|
20
|
+
const inlineNodeSchema = z.discriminatedUnion('type', [
|
|
21
|
+
textNodeSchema,
|
|
22
|
+
linkNodeSchema
|
|
23
|
+
]);
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Root block nodes
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
const paragraphSchema = z.object({
|
|
28
|
+
type: z.literal('paragraph'),
|
|
29
|
+
children: z.array(inlineNodeSchema).min(1)
|
|
30
|
+
});
|
|
31
|
+
const headingSchema = z.object({
|
|
32
|
+
type: z.literal('heading'),
|
|
33
|
+
level: z.union([
|
|
34
|
+
z.literal(1),
|
|
35
|
+
z.literal(2),
|
|
36
|
+
z.literal(3),
|
|
37
|
+
z.literal(4),
|
|
38
|
+
z.literal(5),
|
|
39
|
+
z.literal(6)
|
|
40
|
+
]),
|
|
41
|
+
children: z.array(inlineNodeSchema).min(1)
|
|
42
|
+
});
|
|
43
|
+
const quoteSchema = z.object({
|
|
44
|
+
type: z.literal('quote'),
|
|
45
|
+
children: z.array(inlineNodeSchema).min(1)
|
|
46
|
+
});
|
|
47
|
+
const codeSchema = z.object({
|
|
48
|
+
type: z.literal('code'),
|
|
49
|
+
language: z.string().nullable().optional().describe('Programming language identifier (e.g. "javascript", "python").'),
|
|
50
|
+
children: z.array(textNodeSchema).min(1)
|
|
51
|
+
});
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// List nodes (recursive via z.lazy — mirrors yup.lazy in blocks-validator.ts)
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
const listItemSchema = z.object({
|
|
56
|
+
type: z.literal('list-item'),
|
|
57
|
+
children: z.array(inlineNodeSchema).min(1)
|
|
58
|
+
});
|
|
59
|
+
// ZodType annotation is required because of the self-reference via z.lazy
|
|
60
|
+
const listSchema = z.object({
|
|
61
|
+
type: z.literal('list'),
|
|
62
|
+
format: z.enum([
|
|
63
|
+
'ordered',
|
|
64
|
+
'unordered'
|
|
65
|
+
]),
|
|
66
|
+
indentLevel: z.number().optional(),
|
|
67
|
+
children: z.array(z.lazy(()=>z.union([
|
|
68
|
+
listItemSchema,
|
|
69
|
+
listSchema
|
|
70
|
+
]))).min(1).describe('Children must be list-item or nested list nodes.')
|
|
71
|
+
});
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Image block
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
const imageSchema = z.object({
|
|
76
|
+
type: z.literal('image'),
|
|
77
|
+
image: z.object({
|
|
78
|
+
name: z.string(),
|
|
79
|
+
alternativeText: z.string().nullable().optional(),
|
|
80
|
+
url: z.string(),
|
|
81
|
+
caption: z.string().nullable().optional(),
|
|
82
|
+
width: z.number(),
|
|
83
|
+
height: z.number(),
|
|
84
|
+
formats: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
85
|
+
hash: z.string(),
|
|
86
|
+
ext: z.string(),
|
|
87
|
+
mime: z.string(),
|
|
88
|
+
size: z.number(),
|
|
89
|
+
previewUrl: z.string().nullable().optional(),
|
|
90
|
+
provider: z.string(),
|
|
91
|
+
provider_metadata: z.unknown().nullable().optional(),
|
|
92
|
+
createdAt: z.string(),
|
|
93
|
+
updatedAt: z.string()
|
|
94
|
+
}).describe('An existing media asset. Use media tools to retrieve this data — MCP cannot upload files.'),
|
|
95
|
+
children: z.array(z.object({
|
|
96
|
+
type: z.literal('text'),
|
|
97
|
+
text: z.literal('')
|
|
98
|
+
})).length(1)
|
|
99
|
+
});
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Top-level schema
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
const blockNodeSchema = z.discriminatedUnion('type', [
|
|
104
|
+
paragraphSchema,
|
|
105
|
+
headingSchema,
|
|
106
|
+
quoteSchema,
|
|
107
|
+
codeSchema,
|
|
108
|
+
imageSchema
|
|
109
|
+
]);
|
|
110
|
+
/**
|
|
111
|
+
* Returns the Zod schema for a Strapi Blocks (rich-text) field input.
|
|
112
|
+
* Accepts an array of block nodes — paragraph, heading, quote, code, image, and list —
|
|
113
|
+
* matching Strapi's internal blocks data model.
|
|
114
|
+
*/ const buildBlocksInputSchema = ()=>z.array(// listSchema uses z.lazy so it cannot participate in discriminatedUnion;
|
|
115
|
+
// use a regular union to merge it back in.
|
|
116
|
+
z.union([
|
|
117
|
+
blockNodeSchema,
|
|
118
|
+
listSchema
|
|
119
|
+
])).describe('An array of block nodes representing structured rich text content.');
|
|
120
|
+
|
|
121
|
+
export { buildBlocksInputSchema };
|
|
122
|
+
//# sourceMappingURL=blocks-schema.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks-schema.mjs","sources":["../../../../server/src/mcp/schemas/blocks-schema.ts"],"sourcesContent":["import { z } from '@strapi/utils';\n\n// ---------------------------------------------------------------------------\n// Inline nodes\n// ---------------------------------------------------------------------------\n\nconst textNodeSchema = z\n .object({\n type: z.literal('text'),\n text: z.string().describe('The text content.'),\n bold: z.boolean().optional(),\n italic: z.boolean().optional(),\n underline: z.boolean().optional(),\n strikethrough: z.boolean().optional(),\n code: z.boolean().optional(),\n })\n .describe('A text node with optional formatting marks.');\n\nconst linkNodeSchema = z\n .object({\n type: z.literal('link'),\n url: z.string().describe('The URL the link points to.'),\n children: z.array(textNodeSchema).min(1),\n })\n .describe('An inline link node. Children must be text nodes.');\n\nconst inlineNodeSchema = z.discriminatedUnion('type', [textNodeSchema, linkNodeSchema]);\n\n// ---------------------------------------------------------------------------\n// Root block nodes\n// ---------------------------------------------------------------------------\n\nconst paragraphSchema = z.object({\n type: z.literal('paragraph'),\n children: z.array(inlineNodeSchema).min(1),\n});\n\nconst headingSchema = z.object({\n type: z.literal('heading'),\n level: z.union([\n z.literal(1),\n z.literal(2),\n z.literal(3),\n z.literal(4),\n z.literal(5),\n z.literal(6),\n ]),\n children: z.array(inlineNodeSchema).min(1),\n});\n\nconst quoteSchema = z.object({\n type: z.literal('quote'),\n children: z.array(inlineNodeSchema).min(1),\n});\n\nconst codeSchema = z.object({\n type: z.literal('code'),\n language: z\n .string()\n .nullable()\n .optional()\n .describe('Programming language identifier (e.g. \"javascript\", \"python\").'),\n children: z.array(textNodeSchema).min(1),\n});\n\n// ---------------------------------------------------------------------------\n// List nodes (recursive via z.lazy — mirrors yup.lazy in blocks-validator.ts)\n// ---------------------------------------------------------------------------\n\nconst listItemSchema = z.object({\n type: z.literal('list-item'),\n children: z.array(inlineNodeSchema).min(1),\n});\n\n// ZodType annotation is required because of the self-reference via z.lazy\nconst listSchema: z.ZodType = z.object({\n type: z.literal('list'),\n format: z.enum(['ordered', 'unordered']),\n indentLevel: z.number().optional(),\n children: z\n .array(z.lazy(() => z.union([listItemSchema, listSchema])))\n .min(1)\n .describe('Children must be list-item or nested list nodes.'),\n});\n\n// ---------------------------------------------------------------------------\n// Image block\n// ---------------------------------------------------------------------------\n\nconst imageSchema = z.object({\n type: z.literal('image'),\n image: z\n .object({\n name: z.string(),\n alternativeText: z.string().nullable().optional(),\n url: z.string(),\n caption: z.string().nullable().optional(),\n width: z.number(),\n height: z.number(),\n formats: z.record(z.string(), z.unknown()).nullable().optional(),\n hash: z.string(),\n ext: z.string(),\n mime: z.string(),\n size: z.number(),\n previewUrl: z.string().nullable().optional(),\n provider: z.string(),\n provider_metadata: z.unknown().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .describe(\n 'An existing media asset. Use media tools to retrieve this data — MCP cannot upload files.'\n ),\n children: z.array(z.object({ type: z.literal('text'), text: z.literal('') })).length(1),\n});\n\n// ---------------------------------------------------------------------------\n// Top-level schema\n// ---------------------------------------------------------------------------\n\nconst blockNodeSchema = z.discriminatedUnion('type', [\n paragraphSchema,\n headingSchema,\n quoteSchema,\n codeSchema,\n imageSchema,\n]);\n\n/**\n * Returns the Zod schema for a Strapi Blocks (rich-text) field input.\n * Accepts an array of block nodes — paragraph, heading, quote, code, image, and list —\n * matching Strapi's internal blocks data model.\n */\nexport const buildBlocksInputSchema = (): z.ZodArray<z.ZodTypeAny> =>\n z\n .array(\n // listSchema uses z.lazy so it cannot participate in discriminatedUnion;\n // use a regular union to merge it back in.\n z.union([blockNodeSchema, listSchema])\n )\n .describe('An array of block nodes representing structured rich text content.');\n"],"names":["textNodeSchema","z","object","type","literal","text","string","describe","bold","boolean","optional","italic","underline","strikethrough","code","linkNodeSchema","url","children","array","min","inlineNodeSchema","discriminatedUnion","paragraphSchema","headingSchema","level","union","quoteSchema","codeSchema","language","nullable","listItemSchema","listSchema","format","enum","indentLevel","number","lazy","imageSchema","image","name","alternativeText","caption","width","height","formats","record","unknown","hash","ext","mime","size","previewUrl","provider","provider_metadata","createdAt","updatedAt","length","blockNodeSchema","buildBlocksInputSchema"],"mappings":"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"}
|