Wraps your Payload config to validate it against configurable rules at boot, such as requiring GraphQL to be disabled. It provides a Dto base class, a transformAndValidate helper built on class-transformer, a withResponse wrapper for custom endpoints, and a withDtoReadHook for collection afterRead hooks. It is used as a config wrapper rather than a plugin and requires Payload 3 and Next 15.
A TypeScript library providing DTO utilities and validation hooks for Payload CMS
Installation
npm i @byte5digital/payload-assist0
Stars
0
Forks
0
Open Issues
5 months ago
Last Updated
9
Weekly Downloads
v1.2.8
npm Version
40.3 KB
Unpacked Size
2
Dependencies
Trends appear after 7 days of data. Daily snapshots have not started yet.
Trends appear after 7 days of data. Daily snapshots have not started yet.
Each point is npm's rolling 7-day download count.
Health Score
Composite score based on GitHub activity, stars, npm downloads, publish recency, dependency count, and package size.
Badge for your README
[](https://payloaddirectory.dev/plugins/1049574899-root)<a href="https://payloaddirectory.dev/plugins/1049574899-root"><img src="https://payloaddirectory.dev/badge/1049574899-root.svg" alt="Payload Directory"></a>README
Utilities to add guardrails, DTO tooling, and ergonomic rules to Payload CMS projects.
yarn add @byte5digital/payload-assist
# or
npm install @byte5digital/payload-assist
Peer deps: Payload v3+, Next v15+. Dependencies class-transformer and reflect-metadata are included in the package.
payloadAssist(payloadConfig, options?): Main function that initializes Assist for Payload, validates your payload config against defined rules, and returns the built config.defaultConfig: Default config with built-in rules and transformAndValidate function (can be spread/overridden).Dto: Base abstract class for response DTOs.transformAndValidate(Dto, data): Validate Payload data and transform to DTO. Uses the configured transformer/validator.withResponse(handler): Enforce DTO-only JSON responses in your custom payload endpoints.withDtoReadHook([{ dto, condition }, { dto }]): Attach to collections to return DTOs from read operations with conditional DTO selection.A comprehensive type for Payload collection access control that includes all available access control methods.
import { AccessControl } from "@byte5digital/payload-assist";
export const MyCollection: CollectionConfig = {
slug: "my-collection",
access: {
admin: ({ req }) => req.user?.role === "admin",
create: ({ req }) => req.user?.role === "admin",
read: ({ req }) => true, // public read
update: ({ req }) => req.user?.role === "admin",
delete: ({ req }) => req.user?.role === "admin",
} satisfies AccessControl,
// ...fields
};
The main payloadAssist function initializes the library, validates your payload config against defined rules, and returns the built config. You can customize the ruleSet and transformAndValidate function through options.
payloadAssist is implemenented as a wrapper function and not as a payload plugin, to ensure it validates the raw config that is set by the user, instead of the config that was previously processed by other plugins and enriched by payload.
false.(config: payloadConfig) => boolean | void; throw to fail with an actionable message and return true if the rule is satisfied.(dto: Dto, data: unknown) => Dto Turn raw Payload data into typed DTOs.Built-in rules:
disableQraphQL: Ensures GraphQL is disabled in your configcollectionsEndpointsUseWithResponse: Ensures all collection endpoints use withResponsecollectionsUseWithDtoReadHook: Ensures all collections use withDtoReadHook in their afterRead hooksimport { buildConfig } from "payload";
import payloadAssist, {
defaultConfig,
PayloadAssistError,
} from "@byte5digital/payload-assist";
export default payloadAssist(
{
// your Payload config
},
{
ruleSet: {
...defaultConfig.ruleSet,
// add/override rules here
secretIsSet: (config) => {
if (config.secret?.length > 0) return true;
throw new PayloadAssistError("A secret needs to be set");
},
},
}
);
Define exactly what leaves your API by modeling responses as DTOs. Only explicitly exposed fields and nested DTOs are serialized.
It is important that all DTOs extend the Dto class. The example below shows the usage with the default transformAndValidate.
import { Dto, Expose, Type } from "@byte5digital/payload-assist";
export class MediaResponse extends Dto {
@Expose() url: string;
@Expose() mimeType: string;
}
export class UserResponse extends Dto {
@Expose() id: number;
@Expose() name: string;
}
export class MyCollectionDto extends Dto {
@Expose() name: string;
@Expose() @Type(() => MediaResponse) image: MediaResponse;
@Expose() @Type(() => UserResponse) owner: UserResponse;
}
Transform any raw Payload doc into a DTO. By default transformAndValidate uses class-transformer, but it can be configured through the payloadAssist options.
import { transformAndValidate } from "@byte5digital/payload-assist";
const payloadDoc = await getPayloadDoc();
const dto = transformAndValidate(MyCollectionDto, payloadDoc);
Use withResponse to guarantee your endpoints return DTOs (and nothing else). It centralizes transform/serialize and standardizes error responses. The transformation strategy is configurable.
import payload from "payload";
import {
withResponse,
transformAndValidate,
} from "@byte5digital/payload-assist";
import { MyDataDto } from "path/to/dtos";
export const MyCollection: CollectionConfig = {
slug: "my-collection",
endpoints: [
{
path: "/my-custom-endpoint",
method: "get",
handler: withResponse(async (req: PayloadRequest) => {
const myData = await req.payload.find({
collection: "my-collection",
// ...additional filter logic
});
const myDataDto = transformAndValidate(MyDataDto, myData);
return {
response: myDataDto,
status: 200,
};
}),
},
],
// ...fields
};
Attach withDtoReadHook to your collections afterReadHooks to transform read results automatically to the given DTOs.
Multiple objects with DTOs can be passed, when they include a condition, only the last item can be without a condition.
The first DTO where the condition is met will be used or the DTO without a condition, if given. If none applies, null will be returned.
So the order of the given DTOs should be: More specific first, default last.
// src/collections/MyCollection.ts
import { CollectionConfig } from "payload/types";
import { withDtoReadHook } from "@byte5digital/payload-assist";
import { MyCollectionDto, MyCollectionAdminDto } from "path/to/dtos";
export const MyCollection: CollectionConfig = {
slug: "my-collection",
hooks: {
afterRead: [
withDtoReadHook(
{
dto: MyCollectionAdminDto,
condition: ({ req: { user } }) => user?.role === "admin",
},
{
dto: MyCollectionDto,
}
),
],
},
// ...fields
};
MIT
We're a development company based in Frankfurt, Germany — remote-friendly, open-minded, and tech-driven. Our team brings deep expertise in Node.js, MedusaJS, Laravel, Umbraco, and decentralized tech like IOTA. We collaborate with clients who care about clean code, scalable solutions, and long-term maintainability.
We contribute to open source, run Laravel DACH Meetups, and support developer communities across the DACH region. Our expertise in e-commerce platforms makes us the perfect partner for building robust, scalable solutions.
If you love building smart solutions with real impact — we should talk.
Connect with us:
Built with 🩵 by byte5
Tags
mcp
Adds Model Context Protocol capabilities to Payload so AI clients can work with your CMS
9889.1k/wk45.4kv3
fields select
Select specific fields in Local API and REST API responses, like GraphQL field selection
4726/wk334v3
payload rest client
Typesafe REST API client for Payload collections, globals, auth and custom endpoints
39134/wk49v?
openapi
Generate OpenAPI 3 documents from your Payload config, including collections, globals and custom endpoints
360/wk142v1
payload graphql view plugin
Adds a GraphQL IDE view to Payload collections and globals in the admin panel
150/wk5v2
payload plugin openapi
Generate OpenAPI 3.0, 3.1 or 3.2 specs from your Payload config and serve them with Scalar or Swagger UI
80437/wk18v4