diff --git a/packages/payload/src/config/client.ts b/packages/payload/src/config/client.ts index 0ff9d210849..9f00bef57c2 100644 --- a/packages/payload/src/config/client.ts +++ b/packages/payload/src/config/client.ts @@ -21,6 +21,7 @@ import { type ClientGlobalConfig, createClientGlobalConfigs } from '../globals/c export type ServerOnlyRootProperties = keyof Pick< SanitizedConfig, | 'bin' + | 'collectionsBySlug' | 'cors' | 'csrf' | 'custom' @@ -28,6 +29,7 @@ export type ServerOnlyRootProperties = keyof Pick< | 'editor' | 'email' | 'endpoints' + | 'globalsBySlug' | 'graphQL' | 'hooks' | 'i18n' @@ -99,6 +101,8 @@ export const serverOnlyConfigProperties: readonly Partial { + it('should populate collectionsBySlug map from collections array', async () => { + const config = await sanitizeConfig({ + collections: [ + { slug: 'posts', fields: [] }, + { slug: 'users', auth: true, fields: [] }, + ], + globals: [{ slug: 'settings', fields: [] }], + } as any) + + expect(config.collectionsBySlug).toEqual(expect.objectContaining({ posts: expect.any(Object) })) + expect(Object.keys(config.collectionsBySlug).length).toBe(config.collections.length) + expect(config.collectionsBySlug['posts']).toBe( + config.collections.find((c) => c.slug === 'posts'), + ) + }) + + it('should populate globalsBySlug map from globals array', async () => { + const config = await sanitizeConfig({ + collections: [], + globals: [ + { slug: 'settings', fields: [] }, + { slug: 'nav', fields: [] }, + ], + } as any) + + expect(config.globalsBySlug).toEqual(expect.objectContaining({ settings: expect.any(Object) })) + expect(Object.keys(config.globalsBySlug).length).toBe(config.globals.length) + expect(config.globalsBySlug['settings']).toBe(config.globals.find((g) => g.slug === 'settings')) + }) +}) diff --git a/packages/payload/src/config/sanitize.ts b/packages/payload/src/config/sanitize.ts index e65799c6e6d..fa06ba5529c 100644 --- a/packages/payload/src/config/sanitize.ts +++ b/packages/payload/src/config/sanitize.ts @@ -4,7 +4,12 @@ import { en } from '@payloadcms/translations/languages/en' import { deepMergeSimple } from '@payloadcms/translations/utilities' import type { OrderableJoinInfo } from '../fields/config/sanitizeJoinField.js' -import type { CollectionSlug, GlobalSlug, SanitizedCollectionConfig } from '../index.js' +import type { + CollectionSlug, + GlobalSlug, + SanitizedCollectionConfig, + SanitizedGlobalConfig, +} from '../index.js' import type { SanitizedJobsConfig } from '../queues/config/types/index.js' import type { Config, @@ -504,5 +509,17 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise = {} + for (const collection of config.collections as SanitizedCollectionConfig[]) { + collectionsBySlug[collection.slug] = collection + } + + const globalsBySlug: Record = {} + for (const global of config.globals ?? []) { + globalsBySlug[global.slug] = global + } + + config.collectionsBySlug = collectionsBySlug + config.globalsBySlug = globalsBySlug return config as SanitizedConfig } diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index 8bbfcbf8eb3..30d4f37b786 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -1586,10 +1586,12 @@ export type SanitizedConfig = { } & DeepRequired blocks?: FlattenedBlock[] collections: SanitizedCollectionConfig[] + collectionsBySlug: Record /** Default richtext editor to use for richText fields */ editor?: RichTextAdapter endpoints: Endpoint[] globals: SanitizedGlobalConfig[] + globalsBySlug: Record i18n: Required jobs: SanitizedJobsConfig localization: false | SanitizedLocalizationConfig diff --git a/packages/plugin-import-export/src/export/createExport.ts b/packages/plugin-import-export/src/export/createExport.ts index 161d0f4e1b6..3b8e3f0d832 100644 --- a/packages/plugin-import-export/src/export/createExport.ts +++ b/packages/plugin-import-export/src/export/createExport.ts @@ -92,7 +92,7 @@ export const createExport = async (args: CreateExportArgs) => { } const locale = localeFromInput ?? localeFromReq - const collectionConfig = payload.config.collections.find(({ slug }) => slug === collectionSlug) + const collectionConfig = payload.config.collectionsBySlug[collectionSlug] if (!collectionConfig) { throw new APIError(`Collection with slug ${collectionSlug} not found.`) diff --git a/packages/plugin-import-export/src/import/createImport.ts b/packages/plugin-import-export/src/import/createImport.ts index b05d599422f..bb9b34ee060 100644 --- a/packages/plugin-import-export/src/import/createImport.ts +++ b/packages/plugin-import-export/src/import/createImport.ts @@ -116,9 +116,7 @@ export const createImport = async ({ }) } - const collectionConfig = req.payload.config.collections.find( - ({ slug }) => slug === collectionSlug, - ) + const collectionConfig = req.payload.config.collectionsBySlug[collectionSlug] if (!collectionConfig) { if (!collectionSlug) { diff --git a/packages/plugin-import-export/src/import/getCreateImportCollectionTask.ts b/packages/plugin-import-export/src/import/getCreateImportCollectionTask.ts index 8dfdb59c387..6bcfe308650 100644 --- a/packages/plugin-import-export/src/import/getCreateImportCollectionTask.ts +++ b/packages/plugin-import-export/src/import/getCreateImportCollectionTask.ts @@ -47,9 +47,7 @@ export const getCreateCollectionImportTask = ( } // Get the collection config for the imports collection - const collectionConfig = req.payload.config.collections.find( - (c) => c.slug === importCollection, - ) + const collectionConfig = req.payload.config.collectionsBySlug[importCollection] if (!collectionConfig) { throw new Error(`Collection config not found for: ${importCollection}`) diff --git a/packages/plugin-mcp/src/utils/getVirtualFieldNames.ts b/packages/plugin-mcp/src/utils/getVirtualFieldNames.ts index 3f0cb958307..e4208a19671 100644 --- a/packages/plugin-mcp/src/utils/getVirtualFieldNames.ts +++ b/packages/plugin-mcp/src/utils/getVirtualFieldNames.ts @@ -6,7 +6,7 @@ import { fieldIsVirtual } from 'payload/shared' * Returns the names of all top-level virtual fields for a given collection slug. */ export function getCollectionVirtualFieldNames(config: SanitizedConfig, slug: string): string[] { - const collection = config.collections.find((c) => c.slug === slug) + const collection = config.collectionsBySlug[slug] if (!collection) { return [] @@ -21,7 +21,7 @@ export function getCollectionVirtualFieldNames(config: SanitizedConfig, slug: st * Returns the names of all top-level virtual fields for a given global slug. */ export function getGlobalVirtualFieldNames(config: SanitizedConfig, slug: string): string[] { - const global = config.globals.find((g) => g.slug === slug) + const global = config.globalsBySlug[slug] if (!global) { return [] diff --git a/packages/plugin-seo/src/index.ts b/packages/plugin-seo/src/index.ts index dc81ce03bf9..6f8eb1b8065 100644 --- a/packages/plugin-seo/src/index.ts +++ b/packages/plugin-seo/src/index.ts @@ -144,10 +144,9 @@ export const seoPlugin = const result = pluginConfig.generateTitle ? await pluginConfig.generateTitle({ ...data, - collectionConfig: config.collections?.find( - (c) => c.slug === reqData.collectionSlug, - ), - globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug), + collectionConfig: + req.payload.config.collectionsBySlug[reqData.collectionSlug ?? ''], + globalConfig: req.payload.config.globalsBySlug[reqData.globalSlug ?? ''], req, } satisfies Parameters[0]) : '' @@ -168,10 +167,9 @@ export const seoPlugin = const result = pluginConfig.generateDescription ? await pluginConfig.generateDescription({ ...data, - collectionConfig: config.collections?.find( - (c) => c.slug === reqData.collectionSlug, - ), - globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug), + collectionConfig: + req.payload.config.collectionsBySlug[reqData.collectionSlug ?? ''], + globalConfig: req.payload.config.globalsBySlug[reqData.globalSlug ?? ''], req, } satisfies Parameters[0]) : '' @@ -192,10 +190,9 @@ export const seoPlugin = const result = pluginConfig.generateURL ? await pluginConfig.generateURL({ ...data, - collectionConfig: config.collections?.find( - (c) => c.slug === reqData.collectionSlug, - ), - globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug), + collectionConfig: + req.payload.config.collectionsBySlug[reqData.collectionSlug ?? ''], + globalConfig: req.payload.config.globalsBySlug[reqData.globalSlug ?? ''], req, } satisfies Parameters[0]) : '' @@ -216,10 +213,9 @@ export const seoPlugin = const result = pluginConfig.generateImage ? await pluginConfig.generateImage({ ...data, - collectionConfig: config.collections?.find( - (c) => c.slug === reqData.collectionSlug, - ), - globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug), + collectionConfig: + req.payload.config.collectionsBySlug[reqData.collectionSlug ?? ''], + globalConfig: req.payload.config.globalsBySlug[reqData.globalSlug ?? ''], req, } satisfies Parameters[0]) : ''