Skip to content

payload API

Everything the package exports, by the path you import it from. Open an export for its signature and options.

@evolve-framework/payload

PayloadModule, the built-in content blocks and defineContentBlock for your own, and catalog page sync.

Classes

MapperRegistryRegistry of mappers keyed by Payload block slug (blockType).
import { MapperRegistry } from "@evolve-framework/payload";

Blocks go through three channels. mapValue is the universal one: every block mapper is reachable there by slug, and it is how a container maps its children without importing the blocks that produce them. mapBlock and mapColumnEntry are typed views over the two GraphQL unions, for fields whose type is the union (a page body, a column) and which therefore need no assertion at the call site. Page documents go through a fourth, mapPage, keyed by page type id.

Registering a mapper for an already-known slug overrides the previous registration without throwing. A block for other markets than the request's maps to nothing in every channel but mapPage.

new MapperRegistry()
MethodDescription
registerBlock(slug: string, mapper: BlockMapper): MapperRegistry
registerColumnEntry( slug: string, mapper: ColumnEntryMapper, ): this
registerValue(slug: string, mapper: ContentBlockMapper): MapperRegistry
registerPage(pageType: string, mapper: PageMapper): MapperRegistry
hasBlock(slug: string): boolean
hasColumnEntry(slug: string): boolean
hasValue(slug: string): boolean
hasPage(pageType: string): boolean
mapBlock( storeContext: StoreContext, block: PayloadBlock, ): Block | undefined
mapColumnEntry( storeContext: StoreContext, block: PayloadBlock, ): ColumnEntry | undefined
mapValue<T>( storeContext: StoreContext, block: PayloadBlock, ): T | undefinedMap a child block by its blockType.
mapPage( pageType: string, context: PageMapperContext, doc: unknown, ): MappedPageMap a document as the page type of this id.
PayloadModuleModule wiring the Payload resolvers and typedefs into a Domain Service.
import { PayloadModule } from "@evolve-framework/payload";

Unlike the Contentful and Storyblok modules this one speaks no HTTP to the CMS: it boots Payload's Local API in-process and reads straight from the database the admin app writes to. There is no delivery client, no API key and no page cache to invalidate -- and no webhook route, because the content-modified events are published by an afterChange hook running in the admin process.

Only one PayloadModule instance per process is supported -- the Payload instance and the mapper registry are held as module-scope singletons.

Extends AbstractModule<PayloadLoaderContext>

new PayloadModule(options: PayloadModuleOptions)
OptionTypeDescription
configSanitizedConfig | Promise<SanitizedConfig>

The project's payload config -- the very same module the admin app loads. Import it directly (import config from "./payload.config.ts"); the module boots the Local API from it during init().

articlesPerProduct?number

How many articles a product shows at most. Defaults to 4.

blocks?ContentBlockDef[]

The complete set of content blocks the module serves. Defaults to the built-in contentBlocks; spread it to add or replace, e.g. blocks: [...contentBlocks, myBlock] (a block whose id matches a built-in replaces it). Each block's mapper is registered and its SDL fragment merged into the served schema.

More

Pass the same array you passed to evolveCms() in the payload config.

locales?LocaleMap

Maps store-context locales (nl-NL) onto Payload locale codes. Defaults to stripping the region subtag.

homePath?string

Path the site root is stored under. Frontends ask for the root with an empty path; this is what that resolves to. Defaults to "homepage".

multiTenant?boolean

Whether the config is tenant-scoped, i.e. whether reads must match the request's storeKey against a tenant. Must mirror the multiTenant option passed to evolveCms(). Defaults to true.

tenants?TenantMap

Maps store keys onto tenant slugs, for stores that share a tenant or whose tenant is named differently. A store missing from it reads the tenant whose slug is its store key. When set, catalog pages are kept in the mapped tenants only; when not, in every tenant.

mappers?((registry: MapperRegistry) => void)

Optional callback invoked with the pre-populated MapperRegistry. Use it to add or override mappers for custom Payload blocks.

StoreContextThe store, locale and currency a request is for.
import { StoreContext } from "@evolve-framework/payload";
new StoreContext(storeContext: StoreContextInput)
OptionTypeDescription
currencystring

The currency used in the store context.

localestring

The locale of the store context. For example: en-US.

storeKeystring

The store key associated with the store context.

country?InputMaybe<string>

The market the store context is for; leave out for every market.

Functions

defineContentBlockDefines a content block.
import { defineContentBlock } from "@evolve-framework/payload";
mapper: (context, block: PayloadPromoList): PromoList => ({ ... })

Children are mapped through context.mapValue<T>(child) -- never by importing another block.

The output type is erased on the way out, because a block is meant to be reached through the registry rather than called directly -- that is what lets a container map its children without importing them. Dispatch through mapBlock / mapColumnEntry / mapValue to get a typed result back.

function defineContentBlock<TBlock, TOutput>(
config: { id: string; typename: string; typeDefs?: string | undefined; payload?: Block | undefined; groups?: string[] | undefined; slots?: Record<string, Slot> | undefined; mapper: (context: MapperContext, block: TBlock) => TOutput; },
): ContentBlockDef & {
mapper: ContentBlockMapper;
}
OptionTypeDescription
idstring
typenamestring
mapper(context: MapperContext, block: TBlock) => TOutput
typeDefs?string
payload?Block
groups?string[]
slots?Record<string, Slot>

Returns ContentBlockDef & { mapper: ContentBlockMapper; }

deleteCatalogPageRemove the catalog page for a deleted category from every tenant.
import { deleteCatalogPage } from "@evolve-framework/payload";

A category that no longer exists lists nothing, so the page would render an empty grid on a route the storefront still advertises. Deleting it is the honest outcome — and it is why the engine's fields are kept separable: there is no editor-authored content here that this is entitled to destroy beyond the page the engine created.

function deleteCatalogPage(categoryId: string): Promise<boolean>

Returns Promise<boolean>

getMapperRegistryThe registry PayloadModule configured; throws before it has.
import { getMapperRegistry } from "@evolve-framework/payload";
function getMapperRegistry(): MapperRegistry

Returns MapperRegistry

getPayloadInstanceThe Payload instance PayloadModule booted; throws before it has.
import { getPayloadInstance } from "@evolve-framework/payload";
function getPayloadInstance(): BasePayload

Returns Payload

mapAssetMap a Payload media document onto the shared ContentAsset.
import { mapAsset } from "@evolve-framework/payload";

