@strapi/content-manager 5.58.0 → 5.60.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/components/ConfigurationForm/Fields.js +4 -3
- package/dist/admin/components/ConfigurationForm/Fields.js.map +1 -1
- package/dist/admin/components/ConfigurationForm/Fields.mjs +4 -3
- package/dist/admin/components/ConfigurationForm/Fields.mjs.map +1 -1
- package/dist/admin/components/RelativeTime.js +2 -1
- package/dist/admin/components/RelativeTime.js.map +1 -1
- package/dist/admin/components/RelativeTime.mjs +2 -1
- package/dist/admin/components/RelativeTime.mjs.map +1 -1
- package/dist/admin/content-manager.js.map +1 -1
- package/dist/admin/content-manager.mjs.map +1 -1
- package/dist/admin/history/components/VersionContent.js +8 -8
- package/dist/admin/history/components/VersionContent.js.map +1 -1
- package/dist/admin/history/components/VersionContent.mjs +8 -8
- package/dist/admin/history/components/VersionContent.mjs.map +1 -1
- package/dist/admin/history/components/VersionInputRenderer.js +2 -1
- package/dist/admin/history/components/VersionInputRenderer.js.map +1 -1
- package/dist/admin/history/components/VersionInputRenderer.mjs +2 -1
- package/dist/admin/history/components/VersionInputRenderer.mjs.map +1 -1
- package/dist/admin/hooks/useDocumentActions.js.map +1 -1
- package/dist/admin/hooks/useDocumentActions.mjs.map +1 -1
- package/dist/admin/hooks/useDocumentLayout.js.map +1 -1
- package/dist/admin/hooks/useDocumentLayout.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Input.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Input.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js +3 -2
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs +3 -2
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js +8 -6
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs +8 -6
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.js +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.mjs +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js +6 -3
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs +6 -3
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.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/EditView/components/FormInputs/UID.js +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/UID.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/UID.mjs +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/UID.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.js +5 -4
- package/dist/admin/pages/EditView/components/FormLayout.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.mjs +5 -4
- package/dist/admin/pages/EditView/components/FormLayout.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.js +3 -1
- package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.mjs +3 -1
- package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/Panels.js.map +1 -1
- package/dist/admin/pages/EditView/components/Panels.mjs.map +1 -1
- package/dist/admin/pages/EditView/utils/data.js +3 -3
- package/dist/admin/pages/EditView/utils/data.js.map +1 -1
- package/dist/admin/pages/EditView/utils/data.mjs +3 -3
- package/dist/admin/pages/EditView/utils/data.mjs.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/Settings.js +3 -3
- package/dist/admin/pages/ListConfiguration/components/Settings.js.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/Settings.mjs +3 -3
- package/dist/admin/pages/ListConfiguration/components/Settings.mjs.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/SortDisplayedFields.js +2 -2
- package/dist/admin/pages/ListConfiguration/components/SortDisplayedFields.js.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/SortDisplayedFields.mjs +2 -2
- package/dist/admin/pages/ListConfiguration/components/SortDisplayedFields.mjs.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.js +73 -13
- package/dist/admin/pages/ListView/ListViewPage.js.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.mjs +74 -14
- package/dist/admin/pages/ListView/ListViewPage.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/AutoCloneFailureModal.js +1 -1
- package/dist/admin/pages/ListView/components/AutoCloneFailureModal.js.map +1 -1
- package/dist/admin/pages/ListView/components/AutoCloneFailureModal.mjs +1 -1
- package/dist/admin/pages/ListView/components/AutoCloneFailureModal.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.js.map +1 -1
- package/dist/admin/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/BulkActions/PublishAction.js +4 -1
- package/dist/admin/pages/ListView/components/BulkActions/PublishAction.js.map +1 -1
- package/dist/admin/pages/ListView/components/BulkActions/PublishAction.mjs +4 -1
- package/dist/admin/pages/ListView/components/BulkActions/PublishAction.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.js +12 -10
- package/dist/admin/pages/ListView/components/Filters.js.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.mjs +12 -10
- package/dist/admin/pages/ListView/components/Filters.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/TableCells/Relations.js.map +1 -1
- package/dist/admin/pages/ListView/components/TableCells/Relations.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/ViewSettingsMenu.js +2 -1
- package/dist/admin/pages/ListView/components/ViewSettingsMenu.js.map +1 -1
- package/dist/admin/pages/ListView/components/ViewSettingsMenu.mjs +2 -1
- package/dist/admin/pages/ListView/components/ViewSettingsMenu.mjs.map +1 -1
- package/dist/admin/pages/ListView/utils/applyAttributeRenames.js +68 -0
- package/dist/admin/pages/ListView/utils/applyAttributeRenames.js.map +1 -0
- package/dist/admin/pages/ListView/utils/applyAttributeRenames.mjs +64 -0
- package/dist/admin/pages/ListView/utils/applyAttributeRenames.mjs.map +1 -0
- package/dist/admin/preview/components/PreviewHeader.js +3 -1
- package/dist/admin/preview/components/PreviewHeader.js.map +1 -1
- package/dist/admin/preview/components/PreviewHeader.mjs +3 -1
- package/dist/admin/preview/components/PreviewHeader.mjs.map +1 -1
- package/dist/admin/preview/components/PreviewSidePanel.js +2 -1
- package/dist/admin/preview/components/PreviewSidePanel.js.map +1 -1
- package/dist/admin/preview/components/PreviewSidePanel.mjs +2 -1
- package/dist/admin/preview/components/PreviewSidePanel.mjs.map +1 -1
- package/dist/admin/preview/utils/getPreviewUrlStatus.js +17 -0
- package/dist/admin/preview/utils/getPreviewUrlStatus.js.map +1 -0
- package/dist/admin/preview/utils/getPreviewUrlStatus.mjs +15 -0
- package/dist/admin/preview/utils/getPreviewUrlStatus.mjs.map +1 -0
- package/dist/admin/services/relations.js +2 -2
- package/dist/admin/services/relations.js.map +1 -1
- package/dist/admin/services/relations.mjs +2 -2
- package/dist/admin/services/relations.mjs.map +1 -1
- package/dist/admin/src/components/ConfigurationForm/Fields.d.ts +1 -1
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +3 -1
- package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -0
- package/dist/admin/src/pages/ListView/utils/applyAttributeRenames.d.ts +12 -0
- package/dist/admin/src/preview/utils/getPreviewUrlStatus.d.ts +6 -0
- package/dist/admin/translations/eu.json.js +3 -3
- package/dist/admin/translations/eu.json.mjs +3 -3
- package/dist/admin/translations/gu.json.js +4 -4
- package/dist/admin/translations/gu.json.mjs +4 -4
- package/dist/admin/translations/hi.json.js +9 -9
- package/dist/admin/translations/hi.json.mjs +9 -9
- package/dist/admin/translations/ml.json.js +6 -6
- package/dist/admin/translations/ml.json.mjs +6 -6
- package/dist/admin/translations/sa.json.js +10 -10
- package/dist/admin/translations/sa.json.mjs +10 -10
- package/dist/server/controllers/relations.js +48 -16
- package/dist/server/controllers/relations.js.map +1 -1
- package/dist/server/controllers/relations.mjs +49 -17
- package/dist/server/controllers/relations.mjs.map +1 -1
- package/dist/server/history/services/history.js +1 -1
- package/dist/server/history/services/history.js.map +1 -1
- package/dist/server/history/services/history.mjs +1 -1
- package/dist/server/history/services/history.mjs.map +1 -1
- package/dist/server/homepage/services/homepage.js.map +1 -1
- package/dist/server/homepage/services/homepage.mjs.map +1 -1
- package/dist/server/mcp/schemas/filters-schema.js +10 -2
- package/dist/server/mcp/schemas/filters-schema.js.map +1 -1
- package/dist/server/mcp/schemas/filters-schema.mjs +10 -2
- package/dist/server/mcp/schemas/filters-schema.mjs.map +1 -1
- package/dist/server/preview/controllers/validation/preview.js +1 -1
- package/dist/server/preview/controllers/validation/preview.js.map +1 -1
- package/dist/server/preview/controllers/validation/preview.mjs +2 -2
- package/dist/server/preview/controllers/validation/preview.mjs.map +1 -1
- package/dist/server/preview/services/preview-config.js.map +1 -1
- package/dist/server/preview/services/preview-config.mjs.map +1 -1
- package/dist/server/register.js +6 -0
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs +6 -0
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/services/components.js.map +1 -1
- package/dist/server/services/components.mjs.map +1 -1
- package/dist/server/services/configuration/rename-fields.js +68 -0
- package/dist/server/services/configuration/rename-fields.js.map +1 -0
- package/dist/server/services/configuration/rename-fields.mjs +66 -0
- package/dist/server/services/configuration/rename-fields.mjs.map +1 -0
- package/dist/server/services/document-metadata.js +1 -1
- package/dist/server/services/document-metadata.js.map +1 -1
- package/dist/server/services/document-metadata.mjs +1 -1
- package/dist/server/services/document-metadata.mjs.map +1 -1
- package/dist/server/services/utils/configuration/attribute-renames.js +164 -0
- package/dist/server/services/utils/configuration/attribute-renames.js.map +1 -0
- package/dist/server/services/utils/configuration/attribute-renames.mjs +161 -0
- package/dist/server/services/utils/configuration/attribute-renames.mjs.map +1 -0
- package/dist/server/services/utils/configuration/attributes.js +12 -12
- package/dist/server/services/utils/configuration/attributes.js.map +1 -1
- package/dist/server/services/utils/configuration/attributes.mjs +12 -12
- package/dist/server/services/utils/configuration/attributes.mjs.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/homepage/services/homepage.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +2 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/mcp/schemas/filters-schema.d.ts.map +1 -1
- package/dist/server/src/preview/services/index.d.ts.map +1 -1
- package/dist/server/src/preview/services/preview-config.d.ts.map +1 -1
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/services/components.d.ts +2 -0
- package/dist/server/src/services/components.d.ts.map +1 -1
- package/dist/server/src/services/configuration/rename-fields.d.ts +15 -0
- package/dist/server/src/services/configuration/rename-fields.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +2 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/attribute-renames.d.ts +57 -0
- package/dist/server/src/services/utils/configuration/attribute-renames.d.ts.map +1 -0
- package/dist/shared/contracts/content-types.d.ts +5 -0
- package/dist/shared/contracts/content-types.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homepage.mjs","sources":["../../../../server/src/homepage/services/homepage.ts"],"sourcesContent":["/* eslint-disable func-names */\nimport type { Core, Modules, Schema } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport type {\n GetCountDocuments,\n GetRecentDocuments,\n RecentDocument,\n} from '../../../../shared/contracts/homepage';\n\nimport {\n buildHomepageQueryFields,\n compactSanitizedFields,\n resolveReadableMainField,\n resolveTitleField,\n} from './homepage-query-utils';\n\nconst createHomepageService = ({ strapi }: { strapi: Core.Strapi }) => {\n const MAX_DOCUMENTS = 4;\n\n const metadataService = strapi.plugin('content-manager').service('document-metadata');\n const permissionService = strapi.admin.services.permission;\n\n const getRegisteredContentType = (uid: RecentDocument['contentTypeUid']) => {\n const contentType = strapi.contentTypes[uid];\n\n if (contentType === undefined) {\n strapi.log.warn(\n `Skipping homepage content type \"${uid}\" because it is no longer registered.`\n );\n return undefined;\n }\n\n return contentType;\n };\n\n type ContentTypeConfiguration = {\n uid: RecentDocument['contentTypeUid'];\n settings: { mainField: string };\n };\n const getConfiguration = async (\n contentTypeUids: RecentDocument['contentTypeUid'][]\n ): Promise<ContentTypeConfiguration[]> => {\n /**\n * Don't use the strapi.store util because we need to make\n * more precise queries than exact key matches, in order to make as few queries as possible.\n */\n const coreStore = strapi.db.query('strapi::core-store');\n const rawConfigurations = await coreStore.findMany({\n where: {\n key: {\n $in: contentTypeUids.map(\n (contentType) => `plugin_content_manager_configuration_content_types::${contentType}`\n ),\n },\n },\n });\n\n return rawConfigurations.map((rawConfiguration) => {\n return JSON.parse(rawConfiguration.value);\n });\n };\n\n const getPermittedContentTypes = async () => {\n const readPermissions: Modules.Permissions.PermissionRule[] = await permissionService.findMany({\n where: {\n role: { users: { id: strapi.requestContext.get()?.state?.user.id } },\n action: 'plugin::content-manager.explorer.read',\n },\n });\n\n // Deduplicate subjects using a Set: the JOIN across permission -> role -> users produces one row\n // per role the user belongs to, so a multi-role user gets duplicate subjects.\n // Using a Set collapses them to unique content type UID.\n return [\n ...new Set(\n readPermissions\n .map((permission) => permission.subject)\n .filter((subject): subject is RecentDocument['contentTypeUid'] => {\n if (!subject) {\n return false;\n }\n\n const contentType = strapi.contentTypes[subject as keyof typeof strapi.contentTypes];\n const contentTypeOptions = contentType?.pluginOptions?.['content-manager'] as\n | { visible?: boolean }\n | undefined;\n\n return contentTypeOptions?.visible !== false;\n })\n ),\n ];\n };\n\n type ContentTypeMeta = {\n fields: string[];\n mainField: string;\n contentType: Schema.ContentType;\n hasDraftAndPublish: boolean;\n uid: RecentDocument['contentTypeUid'];\n };\n\n const permissionCheckerService = strapi.plugin('content-manager').service('permission-checker');\n const getPermissionChecker = (uid: string) =>\n permissionCheckerService.create({\n userAbility: strapi.requestContext.get()?.state.userAbility,\n model: uid,\n });\n\n const getContentTypesMeta = (\n allowedContentTypeUids: RecentDocument['contentTypeUid'][],\n configurations: ContentTypeConfiguration[]\n ): ContentTypeMeta[] => {\n return allowedContentTypeUids.reduce<ContentTypeMeta[]>((acc, uid) => {\n const configuration = configurations.find((config) => config.uid === uid);\n const contentType = getRegisteredContentType(uid);\n\n if (contentType === undefined) {\n return acc;\n }\n\n const mainField = resolveReadableMainField(\n contentType,\n configuration,\n getPermissionChecker(uid)\n );\n const fields = buildHomepageQueryFields(contentType, mainField);\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(contentType);\n\n acc.push({\n fields,\n mainField,\n contentType,\n hasDraftAndPublish,\n uid,\n });\n\n return acc;\n }, []);\n };\n\n /**\n * Homepage widgets expect JSON-safe ISO strings. Returning `Date` objects can\n * serialize as `{}` after spread/clone (see https://github.com/strapi/strapi/issues/27013).\n */\n const toIsoDateString = (value: unknown): string | null => {\n if (value == null || value === '') {\n return null;\n }\n\n const date = value instanceof Date ? value : new Date(String(value));\n return Number.isNaN(date.getTime()) ? null : date.toISOString();\n };\n\n const formatDocuments = (\n documents: Modules.Documents.AnyDocument[],\n meta: ContentTypeMeta,\n populate?: string[]\n ) => {\n return documents.map((document) => {\n const additionalFields =\n populate?.reduce(\n (acc, key) => {\n acc[key] = document[key];\n return acc;\n },\n {} as Record<string, any>\n ) || {};\n return {\n documentId: document.documentId,\n locale: document.locale ?? null,\n title: document[meta.mainField ?? 'documentId'],\n contentTypeUid: meta.uid,\n contentTypeDisplayName: meta.contentType.info.displayName,\n kind: meta.contentType.kind,\n ...additionalFields,\n // Keep dates last so populate cannot overwrite with non-JSON-safe values\n updatedAt: toIsoDateString(document.updatedAt) ?? '',\n publishedAt:\n meta.hasDraftAndPublish && document.publishedAt\n ? toIsoDateString(document.publishedAt)\n : null,\n };\n });\n };\n\n const sanitizeHomepageQuery = async (\n meta: ContentTypeMeta,\n additionalQueryParams?: Record<string, unknown>\n ) => {\n const permissionQuery = await getPermissionChecker(meta.uid).sanitizedQuery.read({\n limit: MAX_DOCUMENTS,\n fields: meta.fields,\n ...additionalQueryParams,\n locale: '*',\n });\n\n const sanitizedFields = compactSanitizedFields(permissionQuery.fields);\n if (sanitizedFields !== undefined) {\n permissionQuery.fields = sanitizedFields;\n }\n\n return {\n permissionQuery,\n titleField: resolveTitleField(meta.mainField, sanitizedFields),\n };\n };\n\n return {\n async addStatusToDocuments(documents: RecentDocument[]): Promise<RecentDocument[]> {\n return Promise.all(\n documents.map(async (recentDocument) => {\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(\n strapi.contentType(recentDocument.contentTypeUid)\n );\n /**\n * Tries to query the other version of the document if draft and publish is enabled,\n * so that we know when to give the \"modified\" status.\n */\n const { availableStatus } = await metadataService.getMetadata(\n recentDocument.contentTypeUid,\n recentDocument,\n {\n availableStatus: hasDraftAndPublish,\n availableLocales: false,\n }\n );\n const status: RecentDocument['status'] = metadataService.getStatus(\n recentDocument,\n availableStatus\n );\n\n return {\n ...recentDocument,\n status: hasDraftAndPublish ? status : undefined,\n };\n })\n );\n },\n\n async queryLastDocuments(\n additionalQueryParams?: Record<string, unknown>,\n draftAndPublishOnly?: boolean\n ): Promise<RecentDocument[]> {\n const permittedContentTypes = await getPermittedContentTypes();\n const allowedContentTypeUids = draftAndPublishOnly\n ? permittedContentTypes.filter((uid) => {\n const contentType = getRegisteredContentType(uid);\n\n return contentType !== undefined && contentTypes.hasDraftAndPublish(contentType);\n })\n : permittedContentTypes;\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(allowedContentTypeUids);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(allowedContentTypeUids, configurations);\n\n const recentDocuments = await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const { permissionQuery, titleField } = await sanitizeHomepageQuery(\n meta,\n additionalQueryParams\n );\n\n const docs = await strapi.documents(meta.uid).findMany(permissionQuery);\n const populate = additionalQueryParams?.populate as string[];\n\n return formatDocuments(docs, { ...meta, mainField: titleField }, populate);\n })\n );\n\n return recentDocuments\n .flat()\n .sort((a, b) => {\n // ISO-8601 strings compare lexicographically in chronological order\n const compareIso = (left: string, right: string, direction: 1 | -1) => {\n if (left < right) return -1 * direction;\n if (left > right) return 1 * direction;\n return 0;\n };\n\n switch (additionalQueryParams?.sort) {\n case 'publishedAt:desc':\n if (!a.publishedAt || !b.publishedAt) return 0;\n return compareIso(a.publishedAt, b.publishedAt, -1);\n case 'publishedAt:asc':\n if (!a.publishedAt || !b.publishedAt) return 0;\n return compareIso(a.publishedAt, b.publishedAt, 1);\n case 'updatedAt:desc':\n if (!a.updatedAt || !b.updatedAt) return 0;\n return compareIso(a.updatedAt, b.updatedAt, -1);\n case 'updatedAt:asc':\n if (!a.updatedAt || !b.updatedAt) return 0;\n return compareIso(a.updatedAt, b.updatedAt, 1);\n default:\n return 0;\n }\n })\n .slice(0, MAX_DOCUMENTS);\n },\n\n async getRecentlyPublishedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const recentlyPublishedDocuments = await this.queryLastDocuments(\n {\n sort: 'publishedAt:desc',\n status: 'published',\n },\n true\n );\n\n return this.addStatusToDocuments(recentlyPublishedDocuments);\n },\n\n async getRecentlyUpdatedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const recentlyUpdatedDocuments = await this.queryLastDocuments({\n sort: 'updatedAt:desc',\n });\n\n return this.addStatusToDocuments(recentlyUpdatedDocuments);\n },\n\n async getCountDocuments(): Promise<GetCountDocuments.Response['data']> {\n const permittedContentTypes = await getPermittedContentTypes();\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(permittedContentTypes);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(permittedContentTypes, configurations);\n\n const countDocuments = {\n draft: 0,\n published: 0,\n modified: 0,\n };\n\n await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const strapiDBConnection = strapi.db.connection;\n const tableName = strapi.contentType(meta.uid).collectionName;\n if (!tableName) return;\n\n if (!meta.hasDraftAndPublish) {\n const publishedDocuments = await strapiDBConnection(tableName)\n .countDistinct('document_id as count')\n .first();\n countDocuments.published += Number(publishedDocuments?.count) || 0;\n return;\n }\n\n // Classify each document_id into a single bucket (draft / published / modified)\n // in one pass. Replaces three separate self-join queries that scaled poorly on\n // large tables — see https://github.com/strapi/strapi/issues/25200.\n const classified = strapiDBConnection(tableName)\n .select('document_id')\n .select(\n strapiDBConnection.raw(\n `CASE\n WHEN MAX(CASE WHEN published_at IS NOT NULL THEN 1 ELSE 0 END) = 0\n THEN 'draft'\n WHEN MAX(CASE WHEN published_at IS NULL THEN updated_at END) =\n MAX(CASE WHEN published_at IS NOT NULL THEN updated_at END)\n THEN 'published'\n ELSE 'modified'\n END AS bucket`\n )\n )\n .groupBy('document_id');\n\n const counts = await strapiDBConnection\n .from(classified.as('classified'))\n .select(\n strapiDBConnection.raw(\n `COUNT(CASE WHEN bucket = 'draft' THEN 1 END) AS draft,\n COUNT(CASE WHEN bucket = 'published' THEN 1 END) AS published,\n COUNT(CASE WHEN bucket = 'modified' THEN 1 END) AS modified`\n )\n )\n .first();\n\n countDocuments.draft += Number(counts?.draft) || 0;\n countDocuments.published += Number(counts?.published) || 0;\n countDocuments.modified += Number(counts?.modified) || 0;\n })\n );\n\n return countDocuments;\n },\n };\n};\n\nexport { createHomepageService };\n"],"names":["createHomepageService","strapi","MAX_DOCUMENTS","metadataService","plugin","service","permissionService","admin","services","permission","getRegisteredContentType","uid","contentType","contentTypes","undefined","log","warn","getConfiguration","contentTypeUids","coreStore","db","query","rawConfigurations","findMany","where","key","$in","map","rawConfiguration","JSON","parse","value","getPermittedContentTypes","readPermissions","role","users","id","requestContext","get","state","user","action","Set","subject","filter","contentTypeOptions","pluginOptions","visible","permissionCheckerService","getPermissionChecker","create","userAbility","model","getContentTypesMeta","allowedContentTypeUids","configurations","reduce","acc","configuration","find","config","mainField","resolveReadableMainField","fields","buildHomepageQueryFields","hasDraftAndPublish","push","toIsoDateString","date","Date","String","Number","isNaN","getTime","toISOString","formatDocuments","documents","meta","populate","document","additionalFields","documentId","locale","title","contentTypeUid","contentTypeDisplayName","info","displayName","kind","updatedAt","publishedAt","sanitizeHomepageQuery","additionalQueryParams","permissionQuery","sanitizedQuery","read","limit","sanitizedFields","compactSanitizedFields","titleField","resolveTitleField","addStatusToDocuments","Promise","all","recentDocument","availableStatus","getMetadata","availableLocales","status","getStatus","queryLastDocuments","draftAndPublishOnly","permittedContentTypes","contentTypesMeta","recentDocuments","docs","flat","sort","a","b","compareIso","left","right","direction","slice","getRecentlyPublishedDocuments","recentlyPublishedDocuments","getRecentlyUpdatedDocuments","recentlyUpdatedDocuments","getCountDocuments","countDocuments","draft","published","modified","strapiDBConnection","connection","tableName","collectionName","publishedDocuments","countDistinct","first","count","classified","select","raw","groupBy","counts","from","as"],"mappings":";;;AAiBA,MAAMA,qBAAAA,GAAwB,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAChE,IAAA,MAAMC,aAAAA,GAAgB,CAAA;AAEtB,IAAA,MAAMC,kBAAkBF,MAAAA,CAAOG,MAAM,CAAC,iBAAA,CAAA,CAAmBC,OAAO,CAAC,mBAAA,CAAA;AACjE,IAAA,MAAMC,oBAAoBL,MAAAA,CAAOM,KAAK,CAACC,QAAQ,CAACC,UAAU;AAE1D,IAAA,MAAMC,2BAA2B,CAACC,GAAAA,GAAAA;AAChC,QAAA,MAAMC,WAAAA,GAAcX,MAAAA,CAAOY,YAAY,CAACF,GAAAA,CAAI;AAE5C,QAAA,IAAIC,gBAAgBE,SAAAA,EAAW;YAC7Bb,MAAAA,CAAOc,GAAG,CAACC,IAAI,CACb,CAAC,gCAAgC,EAAEL,GAAAA,CAAI,qCAAqC,CAAC,CAAA;YAE/E,OAAOG,SAAAA;AACT,QAAA;QAEA,OAAOF,WAAAA;AACT,IAAA,CAAA;AAMA,IAAA,MAAMK,mBAAmB,OACvBC,eAAAA,GAAAA;AAEA;;;AAGC,QACD,MAAMC,SAAAA,GAAYlB,MAAAA,CAAOmB,EAAE,CAACC,KAAK,CAAC,oBAAA,CAAA;AAClC,QAAA,MAAMC,iBAAAA,GAAoB,MAAMH,SAAAA,CAAUI,QAAQ,CAAC;YACjDC,KAAAA,EAAO;gBACLC,GAAAA,EAAK;oBACHC,GAAAA,EAAKR,eAAAA,CAAgBS,GAAG,CACtB,CAACf,cAAgB,CAAC,oDAAoD,EAAEA,WAAAA,CAAAA,CAAa;AAEzF;AACF;AACF,SAAA,CAAA;QAEA,OAAOU,iBAAAA,CAAkBK,GAAG,CAAC,CAACC,gBAAAA,GAAAA;AAC5B,YAAA,OAAOC,IAAAA,CAAKC,KAAK,CAACF,gBAAAA,CAAiBG,KAAK,CAAA;AAC1C,QAAA,CAAA,CAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAMC,wBAAAA,GAA2B,UAAA;AAC/B,QAAA,MAAMC,eAAAA,GAAwD,MAAM3B,iBAAAA,CAAkBiB,QAAQ,CAAC;YAC7FC,KAAAA,EAAO;gBACLU,IAAAA,EAAM;oBAAEC,KAAAA,EAAO;AAAEC,wBAAAA,EAAAA,EAAInC,OAAOoC,cAAc,CAACC,GAAG,EAAA,EAAIC,OAAOC,IAAAA,CAAKJ;AAAG;AAAE,iBAAA;gBACnEK,MAAAA,EAAQ;AACV;AACF,SAAA,CAAA;;;;QAKA,OAAO;eACF,IAAIC,GAAAA,CACLT,eAAAA,CACGN,GAAG,CAAC,CAAClB,UAAAA,GAAeA,UAAAA,CAAWkC,OAAO,CAAA,CACtCC,MAAM,CAAC,CAACD,OAAAA,GAAAA;AACP,gBAAA,IAAI,CAACA,OAAAA,EAAS;oBACZ,OAAO,KAAA;AACT,gBAAA;AAEA,gBAAA,MAAM/B,WAAAA,GAAcX,MAAAA,CAAOY,YAAY,CAAC8B,OAAAA,CAA4C;AACpF,gBAAA,MAAME,kBAAAA,GAAqBjC,WAAAA,EAAakC,aAAAA,GAAgB,iBAAA,CAAkB;AAI1E,gBAAA,OAAOD,oBAAoBE,OAAAA,KAAY,KAAA;AACzC,YAAA,CAAA,CAAA;AAEL,SAAA;AACH,IAAA,CAAA;AAUA,IAAA,MAAMC,2BAA2B/C,MAAAA,CAAOG,MAAM,CAAC,iBAAA,CAAA,CAAmBC,OAAO,CAAC,oBAAA,CAAA;AAC1E,IAAA,MAAM4C,oBAAAA,GAAuB,CAACtC,GAAAA,GAC5BqC,wBAAAA,CAAyBE,MAAM,CAAC;AAC9BC,YAAAA,WAAAA,EAAalD,MAAAA,CAAOoC,cAAc,CAACC,GAAG,IAAIC,KAAAA,CAAMY,WAAAA;YAChDC,KAAAA,EAAOzC;AACT,SAAA,CAAA;IAEF,MAAM0C,mBAAAA,GAAsB,CAC1BC,sBAAAA,EACAC,cAAAA,GAAAA;AAEA,QAAA,OAAOD,sBAAAA,CAAuBE,MAAM,CAAoB,CAACC,GAAAA,EAAK9C,GAAAA,GAAAA;YAC5D,MAAM+C,aAAAA,GAAgBH,eAAeI,IAAI,CAAC,CAACC,MAAAA,GAAWA,MAAAA,CAAOjD,GAAG,KAAKA,GAAAA,CAAAA;AACrE,YAAA,MAAMC,cAAcF,wBAAAA,CAAyBC,GAAAA,CAAAA;AAE7C,YAAA,IAAIC,gBAAgBE,SAAAA,EAAW;gBAC7B,OAAO2C,GAAAA;AACT,YAAA;AAEA,YAAA,MAAMI,SAAAA,GAAYC,wBAAAA,CAChBlD,WAAAA,EACA8C,aAAAA,EACAT,oBAAAA,CAAqBtC,GAAAA,CAAAA,CAAAA;YAEvB,MAAMoD,MAAAA,GAASC,yBAAyBpD,WAAAA,EAAaiD,SAAAA,CAAAA;YACrD,MAAMI,kBAAAA,GAAqBpD,YAAAA,CAAaoD,kBAAkB,CAACrD,WAAAA,CAAAA;AAE3D6C,YAAAA,GAAAA,CAAIS,IAAI,CAAC;AACPH,gBAAAA,MAAAA;AACAF,gBAAAA,SAAAA;AACAjD,gBAAAA,WAAAA;AACAqD,gBAAAA,kBAAAA;AACAtD,gBAAAA;AACF,aAAA,CAAA;YAEA,OAAO8C,GAAAA;AACT,QAAA,CAAA,EAAG,EAAE,CAAA;AACP,IAAA,CAAA;AAEA;;;MAIA,MAAMU,kBAAkB,CAACpC,KAAAA,GAAAA;QACvB,IAAIA,KAAAA,IAAS,IAAA,IAAQA,KAAAA,KAAU,EAAA,EAAI;YACjC,OAAO,IAAA;AACT,QAAA;AAEA,QAAA,MAAMqC,OAAOrC,KAAAA,YAAiBsC,IAAAA,GAAOtC,KAAAA,GAAQ,IAAIsC,KAAKC,MAAAA,CAAOvC,KAAAA,CAAAA,CAAAA;QAC7D,OAAOwC,MAAAA,CAAOC,KAAK,CAACJ,IAAAA,CAAKK,OAAO,EAAA,CAAA,GAAM,IAAA,GAAOL,KAAKM,WAAW,EAAA;AAC/D,IAAA,CAAA;IAEA,MAAMC,eAAAA,GAAkB,CACtBC,SAAAA,EACAC,IAAAA,EACAC,QAAAA,GAAAA;QAEA,OAAOF,SAAAA,CAAUjD,GAAG,CAAC,CAACoD,QAAAA,GAAAA;AACpB,YAAA,MAAMC,gBAAAA,GACJF,QAAAA,EAAUtB,MAAAA,CACR,CAACC,GAAAA,EAAKhC,GAAAA,GAAAA;AACJgC,gBAAAA,GAAG,CAAChC,GAAAA,CAAI,GAAGsD,QAAQ,CAACtD,GAAAA,CAAI;gBACxB,OAAOgC,GAAAA;YACT,CAAA,EACA,OACG,EAAC;YACR,OAAO;AACLwB,gBAAAA,UAAAA,EAAYF,SAASE,UAAU;gBAC/BC,MAAAA,EAAQH,QAAAA,CAASG,MAAM,IAAI,IAAA;AAC3BC,gBAAAA,KAAAA,EAAOJ,QAAQ,CAACF,IAAAA,CAAKhB,SAAS,IAAI,YAAA,CAAa;AAC/CuB,gBAAAA,cAAAA,EAAgBP,KAAKlE,GAAG;AACxB0E,gBAAAA,sBAAAA,EAAwBR,IAAAA,CAAKjE,WAAW,CAAC0E,IAAI,CAACC,WAAW;gBACzDC,IAAAA,EAAMX,IAAAA,CAAKjE,WAAW,CAAC4E,IAAI;AAC3B,gBAAA,GAAGR,gBAAgB;;gBAEnBS,SAAAA,EAAWtB,eAAAA,CAAgBY,QAAAA,CAASU,SAAS,CAAA,IAAK,EAAA;gBAClDC,WAAAA,EACEb,IAAAA,CAAKZ,kBAAkB,IAAIc,QAAAA,CAASW,WAAW,GAC3CvB,eAAAA,CAAgBY,QAAAA,CAASW,WAAW,CAAA,GACpC;AACR,aAAA;AACF,QAAA,CAAA,CAAA;AACF,IAAA,CAAA;IAEA,MAAMC,qBAAAA,GAAwB,OAC5Bd,IAAAA,EACAe,qBAAAA,GAAAA;QAEA,MAAMC,eAAAA,GAAkB,MAAM5C,oBAAAA,CAAqB4B,IAAAA,CAAKlE,GAAG,CAAA,CAAEmF,cAAc,CAACC,IAAI,CAAC;YAC/EC,KAAAA,EAAO9F,aAAAA;AACP6D,YAAAA,MAAAA,EAAQc,KAAKd,MAAM;AACnB,YAAA,GAAG6B,qBAAqB;YACxBV,MAAAA,EAAQ;AACV,SAAA,CAAA;QAEA,MAAMe,eAAAA,GAAkBC,sBAAAA,CAAuBL,eAAAA,CAAgB9B,MAAM,CAAA;AACrE,QAAA,IAAIkC,oBAAoBnF,SAAAA,EAAW;AACjC+E,YAAAA,eAAAA,CAAgB9B,MAAM,GAAGkC,eAAAA;AAC3B,QAAA;QAEA,OAAO;AACLJ,YAAAA,eAAAA;YACAM,UAAAA,EAAYC,iBAAAA,CAAkBvB,IAAAA,CAAKhB,SAAS,EAAEoC,eAAAA;AAChD,SAAA;AACF,IAAA,CAAA;IAEA,OAAO;AACL,QAAA,MAAMI,sBAAqBzB,SAA2B,EAAA;AACpD,YAAA,OAAO0B,QAAQC,GAAG,CAChB3B,SAAAA,CAAUjD,GAAG,CAAC,OAAO6E,cAAAA,GAAAA;gBACnB,MAAMvC,kBAAAA,GAAqBpD,aAAaoD,kBAAkB,CACxDhE,OAAOW,WAAW,CAAC4F,eAAepB,cAAc,CAAA,CAAA;AAElD;;;AAGC,cACD,MAAM,EAAEqB,eAAe,EAAE,GAAG,MAAMtG,eAAAA,CAAgBuG,WAAW,CAC3DF,cAAAA,CAAepB,cAAc,EAC7BoB,cAAAA,EACA;oBACEC,eAAAA,EAAiBxC,kBAAAA;oBACjB0C,gBAAAA,EAAkB;AACpB,iBAAA,CAAA;AAEF,gBAAA,MAAMC,MAAAA,GAAmCzG,eAAAA,CAAgB0G,SAAS,CAChEL,cAAAA,EACAC,eAAAA,CAAAA;gBAGF,OAAO;AACL,oBAAA,GAAGD,cAAc;AACjBI,oBAAAA,MAAAA,EAAQ3C,qBAAqB2C,MAAAA,GAAS9F;AACxC,iBAAA;AACF,YAAA,CAAA,CAAA,CAAA;AAEJ,QAAA,CAAA;QAEA,MAAMgG,kBAAAA,CAAAA,CACJlB,qBAA+C,EAC/CmB,mBAA6B,EAAA;AAE7B,YAAA,MAAMC,wBAAwB,MAAMhF,wBAAAA,EAAAA;AACpC,YAAA,MAAMsB,sBAAAA,GAAyByD,mBAAAA,GAC3BC,qBAAAA,CAAsBpE,MAAM,CAAC,CAACjC,GAAAA,GAAAA;AAC5B,gBAAA,MAAMC,cAAcF,wBAAAA,CAAyBC,GAAAA,CAAAA;AAE7C,gBAAA,OAAOC,WAAAA,KAAgBE,SAAAA,IAAaD,YAAAA,CAAaoD,kBAAkB,CAACrD,WAAAA,CAAAA;YACtE,CAAA,CAAA,GACAoG,qBAAAA;;YAEJ,MAAMzD,cAAAA,GAAiB,MAAMtC,gBAAAA,CAAiBqC,sBAAAA,CAAAA;;YAE9C,MAAM2D,gBAAAA,GAAmB5D,oBAAoBC,sBAAAA,EAAwBC,cAAAA,CAAAA;YAErE,MAAM2D,eAAAA,GAAkB,MAAMZ,OAAAA,CAAQC,GAAG,CACvCU,gBAAAA,CAAiBtF,GAAG,CAAC,OAAOkD,IAAAA,GAAAA;gBAC1B,MAAM,EAAEgB,eAAe,EAAEM,UAAU,EAAE,GAAG,MAAMR,sBAC5Cd,IAAAA,EACAe,qBAAAA,CAAAA;gBAGF,MAAMuB,IAAAA,GAAO,MAAMlH,MAAAA,CAAO2E,SAAS,CAACC,IAAAA,CAAKlE,GAAG,CAAA,CAAEY,QAAQ,CAACsE,eAAAA,CAAAA;AACvD,gBAAA,MAAMf,WAAWc,qBAAAA,EAAuBd,QAAAA;AAExC,gBAAA,OAAOH,gBAAgBwC,IAAAA,EAAM;AAAE,oBAAA,GAAGtC,IAAI;oBAAEhB,SAAAA,EAAWsC;iBAAW,EAAGrB,QAAAA,CAAAA;AACnE,YAAA,CAAA,CAAA,CAAA;AAGF,YAAA,OAAOoC,gBACJE,IAAI,EAAA,CACJC,IAAI,CAAC,CAACC,CAAAA,EAAGC,CAAAA,GAAAA;;gBAER,MAAMC,UAAAA,GAAa,CAACC,IAAAA,EAAcC,KAAAA,EAAeC,SAAAA,GAAAA;AAC/C,oBAAA,IAAIF,IAAAA,GAAOC,KAAAA,EAAO,OAAO,EAAC,GAAIC,SAAAA;oBAC9B,IAAIF,IAAAA,GAAOC,KAAAA,EAAO,OAAO,CAAA,GAAIC,SAAAA;oBAC7B,OAAO,CAAA;AACT,gBAAA,CAAA;AAEA,gBAAA,OAAQ/B,qBAAAA,EAAuByB,IAAAA;oBAC7B,KAAK,kBAAA;wBACH,IAAI,CAACC,EAAE5B,WAAW,IAAI,CAAC6B,CAAAA,CAAE7B,WAAW,EAAE,OAAO,CAAA;AAC7C,wBAAA,OAAO8B,WAAWF,CAAAA,CAAE5B,WAAW,EAAE6B,CAAAA,CAAE7B,WAAW,EAAE,EAAC,CAAA;oBACnD,KAAK,iBAAA;wBACH,IAAI,CAAC4B,EAAE5B,WAAW,IAAI,CAAC6B,CAAAA,CAAE7B,WAAW,EAAE,OAAO,CAAA;AAC7C,wBAAA,OAAO8B,WAAWF,CAAAA,CAAE5B,WAAW,EAAE6B,CAAAA,CAAE7B,WAAW,EAAE,CAAA,CAAA;oBAClD,KAAK,gBAAA;wBACH,IAAI,CAAC4B,EAAE7B,SAAS,IAAI,CAAC8B,CAAAA,CAAE9B,SAAS,EAAE,OAAO,CAAA;AACzC,wBAAA,OAAO+B,WAAWF,CAAAA,CAAE7B,SAAS,EAAE8B,CAAAA,CAAE9B,SAAS,EAAE,EAAC,CAAA;oBAC/C,KAAK,eAAA;wBACH,IAAI,CAAC6B,EAAE7B,SAAS,IAAI,CAAC8B,CAAAA,CAAE9B,SAAS,EAAE,OAAO,CAAA;AACzC,wBAAA,OAAO+B,WAAWF,CAAAA,CAAE7B,SAAS,EAAE8B,CAAAA,CAAE9B,SAAS,EAAE,CAAA,CAAA;AAC9C,oBAAA;wBACE,OAAO,CAAA;AACX;YACF,CAAA,CAAA,CACCmC,KAAK,CAAC,CAAA,EAAG1H,aAAAA,CAAAA;AACd,QAAA,CAAA;QAEA,MAAM2H,6BAAAA,CAAAA,GAAAA;AACJ,YAAA,MAAMC,0BAAAA,GAA6B,MAAM,IAAI,CAAChB,kBAAkB,CAC9D;gBACEO,IAAAA,EAAM,kBAAA;gBACNT,MAAAA,EAAQ;aACV,EACA,IAAA,CAAA;YAGF,OAAO,IAAI,CAACP,oBAAoB,CAACyB,0BAAAA,CAAAA;AACnC,QAAA,CAAA;QAEA,MAAMC,2BAAAA,CAAAA,GAAAA;AACJ,YAAA,MAAMC,wBAAAA,GAA2B,MAAM,IAAI,CAAClB,kBAAkB,CAAC;gBAC7DO,IAAAA,EAAM;AACR,aAAA,CAAA;YAEA,OAAO,IAAI,CAAChB,oBAAoB,CAAC2B,wBAAAA,CAAAA;AACnC,QAAA,CAAA;QAEA,MAAMC,iBAAAA,CAAAA,GAAAA;AACJ,YAAA,MAAMjB,wBAAwB,MAAMhF,wBAAAA,EAAAA;;YAEpC,MAAMuB,cAAAA,GAAiB,MAAMtC,gBAAAA,CAAiB+F,qBAAAA,CAAAA;;YAE9C,MAAMC,gBAAAA,GAAmB5D,oBAAoB2D,qBAAAA,EAAuBzD,cAAAA,CAAAA;AAEpE,YAAA,MAAM2E,cAAAA,GAAiB;gBACrBC,KAAAA,EAAO,CAAA;gBACPC,SAAAA,EAAW,CAAA;gBACXC,QAAAA,EAAU;AACZ,aAAA;AAEA,YAAA,MAAM/B,QAAQC,GAAG,CACfU,gBAAAA,CAAiBtF,GAAG,CAAC,OAAOkD,IAAAA,GAAAA;AAC1B,gBAAA,MAAMyD,kBAAAA,GAAqBrI,MAAAA,CAAOmB,EAAE,CAACmH,UAAU;AAC/C,gBAAA,MAAMC,YAAYvI,MAAAA,CAAOW,WAAW,CAACiE,IAAAA,CAAKlE,GAAG,EAAE8H,cAAc;AAC7D,gBAAA,IAAI,CAACD,SAAAA,EAAW;gBAEhB,IAAI,CAAC3D,IAAAA,CAAKZ,kBAAkB,EAAE;AAC5B,oBAAA,MAAMyE,qBAAqB,MAAMJ,kBAAAA,CAAmBE,WACjDG,aAAa,CAAC,wBACdC,KAAK,EAAA;AACRV,oBAAAA,cAAAA,CAAeE,SAAS,IAAI7D,MAAAA,CAAOmE,kBAAAA,EAAoBG,KAAAA,CAAAA,IAAU,CAAA;AACjE,oBAAA;AACF,gBAAA;;;;gBAKA,MAAMC,UAAAA,GAAaR,kBAAAA,CAAmBE,SAAAA,CAAAA,CACnCO,MAAM,CAAC,aAAA,CAAA,CACPA,MAAM,CACLT,kBAAAA,CAAmBU,GAAG,CACpB,CAAC;;;;;;;6BAOY,CAAC,CAAA,CAAA,CAGjBC,OAAO,CAAC,aAAA,CAAA;AAEX,gBAAA,MAAMC,MAAAA,GAAS,MAAMZ,kBAAAA,CAClBa,IAAI,CAACL,UAAAA,CAAWM,EAAE,CAAC,YAAA,CAAA,CAAA,CACnBL,MAAM,CACLT,kBAAAA,CAAmBU,GAAG,CACpB,CAAC;;AAE2D,4EAAA,CAAC,GAGhEJ,KAAK,EAAA;AAERV,gBAAAA,cAAAA,CAAeC,KAAK,IAAI5D,MAAAA,CAAO2E,MAAAA,EAAQf,KAAAA,CAAAA,IAAU,CAAA;AACjDD,gBAAAA,cAAAA,CAAeE,SAAS,IAAI7D,MAAAA,CAAO2E,MAAAA,EAAQd,SAAAA,CAAAA,IAAc,CAAA;AACzDF,gBAAAA,cAAAA,CAAeG,QAAQ,IAAI9D,MAAAA,CAAO2E,MAAAA,EAAQb,QAAAA,CAAAA,IAAa,CAAA;AACzD,YAAA,CAAA,CAAA,CAAA;YAGF,OAAOH,cAAAA;AACT,QAAA;AACF,KAAA;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"homepage.mjs","sources":["../../../../server/src/homepage/services/homepage.ts"],"sourcesContent":["/* eslint-disable func-names */\nimport type { Core, Modules, Schema } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport type {\n GetCountDocuments,\n GetRecentDocuments,\n RecentDocument,\n} from '../../../../shared/contracts/homepage';\n\nimport {\n buildHomepageQueryFields,\n compactSanitizedFields,\n resolveReadableMainField,\n resolveTitleField,\n} from './homepage-query-utils';\n\nconst createHomepageService = ({ strapi }: { strapi: Core.Strapi }) => {\n const MAX_DOCUMENTS = 4;\n\n const metadataService = strapi.plugin('content-manager').service('document-metadata');\n const permissionService = strapi.admin.services.permission;\n\n const getRegisteredContentType = (uid: RecentDocument['contentTypeUid']) => {\n const contentType = strapi.contentTypes[uid];\n\n if (contentType === undefined) {\n strapi.log.warn(\n `Skipping homepage content type \"${uid}\" because it is no longer registered.`\n );\n return undefined;\n }\n\n return contentType;\n };\n\n type ContentTypeConfiguration = {\n uid: RecentDocument['contentTypeUid'];\n settings: { mainField: string };\n };\n const getConfiguration = async (\n contentTypeUids: RecentDocument['contentTypeUid'][]\n ): Promise<ContentTypeConfiguration[]> => {\n /**\n * Don't use the strapi.store util because we need to make\n * more precise queries than exact key matches, in order to make as few queries as possible.\n */\n const coreStore = strapi.db.query('strapi::core-store');\n const rawConfigurations = await coreStore.findMany({\n where: {\n key: {\n $in: contentTypeUids.map(\n (contentType) => `plugin_content_manager_configuration_content_types::${contentType}`\n ),\n },\n },\n });\n\n return rawConfigurations.map((rawConfiguration) => {\n return JSON.parse(rawConfiguration.value);\n });\n };\n\n const getPermittedContentTypes = async () => {\n const readPermissions: Modules.Permissions.PermissionRule[] = await permissionService.findMany({\n where: {\n role: { users: { id: strapi.requestContext.get()?.state?.user.id } },\n action: 'plugin::content-manager.explorer.read',\n },\n });\n\n // Deduplicate subjects using a Set: the JOIN across permission -> role -> users produces one row\n // per role the user belongs to, so a multi-role user gets duplicate subjects.\n // Using a Set collapses them to unique content type UID.\n return [\n ...new Set(\n readPermissions\n .map((permission) => permission.subject)\n .filter((subject): subject is RecentDocument['contentTypeUid'] => {\n if (!subject) {\n return false;\n }\n\n const contentType = strapi.contentTypes[subject as keyof typeof strapi.contentTypes];\n const contentTypeOptions = contentType?.pluginOptions?.['content-manager'] as\n { visible?: boolean } | undefined;\n\n return contentTypeOptions?.visible !== false;\n })\n ),\n ];\n };\n\n type ContentTypeMeta = {\n fields: string[];\n mainField: string;\n contentType: Schema.ContentType;\n hasDraftAndPublish: boolean;\n uid: RecentDocument['contentTypeUid'];\n };\n\n const permissionCheckerService = strapi.plugin('content-manager').service('permission-checker');\n const getPermissionChecker = (uid: string) =>\n permissionCheckerService.create({\n userAbility: strapi.requestContext.get()?.state.userAbility,\n model: uid,\n });\n\n const getContentTypesMeta = (\n allowedContentTypeUids: RecentDocument['contentTypeUid'][],\n configurations: ContentTypeConfiguration[]\n ): ContentTypeMeta[] => {\n return allowedContentTypeUids.reduce<ContentTypeMeta[]>((acc, uid) => {\n const configuration = configurations.find((config) => config.uid === uid);\n const contentType = getRegisteredContentType(uid);\n\n if (contentType === undefined) {\n return acc;\n }\n\n const mainField = resolveReadableMainField(\n contentType,\n configuration,\n getPermissionChecker(uid)\n );\n const fields = buildHomepageQueryFields(contentType, mainField);\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(contentType);\n\n acc.push({\n fields,\n mainField,\n contentType,\n hasDraftAndPublish,\n uid,\n });\n\n return acc;\n }, []);\n };\n\n /**\n * Homepage widgets expect JSON-safe ISO strings. Returning `Date` objects can\n * serialize as `{}` after spread/clone (see https://github.com/strapi/strapi/issues/27013).\n */\n const toIsoDateString = (value: unknown): string | null => {\n if (value == null || value === '') {\n return null;\n }\n\n const date = value instanceof Date ? value : new Date(String(value));\n return Number.isNaN(date.getTime()) ? null : date.toISOString();\n };\n\n const formatDocuments = (\n documents: Modules.Documents.AnyDocument[],\n meta: ContentTypeMeta,\n populate?: string[]\n ) => {\n return documents.map((document) => {\n const additionalFields =\n populate?.reduce(\n (acc, key) => {\n acc[key] = document[key];\n return acc;\n },\n {} as Record<string, any>\n ) || {};\n return {\n documentId: document.documentId,\n locale: document.locale ?? null,\n title: document[meta.mainField ?? 'documentId'],\n contentTypeUid: meta.uid,\n contentTypeDisplayName: meta.contentType.info.displayName,\n kind: meta.contentType.kind,\n ...additionalFields,\n // Keep dates last so populate cannot overwrite with non-JSON-safe values\n updatedAt: toIsoDateString(document.updatedAt) ?? '',\n publishedAt:\n meta.hasDraftAndPublish && document.publishedAt\n ? toIsoDateString(document.publishedAt)\n : null,\n };\n });\n };\n\n const sanitizeHomepageQuery = async (\n meta: ContentTypeMeta,\n additionalQueryParams?: Record<string, unknown>\n ) => {\n const permissionQuery = await getPermissionChecker(meta.uid).sanitizedQuery.read({\n limit: MAX_DOCUMENTS,\n fields: meta.fields,\n ...additionalQueryParams,\n locale: '*',\n });\n\n const sanitizedFields = compactSanitizedFields(permissionQuery.fields);\n if (sanitizedFields !== undefined) {\n permissionQuery.fields = sanitizedFields;\n }\n\n return {\n permissionQuery,\n titleField: resolveTitleField(meta.mainField, sanitizedFields),\n };\n };\n\n return {\n async addStatusToDocuments(documents: RecentDocument[]): Promise<RecentDocument[]> {\n return Promise.all(\n documents.map(async (recentDocument) => {\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(\n strapi.contentType(recentDocument.contentTypeUid)\n );\n /**\n * Tries to query the other version of the document if draft and publish is enabled,\n * so that we know when to give the \"modified\" status.\n */\n const { availableStatus } = await metadataService.getMetadata(\n recentDocument.contentTypeUid,\n recentDocument,\n {\n availableStatus: hasDraftAndPublish,\n availableLocales: false,\n }\n );\n const status: RecentDocument['status'] = metadataService.getStatus(\n recentDocument,\n availableStatus\n );\n\n return {\n ...recentDocument,\n status: hasDraftAndPublish ? status : undefined,\n };\n })\n );\n },\n\n async queryLastDocuments(\n additionalQueryParams?: Record<string, unknown>,\n draftAndPublishOnly?: boolean\n ): Promise<RecentDocument[]> {\n const permittedContentTypes = await getPermittedContentTypes();\n const allowedContentTypeUids = draftAndPublishOnly\n ? permittedContentTypes.filter((uid) => {\n const contentType = getRegisteredContentType(uid);\n\n return contentType !== undefined && contentTypes.hasDraftAndPublish(contentType);\n })\n : permittedContentTypes;\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(allowedContentTypeUids);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(allowedContentTypeUids, configurations);\n\n const recentDocuments = await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const { permissionQuery, titleField } = await sanitizeHomepageQuery(\n meta,\n additionalQueryParams\n );\n\n const docs = await strapi.documents(meta.uid).findMany(permissionQuery);\n const populate = additionalQueryParams?.populate as string[];\n\n return formatDocuments(docs, { ...meta, mainField: titleField }, populate);\n })\n );\n\n return recentDocuments\n .flat()\n .sort((a, b) => {\n // ISO-8601 strings compare lexicographically in chronological order\n const compareIso = (left: string, right: string, direction: 1 | -1) => {\n if (left < right) return -1 * direction;\n if (left > right) return 1 * direction;\n return 0;\n };\n\n switch (additionalQueryParams?.sort) {\n case 'publishedAt:desc':\n if (!a.publishedAt || !b.publishedAt) return 0;\n return compareIso(a.publishedAt, b.publishedAt, -1);\n case 'publishedAt:asc':\n if (!a.publishedAt || !b.publishedAt) return 0;\n return compareIso(a.publishedAt, b.publishedAt, 1);\n case 'updatedAt:desc':\n if (!a.updatedAt || !b.updatedAt) return 0;\n return compareIso(a.updatedAt, b.updatedAt, -1);\n case 'updatedAt:asc':\n if (!a.updatedAt || !b.updatedAt) return 0;\n return compareIso(a.updatedAt, b.updatedAt, 1);\n default:\n return 0;\n }\n })\n .slice(0, MAX_DOCUMENTS);\n },\n\n async getRecentlyPublishedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const recentlyPublishedDocuments = await this.queryLastDocuments(\n {\n sort: 'publishedAt:desc',\n status: 'published',\n },\n true\n );\n\n return this.addStatusToDocuments(recentlyPublishedDocuments);\n },\n\n async getRecentlyUpdatedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const recentlyUpdatedDocuments = await this.queryLastDocuments({\n sort: 'updatedAt:desc',\n });\n\n return this.addStatusToDocuments(recentlyUpdatedDocuments);\n },\n\n async getCountDocuments(): Promise<GetCountDocuments.Response['data']> {\n const permittedContentTypes = await getPermittedContentTypes();\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(permittedContentTypes);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(permittedContentTypes, configurations);\n\n const countDocuments = {\n draft: 0,\n published: 0,\n modified: 0,\n };\n\n await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const strapiDBConnection = strapi.db.connection;\n const tableName = strapi.contentType(meta.uid).collectionName;\n if (!tableName) return;\n\n if (!meta.hasDraftAndPublish) {\n const publishedDocuments = await strapiDBConnection(tableName)\n .countDistinct('document_id as count')\n .first();\n countDocuments.published += Number(publishedDocuments?.count) || 0;\n return;\n }\n\n // Classify each document_id into a single bucket (draft / published / modified)\n // in one pass. Replaces three separate self-join queries that scaled poorly on\n // large tables — see https://github.com/strapi/strapi/issues/25200.\n const classified = strapiDBConnection(tableName)\n .select('document_id')\n .select(\n strapiDBConnection.raw(\n `CASE\n WHEN MAX(CASE WHEN published_at IS NOT NULL THEN 1 ELSE 0 END) = 0\n THEN 'draft'\n WHEN MAX(CASE WHEN published_at IS NULL THEN updated_at END) =\n MAX(CASE WHEN published_at IS NOT NULL THEN updated_at END)\n THEN 'published'\n ELSE 'modified'\n END AS bucket`\n )\n )\n .groupBy('document_id');\n\n const counts = await strapiDBConnection\n .from(classified.as('classified'))\n .select(\n strapiDBConnection.raw(\n `COUNT(CASE WHEN bucket = 'draft' THEN 1 END) AS draft,\n COUNT(CASE WHEN bucket = 'published' THEN 1 END) AS published,\n COUNT(CASE WHEN bucket = 'modified' THEN 1 END) AS modified`\n )\n )\n .first();\n\n countDocuments.draft += Number(counts?.draft) || 0;\n countDocuments.published += Number(counts?.published) || 0;\n countDocuments.modified += Number(counts?.modified) || 0;\n })\n );\n\n return countDocuments;\n },\n };\n};\n\nexport { createHomepageService };\n"],"names":["createHomepageService","strapi","MAX_DOCUMENTS","metadataService","plugin","service","permissionService","admin","services","permission","getRegisteredContentType","uid","contentType","contentTypes","undefined","log","warn","getConfiguration","contentTypeUids","coreStore","db","query","rawConfigurations","findMany","where","key","$in","map","rawConfiguration","JSON","parse","value","getPermittedContentTypes","readPermissions","role","users","id","requestContext","get","state","user","action","Set","subject","filter","contentTypeOptions","pluginOptions","visible","permissionCheckerService","getPermissionChecker","create","userAbility","model","getContentTypesMeta","allowedContentTypeUids","configurations","reduce","acc","configuration","find","config","mainField","resolveReadableMainField","fields","buildHomepageQueryFields","hasDraftAndPublish","push","toIsoDateString","date","Date","String","Number","isNaN","getTime","toISOString","formatDocuments","documents","meta","populate","document","additionalFields","documentId","locale","title","contentTypeUid","contentTypeDisplayName","info","displayName","kind","updatedAt","publishedAt","sanitizeHomepageQuery","additionalQueryParams","permissionQuery","sanitizedQuery","read","limit","sanitizedFields","compactSanitizedFields","titleField","resolveTitleField","addStatusToDocuments","Promise","all","recentDocument","availableStatus","getMetadata","availableLocales","status","getStatus","queryLastDocuments","draftAndPublishOnly","permittedContentTypes","contentTypesMeta","recentDocuments","docs","flat","sort","a","b","compareIso","left","right","direction","slice","getRecentlyPublishedDocuments","recentlyPublishedDocuments","getRecentlyUpdatedDocuments","recentlyUpdatedDocuments","getCountDocuments","countDocuments","draft","published","modified","strapiDBConnection","connection","tableName","collectionName","publishedDocuments","countDistinct","first","count","classified","select","raw","groupBy","counts","from","as"],"mappings":"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"}
|
|
@@ -79,8 +79,15 @@ var sortSchema = require('./sort-schema.js');
|
|
|
79
79
|
if (scalarKeys.length === 0) {
|
|
80
80
|
return strapiUtils.z.never();
|
|
81
81
|
}
|
|
82
|
-
// Lazy reference for recursion ($and / $or / $not)
|
|
82
|
+
// Lazy reference for recursion ($and / $or / $not).
|
|
83
|
+
// The getter is memoized: zod's JSON Schema conversion calls `def.getter()` directly for every
|
|
84
|
+
// node that reaches the lazy, bypassing zod's own cache, so an unmemoized getter rebuilds the
|
|
85
|
+
// whole object (fields x operators) many times per conversion.
|
|
86
|
+
let resolvedFiltersObject;
|
|
83
87
|
const filtersSchema = strapiUtils.z.lazy(()=>{
|
|
88
|
+
if (resolvedFiltersObject !== undefined) {
|
|
89
|
+
return resolvedFiltersObject;
|
|
90
|
+
}
|
|
84
91
|
const fieldShapes = {};
|
|
85
92
|
for (const key of scalarKeys){
|
|
86
93
|
const attr = attributes[key];
|
|
@@ -95,12 +102,13 @@ var sortSchema = require('./sort-schema.js');
|
|
|
95
102
|
operatorObject
|
|
96
103
|
]).optional();
|
|
97
104
|
}
|
|
98
|
-
|
|
105
|
+
resolvedFiltersObject = strapiUtils.z.object({
|
|
99
106
|
$and: strapiUtils.z.array(filtersSchema).optional(),
|
|
100
107
|
$or: strapiUtils.z.array(filtersSchema).optional(),
|
|
101
108
|
$not: filtersSchema.optional(),
|
|
102
109
|
...fieldShapes
|
|
103
110
|
}).strict();
|
|
111
|
+
return resolvedFiltersObject;
|
|
104
112
|
});
|
|
105
113
|
return filtersSchema.optional().describe(`Filter object. Supports logical operators ($and, $or, $not) and field operators ` + `($eq, $ne, $in, $contains, $gt, $lt, etc.). Valid fields: ${scalarKeys.join(', ')}.`);
|
|
106
114
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filters-schema.js","sources":["../../../../server/src/mcp/schemas/filters-schema.ts"],"sourcesContent":["import { z } from '@strapi/utils';\nimport type { Schema, Struct } from '@strapi/types';\nimport { getScalarAttributeKeys } from './sort-schema';\n\n/**\n * Maps a scalar Strapi attribute type to the appropriate Zod leaf value schema\n * used inside filter operator objects (e.g. { $eq: <value> }).\n */\nexport const attributeTypeToFilterValue = (attr: Schema.Attribute.AnyAttribute): z.ZodTypeAny => {\n switch (attr.type) {\n case 'integer':\n case 'biginteger':\n case 'decimal':\n case 'float':\n return z.union([z.number(), z.array(z.number())]);\n case 'boolean':\n return z.boolean();\n case 'enumeration': {\n const enumAttr = attr as Schema.Attribute.Enumeration<string[]>;\n if (Array.isArray(enumAttr.enum) && enumAttr.enum.length > 0) {\n return z.union([\n z.enum(enumAttr.enum as [string, ...string[]]),\n z.array(z.enum(enumAttr.enum as [string, ...string[]])),\n ]);\n }\n return z.union([z.string(), z.array(z.string())]);\n }\n default:\n // string, text, richtext, email, password, uid, date, datetime, time, timestamp\n return z.union([z.string(), z.array(z.string()), z.null()]);\n }\n};\n\n/** All supported Strapi filter operators (excludes the experimental `$jsonSupersetOf`). */\nexport const FILTER_OPERATORS = [\n '$eq',\n '$eqi',\n '$ne',\n '$nei',\n '$in',\n '$notIn',\n '$lt',\n '$lte',\n '$gt',\n '$gte',\n '$between',\n '$contains',\n '$notContains',\n '$containsi',\n '$notContainsi',\n '$startsWith',\n '$startsWithi',\n '$endsWith',\n '$endsWithi',\n '$null',\n '$notNull',\n] as const;\n\n/**\n * Builds a per-content-type recursive filters Zod schema.\n *\n * Shape:\n * - Logical operators: $and, $or accept an array of filter objects.\n * - Logical operator: $not accepts a single filter object.\n * - Field keys (scalar attrs only): accept either a direct value (implicit $eq)\n * or an operator object { $eq, $contains, $gt, … }.\n *\n * If the model has no scalar attributes, the schema is z.never() (filters not allowed).\n */\nexport const buildFiltersSchema = (\n attributes: Struct.SchemaAttributes,\n permittedFields?: Set<string> | null\n): z.ZodTypeAny => {\n const scalarKeys = getScalarAttributeKeys(attributes, permittedFields);\n\n if (scalarKeys.length === 0) {\n return z.never();\n }\n\n // Lazy reference for recursion ($and / $or / $not)\n const filtersSchema: z.ZodTypeAny = z.lazy(() => {\n const fieldShapes: Record<string, z.ZodTypeAny> = {};\n\n for (const key of scalarKeys) {\n const attr = attributes[key];\n const valueSchema = attributeTypeToFilterValue(attr);\n const operatorObject = z.object(\n Object.fromEntries(FILTER_OPERATORS.map((op) => [op, valueSchema.optional()]))\n );\n // Field accepts either a direct value (implicit $eq) or operator object\n fieldShapes[key] = z.union([valueSchema, operatorObject]).optional();\n }\n\n
|
|
1
|
+
{"version":3,"file":"filters-schema.js","sources":["../../../../server/src/mcp/schemas/filters-schema.ts"],"sourcesContent":["import { z } from '@strapi/utils';\nimport type { Schema, Struct } from '@strapi/types';\nimport { getScalarAttributeKeys } from './sort-schema';\n\n/**\n * Maps a scalar Strapi attribute type to the appropriate Zod leaf value schema\n * used inside filter operator objects (e.g. { $eq: <value> }).\n */\nexport const attributeTypeToFilterValue = (attr: Schema.Attribute.AnyAttribute): z.ZodTypeAny => {\n switch (attr.type) {\n case 'integer':\n case 'biginteger':\n case 'decimal':\n case 'float':\n return z.union([z.number(), z.array(z.number())]);\n case 'boolean':\n return z.boolean();\n case 'enumeration': {\n const enumAttr = attr as Schema.Attribute.Enumeration<string[]>;\n if (Array.isArray(enumAttr.enum) && enumAttr.enum.length > 0) {\n return z.union([\n z.enum(enumAttr.enum as [string, ...string[]]),\n z.array(z.enum(enumAttr.enum as [string, ...string[]])),\n ]);\n }\n return z.union([z.string(), z.array(z.string())]);\n }\n default:\n // string, text, richtext, email, password, uid, date, datetime, time, timestamp\n return z.union([z.string(), z.array(z.string()), z.null()]);\n }\n};\n\n/** All supported Strapi filter operators (excludes the experimental `$jsonSupersetOf`). */\nexport const FILTER_OPERATORS = [\n '$eq',\n '$eqi',\n '$ne',\n '$nei',\n '$in',\n '$notIn',\n '$lt',\n '$lte',\n '$gt',\n '$gte',\n '$between',\n '$contains',\n '$notContains',\n '$containsi',\n '$notContainsi',\n '$startsWith',\n '$startsWithi',\n '$endsWith',\n '$endsWithi',\n '$null',\n '$notNull',\n] as const;\n\n/**\n * Builds a per-content-type recursive filters Zod schema.\n *\n * Shape:\n * - Logical operators: $and, $or accept an array of filter objects.\n * - Logical operator: $not accepts a single filter object.\n * - Field keys (scalar attrs only): accept either a direct value (implicit $eq)\n * or an operator object { $eq, $contains, $gt, … }.\n *\n * If the model has no scalar attributes, the schema is z.never() (filters not allowed).\n */\nexport const buildFiltersSchema = (\n attributes: Struct.SchemaAttributes,\n permittedFields?: Set<string> | null\n): z.ZodTypeAny => {\n const scalarKeys = getScalarAttributeKeys(attributes, permittedFields);\n\n if (scalarKeys.length === 0) {\n return z.never();\n }\n\n // Lazy reference for recursion ($and / $or / $not).\n // The getter is memoized: zod's JSON Schema conversion calls `def.getter()` directly for every\n // node that reaches the lazy, bypassing zod's own cache, so an unmemoized getter rebuilds the\n // whole object (fields x operators) many times per conversion.\n let resolvedFiltersObject: z.ZodTypeAny | undefined;\n const filtersSchema: z.ZodTypeAny = z.lazy(() => {\n if (resolvedFiltersObject !== undefined) {\n return resolvedFiltersObject;\n }\n\n const fieldShapes: Record<string, z.ZodTypeAny> = {};\n\n for (const key of scalarKeys) {\n const attr = attributes[key];\n const valueSchema = attributeTypeToFilterValue(attr);\n const operatorObject = z.object(\n Object.fromEntries(FILTER_OPERATORS.map((op) => [op, valueSchema.optional()]))\n );\n // Field accepts either a direct value (implicit $eq) or operator object\n fieldShapes[key] = z.union([valueSchema, operatorObject]).optional();\n }\n\n resolvedFiltersObject = z\n .object({\n $and: z.array(filtersSchema).optional(),\n $or: z.array(filtersSchema).optional(),\n $not: filtersSchema.optional(),\n ...fieldShapes,\n })\n .strict();\n\n return resolvedFiltersObject;\n });\n\n return filtersSchema\n .optional()\n .describe(\n `Filter object. Supports logical operators ($and, $or, $not) and field operators ` +\n `($eq, $ne, $in, $contains, $gt, $lt, etc.). Valid fields: ${scalarKeys.join(', ')}.`\n );\n};\n"],"names":["attributeTypeToFilterValue","attr","type","z","union","number","array","boolean","enumAttr","Array","isArray","enum","length","string","null","FILTER_OPERATORS","buildFiltersSchema","attributes","permittedFields","scalarKeys","getScalarAttributeKeys","never","resolvedFiltersObject","filtersSchema","lazy","undefined","fieldShapes","key","valueSchema","operatorObject","object","Object","fromEntries","map","op","optional","$and","$or","$not","strict","describe","join"],"mappings":"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"}
|
|
@@ -77,8 +77,15 @@ import { getScalarAttributeKeys } from './sort-schema.mjs';
|
|
|
77
77
|
if (scalarKeys.length === 0) {
|
|
78
78
|
return z.never();
|
|
79
79
|
}
|
|
80
|
-
// Lazy reference for recursion ($and / $or / $not)
|
|
80
|
+
// Lazy reference for recursion ($and / $or / $not).
|
|
81
|
+
// The getter is memoized: zod's JSON Schema conversion calls `def.getter()` directly for every
|
|
82
|
+
// node that reaches the lazy, bypassing zod's own cache, so an unmemoized getter rebuilds the
|
|
83
|
+
// whole object (fields x operators) many times per conversion.
|
|
84
|
+
let resolvedFiltersObject;
|
|
81
85
|
const filtersSchema = z.lazy(()=>{
|
|
86
|
+
if (resolvedFiltersObject !== undefined) {
|
|
87
|
+
return resolvedFiltersObject;
|
|
88
|
+
}
|
|
82
89
|
const fieldShapes = {};
|
|
83
90
|
for (const key of scalarKeys){
|
|
84
91
|
const attr = attributes[key];
|
|
@@ -93,12 +100,13 @@ import { getScalarAttributeKeys } from './sort-schema.mjs';
|
|
|
93
100
|
operatorObject
|
|
94
101
|
]).optional();
|
|
95
102
|
}
|
|
96
|
-
|
|
103
|
+
resolvedFiltersObject = z.object({
|
|
97
104
|
$and: z.array(filtersSchema).optional(),
|
|
98
105
|
$or: z.array(filtersSchema).optional(),
|
|
99
106
|
$not: filtersSchema.optional(),
|
|
100
107
|
...fieldShapes
|
|
101
108
|
}).strict();
|
|
109
|
+
return resolvedFiltersObject;
|
|
102
110
|
});
|
|
103
111
|
return filtersSchema.optional().describe(`Filter object. Supports logical operators ($and, $or, $not) and field operators ` + `($eq, $ne, $in, $contains, $gt, $lt, etc.). Valid fields: ${scalarKeys.join(', ')}.`);
|
|
104
112
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filters-schema.mjs","sources":["../../../../server/src/mcp/schemas/filters-schema.ts"],"sourcesContent":["import { z } from '@strapi/utils';\nimport type { Schema, Struct } from '@strapi/types';\nimport { getScalarAttributeKeys } from './sort-schema';\n\n/**\n * Maps a scalar Strapi attribute type to the appropriate Zod leaf value schema\n * used inside filter operator objects (e.g. { $eq: <value> }).\n */\nexport const attributeTypeToFilterValue = (attr: Schema.Attribute.AnyAttribute): z.ZodTypeAny => {\n switch (attr.type) {\n case 'integer':\n case 'biginteger':\n case 'decimal':\n case 'float':\n return z.union([z.number(), z.array(z.number())]);\n case 'boolean':\n return z.boolean();\n case 'enumeration': {\n const enumAttr = attr as Schema.Attribute.Enumeration<string[]>;\n if (Array.isArray(enumAttr.enum) && enumAttr.enum.length > 0) {\n return z.union([\n z.enum(enumAttr.enum as [string, ...string[]]),\n z.array(z.enum(enumAttr.enum as [string, ...string[]])),\n ]);\n }\n return z.union([z.string(), z.array(z.string())]);\n }\n default:\n // string, text, richtext, email, password, uid, date, datetime, time, timestamp\n return z.union([z.string(), z.array(z.string()), z.null()]);\n }\n};\n\n/** All supported Strapi filter operators (excludes the experimental `$jsonSupersetOf`). */\nexport const FILTER_OPERATORS = [\n '$eq',\n '$eqi',\n '$ne',\n '$nei',\n '$in',\n '$notIn',\n '$lt',\n '$lte',\n '$gt',\n '$gte',\n '$between',\n '$contains',\n '$notContains',\n '$containsi',\n '$notContainsi',\n '$startsWith',\n '$startsWithi',\n '$endsWith',\n '$endsWithi',\n '$null',\n '$notNull',\n] as const;\n\n/**\n * Builds a per-content-type recursive filters Zod schema.\n *\n * Shape:\n * - Logical operators: $and, $or accept an array of filter objects.\n * - Logical operator: $not accepts a single filter object.\n * - Field keys (scalar attrs only): accept either a direct value (implicit $eq)\n * or an operator object { $eq, $contains, $gt, … }.\n *\n * If the model has no scalar attributes, the schema is z.never() (filters not allowed).\n */\nexport const buildFiltersSchema = (\n attributes: Struct.SchemaAttributes,\n permittedFields?: Set<string> | null\n): z.ZodTypeAny => {\n const scalarKeys = getScalarAttributeKeys(attributes, permittedFields);\n\n if (scalarKeys.length === 0) {\n return z.never();\n }\n\n // Lazy reference for recursion ($and / $or / $not)\n const filtersSchema: z.ZodTypeAny = z.lazy(() => {\n const fieldShapes: Record<string, z.ZodTypeAny> = {};\n\n for (const key of scalarKeys) {\n const attr = attributes[key];\n const valueSchema = attributeTypeToFilterValue(attr);\n const operatorObject = z.object(\n Object.fromEntries(FILTER_OPERATORS.map((op) => [op, valueSchema.optional()]))\n );\n // Field accepts either a direct value (implicit $eq) or operator object\n fieldShapes[key] = z.union([valueSchema, operatorObject]).optional();\n }\n\n
|
|
1
|
+
{"version":3,"file":"filters-schema.mjs","sources":["../../../../server/src/mcp/schemas/filters-schema.ts"],"sourcesContent":["import { z } from '@strapi/utils';\nimport type { Schema, Struct } from '@strapi/types';\nimport { getScalarAttributeKeys } from './sort-schema';\n\n/**\n * Maps a scalar Strapi attribute type to the appropriate Zod leaf value schema\n * used inside filter operator objects (e.g. { $eq: <value> }).\n */\nexport const attributeTypeToFilterValue = (attr: Schema.Attribute.AnyAttribute): z.ZodTypeAny => {\n switch (attr.type) {\n case 'integer':\n case 'biginteger':\n case 'decimal':\n case 'float':\n return z.union([z.number(), z.array(z.number())]);\n case 'boolean':\n return z.boolean();\n case 'enumeration': {\n const enumAttr = attr as Schema.Attribute.Enumeration<string[]>;\n if (Array.isArray(enumAttr.enum) && enumAttr.enum.length > 0) {\n return z.union([\n z.enum(enumAttr.enum as [string, ...string[]]),\n z.array(z.enum(enumAttr.enum as [string, ...string[]])),\n ]);\n }\n return z.union([z.string(), z.array(z.string())]);\n }\n default:\n // string, text, richtext, email, password, uid, date, datetime, time, timestamp\n return z.union([z.string(), z.array(z.string()), z.null()]);\n }\n};\n\n/** All supported Strapi filter operators (excludes the experimental `$jsonSupersetOf`). */\nexport const FILTER_OPERATORS = [\n '$eq',\n '$eqi',\n '$ne',\n '$nei',\n '$in',\n '$notIn',\n '$lt',\n '$lte',\n '$gt',\n '$gte',\n '$between',\n '$contains',\n '$notContains',\n '$containsi',\n '$notContainsi',\n '$startsWith',\n '$startsWithi',\n '$endsWith',\n '$endsWithi',\n '$null',\n '$notNull',\n] as const;\n\n/**\n * Builds a per-content-type recursive filters Zod schema.\n *\n * Shape:\n * - Logical operators: $and, $or accept an array of filter objects.\n * - Logical operator: $not accepts a single filter object.\n * - Field keys (scalar attrs only): accept either a direct value (implicit $eq)\n * or an operator object { $eq, $contains, $gt, … }.\n *\n * If the model has no scalar attributes, the schema is z.never() (filters not allowed).\n */\nexport const buildFiltersSchema = (\n attributes: Struct.SchemaAttributes,\n permittedFields?: Set<string> | null\n): z.ZodTypeAny => {\n const scalarKeys = getScalarAttributeKeys(attributes, permittedFields);\n\n if (scalarKeys.length === 0) {\n return z.never();\n }\n\n // Lazy reference for recursion ($and / $or / $not).\n // The getter is memoized: zod's JSON Schema conversion calls `def.getter()` directly for every\n // node that reaches the lazy, bypassing zod's own cache, so an unmemoized getter rebuilds the\n // whole object (fields x operators) many times per conversion.\n let resolvedFiltersObject: z.ZodTypeAny | undefined;\n const filtersSchema: z.ZodTypeAny = z.lazy(() => {\n if (resolvedFiltersObject !== undefined) {\n return resolvedFiltersObject;\n }\n\n const fieldShapes: Record<string, z.ZodTypeAny> = {};\n\n for (const key of scalarKeys) {\n const attr = attributes[key];\n const valueSchema = attributeTypeToFilterValue(attr);\n const operatorObject = z.object(\n Object.fromEntries(FILTER_OPERATORS.map((op) => [op, valueSchema.optional()]))\n );\n // Field accepts either a direct value (implicit $eq) or operator object\n fieldShapes[key] = z.union([valueSchema, operatorObject]).optional();\n }\n\n resolvedFiltersObject = z\n .object({\n $and: z.array(filtersSchema).optional(),\n $or: z.array(filtersSchema).optional(),\n $not: filtersSchema.optional(),\n ...fieldShapes,\n })\n .strict();\n\n return resolvedFiltersObject;\n });\n\n return filtersSchema\n .optional()\n .describe(\n `Filter object. Supports logical operators ($and, $or, $not) and field operators ` +\n `($eq, $ne, $in, $contains, $gt, $lt, etc.). Valid fields: ${scalarKeys.join(', ')}.`\n );\n};\n"],"names":["attributeTypeToFilterValue","attr","type","z","union","number","array","boolean","enumAttr","Array","isArray","enum","length","string","null","FILTER_OPERATORS","buildFiltersSchema","attributes","permittedFields","scalarKeys","getScalarAttributeKeys","never","resolvedFiltersObject","filtersSchema","lazy","undefined","fieldShapes","key","valueSchema","operatorObject","object","Object","fromEntries","map","op","optional","$and","$or","$not","strict","describe","join"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ const getPreviewUrlSchema = strapiUtils.z.object({
|
|
|
7
7
|
// Will be undefined for single types
|
|
8
8
|
documentId: strapiUtils.z.string().optional(),
|
|
9
9
|
locale: strapiUtils.z.string().nullable().optional(),
|
|
10
|
-
status: strapiUtils.
|
|
10
|
+
status: strapiUtils.statusSchema.optional()
|
|
11
11
|
});
|
|
12
12
|
const validatePreviewUrl = async (strapi, uid, params)=>{
|
|
13
13
|
// Validate the request parameters format
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview.js","sources":["../../../../../server/src/preview/controllers/validation/preview.ts"],"sourcesContent":["import { pick } from 'lodash';\n\nimport type { Core, UID } from '@strapi/types';\nimport { z, validateZodSchema, errors } from '@strapi/utils';\n\nimport { Preview } from '../../../../../shared/contracts';\nimport type { HandlerParams } from '../../services/preview-config';\n\nconst getPreviewUrlSchema = z.object({\n // Will be undefined for single types\n documentId: z.string().optional(),\n locale: z.string().nullable().optional(),\n status:
|
|
1
|
+
{"version":3,"file":"preview.js","sources":["../../../../../server/src/preview/controllers/validation/preview.ts"],"sourcesContent":["import { pick } from 'lodash';\n\nimport type { Core, UID } from '@strapi/types';\nimport { z, validateZodSchema, errors, statusSchema } from '@strapi/utils';\n\nimport { Preview } from '../../../../../shared/contracts';\nimport type { HandlerParams } from '../../services/preview-config';\n\nconst getPreviewUrlSchema = z.object({\n // Will be undefined for single types\n documentId: z.string().optional(),\n locale: z.string().nullable().optional(),\n status: statusSchema.optional(),\n});\n\nexport const validatePreviewUrl = async (\n strapi: Core.Strapi,\n uid: UID.ContentType,\n params: Preview.GetPreviewUrl.Request['query']\n): Promise<HandlerParams> => {\n // Validate the request parameters format\n validateZodSchema(getPreviewUrlSchema)(params);\n\n const newParams = pick(params, ['documentId', 'locale', 'status']) as HandlerParams;\n const model = strapi.getModel(uid);\n\n // If it's not a collection type or single type\n if (!model || model.modelType !== 'contentType') {\n throw new errors.ValidationError('Invalid content type');\n }\n\n // Document id is not required for single types\n const isSingleType = model?.kind === 'singleType';\n if (!isSingleType && !params.documentId) {\n throw new errors.ValidationError('documentId is required for Collection Types');\n }\n\n // Fill the documentId if it's a single type\n if (isSingleType) {\n const doc = await strapi.documents(uid).findFirst();\n\n if (!doc) {\n throw new errors.NotFoundError('Document not found');\n }\n\n newParams.documentId = doc?.documentId;\n }\n\n /**\n * If status is not specified, follow the following rules:\n * - D&P disabled: status is considered published\n * - D&P enabled: status is considered draft\n */\n if (!newParams.status) {\n const isDPEnabled = model?.options?.draftAndPublish;\n newParams.status = isDPEnabled ? 'draft' : 'published';\n }\n\n return newParams;\n};\n"],"names":["getPreviewUrlSchema","z","object","documentId","string","optional","locale","nullable","status","statusSchema","validatePreviewUrl","strapi","uid","params","validateZodSchema","newParams","pick","model","getModel","modelType","errors","ValidationError","isSingleType","kind","doc","documents","findFirst","NotFoundError","isDPEnabled","options","draftAndPublish"],"mappings":";;;;;AAQA,MAAMA,mBAAAA,GAAsBC,aAAAA,CAAEC,MAAM,CAAC;;IAEnCC,UAAAA,EAAYF,aAAAA,CAAEG,MAAM,EAAA,CAAGC,QAAQ,EAAA;AAC/BC,IAAAA,MAAAA,EAAQL,aAAAA,CAAEG,MAAM,EAAA,CAAGG,QAAQ,GAAGF,QAAQ,EAAA;AACtCG,IAAAA,MAAAA,EAAQC,yBAAaJ,QAAQ;AAC/B,CAAA,CAAA;AAEO,MAAMK,kBAAAA,GAAqB,OAChCC,MAAAA,EACAC,GAAAA,EACAC,MAAAA,GAAAA;;AAGAC,IAAAA,6BAAAA,CAAkBd,mBAAAA,CAAAA,CAAqBa,MAAAA,CAAAA;IAEvC,MAAME,SAAAA,GAAYC,OAAKH,MAAAA,EAAQ;AAAC,QAAA,YAAA;AAAc,QAAA,QAAA;AAAU,QAAA;AAAS,KAAA,CAAA;IACjE,MAAMI,KAAAA,GAAQN,MAAAA,CAAOO,QAAQ,CAACN,GAAAA,CAAAA;;AAG9B,IAAA,IAAI,CAACK,KAAAA,IAASA,KAAAA,CAAME,SAAS,KAAK,aAAA,EAAe;QAC/C,MAAM,IAAIC,kBAAAA,CAAOC,eAAe,CAAC,sBAAA,CAAA;AACnC,IAAA;;IAGA,MAAMC,YAAAA,GAAeL,OAAOM,IAAAA,KAAS,YAAA;AACrC,IAAA,IAAI,CAACD,YAAAA,IAAgB,CAACT,MAAAA,CAAOV,UAAU,EAAE;QACvC,MAAM,IAAIiB,kBAAAA,CAAOC,eAAe,CAAC,6CAAA,CAAA;AACnC,IAAA;;AAGA,IAAA,IAAIC,YAAAA,EAAc;AAChB,QAAA,MAAME,MAAM,MAAMb,MAAAA,CAAOc,SAAS,CAACb,KAAKc,SAAS,EAAA;AAEjD,QAAA,IAAI,CAACF,GAAAA,EAAK;YACR,MAAM,IAAIJ,kBAAAA,CAAOO,aAAa,CAAC,oBAAA,CAAA;AACjC,QAAA;QAEAZ,SAAAA,CAAUZ,UAAU,GAAGqB,GAAAA,EAAKrB,UAAAA;AAC9B,IAAA;AAEA;;;;AAIC,MACD,IAAI,CAACY,SAAAA,CAAUP,MAAM,EAAE;QACrB,MAAMoB,WAAAA,GAAcX,OAAOY,OAAAA,EAASC,eAAAA;QACpCf,SAAAA,CAAUP,MAAM,GAAGoB,WAAAA,GAAc,OAAA,GAAU,WAAA;AAC7C,IAAA;IAEA,OAAOb,SAAAA;AACT;;;;"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { pick } from 'lodash';
|
|
2
|
-
import { z, validateZodSchema, errors } from '@strapi/utils';
|
|
2
|
+
import { z, statusSchema, validateZodSchema, errors } from '@strapi/utils';
|
|
3
3
|
|
|
4
4
|
const getPreviewUrlSchema = z.object({
|
|
5
5
|
// Will be undefined for single types
|
|
6
6
|
documentId: z.string().optional(),
|
|
7
7
|
locale: z.string().nullable().optional(),
|
|
8
|
-
status:
|
|
8
|
+
status: statusSchema.optional()
|
|
9
9
|
});
|
|
10
10
|
const validatePreviewUrl = async (strapi, uid, params)=>{
|
|
11
11
|
// Validate the request parameters format
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview.mjs","sources":["../../../../../server/src/preview/controllers/validation/preview.ts"],"sourcesContent":["import { pick } from 'lodash';\n\nimport type { Core, UID } from '@strapi/types';\nimport { z, validateZodSchema, errors } from '@strapi/utils';\n\nimport { Preview } from '../../../../../shared/contracts';\nimport type { HandlerParams } from '../../services/preview-config';\n\nconst getPreviewUrlSchema = z.object({\n // Will be undefined for single types\n documentId: z.string().optional(),\n locale: z.string().nullable().optional(),\n status:
|
|
1
|
+
{"version":3,"file":"preview.mjs","sources":["../../../../../server/src/preview/controllers/validation/preview.ts"],"sourcesContent":["import { pick } from 'lodash';\n\nimport type { Core, UID } from '@strapi/types';\nimport { z, validateZodSchema, errors, statusSchema } from '@strapi/utils';\n\nimport { Preview } from '../../../../../shared/contracts';\nimport type { HandlerParams } from '../../services/preview-config';\n\nconst getPreviewUrlSchema = z.object({\n // Will be undefined for single types\n documentId: z.string().optional(),\n locale: z.string().nullable().optional(),\n status: statusSchema.optional(),\n});\n\nexport const validatePreviewUrl = async (\n strapi: Core.Strapi,\n uid: UID.ContentType,\n params: Preview.GetPreviewUrl.Request['query']\n): Promise<HandlerParams> => {\n // Validate the request parameters format\n validateZodSchema(getPreviewUrlSchema)(params);\n\n const newParams = pick(params, ['documentId', 'locale', 'status']) as HandlerParams;\n const model = strapi.getModel(uid);\n\n // If it's not a collection type or single type\n if (!model || model.modelType !== 'contentType') {\n throw new errors.ValidationError('Invalid content type');\n }\n\n // Document id is not required for single types\n const isSingleType = model?.kind === 'singleType';\n if (!isSingleType && !params.documentId) {\n throw new errors.ValidationError('documentId is required for Collection Types');\n }\n\n // Fill the documentId if it's a single type\n if (isSingleType) {\n const doc = await strapi.documents(uid).findFirst();\n\n if (!doc) {\n throw new errors.NotFoundError('Document not found');\n }\n\n newParams.documentId = doc?.documentId;\n }\n\n /**\n * If status is not specified, follow the following rules:\n * - D&P disabled: status is considered published\n * - D&P enabled: status is considered draft\n */\n if (!newParams.status) {\n const isDPEnabled = model?.options?.draftAndPublish;\n newParams.status = isDPEnabled ? 'draft' : 'published';\n }\n\n return newParams;\n};\n"],"names":["getPreviewUrlSchema","z","object","documentId","string","optional","locale","nullable","status","statusSchema","validatePreviewUrl","strapi","uid","params","validateZodSchema","newParams","pick","model","getModel","modelType","errors","ValidationError","isSingleType","kind","doc","documents","findFirst","NotFoundError","isDPEnabled","options","draftAndPublish"],"mappings":";;;AAQA,MAAMA,mBAAAA,GAAsBC,CAAAA,CAAEC,MAAM,CAAC;;IAEnCC,UAAAA,EAAYF,CAAAA,CAAEG,MAAM,EAAA,CAAGC,QAAQ,EAAA;AAC/BC,IAAAA,MAAAA,EAAQL,CAAAA,CAAEG,MAAM,EAAA,CAAGG,QAAQ,GAAGF,QAAQ,EAAA;AACtCG,IAAAA,MAAAA,EAAQC,aAAaJ,QAAQ;AAC/B,CAAA,CAAA;AAEO,MAAMK,kBAAAA,GAAqB,OAChCC,MAAAA,EACAC,GAAAA,EACAC,MAAAA,GAAAA;;AAGAC,IAAAA,iBAAAA,CAAkBd,mBAAAA,CAAAA,CAAqBa,MAAAA,CAAAA;IAEvC,MAAME,SAAAA,GAAYC,KAAKH,MAAAA,EAAQ;AAAC,QAAA,YAAA;AAAc,QAAA,QAAA;AAAU,QAAA;AAAS,KAAA,CAAA;IACjE,MAAMI,KAAAA,GAAQN,MAAAA,CAAOO,QAAQ,CAACN,GAAAA,CAAAA;;AAG9B,IAAA,IAAI,CAACK,KAAAA,IAASA,KAAAA,CAAME,SAAS,KAAK,aAAA,EAAe;QAC/C,MAAM,IAAIC,MAAAA,CAAOC,eAAe,CAAC,sBAAA,CAAA;AACnC,IAAA;;IAGA,MAAMC,YAAAA,GAAeL,OAAOM,IAAAA,KAAS,YAAA;AACrC,IAAA,IAAI,CAACD,YAAAA,IAAgB,CAACT,MAAAA,CAAOV,UAAU,EAAE;QACvC,MAAM,IAAIiB,MAAAA,CAAOC,eAAe,CAAC,6CAAA,CAAA;AACnC,IAAA;;AAGA,IAAA,IAAIC,YAAAA,EAAc;AAChB,QAAA,MAAME,MAAM,MAAMb,MAAAA,CAAOc,SAAS,CAACb,KAAKc,SAAS,EAAA;AAEjD,QAAA,IAAI,CAACF,GAAAA,EAAK;YACR,MAAM,IAAIJ,MAAAA,CAAOO,aAAa,CAAC,oBAAA,CAAA;AACjC,QAAA;QAEAZ,SAAAA,CAAUZ,UAAU,GAAGqB,GAAAA,EAAKrB,UAAAA;AAC9B,IAAA;AAEA;;;;AAIC,MACD,IAAI,CAACY,SAAAA,CAAUP,MAAM,EAAE;QACrB,MAAMoB,WAAAA,GAAcX,OAAOY,OAAAA,EAASC,eAAAA;QACpCf,SAAAA,CAAUP,MAAM,GAAGoB,WAAAA,GAAc,OAAA,GAAU,WAAA;AAC7C,IAAA;IAEA,OAAOb,SAAAA;AACT;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview-config.js","sources":["../../../../server/src/preview/services/preview-config.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { errors, extendMiddlewareConfiguration } from '@strapi/utils';\n\nexport type HandlerParams = {\n documentId: string;\n locale: string;\n status: 'published' | 'draft';\n};\n\n/**\n * @deprecated Use Core.Config.Admin['preview'] from @strapi/types instead\n * Keeping for backward compatibility\n */\nexport type PreviewConfig = NonNullable<Core.Config.Admin['preview']>;\n\n/**\n * Read configuration for static preview\n */\nconst createPreviewConfigService = ({ strapi }: { strapi: Core.Strapi }) => {\n return {\n register() {\n if (!this.isEnabled()) {\n return;\n }\n\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n /**\n * Register the allowed origins for CSP, so the preview URL can be displayed\n */\n if (config.config?.allowedOrigins) {\n const middlewares = strapi.config.get('middlewares') as (\n
|
|
1
|
+
{"version":3,"file":"preview-config.js","sources":["../../../../server/src/preview/services/preview-config.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { errors, extendMiddlewareConfiguration } from '@strapi/utils';\n\nexport type HandlerParams = {\n documentId: string;\n locale: string;\n status: 'published' | 'draft';\n};\n\n/**\n * @deprecated Use Core.Config.Admin['preview'] from @strapi/types instead\n * Keeping for backward compatibility\n */\nexport type PreviewConfig = NonNullable<Core.Config.Admin['preview']>;\n\n/**\n * Read configuration for static preview\n */\nconst createPreviewConfigService = ({ strapi }: { strapi: Core.Strapi }) => {\n return {\n register() {\n if (!this.isEnabled()) {\n return;\n }\n\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n /**\n * Register the allowed origins for CSP, so the preview URL can be displayed\n */\n if (config.config?.allowedOrigins) {\n const middlewares = strapi.config.get('middlewares') as (\n string | { name?: string; config?: any }\n )[];\n\n const configuredMiddlewares = extendMiddlewareConfiguration(middlewares, {\n name: 'strapi::security',\n config: {\n contentSecurityPolicy: {\n directives: {\n 'frame-src': config.config.allowedOrigins,\n },\n },\n },\n });\n\n strapi.config.set('middlewares', configuredMiddlewares);\n }\n },\n\n isConfigured() {\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n return config?.enabled === false || config?.config?.handler != null;\n },\n\n isEnabled() {\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n if (!config) {\n return false;\n }\n\n return config?.enabled ?? true;\n },\n\n /**\n * Validate if the configuration is valid\n */\n validate() {\n if (!this.isEnabled()) {\n return;\n }\n\n const handler = this.getPreviewHandler();\n\n // Handler must be a function\n if (typeof handler !== 'function') {\n throw new errors.ValidationError(\n 'Preview configuration is invalid. Handler must be a function'\n );\n }\n },\n\n /**\n * Utility to get the preview handler from the configuration\n */\n getPreviewHandler(): NonNullable<Core.Config.Admin['preview']>['config']['handler'] {\n const emptyHandler = () => {\n return undefined;\n };\n\n if (!this.isEnabled()) {\n return emptyHandler;\n }\n\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n return config?.config?.handler || emptyHandler;\n },\n };\n};\n\nexport { createPreviewConfigService };\n"],"names":["createPreviewConfigService","strapi","register","isEnabled","config","get","allowedOrigins","middlewares","configuredMiddlewares","extendMiddlewareConfiguration","name","contentSecurityPolicy","directives","set","isConfigured","enabled","handler","validate","getPreviewHandler","errors","ValidationError","emptyHandler","undefined"],"mappings":";;;;AAeA;;AAEC,IACD,MAAMA,0BAAAA,GAA6B,CAAC,EAAEC,MAAM,EAA2B,GAAA;IACrE,OAAO;AACLC,QAAAA,QAAAA,CAAAA,GAAAA;AACE,YAAA,IAAI,CAAC,IAAI,CAACC,SAAS,EAAA,EAAI;AACrB,gBAAA;AACF,YAAA;AAEA,YAAA,MAAMC,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;AAEjC;;AAEC,UACD,IAAID,MAAAA,CAAOA,MAAM,EAAEE,cAAAA,EAAgB;AACjC,gBAAA,MAAMC,WAAAA,GAAcN,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,aAAA,CAAA;gBAItC,MAAMG,qBAAAA,GAAwBC,0CAA8BF,WAAAA,EAAa;oBACvEG,IAAAA,EAAM,kBAAA;oBACNN,MAAAA,EAAQ;wBACNO,qBAAAA,EAAuB;4BACrBC,UAAAA,EAAY;gCACV,WAAA,EAAaR,MAAAA,CAAOA,MAAM,CAACE;AAC7B;AACF;AACF;AACF,iBAAA,CAAA;AAEAL,gBAAAA,MAAAA,CAAOG,MAAM,CAACS,GAAG,CAAC,aAAA,EAAeL,qBAAAA,CAAAA;AACnC,YAAA;AACF,QAAA,CAAA;AAEAM,QAAAA,YAAAA,CAAAA,GAAAA;AACE,YAAA,MAAMV,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;AACjC,YAAA,OAAOD,MAAAA,EAAQW,OAAAA,KAAY,KAAA,IAASX,MAAAA,EAAQA,QAAQY,OAAAA,IAAW,IAAA;AACjE,QAAA,CAAA;AAEAb,QAAAA,SAAAA,CAAAA,GAAAA;AACE,YAAA,MAAMC,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;AAEjC,YAAA,IAAI,CAACD,MAAAA,EAAQ;gBACX,OAAO,KAAA;AACT,YAAA;AAEA,YAAA,OAAOA,QAAQW,OAAAA,IAAW,IAAA;AAC5B,QAAA,CAAA;AAEA;;QAGAE,QAAAA,CAAAA,GAAAA;AACE,YAAA,IAAI,CAAC,IAAI,CAACd,SAAS,EAAA,EAAI;AACrB,gBAAA;AACF,YAAA;YAEA,MAAMa,OAAAA,GAAU,IAAI,CAACE,iBAAiB,EAAA;;YAGtC,IAAI,OAAOF,YAAY,UAAA,EAAY;gBACjC,MAAM,IAAIG,kBAAAA,CAAOC,eAAe,CAC9B,8DAAA,CAAA;AAEJ,YAAA;AACF,QAAA,CAAA;AAEA;;QAGAF,iBAAAA,CAAAA,GAAAA;AACE,YAAA,MAAMG,YAAAA,GAAe,IAAA;gBACnB,OAAOC,SAAAA;AACT,YAAA,CAAA;AAEA,YAAA,IAAI,CAAC,IAAI,CAACnB,SAAS,EAAA,EAAI;gBACrB,OAAOkB,YAAAA;AACT,YAAA;AAEA,YAAA,MAAMjB,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;YAEjC,OAAOD,MAAAA,EAAQA,QAAQY,OAAAA,IAAWK,YAAAA;AACpC,QAAA;AACF,KAAA;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview-config.mjs","sources":["../../../../server/src/preview/services/preview-config.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { errors, extendMiddlewareConfiguration } from '@strapi/utils';\n\nexport type HandlerParams = {\n documentId: string;\n locale: string;\n status: 'published' | 'draft';\n};\n\n/**\n * @deprecated Use Core.Config.Admin['preview'] from @strapi/types instead\n * Keeping for backward compatibility\n */\nexport type PreviewConfig = NonNullable<Core.Config.Admin['preview']>;\n\n/**\n * Read configuration for static preview\n */\nconst createPreviewConfigService = ({ strapi }: { strapi: Core.Strapi }) => {\n return {\n register() {\n if (!this.isEnabled()) {\n return;\n }\n\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n /**\n * Register the allowed origins for CSP, so the preview URL can be displayed\n */\n if (config.config?.allowedOrigins) {\n const middlewares = strapi.config.get('middlewares') as (\n
|
|
1
|
+
{"version":3,"file":"preview-config.mjs","sources":["../../../../server/src/preview/services/preview-config.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { errors, extendMiddlewareConfiguration } from '@strapi/utils';\n\nexport type HandlerParams = {\n documentId: string;\n locale: string;\n status: 'published' | 'draft';\n};\n\n/**\n * @deprecated Use Core.Config.Admin['preview'] from @strapi/types instead\n * Keeping for backward compatibility\n */\nexport type PreviewConfig = NonNullable<Core.Config.Admin['preview']>;\n\n/**\n * Read configuration for static preview\n */\nconst createPreviewConfigService = ({ strapi }: { strapi: Core.Strapi }) => {\n return {\n register() {\n if (!this.isEnabled()) {\n return;\n }\n\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n /**\n * Register the allowed origins for CSP, so the preview URL can be displayed\n */\n if (config.config?.allowedOrigins) {\n const middlewares = strapi.config.get('middlewares') as (\n string | { name?: string; config?: any }\n )[];\n\n const configuredMiddlewares = extendMiddlewareConfiguration(middlewares, {\n name: 'strapi::security',\n config: {\n contentSecurityPolicy: {\n directives: {\n 'frame-src': config.config.allowedOrigins,\n },\n },\n },\n });\n\n strapi.config.set('middlewares', configuredMiddlewares);\n }\n },\n\n isConfigured() {\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n return config?.enabled === false || config?.config?.handler != null;\n },\n\n isEnabled() {\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n if (!config) {\n return false;\n }\n\n return config?.enabled ?? true;\n },\n\n /**\n * Validate if the configuration is valid\n */\n validate() {\n if (!this.isEnabled()) {\n return;\n }\n\n const handler = this.getPreviewHandler();\n\n // Handler must be a function\n if (typeof handler !== 'function') {\n throw new errors.ValidationError(\n 'Preview configuration is invalid. Handler must be a function'\n );\n }\n },\n\n /**\n * Utility to get the preview handler from the configuration\n */\n getPreviewHandler(): NonNullable<Core.Config.Admin['preview']>['config']['handler'] {\n const emptyHandler = () => {\n return undefined;\n };\n\n if (!this.isEnabled()) {\n return emptyHandler;\n }\n\n const config = strapi.config.get('admin.preview') as PreviewConfig;\n\n return config?.config?.handler || emptyHandler;\n },\n };\n};\n\nexport { createPreviewConfigService };\n"],"names":["createPreviewConfigService","strapi","register","isEnabled","config","get","allowedOrigins","middlewares","configuredMiddlewares","extendMiddlewareConfiguration","name","contentSecurityPolicy","directives","set","isConfigured","enabled","handler","validate","getPreviewHandler","errors","ValidationError","emptyHandler","undefined"],"mappings":";;AAeA;;AAEC,IACD,MAAMA,0BAAAA,GAA6B,CAAC,EAAEC,MAAM,EAA2B,GAAA;IACrE,OAAO;AACLC,QAAAA,QAAAA,CAAAA,GAAAA;AACE,YAAA,IAAI,CAAC,IAAI,CAACC,SAAS,EAAA,EAAI;AACrB,gBAAA;AACF,YAAA;AAEA,YAAA,MAAMC,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;AAEjC;;AAEC,UACD,IAAID,MAAAA,CAAOA,MAAM,EAAEE,cAAAA,EAAgB;AACjC,gBAAA,MAAMC,WAAAA,GAAcN,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,aAAA,CAAA;gBAItC,MAAMG,qBAAAA,GAAwBC,8BAA8BF,WAAAA,EAAa;oBACvEG,IAAAA,EAAM,kBAAA;oBACNN,MAAAA,EAAQ;wBACNO,qBAAAA,EAAuB;4BACrBC,UAAAA,EAAY;gCACV,WAAA,EAAaR,MAAAA,CAAOA,MAAM,CAACE;AAC7B;AACF;AACF;AACF,iBAAA,CAAA;AAEAL,gBAAAA,MAAAA,CAAOG,MAAM,CAACS,GAAG,CAAC,aAAA,EAAeL,qBAAAA,CAAAA;AACnC,YAAA;AACF,QAAA,CAAA;AAEAM,QAAAA,YAAAA,CAAAA,GAAAA;AACE,YAAA,MAAMV,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;AACjC,YAAA,OAAOD,MAAAA,EAAQW,OAAAA,KAAY,KAAA,IAASX,MAAAA,EAAQA,QAAQY,OAAAA,IAAW,IAAA;AACjE,QAAA,CAAA;AAEAb,QAAAA,SAAAA,CAAAA,GAAAA;AACE,YAAA,MAAMC,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;AAEjC,YAAA,IAAI,CAACD,MAAAA,EAAQ;gBACX,OAAO,KAAA;AACT,YAAA;AAEA,YAAA,OAAOA,QAAQW,OAAAA,IAAW,IAAA;AAC5B,QAAA,CAAA;AAEA;;QAGAE,QAAAA,CAAAA,GAAAA;AACE,YAAA,IAAI,CAAC,IAAI,CAACd,SAAS,EAAA,EAAI;AACrB,gBAAA;AACF,YAAA;YAEA,MAAMa,OAAAA,GAAU,IAAI,CAACE,iBAAiB,EAAA;;YAGtC,IAAI,OAAOF,YAAY,UAAA,EAAY;gBACjC,MAAM,IAAIG,MAAAA,CAAOC,eAAe,CAC9B,8DAAA,CAAA;AAEJ,YAAA;AACF,QAAA,CAAA;AAEA;;QAGAF,iBAAAA,CAAAA,GAAAA;AACE,YAAA,MAAMG,YAAAA,GAAe,IAAA;gBACnB,OAAOC,SAAAA;AACT,YAAA,CAAA;AAEA,YAAA,IAAI,CAAC,IAAI,CAACnB,SAAS,EAAA,EAAI;gBACrB,OAAOkB,YAAAA;AACT,YAAA;AAEA,YAAA,MAAMjB,MAAAA,GAASH,MAAAA,CAAOG,MAAM,CAACC,GAAG,CAAC,eAAA,CAAA;YAEjC,OAAOD,MAAAA,EAAQA,QAAQY,OAAAA,IAAWK,YAAAA;AACpC,QAAA;AACF,KAAA;AACF;;;;"}
|
package/dist/server/register.js
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
var index = require('./history/index.js');
|
|
4
4
|
var index$1 = require('./preview/index.js');
|
|
5
|
+
var renameFields = require('./services/configuration/rename-fields.js');
|
|
5
6
|
|
|
6
7
|
const register = async ({ strapi })=>{
|
|
8
|
+
// Before user migrations run, so a generated rename migration can rewrite the
|
|
9
|
+
// saved layouts and leave the old-to-new map for each admin's browser.
|
|
10
|
+
strapi.db.schema.registerAttributeRenameHandler(renameFields.createContentManagerConfigurationRenamer({
|
|
11
|
+
strapi
|
|
12
|
+
}));
|
|
7
13
|
await index.register?.({
|
|
8
14
|
strapi
|
|
9
15
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sources":["../../server/src/register.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\nimport history from './history';\nimport preview from './preview';\n\nconst register: Plugin.LoadedPlugin['register'] = async ({ strapi }) => {\n await history.register?.({ strapi });\n await preview.register?.({ strapi });\n};\n\nexport default register;\n"],"names":["register","strapi","history","preview"],"mappings":"
|
|
1
|
+
{"version":3,"file":"register.js","sources":["../../server/src/register.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\nimport history from './history';\nimport preview from './preview';\nimport { createContentManagerConfigurationRenamer } from './services/configuration/rename-fields';\n\nconst register: Plugin.LoadedPlugin['register'] = async ({ strapi }) => {\n // Before user migrations run, so a generated rename migration can rewrite the\n // saved layouts and leave the old-to-new map for each admin's browser.\n strapi.db.schema.registerAttributeRenameHandler(\n createContentManagerConfigurationRenamer({ strapi })\n );\n\n await history.register?.({ strapi });\n await preview.register?.({ strapi });\n};\n\nexport default register;\n"],"names":["register","strapi","db","schema","registerAttributeRenameHandler","createContentManagerConfigurationRenamer","history","preview"],"mappings":";;;;;;AAKA,MAAMA,QAAAA,GAA4C,OAAO,EAAEC,MAAM,EAAE,GAAA;;;AAGjEA,IAAAA,MAAAA,CAAOC,EAAE,CAACC,MAAM,CAACC,8BAA8B,CAC7CC,qDAAAA,CAAyC;AAAEJ,QAAAA;AAAO,KAAA,CAAA,CAAA;IAGpD,MAAMK,KAAAA,CAAQN,QAAQ,GAAG;AAAEC,QAAAA;AAAO,KAAA,CAAA;IAClC,MAAMM,OAAAA,CAAQP,QAAQ,GAAG;AAAEC,QAAAA;AAAO,KAAA,CAAA;AACpC;;;;"}
|
package/dist/server/register.mjs
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import history from './history/index.mjs';
|
|
2
2
|
import preview from './preview/index.mjs';
|
|
3
|
+
import { createContentManagerConfigurationRenamer } from './services/configuration/rename-fields.mjs';
|
|
3
4
|
|
|
4
5
|
const register = async ({ strapi })=>{
|
|
6
|
+
// Before user migrations run, so a generated rename migration can rewrite the
|
|
7
|
+
// saved layouts and leave the old-to-new map for each admin's browser.
|
|
8
|
+
strapi.db.schema.registerAttributeRenameHandler(createContentManagerConfigurationRenamer({
|
|
9
|
+
strapi
|
|
10
|
+
}));
|
|
5
11
|
await history.register?.({
|
|
6
12
|
strapi
|
|
7
13
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.mjs","sources":["../../server/src/register.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\nimport history from './history';\nimport preview from './preview';\n\nconst register: Plugin.LoadedPlugin['register'] = async ({ strapi }) => {\n await history.register?.({ strapi });\n await preview.register?.({ strapi });\n};\n\nexport default register;\n"],"names":["register","strapi","history","preview"],"mappings":"
|
|
1
|
+
{"version":3,"file":"register.mjs","sources":["../../server/src/register.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\nimport history from './history';\nimport preview from './preview';\nimport { createContentManagerConfigurationRenamer } from './services/configuration/rename-fields';\n\nconst register: Plugin.LoadedPlugin['register'] = async ({ strapi }) => {\n // Before user migrations run, so a generated rename migration can rewrite the\n // saved layouts and leave the old-to-new map for each admin's browser.\n strapi.db.schema.registerAttributeRenameHandler(\n createContentManagerConfigurationRenamer({ strapi })\n );\n\n await history.register?.({ strapi });\n await preview.register?.({ strapi });\n};\n\nexport default register;\n"],"names":["register","strapi","db","schema","registerAttributeRenameHandler","createContentManagerConfigurationRenamer","history","preview"],"mappings":";;;;AAKA,MAAMA,QAAAA,GAA4C,OAAO,EAAEC,MAAM,EAAE,GAAA;;;AAGjEA,IAAAA,MAAAA,CAAOC,EAAE,CAACC,MAAM,CAACC,8BAA8B,CAC7CC,wCAAAA,CAAyC;AAAEJ,QAAAA;AAAO,KAAA,CAAA,CAAA;IAGpD,MAAMK,OAAAA,CAAQN,QAAQ,GAAG;AAAEC,QAAAA;AAAO,KAAA,CAAA;IAClC,MAAMM,OAAAA,CAAQP,QAAQ,GAAG;AAAEC,QAAAA;AAAO,KAAA,CAAA;AACpC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.js","sources":["../../../server/src/services/components.ts"],"sourcesContent":["import { mapValues } from 'lodash';\n\nimport type { UID, Struct, Core } from '@strapi/types';\nimport type { Configuration } from '../../../shared/contracts/content-types';\nimport type { ConfigurationUpdate } from './configuration';\n\nimport { getService } from '../utils';\nimport storeUtils from './utils/store';\nimport createConfigurationService from './configuration';\n\nconst STORE_KEY_PREFIX = 'components';\n\nconst configurationService = createConfigurationService({\n storeUtils,\n isComponent: true,\n prefix: STORE_KEY_PREFIX,\n getModels() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return mapValues(strapi.components, (value) => toContentManagerModel(value));\n },\n});\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n findAllComponents() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return Object.values(strapi.components).map(toContentManagerModel);\n },\n\n findComponent(uid: UID.Component) {\n const { toContentManagerModel } = getService('data-mapper');\n\n const component = strapi.components[uid];\n\n return component == null ? component : toContentManagerModel(component);\n },\n\n async findConfiguration(component: Struct.ComponentSchema) {\n const configuration: Configuration = await configurationService.getConfiguration(component.uid);\n\n return {\n uid: component.uid,\n category: component.category,\n ...configuration,\n };\n },\n\n async updateConfiguration(\n component: Struct.ComponentSchema,\n newConfiguration: ConfigurationUpdate\n ) {\n await configurationService.setConfiguration(component.uid, newConfiguration);\n\n return this.findConfiguration(component);\n },\n\n /**\n * Batch load component configurations.\n *\n * Collects all component UIDs upfront, then loads configurations in a single\n * batch query instead of sequential queries per component.\n */\n async findComponentsConfigurations(model: Struct.ComponentSchema) {\n // Cache on request state so the same request can reuse configs\n const requestState = strapi.requestContext?.get?.()?.state as\n
|
|
1
|
+
{"version":3,"file":"components.js","sources":["../../../server/src/services/components.ts"],"sourcesContent":["import { mapValues } from 'lodash';\n\nimport type { UID, Struct, Core } from '@strapi/types';\nimport type { Configuration } from '../../../shared/contracts/content-types';\nimport type { ConfigurationUpdate } from './configuration';\n\nimport { getService } from '../utils';\nimport storeUtils from './utils/store';\nimport createConfigurationService from './configuration';\n\nconst STORE_KEY_PREFIX = 'components';\n\nconst configurationService = createConfigurationService({\n storeUtils,\n isComponent: true,\n prefix: STORE_KEY_PREFIX,\n getModels() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return mapValues(strapi.components, (value) => toContentManagerModel(value));\n },\n});\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n findAllComponents() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return Object.values(strapi.components).map(toContentManagerModel);\n },\n\n findComponent(uid: UID.Component) {\n const { toContentManagerModel } = getService('data-mapper');\n\n const component = strapi.components[uid];\n\n return component == null ? component : toContentManagerModel(component);\n },\n\n async findConfiguration(component: Struct.ComponentSchema) {\n const configuration: Configuration = await configurationService.getConfiguration(component.uid);\n\n return {\n uid: component.uid,\n category: component.category,\n ...configuration,\n };\n },\n\n async updateConfiguration(\n component: Struct.ComponentSchema,\n newConfiguration: ConfigurationUpdate\n ) {\n await configurationService.setConfiguration(component.uid, newConfiguration);\n\n return this.findConfiguration(component);\n },\n\n /**\n * Batch load component configurations.\n *\n * Collects all component UIDs upfront, then loads configurations in a single\n * batch query instead of sequential queries per component.\n */\n async findComponentsConfigurations(model: Struct.ComponentSchema) {\n // Cache on request state so the same request can reuse configs\n const requestState = strapi.requestContext?.get?.()?.state as\n { __componentsConfigurationsCache?: Map<string, Record<string, Configuration>> } | undefined;\n const requestCache = requestState?.__componentsConfigurationsCache;\n\n const componentUids = new Set<UID.Component>();\n\n const collectComponentUids = (schema: Struct.ComponentSchema) => {\n for (const key of Object.keys(schema.attributes)) {\n const attribute = schema.attributes[key];\n\n if (attribute.type === 'component') {\n const uid = attribute.component;\n if (!componentUids.has(uid)) {\n componentUids.add(uid);\n const nestedComponent = this.findComponent(uid);\n if (nestedComponent) {\n collectComponentUids(nestedComponent);\n }\n }\n }\n\n if (attribute.type === 'dynamiczone') {\n for (const uid of attribute.components) {\n if (!componentUids.has(uid)) {\n componentUids.add(uid);\n const nestedComponent = this.findComponent(uid);\n if (nestedComponent) {\n collectComponentUids(nestedComponent);\n }\n }\n }\n }\n }\n };\n\n collectComponentUids(model);\n\n if (componentUids.size === 0) {\n return {};\n }\n\n // Key format must match configuration.ts uidToStoreKey: `${prefix}::${uid}`\n const uidsArray = Array.from(componentUids);\n const prefixedKeys = uidsArray.map((uid) => `components::${uid}`);\n const cacheKey = prefixedKeys.slice().sort().join('|');\n if (requestCache?.has(cacheKey)) {\n return requestCache.get(cacheKey)! as Record<\n string,\n Configuration & { category: string; isComponent: boolean }\n >;\n }\n\n const configs = await storeUtils.getModelConfigurations(prefixedKeys);\n\n const componentsMap: Record<\n string,\n Configuration & { category: string; isComponent: boolean }\n > = {};\n\n for (const uid of uidsArray) {\n const component = this.findComponent(uid);\n const configKey = `components::${uid}`;\n // Fallback must include proper layouts structure for frontend compatibility\n const configuration = configs[configKey] || {\n settings: {},\n metadatas: {},\n layouts: { list: [], edit: [] },\n };\n\n componentsMap[uid] = {\n uid: component.uid,\n category: component.category,\n ...configuration,\n };\n }\n\n if (requestState) {\n if (!requestState.__componentsConfigurationsCache) {\n requestState.__componentsConfigurationsCache = new Map();\n }\n requestState.__componentsConfigurationsCache.set(cacheKey, componentsMap);\n }\n\n return componentsMap;\n },\n\n syncConfigurations() {\n return configurationService.syncConfigurations();\n },\n});\n"],"names":["STORE_KEY_PREFIX","configurationService","createConfigurationService","storeUtils","isComponent","prefix","getModels","toContentManagerModel","getService","mapValues","strapi","components","value","findAllComponents","Object","values","map","findComponent","uid","component","findConfiguration","configuration","getConfiguration","category","updateConfiguration","newConfiguration","setConfiguration","findComponentsConfigurations","model","requestState","requestContext","get","state","requestCache","__componentsConfigurationsCache","componentUids","Set","collectComponentUids","schema","key","keys","attributes","attribute","type","has","add","nestedComponent","size","uidsArray","Array","from","prefixedKeys","cacheKey","slice","sort","join","configs","getModelConfigurations","componentsMap","configKey","settings","metadatas","layouts","list","edit","Map","set","syncConfigurations"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.mjs","sources":["../../../server/src/services/components.ts"],"sourcesContent":["import { mapValues } from 'lodash';\n\nimport type { UID, Struct, Core } from '@strapi/types';\nimport type { Configuration } from '../../../shared/contracts/content-types';\nimport type { ConfigurationUpdate } from './configuration';\n\nimport { getService } from '../utils';\nimport storeUtils from './utils/store';\nimport createConfigurationService from './configuration';\n\nconst STORE_KEY_PREFIX = 'components';\n\nconst configurationService = createConfigurationService({\n storeUtils,\n isComponent: true,\n prefix: STORE_KEY_PREFIX,\n getModels() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return mapValues(strapi.components, (value) => toContentManagerModel(value));\n },\n});\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n findAllComponents() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return Object.values(strapi.components).map(toContentManagerModel);\n },\n\n findComponent(uid: UID.Component) {\n const { toContentManagerModel } = getService('data-mapper');\n\n const component = strapi.components[uid];\n\n return component == null ? component : toContentManagerModel(component);\n },\n\n async findConfiguration(component: Struct.ComponentSchema) {\n const configuration: Configuration = await configurationService.getConfiguration(component.uid);\n\n return {\n uid: component.uid,\n category: component.category,\n ...configuration,\n };\n },\n\n async updateConfiguration(\n component: Struct.ComponentSchema,\n newConfiguration: ConfigurationUpdate\n ) {\n await configurationService.setConfiguration(component.uid, newConfiguration);\n\n return this.findConfiguration(component);\n },\n\n /**\n * Batch load component configurations.\n *\n * Collects all component UIDs upfront, then loads configurations in a single\n * batch query instead of sequential queries per component.\n */\n async findComponentsConfigurations(model: Struct.ComponentSchema) {\n // Cache on request state so the same request can reuse configs\n const requestState = strapi.requestContext?.get?.()?.state as\n
|
|
1
|
+
{"version":3,"file":"components.mjs","sources":["../../../server/src/services/components.ts"],"sourcesContent":["import { mapValues } from 'lodash';\n\nimport type { UID, Struct, Core } from '@strapi/types';\nimport type { Configuration } from '../../../shared/contracts/content-types';\nimport type { ConfigurationUpdate } from './configuration';\n\nimport { getService } from '../utils';\nimport storeUtils from './utils/store';\nimport createConfigurationService from './configuration';\n\nconst STORE_KEY_PREFIX = 'components';\n\nconst configurationService = createConfigurationService({\n storeUtils,\n isComponent: true,\n prefix: STORE_KEY_PREFIX,\n getModels() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return mapValues(strapi.components, (value) => toContentManagerModel(value));\n },\n});\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n findAllComponents() {\n const { toContentManagerModel } = getService('data-mapper');\n\n return Object.values(strapi.components).map(toContentManagerModel);\n },\n\n findComponent(uid: UID.Component) {\n const { toContentManagerModel } = getService('data-mapper');\n\n const component = strapi.components[uid];\n\n return component == null ? component : toContentManagerModel(component);\n },\n\n async findConfiguration(component: Struct.ComponentSchema) {\n const configuration: Configuration = await configurationService.getConfiguration(component.uid);\n\n return {\n uid: component.uid,\n category: component.category,\n ...configuration,\n };\n },\n\n async updateConfiguration(\n component: Struct.ComponentSchema,\n newConfiguration: ConfigurationUpdate\n ) {\n await configurationService.setConfiguration(component.uid, newConfiguration);\n\n return this.findConfiguration(component);\n },\n\n /**\n * Batch load component configurations.\n *\n * Collects all component UIDs upfront, then loads configurations in a single\n * batch query instead of sequential queries per component.\n */\n async findComponentsConfigurations(model: Struct.ComponentSchema) {\n // Cache on request state so the same request can reuse configs\n const requestState = strapi.requestContext?.get?.()?.state as\n { __componentsConfigurationsCache?: Map<string, Record<string, Configuration>> } | undefined;\n const requestCache = requestState?.__componentsConfigurationsCache;\n\n const componentUids = new Set<UID.Component>();\n\n const collectComponentUids = (schema: Struct.ComponentSchema) => {\n for (const key of Object.keys(schema.attributes)) {\n const attribute = schema.attributes[key];\n\n if (attribute.type === 'component') {\n const uid = attribute.component;\n if (!componentUids.has(uid)) {\n componentUids.add(uid);\n const nestedComponent = this.findComponent(uid);\n if (nestedComponent) {\n collectComponentUids(nestedComponent);\n }\n }\n }\n\n if (attribute.type === 'dynamiczone') {\n for (const uid of attribute.components) {\n if (!componentUids.has(uid)) {\n componentUids.add(uid);\n const nestedComponent = this.findComponent(uid);\n if (nestedComponent) {\n collectComponentUids(nestedComponent);\n }\n }\n }\n }\n }\n };\n\n collectComponentUids(model);\n\n if (componentUids.size === 0) {\n return {};\n }\n\n // Key format must match configuration.ts uidToStoreKey: `${prefix}::${uid}`\n const uidsArray = Array.from(componentUids);\n const prefixedKeys = uidsArray.map((uid) => `components::${uid}`);\n const cacheKey = prefixedKeys.slice().sort().join('|');\n if (requestCache?.has(cacheKey)) {\n return requestCache.get(cacheKey)! as Record<\n string,\n Configuration & { category: string; isComponent: boolean }\n >;\n }\n\n const configs = await storeUtils.getModelConfigurations(prefixedKeys);\n\n const componentsMap: Record<\n string,\n Configuration & { category: string; isComponent: boolean }\n > = {};\n\n for (const uid of uidsArray) {\n const component = this.findComponent(uid);\n const configKey = `components::${uid}`;\n // Fallback must include proper layouts structure for frontend compatibility\n const configuration = configs[configKey] || {\n settings: {},\n metadatas: {},\n layouts: { list: [], edit: [] },\n };\n\n componentsMap[uid] = {\n uid: component.uid,\n category: component.category,\n ...configuration,\n };\n }\n\n if (requestState) {\n if (!requestState.__componentsConfigurationsCache) {\n requestState.__componentsConfigurationsCache = new Map();\n }\n requestState.__componentsConfigurationsCache.set(cacheKey, componentsMap);\n }\n\n return componentsMap;\n },\n\n syncConfigurations() {\n return configurationService.syncConfigurations();\n },\n});\n"],"names":["STORE_KEY_PREFIX","configurationService","createConfigurationService","storeUtils","isComponent","prefix","getModels","toContentManagerModel","getService","mapValues","strapi","components","value","findAllComponents","Object","values","map","findComponent","uid","component","findConfiguration","configuration","getConfiguration","category","updateConfiguration","newConfiguration","setConfiguration","findComponentsConfigurations","model","requestState","requestContext","get","state","requestCache","__componentsConfigurationsCache","componentUids","Set","collectComponentUids","schema","key","keys","attributes","attribute","type","has","add","nestedComponent","size","uidsArray","Array","from","prefixedKeys","cacheKey","slice","sort","join","configs","getModelConfigurations","componentsMap","configKey","settings","metadatas","layouts","list","edit","Map","set","syncConfigurations"],"mappings":"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"}
|