ContentAsset has no url field -- the other two CMS packages put the full CDN url in filename (Storyblok's filename is the url), so we do the same with Payload's url and keep the frontend contract identical. See the masterplan's open question on adding url to the shared type.

function mapAsset(media: MediaRelation): ContentAsset | undefined

Returns ContentAsset | undefined

mapBlocksMap a blocks field onto the Block union, dropping anything the registry has no mapper for (it is logged there), and any block whose mapper throws, so that one malformed block cannot fail the page or listing it is part of.
import { mapBlocks } from "@evolve-framework/payload";

A block registered only as a column entry is answered as Columns holding that one entry, so column content (an image, an FAQ) can be dropped straight into a page body without the editor having to reach for a layout block first. Rich text is a block of its own and is answered as it is. The blocks a snippet places are mapped as the body's own.

function mapBlocks(
blocks: PayloadBlock[] | undefined,
storeContext: StoreContext,
source?: string,
): Block[]

Returns Block[]

mapBlockSettingsThe settings every block of the content model carries: the anchor an in-page link points to, and who the block is shown to, everyone where unset.
import { mapBlockSettings } from "@evolve-framework/payload";
function mapBlockSettings(
block: { anchor?: string | null | undefined; audience?: string | null | undefined; },
): {
anchor: string | undefined;
audience: AudienceType;
}
OptionTypeDescription
anchor?string | null
audience?string | null

Returns { anchor: string | undefined; audience: AudienceType; }

mapCategoriesA categories field as the categories the commerce subgraph resolves by key.
import { mapCategories } from "@evolve-framework/payload";
function mapCategories(
keys: (string | null)[] | null | undefined,
): ProductCategory[]

Returns ProductCategory[]

mapContentPageA content_page document as ContentPage, by its registered page mapper.
import { mapContentPage } from "@evolve-framework/payload";
function mapContentPage(
doc: PayloadPage,
storeContext: StoreContext,
): ContentPage
OptionTypeDescription
idstring | number
name?string
path?string
seoTitle?string | null
seoDescription?string | null
seoImage?MediaRelation
intro?string | null
leadImage?MediaRelation
body?PayloadBlock[] | null
categories?string[] | null
headingVisible?boolean | null
createdAt?string

Returns ContentPage

mapLinkValueMap a link group onto Link.
import { mapLinkValue } from "@evolve-framework/payload";
function mapLinkValue(
link: PayloadLinkValue | null | undefined,
): MappedLink | undefined
OptionTypeDescription
label?string | null
page?PageRelation
product?string | null
route?string | null
url?string | null
variant?string | null

Returns MappedLink | undefined

mapPageMetaA page's metadata from its three SEO fields, the image falling back to the lead image.
import { mapPageMeta } from "@evolve-framework/payload";
function mapPageMeta(
doc: { seoTitle?: string | null | undefined; seoDescription?: string | null | undefined; seoImage?: MediaRelation; },
fallbackImage?: MediaRelation,
): PageMeta | undefined
OptionTypeDescription
seoTitle?string | null
seoDescription?string | null
seoImage?MediaRelation

Returns PageMeta | undefined

mapProductSourceA stored product source, or undefined where it names no category, filters or sort.
import { mapProductSource } from "@evolve-framework/payload";
function mapProductSource(
doc: PayloadProductSource,
fallbackFilters?: readonly FacetFilter[],
): ProductSource | undefined
OptionTypeDescription
category?string | null
filters?string | null
sort?string | null

Returns ProductSource | undefined

mapPromoMap a promo onto Promo; one without a title is no promo.
import { mapPromo } from "@evolve-framework/payload";
function mapPromo(
promo: PayloadPromo | null | undefined,
fallbackId: string,
): MappedPromo | undefined
OptionTypeDescription
id?string | null
title?string | null
text?string | null
image?MediaRelation
link?PayloadLinkValue | null

Returns MappedPromo | undefined

mapPromosMap a list of promos, leaving out the rows without a title.
import { mapPromos } from "@evolve-framework/payload";
function mapPromos(
promos: PayloadPromo[] | null | undefined,
parentId: string,
): MappedPromo[]

Returns MappedPromo[]

mapRichTextA Lexical document as rich text: the vendor-neutral tree, with each block placed in the text mapped through the registry as the embed that wraps it.
import { mapRichText } from "@evolve-framework/payload";
function mapRichText(
context: Pick<MapperContext, "mapValue">,
id: string,
document: unknown,
): RichText
OptionTypeDescription
mapValue<T>(block: PayloadBlock) => T | undefined

Map a child block by its blockType. T names the type the caller expects, which the slot's blockReferences is what actually guarantees.

Returns RichText

mapUspsMap selling points onto Usp, leaving out a row without text.
import { mapUsps } from "@evolve-framework/payload";
function mapUsps(usps: PayloadUsp[] | null | undefined, parentId: string): Usp[]

Returns Usp[]

normalizePathNormalise a requested page path to the stored form.
import { normalizePath } from "@evolve-framework/payload";

The empty path and / both mean the root and resolve to the configured home path. Everything else keeps its segments and gains a leading slash, so an editor sees /contact rather than contact.

function normalizePath(path: string): string

Returns string

registerBlocksRegisters each block's mapper into the registry.
import { registerBlocks } from "@evolve-framework/payload";

A page type's mapper goes into the page channel instead. Blocks without either (layout wrappers, bare union declarations) are assembled by their resolver and skipped.

function registerBlocks(
registry: MapperRegistry,
blocks: ContentBlockDef[],
): void

Returns void

scopedWhereCombine a lookup constraint with the tenant constraint.
import { scopedWhere } from "@evolve-framework/payload";

Every read goes through here: forgetting it would silently serve another store's content, which is the one failure mode of a shared database that no test of a single tenant can catch.

function scopedWhere(storeContext: StoreContext, ...constraints: Where[]): Where

Returns Where

tenantWhereThe tenant constraint for a request, as a where fragment.
import { tenantWhere } from "@evolve-framework/payload";

The multi-tenant plugin adds a tenant relationship to every scoped collection; matching on tenant.slug means a read needs no tenant lookup of its own.

Returns nothing when tenancy is off, so callers can spread it either way.

function tenantWhere(storeContext: StoreContext): Where[]

Returns Where[]

toAudienceA stored audience as AudienceType; EVERYONE when unset or unknown.
import { toAudience } from "@evolve-framework/payload";
function toAudience(value: string | undefined): AudienceType

Returns AudienceType

toCatalogPageLayoutA stored catalog page layout as CatalogPageLayoutType, or fallback.
import { toCatalogPageLayout } from "@evolve-framework/payload";
function toCatalogPageLayout(
value: string | undefined,
fallback: CatalogPageLayoutType,
): CatalogPageLayoutType

Returns CatalogPageLayoutType

toColumnsRatioA stored columns ratio as ColumnsRatioType, or fallback.
import { toColumnsRatio } from "@evolve-framework/payload";
function toColumnsRatio(
value: string | undefined,
fallback: ColumnsRatioType,
): ColumnsRatioType

Returns ColumnsRatioType

toPayloadLocaleMap the store context locale onto a Payload locale code.
import { toPayloadLocale } from "@evolve-framework/payload";

storeContext.locale is a full BCP-47 tag (nl-NL); Payload locale codes are whatever the project config declares, commonly just the language subtag. The default strips the region; pass an explicit map to the module when the project uses something else.

function toPayloadLocale(locale: string): string

Returns string

toResourceLinkTypeA stored link type as ResourceLinkType, or fallback.
import { toResourceLinkType } from "@evolve-framework/payload";
function toResourceLinkType(
value: string | undefined,
fallback: ResourceLinkType,
): ResourceLinkType

Returns ResourceLinkType

upsertCatalogPageCreate the catalog page for a category in every tenant, or refresh the fields the engine owns on the ones that already exist.
import { upsertCatalogPage } from "@evolve-framework/payload";

Returns created when any tenant gained a page, so a backfill can report rather than guess.

function upsertCatalogPage(
input: CatalogPageInput,
): Promise<"created" | "updated">
OptionTypeDescription
categoryIdstring

The commerce engine's category id. The join key, and the natural key.

nameRecord<string, string>

Category name per store locale, e.g. { "en-GB": "Shirts" }.

pathstring | Record<string, string>

The path the storefront routes.

More

Per store locale where the engine translates its slugs — /chemises in French, /hemden in German — or one string when it does not. Both are accepted because engines differ on this: Medusa's own handle is not translatable and a localised slug comes from a plugin, so a deployment without it has one path for every locale.

categoryKey?string

The category's key, which the page's product source refers to.

parentCategoryId?string

The parent category's id, whose catalog page becomes this page's parent. Absent for a root category.

Returns Promise<"created" | "updated">

Constants

blocksBuilt-in content blocks keyed by their Payload block slug.
import { blocks } from "@evolve-framework/payload";
const blocks: Record<string, ContentBlockDef>
BODY_BLOCKSWhat a page body accepts: every block, and rich text of its own.
import { BODY_BLOCKS } from "@evolve-framework/payload";
const BODY_BLOCKS: SlotAccepts
contentBlocksBuilt-in content blocks.
import { contentBlocks } from "@evolve-framework/payload";
const contentBlocks: ContentBlockDef[]
pageTypesThe built-in page types.
import { pageTypes } from "@evolve-framework/payload";
const pageTypes: ContentBlockDef[]
SNIPPET_BODY_BLOCKSWhat a content snippet's body accepts: a page body's blocks, but no snippet.
import { SNIPPET_BODY_BLOCKS } from "@evolve-framework/payload";
const SNIPPET_BODY_BLOCKS: SlotAccepts

Types

BlockMapperMaps a stored block onto a Block, or undefined to leave it out.
import { type BlockMapper } from "@evolve-framework/payload";
export type BlockMapper = (context: MapperContext, block: PayloadBlock) => Block | undefined;
ColumnEntryMapperMaps a stored block onto a ColumnEntry, or undefined to leave it out.
import { type ColumnEntryMapper } from "@evolve-framework/payload";
export type ColumnEntryMapper = (context: MapperContext, block: PayloadBlock) => ColumnEntry | undefined;
ContentBlockDefA content block bundles everything one Payload block needs: its output typename, SDL fragment, mapper (Payload block -> GraphQL type), the Payload field config that defines it, and its composition metadata (which groups it belongs to, and which slots it exposes).
import { type ContentBlockDef } from "@evolve-framework/payload";

A block references other blocks only by slug or group -- never by import -- so any one can be ejected while still referencing the rest. A container maps its children by dispatching them through the registry on their blockType, so each block owns the mapping of its own type and nothing else.

export type ContentBlockDef = {
id: string;
typename: string;
typeDefs?: string;
payload?: Block;
groups?: GroupId[];
slots?: Record<string, Slot>;
mapper?: ContentBlockMapper;
pageMapper?: PageMapper;
};
ContentBlockMapperThe registry-facing mapper: takes an untyped block and returns whatever the block's GraphQL type is.
import { type ContentBlockMapper } from "@evolve-framework/payload";
export type ContentBlockMapper = (context: MapperContext, block: PayloadBlock) => unknown;
ContextValueThe GraphQL context the resolvers of this package read.
import { type ContextValue } from "@evolve-framework/payload";
export type ContextValue = {
storeContext: StoreContext;
loaders: {
articlesByCategoryTrail: DataLoader<string, TaggedDocument[]>;
};
};
GroupIdA slot-group: a named set of blocks that can fill a slot.
import { type GroupId } from "@evolve-framework/payload";
export type GroupId = string;
LocaleMapStore-context locales (nl-NL) mapped onto Payload locale codes.
import { type LocaleMap } from "@evolve-framework/payload";
export type LocaleMap = Record<string, string>;
MappedPageEach concrete page type, so a page mapper can return any of them.
import { type MappedPage } from "@evolve-framework/payload";
export type MappedPage = ArticleOverviewPage | ArticlePage | CatalogPage | ContentPage;
MappedPromoA Promo whose link names its page by reference, not resolved yet.
import { type MappedPromo } from "@evolve-framework/payload";
export type MappedPromo = Omit<Promo, "link"> & {
link?: MappedLink;
};
MediaRelationAn upload field as read: the media document, its id, or nothing.
import { type MediaRelation } from "@evolve-framework/payload";
export type MediaRelation = PayloadMedia | string | null | undefined;
PageMapperMaps a document of a page type's collection onto its GraphQL page.
import { type PageMapper } from "@evolve-framework/payload";
export type PageMapper = (context: PageMapperContext, doc: unknown) => MappedPage;
PageMapperContextWhat a page mapper is handed: a mapper's context, plus what a page needs for its blocks fields and the pages it links to.
import { type PageMapperContext } from "@evolve-framework/payload";
export type PageMapperContext = MapperContext & {
mapBlocks: (blocks: PayloadBlock[] | null | undefined, source: string | undefined) => Block$1[];
mapSingle: <T>(blocks: PayloadBlock[] | null | undefined, source: string | undefined) => T | undefined;
mapPage: <T extends MappedPage>(pageType: string, doc: unknown) => T;
};
PayloadArticleOverviewPageAn article_overview_page document as returned by the Local API.
import { type PayloadArticleOverviewPage } from "@evolve-framework/payload";
export type PayloadArticleOverviewPage = PayloadPage & {
heading?: string | null;
intro?: string | null;
featured?: PayloadArticlePage | string | number | null;
};
PayloadArticlePageAn article_page document as returned by the Local API.
import { type PayloadArticlePage } from "@evolve-framework/payload";
export type PayloadArticlePage = PayloadPage & {
title?: string | null;
lead?: string | null;
leadImage?: MediaRelation;
publishedAt?: string | null;
author?: PayloadAuthor | string | number | null;
topics?: (PayloadTopic | string | number)[] | null;
categories?: string[] | null;
parent?: PayloadArticleOverviewPage | string | number | null;
related?: (PayloadArticlePage | string | number)[] | null;
};
PayloadAuthorAn author document as returned by the Local API.
import { type PayloadAuthor } from "@evolve-framework/payload";
export type PayloadAuthor = {
id: string | number;
name?: string | null;
role?: string | null;
photo?: MediaRelation;
bio?: string | null;
};
PayloadBlockThe shape every raw Payload block shares.
import { type PayloadBlock } from "@evolve-framework/payload";
export type PayloadBlock = {
blockType: string;
id?: string;
[key: string]: unknown;
};
PayloadCatalogPageA catalog_page document as returned by the Local API.
import { type PayloadCatalogPage } from "@evolve-framework/payload";
export type PayloadCatalogPage = Omit<PayloadPage, "body"> & PayloadProductSource & {
categoryId?: string | null;
layout?: string | null;
facetFilters?: {
key?: string | null;
values?: string[] | null;
}[] | null;
topContent?: PayloadBlock[] | null;
bottomContent?: PayloadBlock[] | null;
promos?: PayloadPromo[] | null;
};
PayloadLinkRowOne row of a linkListField array.
import { type PayloadLinkRow } from "@evolve-framework/payload";
export type PayloadLinkRow = {
link?: PayloadLink;
};
PayloadLinkValueA link group, as produced by config/fields/link-value.ts.
import { type PayloadLinkValue } from "@evolve-framework/payload";
export type PayloadLinkValue = {
label?: string | null;
page?: PageRelation;
product?: string | null;
route?: string | null;
url?: string | null;
variant?: string | null;
};
PayloadPageA content_page document as returned by the Local API.
import { type PayloadPage } from "@evolve-framework/payload";
export type PayloadPage = {
id: string | number;
name?: string;
path?: string;
seoTitle?: string | null;
seoDescription?: string | null;
seoImage?: MediaRelation;
intro?: string | null;
leadImage?: MediaRelation;
body?: PayloadBlock[] | null;
categories?: string[] | null;
headingVisible?: boolean | null;
createdAt?: string;
};
PayloadProductSourceThe fields productSourceFields stores a product source in.
import { type PayloadProductSource } from "@evolve-framework/payload";
export type PayloadProductSource = {
category?: string | null;
filters?: string | null;
sort?: string | null;
};
PayloadPromoA promo as stored: an array row, or a group in a menu entry.
import { type PayloadPromo } from "@evolve-framework/payload";
export type PayloadPromo = {
id?: string | null;
title?: string | null;
text?: string | null;
image?: MediaRelation;
link?: PayloadLinkValue | null;
};
PayloadTopicA topic document as returned by the Local API.
import { type PayloadTopic } from "@evolve-framework/payload";
export type PayloadTopic = {
id: string | number;
name?: string | null;
slug?: string | null;
description?: string | null;
leadImage?: MediaRelation;
};
PayloadUspA selling point as stored: an array row of the site or a usp_list.
import { type PayloadUsp } from "@evolve-framework/payload";
export type PayloadUsp = {
id?: string | null;
text?: string | null;
description?: string | null;
icon?: string | null;
link?: PayloadLinkValue | null;
};
PlacedBlocksBlocks a mapper places where it stands, as snippet places a content snippet's: mapBlocks maps them as the surrounding body's own, so the storefront never sees the wrapper.
import { type PlacedBlocks } from "@evolve-framework/payload";
export type PlacedBlocks = {
__typename: "PlacedBlocks";
source: string | undefined;
blocks: PayloadBlock[];
};
SlotA named containment point a block exposes.
import { type Slot } from "@evolve-framework/payload";
export type Slot = {
accepts: SlotAccepts;
};
SlotAcceptsWhat a slot accepts.
import { type SlotAccepts } from "@evolve-framework/payload";
export type SlotAccepts = GroupId | {
group?: GroupId;
ids?: string[];
exclude?: string[];
};
TenantMapMaps store keys onto tenant slugs.
import { type TenantMap } from "@evolve-framework/payload";
export type TenantMap = Record<string, string>;

@evolve-framework/payload/config

evolveCms, the Payload plugin with the pages and media collections, multi-tenancy by store and the catalog pickers, plus the collections on their own.

Functions

applySlotReferencesFill in blockReferences on every field whose name matches a declared slot.
import { applySlotReferences } from "@evolve-framework/payload/config";

A block declares its containment points once, in slots; the field config writes blockReferences: [] and this fills it. Keeping the slot declaration as the single source of truth is what makes groups: ["block"] sufficient to make a new block droppable into a page body -- the same property the Terraform whitelist gives the other two CMS packages. Fields inside tabs are filled too, so it applies before or after withFieldTabs.

function applySlotReferences(
fields: Field[],
slots: Record<string, Slot> | undefined,
blocks: ContentBlockDef[],
): Field[]

Returns Field[]

blockSettingsFieldsThe fields every block of the content model carries, on its Settings tab: the anchor an in-page link or the table of contents points to, who the block is shown to, and the markets it is shown in.
import { blockSettingsFields } from "@evolve-framework/payload/config";
function blockSettingsFields(): Field[]

Returns Field[]

contentPageCollectionThe content_page collection backing ContentPage.
import { contentPageCollection } from "@evolve-framework/payload/config";

Unlike Storyblok and Contentful -- where a page is a component/content type like any other -- a Payload page is a collection. The content_page block def still declares the slots (body); this reads them so a block that declares groups: ["block"] becomes droppable into a page body with no further wiring, the same property the Terraform whitelist gives the other two CMS packages.

path is derived from slug and parent per locale, and stored so a page is found by one query on it; one read with locale: "all" yields every locale's path.

function contentPageCollection(blocks: ContentBlockDef[]): CollectionConfig

Returns CollectionConfig

createGatewayCatalogThe picker callbacks for a project, ready to hand to evolveCms.
import { createGatewayCatalog } from "@evolve-framework/payload/config";

Returns CatalogOptions minus components, which stay a project's own — they have to be bound to Payload's form state in the admin app.

function createGatewayCatalog(
options: GatewayCatalogOptions,
): Omit<CatalogOptions, "components">
OptionTypeDescription
endpointstring

Where the graph is, e.g. http://localhost:4000.

storeContext{ storeKey: string; locale: string; currency: string; }

The store an editor authors for.

More

Fixed rather than per-request: an admin is one editor looking at one store's catalogue. A deployment serving several would vary it by tenant, which is what multiTenant is for.

categoryLookupLimit?number

How many categories to scan when resolving one by id.

More

The contract has no lookup by id — only by search term and by path — so this walks the list. Fine for a catalogue of ordinary size and wrong for a very large one, where a category past the cap resolves to nothing and an editor sees a bare id. The real fix is a category(id:) query on both adapters; until then this is the honest limit.

Returns Omit<CatalogOptions, "components">

defineContentBlockDefines a content block.
import { defineContentBlock } from "@evolve-framework/payload/config";
mapper: (context, block: PayloadPromoList): PromoList => ({ ... })

Children are mapped through context.mapValue<T>(child) -- never by importing another block.

The output type is erased on the way out, because a block is meant to be reached through the registry rather than called directly -- that is what lets a container map its children without importing them. Dispatch through mapBlock / mapColumnEntry / mapValue to get a typed result back.

function defineContentBlock<TBlock, TOutput>(
config: { id: string; typename: string; typeDefs?: string | undefined; payload?: Block | undefined; groups?: string[] | undefined; slots?: Record<string, Slot> | undefined; mapper: (context: MapperContext, block: TBlock) => TOutput; },
): ContentBlockDef & {
mapper: ContentBlockMapper;
}
OptionTypeDescription
idstring
typenamestring
mapper(context: MapperContext, block: TBlock) => TOutput
typeDefs?string
payload?Block
groups?string[]
slots?Record<string, Slot>

Returns ContentBlockDef & { mapper: ContentBlockMapper; }

evolveCmsThe Payload plugin that installs everything Evolve's CMS subgraph expects: the block configs (into config.blocks, so slots can reference them by slug) and the collections that back the content types.
import { evolveCms } from "@evolve-framework/payload/config";

This runs inside the Payload process -- the admin app and any migration job. It must not import runtime service code from @evolve-framework/core.

function evolveCms(options?: EvolveCmsOptions | undefined): Plugin[]
OptionTypeDescription
blocks?ContentBlockDef[]

The complete set of content blocks to register. Defaults to the built-in contentBlocks; spread it to add or replace, e.g. blocks: [...contentBlocks, myBlock] (a block whose id matches a built-in replaces it).

More

Pass the same array to PayloadModule -- it is the single source of truth for which blocks exist on both sides.

collections?boolean

Whether to register the built-in collections (content_page, media). Set to false to keep only the blocks and bring your own collections. Defaults to true.

media?MediaOptions

Options for the built-in media collection.

multiTenant?boolean

Scope every content collection to a tenant, where a tenant is a content space of its own, the way a separate Storyblok space is.

More

Every request into the subgraph carries a store context, and the resolvers match documents on the tenant its storeKey maps to through the module's tenants option, which defaults to the tenant whose slug is the store key. Set to false for a database that serves exactly one store and never will serve two.

Defaults to true.

catalog?CatalogOptions

Where the catalogue pickers read from.

More

Supplying these turns the commerce identifier fields — a variant's sku, a product's slug, a category's id — from free text into pickers, and adds the admin routes they call. Leave it out and those fields stay plain text, which is the correct behaviour for a project that has not wired a commerce backend into its admin.

users?boolean

Whether to provide a bare auth-enabled users collection. The multi-tenant plugin requires one to exist at plugin time, which is earlier than Payload injects its default. Set to false when you declare your own.

More

Defaults to true.

contentEvents?ContentEventsOptions

Publish a content-modified event when a page, catalog page, snippet or piece of site chrome is published, unpublished or deleted. Each event is queued as a Payload job and published by the job runner, which the project has to run (see the README). Leave it out to publish nothing.

keyPatterns?Partial<Record<"sku" | "category" | "categoryKey" | "brand", string | RegExp>>

The format of each commerce key an editor types, such as a SKU, as this project's commerce backend writes it. Unset, a key only may not contain whitespace.

markets?string[]

The countries the store sells in, as ISO 3166-1 alpha-2 codes, which an editor can limit a page or a block to. A request's store context names its market; content for other markets is left out of it. Unset, no content can be limited to a market.

Returns Plugin[]

keysValidationkeyValidation for a hasMany text field, checking every key.
import { keysValidation } from "@evolve-framework/payload/config";
function keysValidation(
kind: "sku" | "category" | "categoryKey" | "brand",
): TextFieldManyValidation

Returns TextFieldManyValidation

keyValidationValidation for a text field holding a commerce key: Payload's own text checks first, required among them, then the project's pattern for that kind of key.
import { keyValidation } from "@evolve-framework/payload/config";
function keyValidation(
kind: "sku" | "category" | "categoryKey" | "brand",
): TextFieldSingleValidation

Returns TextFieldSingleValidation

linkFieldThe ResourceLink field.
import { linkField } from "@evolve-framework/payload/config";

type mirrors the shared ResourceLinkType enum, because frontends switch on it to build the href -- a link typed external where the storefront expects content renders as no link at all. Each type has its own target field and the admin UI hides the rest.

Shipped as a factory rather than a constant because blocks need it under different names (link, viewMoreLink) and requiredness.

function linkField(options?: LinkFieldOptions | undefined): Field
OptionTypeDescription
name?string

Field name. Defaults to "link".

required?boolean

Whether the editor must fill in a target for the chosen type.

label?string

Label shown in the admin UI.

Returns Field

linkListFieldA repeatable list of links (top bar, socials, payment methods, ...).
import { linkListField } from "@evolve-framework/payload/config";

Each row wraps a link group rather than flattening its fields, so the same mapLink handles a single link and a list entry alike.

function linkListField(name: string, label?: string | undefined): Field

Returns Field

linkValueFieldThe Link value object: a label and exactly one target, a page, a product by its sku, a storefront route or a URL, drawn as a primary or a secondary call to action.
import { linkValueField } from "@evolve-framework/payload/config";
function linkValueField(options?: LinkValueOptions | undefined): Field
OptionTypeDescription
name?string

Field name. Defaults to "link".

required?boolean

Whether the link must point somewhere.

label?string

Label shown in the admin UI.

Returns Field

marketsFieldThe markets field: country codes the content is limited to, empty for every market.
import { marketsField } from "@evolve-framework/payload/config";
function marketsField(description: string): Field

Returns Field

mediaCollectionUploads.
import { mediaCollection } from "@evolve-framework/payload/config";

For anything beyond local development, add @payloadcms/storage-s3 (or -azure, -gcs) in the project config; a container's local disk is not a place to keep uploads.

function mediaCollection(options?: MediaOptions | undefined): CollectionConfig
OptionTypeDescription
staticDir?string

Absolute directory uploads are written to and read from.

More

Payload defaults this to ./media relative to the process cwd, which breaks the moment two processes share a database: the admin app and the CMS service run from different directories and would look in different folders for the same file. Pass an absolute path (or configure a storage adapter) so both agree.

Returns CollectionConfig

pagePathFieldsThe slug, parent and path fields of a page collection.
import { pagePathFields } from "@evolve-framework/payload/config";
function pagePathFields(
collection: PageCollection,
parent: { required?: boolean | undefined; description: string; },
): Field[]
OptionTypeDescription
descriptionstring
required?boolean

Returns Field[]

pagePathHooksThe hooks that keep a page collection's paths derived, and that redirect a published page's old path to it when the path changes.
import { pagePathHooks } from "@evolve-framework/payload/config";
function pagePathHooks(
collection: PageCollection,
): {
beforeChange: CollectionBeforeChangeHook[];
afterChange: CollectionAfterChangeHook[];
}

Returns { beforeChange: CollectionBeforeChangeHook[]; afterChange: CollectionAfterChangeHook[]; }

payloadBlocksThe block configs registered into config.blocks, with every slot resolved and every field on its tab.
import { payloadBlocks } from "@evolve-framework/payload/config";
function payloadBlocks(blocks: ContentBlockDef[]): Block[]

Returns Block[]

productSourceFieldsThe fields a product source is stored in, shared by the catalog page and the product list: a category key, the filters pasted from a storefront URL, and a sort order.
import { productSourceFields } from "@evolve-framework/payload/config";
function productSourceFields(): Field[]

Returns Field[]

promoFieldsThe fields of the Promo value object: a card with a title, a short text, an image and the link it leads to.
import { promoFields } from "@evolve-framework/payload/config";
function promoFields(
options?: { optional?: boolean | undefined; },
): Field[]
OptionTypeDescription
optional?boolean

Returns Field[]

readPublishedRead access for a collection with drafts: a logged-in user reads everything, anyone else only published documents.
import { readPublished } from "@evolve-framework/payload/config";
function readPublished(
args: AccessArgs<any>,
): AccessResult | Promise<AccessResult>

Returns AccessResult | Promise<AccessResult>

resolveSlotResolve what a slot accepts into a concrete list of Payload block slugs: the slot's explicit ids plus every block declaring the accepted group, less the ids it excludes.
import { resolveSlot } from "@evolve-framework/payload/config";

This is the Payload counterpart of Storyblok's generated component_whitelist local -- same derivation from groups, but the output is a TS array assembled at import time rather than HCL written to disk.

function resolveSlot(slot: Slot, blocks: ContentBlockDef[]): string[]
OptionTypeDescription
acceptsSlotAccepts

Returns string[]

uspFieldsThe fields of the Usp value object: a selling point, an optional second line and icon, and where it leads.
import { uspFields } from "@evolve-framework/payload/config";
function uspFields(): Field[]

Returns Field[]

withFieldTabsA content type's fields on the Content, SEO and Settings tabs, by the rule every CMS shares.
import { withFieldTabs } from "@evolve-framework/payload/config";
function withFieldTabs(fields: Field[]): Field[]

Returns Field[]

Constants

blocksBuilt-in content blocks keyed by their Payload block slug.
import { blocks } from "@evolve-framework/payload/config";
const blocks: Record<string, ContentBlockDef>
CONTENT_MODIFIED_TASKThe task that publishes a queued event.
import { CONTENT_MODIFIED_TASK } from "@evolve-framework/payload/config";
const CONTENT_MODIFIED_TASK: "evolve-content-modified"
contentBlocksBuilt-in content blocks.
import { contentBlocks } from "@evolve-framework/payload/config";
const contentBlocks: ContentBlockDef[]
PAGE_RELATIONSThe collections a link may open, one per page type.
import { PAGE_RELATIONS } from "@evolve-framework/payload/config";
const PAGE_RELATIONS: string[]

Types

CatalogCategoryOne category in the search list.
import { type CatalogCategory } from "@evolve-framework/payload/config";
export type CatalogCategory = {
id: string;
name: string;
path?: string;
ancestors?: string[];
};
CatalogOptionsThe catalog lookups behind the product, variant and category pickers.
import { type CatalogOptions } from "@evolve-framework/payload/config";
export type CatalogOptions = {
searchProducts?: (term: string) => Promise<CatalogProduct[]>;
variantSelector?: (slug: string, selectedSku?: string) => Promise<CatalogVariantSelector | undefined>;
productForSku?: (sku: string) => Promise<CatalogProduct | undefined>;
searchCategories?: (term: string) => Promise<CatalogCategory[]>;
categoryById?: (id: string) => Promise<CatalogCategory | undefined>;
components?: {
variant?: string;
product?: string;
category?: string;
variantRowLabel?: string;
};
};
CatalogProductOne product in the search list.
import { type CatalogProduct } from "@evolve-framework/payload/config";
export type CatalogProduct = {
slug: string;
name: string;
image?: string;
};
CatalogVariantDimensionA dimension a product varies along, e.g.
import { type CatalogVariantDimension } from "@evolve-framework/payload/config";
export type CatalogVariantDimension = {
name: string;
label: string;
options: CatalogVariantOption[];
};
CatalogVariantOptionOne choice within a dimension, and the variant it lands on.
import { type CatalogVariantOption } from "@evolve-framework/payload/config";
export type CatalogVariantOption = {
label: string;
value: string;
sku: string;
availability?: string;
};
CatalogVariantSelectorThe variant selector for a product.
import { type CatalogVariantSelector } from "@evolve-framework/payload/config";

Mirrors what a product detail page renders: the dimensions are relative to the currently selected sku, so choosing an option means asking again with the sku it resolved to. A product with one variant reports no dimensions and just its sku, which is what lets the picker skip the second step entirely.

export type CatalogVariantSelector = {
sku: string;
dimensions: CatalogVariantDimension[];
};
ContentBlockDefA content block bundles everything one Payload block needs: its output typename, SDL fragment, mapper (Payload block -> GraphQL type), the Payload field config that defines it, and its composition metadata (which groups it belongs to, and which slots it exposes).
import { type ContentBlockDef } from "@evolve-framework/payload/config";

A block references other blocks only by slug or group -- never by import -- so any one can be ejected while still referencing the rest. A container maps its children by dispatching them through the registry on their blockType, so each block owns the mapping of its own type and nothing else.

export type ContentBlockDef = {
id: string;
typename: string;
typeDefs?: string;
payload?: Block;
groups?: GroupId[];
slots?: Record<string, Slot>;
mapper?: ContentBlockMapper;
pageMapper?: PageMapper;
};
ContentEventsOptionsWhere and how evolveCms publishes content-modified events.
import { type ContentEventsOptions } from "@evolve-framework/payload/config";
export type ContentEventsOptions = {
publisher: MessagePublisher;
origin: string;
locales?: Record<string, string>;
retries?: number;
siteRevalidation?: SiteRevalidationOptions;
homePath?: string;
};
ContentModifiedEventThe shared content-modified message schema, as this package publishes it.
import { type ContentModifiedEvent } from "@evolve-framework/payload/config";
export type ContentModifiedEvent = {
type: "content-modified-event";
origin: string;
timestamp: string;
changes: ContentChange[];
};
GroupIdA slot-group: a named set of blocks that can fill a slot.
import { type GroupId } from "@evolve-framework/payload/config";
export type GroupId = string;
KeyPatternsA pattern per key kind; a string is read as a regular expression.
import { type KeyPatterns } from "@evolve-framework/payload/config";
export type KeyPatterns = Partial<Record<KeyKind, RegExp | string>>;
PageCollectionThe slugs of the page collections.
import { type PageCollection } from "@evolve-framework/payload/config";
export type PageCollection = "content_page" | "catalog_page" | "article_page" | "article_overview_page";
PayloadBlockThe shape every raw Payload block shares.
import { type PayloadBlock } from "@evolve-framework/payload/config";
export type PayloadBlock = {
blockType: string;
id?: string;
[key: string]: unknown;
};
SlotA named containment point a block exposes.
import { type Slot } from "@evolve-framework/payload/config";
export type Slot = {
accepts: SlotAccepts;
};
SlotAcceptsWhat a slot accepts.
import { type SlotAccepts } from "@evolve-framework/payload/config";
export type SlotAccepts = GroupId | {
group?: GroupId;
ids?: string[];
exclude?: string[];
};

@evolve-framework/payload/graphql/context

The request context the module's resolvers expect.

Classes

StoreContextThe store, locale and currency a request is for.
import { StoreContext } from "@evolve-framework/payload/graphql/context";
new StoreContext(storeContext: StoreContextInput)
OptionTypeDescription
currencystring

The currency used in the store context.

localestring

The locale of the store context. For example: en-US.

storeKeystring

The store key associated with the store context.

country?InputMaybe<string>

The market the store context is for; leave out for every market.

Functions

initContextValueA request's context: its store context and the data loaders built on it.
import { initContextValue } from "@evolve-framework/payload/graphql/context";
function initContextValue({ request }: YogaInitialContext): ContextValue

Returns ContextValue

Types

ContextValueThe GraphQL context the resolvers of this package read.
import { type ContextValue } from "@evolve-framework/payload/graphql/context";
export type ContextValue = {
storeContext: StoreContext;
loaders: {
articlesByCategoryTrail: DataLoader<string, TaggedDocument[]>;
};
};

@evolve-framework/payload/graphql/types

The generated GraphQL types of the content contract.

Generated types237Generated from the schema, one per type.
ArticleListArticle cards: the articles the editor picked, or else the newest that match its filters on section, topic and category.
ArticleListResolvers
ArticleOverviewPageThe overview of one section of articles, such as a blog or the buying guides.
ArticleOverviewPageResolvers
ArticlePageAn article, such as a blog post, a buying guide or a news item: a page whose text owns it.
ArticlePageResolvers
ArticleResultOne page of articles, newest first.
ArticleResultResolvers
AudienceTypeWho a block is shown to.
AuthorWho wrote an article, as the byline and the author markup name them.
AuthorResolvers
BlockRich text is also a block of its own, placed directly in a page body.
BlockResolvers
BrandA brand.
BrandListBrand logos that link to their brand pages, in the order the editor placed them.
BrandListResolvers
BrandResolvers
BreadcrumbRepresents a single item in a breadcrumb trail.
BreadcrumbResolvers
BreadcrumbTypeRepresents different types of breadcrumbs in the navigation structure.
CampaignBannerA campaign: an image with the text beside it, not on it, and one call to action.
CampaignBannerResolvers
CatalogPageRepresents a product listing page with its surrounding content.
CatalogPageFacetFilterOne facet of a curated collection and the values it selects.
CatalogPageFacetFilterInputOne facet of a listing's filter and the values it selects.
CatalogPageFacetFilterResolvers
CatalogPageLayoutTypeHow a catalog page presents its category.
CatalogPageResolvers
CategoryListEntrances to categories: the ones the editor picked, or the children of one category.
CategoryListResolvers
ColumnEntryRepresents content types that can be used in columns.
ColumnEntryResolvers
ColumnsTwo to four blocks side by side, stacked in their order on a narrow screen.
ColumnsRatioTypeHow the width is shared between two columns, in the order they are placed.
ColumnsResolvers
ContentAssetRepresents a content asset, such as an image or file.
ContentAssetResolvers
ContentPageRepresents a content page with various sections and blocks.
ContentPageResolvers
ContentSearchHitA page or an article that matches a search.
ContentSearchHitResolvers
ContentSearchResultWhat the CMS answers to a search term.
ContentSearchResultResolvers
ContentSnippetRepresents a snippet of content that can be used in various places.
ContentSnippetResolvers
ContentTeaserAn image beside text, or text alone, with up to two links.
ContentTeaserResolvers
ContentVersionTypeSpecifies different versions of content.
CountryCodeScalarConfig
CurrencyScalarConfig
DateScalarConfig
DateTimeScalarConfig
DirectiveResolverFn
DirectiveResolvers
EmailAddressScalarConfig
ErrorShared interface for every error returned as data.
ErrorResolvers
Faq
FaqGroup
FaqGroupResolvers
FaqItem
FaqItemResolvers
FaqResolvers
FederationReferenceTypesMapping of federation reference types
FederationTypesMapping of federation types
FieldValidationIssueA single field-level validation failure, to attach to its input control
FieldValidationIssueResolvers
FigureOne key figure: a value with what it measures.
FigureListTwo to four key figures.
FigureListResolvers
FigureResolvers
FocalPointA point in an image, in percent from its left and top edges.
FocalPointResolvers
GraphQLRecursivePick
HotspotOne product pinned on a shoppable image.
HotspotResolvers
ImageOne image, or a pair side by side.
ImageResolvers
InputMaybe
IsTypeOfResolverFn
JsonScalarConfig
LinkA link with its own label, to one target: a page, a product, a storefront route or a URL.
LinkKindTypeWhat a resolved link points at: a page of the site, or a URL.
LinkResolvers
LinkVariantTypeHow prominently a link is drawn.
LocaleScalarConfig
Maybe
MenuItemOne menu entry: a link, or a heading for the entries below it.
MenuItemResolvers
MessagesThe store's fixed system copy, one entry per store, for the places no editor fills by hand.
MessagesResolvers
MutationDefines the available mutations in the schema.
MutationResolvers
MutationStoreContentPreviewArgsDefines the available mutations in the schema.
NavigationA menu: the header's, the footer's, or one of the project's own.
NavigationResolvers
NextResolverFn
Omit
OpenGraphOpen Graph protocol metadata for social media sharing
OpenGraphResolvers
PageA page a route can land on.
PageMetaPage metadata for SEO, from the page's three SEO fields.
PageMetaResolvers
PageRedirectWhere a path sends a visitor: written by an editor, or by the CMS when a page's path changed, from the old path to the page.
PageRedirectResolvers
PageResolvers
PageSortOrderTypeSpecifies sorting options for pages.
PagesResultRepresents the result of a query for multiple pages.
PagesResultResolvers
PageTypeDefines the different types of pages available in the system.
PaginationWhere a page sits within the full result set.
PaginationResolvers
PaymentBrandTypeA way to pay the store accepts, which the site draws as that brand's logo.
ProductProduct entity containing all product information, variants, and metadata.
ProductCategoryRepresents a category of products.
ProductCategoryResolvers
ProductListProducts, either the variants the editor picked or those a source selects.
ProductListResolvers
ProductResolvers
ProductSortOrderTypeAvailable sorting options for product listings
ProductSourceWhich products a listing shows: those in a category, narrowed by facet selections, in a sort order.
ProductSourceFilterOne facet of a product source and the values it selects.
ProductSourceFilterResolvers
ProductSourceResolvers
ProductVariant
ProductVariantResolvers
PromoA card that links somewhere.
PromoListTwo to four promo cards side by side.
PromoListResolvers
PromoResolvers
QueryDefines the available queries in the schema.
QueryArticlesArgsDefines the available queries in the schema.
QueryCatalogPageArgsDefines the available queries in the schema.
QueryCatalogPageByFilterArgsDefines the available queries in the schema.
QueryContentPageArgsDefines the available queries in the schema.
QueryContentSearchArgsDefines the available queries in the schema.
QueryContentSnippetArgsDefines the available queries in the schema.
QueryMessagesArgsDefines the available queries in the schema.
QueryPageArgsDefines the available queries in the schema.
QueryPagesArgsDefines the available queries in the schema.
QueryRedirectArgsDefines the available queries in the schema.
QueryResolvers
QuerySiteArgsDefines the available queries in the schema.
QuerySiteSettingsArgsDefines the available queries in the schema.
ReferenceResolver
RequireFields
RequiresSessionDirectiveArgs
RequiresSessionDirectiveResolver
Resolver
ResolverFn
Resolvers
ResolversInterfaceTypesMapping of interface types
ResolversParentTypesMapping between all available schema types and the resolvers parents
ResolversTypesMapping between all available schema types and the resolvers types
ResolversUnionTypesMapping of union types
ResolverTypeWrapper
ResourceLinkRepresents a link to a resource, either internal or external.
ResourceLinkResolvers
ResourceLinkTypeSpecifies different types of resource links.
RichTextFormatted text, the same whichever CMS wrote it.
RichTextEmbedWhat rich text can embed.
RichTextEmbedResolvers
RichTextImageEmbedAn image placed in rich text.
RichTextImageEmbedResolvers
RichTextLinkA link in rich text, resolved by the adapter.
RichTextLinkResolvers
RichTextProductEmbedA product placed in rich text, by its sku.
RichTextProductEmbedResolvers
RichTextPromoEmbedA promo placed in rich text.
RichTextPromoEmbedResolvers
RichTextResolvers
RichTextShoppableImageEmbedA shoppable image placed in rich text.
RichTextShoppableImageEmbedResolvers
RichTextTipEmbedA tip placed in rich text.
RichTextTipEmbedResolvers
RichTextVideoEmbedA video placed in rich text.
RichTextVideoEmbedResolvers
ScalarsAll built-in and custom scalars, mapped to their actual values
SearchRedirectWhere a keyword rule sends a search instead of to a result page.
SearchRedirectResolvers
ShareableDirectiveArgs
ShareableDirectiveResolver
ShoppableImageOne image with two to six products pinned on it, also listed beside or below it.
ShoppableImageResolvers
SiteThe store's settings, one per store: its menus, the selling points in the header bar, its social profiles, payment brands and review rating, and the templates the SEO title and description of a page fall back to.
SiteResolvers
SiteSettingsWhich page of the site answers each recurring purpose, such as the contact or the returns page, one entry per store.
SiteSettingsResolvers
SocialLinkThe store's profile on a social network; the site draws the network's icon.
SocialLinkResolvers
SocialPlatformTypeA social network a store keeps a profile on.
StepOne step of a step list.
StepListTwo to four numbered steps, such as how an account, a return or a job works.
StepListResolvers
StepResolvers
StoreContentPreviewDataRepresents data for storing content previews.
StoreContentPreviewDataResolvers
StoreContentPreviewError
StoreContentPreviewErrorResolvers
StoreContentPreviewResponse
StoreContentPreviewResponseResolvers
StoreContext
StoreContextResolvers
StorefrontRouteTypeA page the storefront itself serves rather than the CMS.
SubscriptionObject
SubscriptionResolveFn
SubscriptionResolver
SubscriptionResolverObject
SubscriptionSubscribeFn
SubscriptionSubscriberObject
TableOfContentsLinks to the anchors on the page.
TableOfContentsResolvers
TimeScalarConfig
TipA highlighted tip, in a page body or inside rich text.
TipResolvers
TopicWhat an article is about, such as tennis or maintenance.
TopicPageA topic's page below a section of articles.
TopicPageResolvers
TopicResolvers
TranslatedPathRepresents a translated path for a specific locale.
TranslatedPathResolvers
TrustRatingThe store's average review score at a review service, such as 9.2 out of 10 from 1,284 reviews, as an editor entered it.
TrustRatingResolvers
TypeResolveFn
UrlScalarConfig
UspRepresents a single Unique Selling Point (USP).
UspIconTypeThe icon a selling point shows, from a fixed set the storefront maps to its own glyphs.
UspListThe store's selling points, two to six of them.
UspListResolvers
UspResolvers
ValidationErrorThe input was malformed: one or more fields need editing before the operation can succeed.
ValidationErrorResolvers
VideoA YouTube video, played from the privacy-enhanced domain once the visitor consents.
VideoResolvers
WithInternalFieldsA GraphQL type T that can also carry its source object (__instance) and its own field resolvers (__fieldResolvers).
YoutubeVideoA YouTube video embedded in rich text.
YoutubeVideoResolvers

@evolve-framework/payload/testing

A test configuration, tenant seeding and a test executor.

Functions

createTestConfigA real Payload config, assembled exactly the way a project assembles one, on an in-memory sqlite database.
import { createTestConfig } from "@evolve-framework/payload/testing";

The other CMS packages mock the vendor's HTTP API with MSW; here the package owns the config, so a test can run the actual Payload against actual storage. That catches block and collection drift the fixtures never would.

function createTestConfig(
blocks?: ContentBlockDef[],
): Promise<import("payload").SanitizedConfig>

Returns Promise<import("payload").SanitizedConfig>

createTestExecutorA GraphQL executor for tests.
import { createTestExecutor } from "@evolve-framework/payload/testing";
function createTestExecutor(): DisposableAsyncExecutor

Returns DisposableAsyncExecutor

seedTenantSeed the tenant the test store context resolves to.
import { seedTenant } from "@evolve-framework/payload/testing";

The test executor sends X-StoreContext-StoreKey: example, and every resolver matches documents on tenant.slug === storeKey — so without this, reads find nothing.

function seedTenant(slug?: string | undefined): Promise<JsonObject & TypeWithID>

Returns Promise<import("payload").JsonObject & import("payload").TypeWithID>

@evolve-framework/payload/admin

The admin UI components for picking products, variants and categories from the catalog.

Functions

BlockRowLabelThe collapsed label of a block row: its number, its type and the first of titleFields that holds text, else "Untitled".
import { BlockRowLabel } from "@evolve-framework/payload/admin";
PropTypeDescription
blockLabelstring
titleFieldsstring[]
CategoryPickerPick a category, and store the engine's id for it.
import { CategoryPicker } from "@evolve-framework/payload/admin";

Catalog pages normally get this from the category events, which create the page and fill the id in. This is for the page an editor makes by hand — the one case where the join key would otherwise be copied out of a commerce admin.

Each result carries its ancestor trail and its path, because category names repeat: "Shirts" under Men and under Women are different pages, and the name alone cannot tell an editor which one they are about to point at.

PropTypeDescription
valuestring | undefined
setValue(value: string) => void
apiBasestring

Where Payload's REST API is mounted, e.g. /cms-api.

More

Passed in rather than derived from the url. The admin and the api are mounted independently — this project serves /admin and /cms-api — so there is nothing in the current path to infer it from, and guessing gives a picker that silently returns no results. The wrapper reads it from Payload's own config.

CategoryPickerFieldThe category picker as a Payload text field.
import { CategoryPickerField } from "@evolve-framework/payload/admin";
PropTypeDescription
fieldOmit<TextFieldClient, "type"> & Partial<Pick<TextFieldClient, "type">>
pathstring
readOnly?boolean
forceRender?boolean

Controls the rendering behavior of the fields, i.e. defers rendering until they intersect with the viewport using the Intersection Observer API.

More

If true, the fields will be rendered immediately, rather than waiting for them to intersect with the viewport.

If a number is provided, will immediately render fields up to that index.

permissions?SanitizedFieldPermissions
renderedBlocks?RenderedField[]
schemaPath?string
Default: field.name

Used to extract field configs from a schemaMap. Does not include indexes.

inputRef?RefObject<HTMLInputElement>
onKeyDown?KeyboardEventHandler<HTMLInputElement>
validate?TextFieldValidation
ProductPickerPick a product, and store its slug.
import { ProductPicker } from "@evolve-framework/payload/admin";

A product link points at a product, not a variant, so this stops where the variant picker continues. The slug is the canonical one the engine reports; the storefront resolves the reader's locale from it, the same way a catalog page does.

PropTypeDescription
valuestring | undefined
setValue(value: string) => void
apiBasestring

Where Payload's REST API is mounted, e.g. /cms-api.

More

Passed in rather than derived from the url. The admin and the api are mounted independently — this project serves /admin and /cms-api — so there is nothing in the current path to infer it from, and guessing gives a picker that silently returns no results. The wrapper reads it from Payload's own config.

ProductPickerFieldThe product picker as a Payload text field.
import { ProductPickerField } from "@evolve-framework/payload/admin";
PropTypeDescription
fieldOmit<TextFieldClient, "type"> & Partial<Pick<TextFieldClient, "type">>
pathstring
readOnly?boolean
forceRender?boolean

Controls the rendering behavior of the fields, i.e. defers rendering until they intersect with the viewport using the Intersection Observer API.

More

If true, the fields will be rendered immediately, rather than waiting for them to intersect with the viewport.

If a number is provided, will immediately render fields up to that index.

permissions?SanitizedFieldPermissions
renderedBlocks?RenderedField[]
schemaPath?string
Default: field.name

Used to extract field configs from a schemaMap. Does not include indexes.

inputRef?RefObject<HTMLInputElement>
onKeyDown?KeyboardEventHandler<HTMLInputElement>
validate?TextFieldValidation
VariantPickerPick a product variant, and store its sku.
import { VariantPicker } from "@evolve-framework/payload/admin";

Two steps, because a sku identifies a variant and a product that comes in sizes and colours has several. Searching lands on the product; the dimensions then resolve which one, the way a product detail page does — so an editor chooses "M" and "Black" rather than recalling T-SHIRT-M-BLACK.

The stored value is still the sku, so nothing downstream changes: this replaces how the field is filled in, not what it holds. A project without a catalogue wired up keeps a plain text input.

PropTypeDescription
valuestring | undefined
setValue(value: string) => void
apiBasestring

Where Payload's REST API is mounted, e.g. /cms-api.

More

Passed in rather than derived from the url. The admin and the api are mounted independently — this project serves /admin and /cms-api — so there is nothing in the current path to infer it from, and guessing gives a picker that silently returns no results. The wrapper reads it from Payload's own config.

VariantPickerFieldThe variant picker as a Payload text field.
import { VariantPickerField } from "@evolve-framework/payload/admin";
PropTypeDescription
fieldOmit<TextFieldClient, "type"> & Partial<Pick<TextFieldClient, "type">>
pathstring
readOnly?boolean
forceRender?boolean

Controls the rendering behavior of the fields, i.e. defers rendering until they intersect with the viewport using the Intersection Observer API.

More

If true, the fields will be rendered immediately, rather than waiting for them to intersect with the viewport.

If a number is provided, will immediately render fields up to that index.

permissions?SanitizedFieldPermissions
renderedBlocks?RenderedField[]
schemaPath?string
Default: field.name

Used to extract field configs from a schemaMap. Does not include indexes.

inputRef?RefObject<HTMLInputElement>
onKeyDown?KeyboardEventHandler<HTMLInputElement>
validate?TextFieldValidation
VariantRowLabelThe collapsed label of a product row.
import { VariantRowLabel } from "@evolve-framework/payload/admin";

Payload labels a block row by a field it recognises, and a variant row holds only a sku — so every row reads "Untitled" and a list of six products cannot be told apart while collapsed. The product name comes from the same lookup the picker uses, with the sku beside it because the whole point of the row is which variant.

Falls back to the sku alone while the lookup is in flight, so the row never flashes empty.

PropTypeDescription
skustring | undefined
apiBasestring
VariantRowLabelFieldThe collapsed label of a product variant row.
import { VariantRowLabelField } from "@evolve-framework/payload/admin";

Types

PickerPropsWhat a picker needs, and nothing more.
import { type PickerProps } from "@evolve-framework/payload/admin";

Deliberately not Payload's TextFieldClientProps, and deliberately no useField. These components are consumed as source and transpiled by the project that uses them, so an import of @payloadcms/ui here resolves against this package rather than the admin app — and pnpm will happily produce a second copy whose hooks are undefined inside the first copy's render tree.

So the field binding stays in the admin app, which has exactly one copy, and the app's own wrapper hands the value down.

export type PickerProps = {
value: string | undefined;
setValue: (value: string) => void;
apiBase: string;
};

@evolve-framework/payload/migrations/drop-removed-schema

A predefined migration, for payload migrate:create --file, that drops the tables, enums and columns the config no longer declares.

Functions

dynamicThe migration template: up drops what the config removed, down recreates it, and the pruned snapshot is written for the next migration to diff against.
import { dynamic } from "@evolve-framework/payload/migrations/drop-removed-schema";
function dynamic(
args: { filePath: string; payload: BasePayload; },
): Promise<{
downSQL?: string;
imports?: string;
upSQL?: string;
}>

Returns Promise<{ downSQL?: string; imports?: string; upSQL?: string; }>

withoutRemovedbefore without anything after lacks.
import { withoutRemoved } from "@evolve-framework/payload/migrations/drop-removed-schema";
function withoutRemoved(before: Snapshot, after: Snapshot): Snapshot
OptionTypeDescription
idstring
prevIdstring
versionstring
tablesRecord<string, Record<string, unknown>>
idstring
prevIdstring
versionstring
tablesRecord<string, Record<string, unknown>>
enums?Record<string, unknown>
enums?Record<string, unknown>

Returns Snapshot

Not listed: 8 options types. They appear as the tables under the constructors and functions they type.