{"_id":"@byte5digital/payload-assist","_rev":"19-077cb2999cfd1d305026b3d1f521906e","name":"@byte5digital/payload-assist","dist-tags":{"latest":"1.2.8"},"versions":{"1.2.6":{"name":"@byte5digital/payload-assist","version":"1.2.6","keywords":["payload","cms","dto","typescript","validation","config"],"author":{"name":"byte5"},"license":"MIT","_id":"@byte5digital/payload-assist@1.2.6","maintainers":[{"name":"connyscode","email":"concode@outlook.de"}],"homepage":"https://github.com/byte5digital/payload-assist#readme","bugs":{"url":"https://github.com/byte5digital/payload-assist/issues"},"dist":{"shasum":"7881f6a2a20df304da87724c04cee6b77782fac6","tarball":"https://registry.npmjs.org/@byte5digital/payload-assist/-/payload-assist-1.2.6.tgz","fileCount":55,"integrity":"sha512-vcGiOmrFTKyg71OoNjP6EFizIMjQMIV1uvdxTfwYTy3gXLGt1ktqqw+lWfE+5iLEDgPsVaROXBUom04E5RE0mQ==","signatures":[{"sig":"MEQCIGg3/yR3bwlnQ8/L3U/Hv/UnZDKMZYSAbCOI3iNVs4pPAiAMp60oZfrntQG4I7onBic42lGPKiwsZx6X9ZJE2Adi+A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40917},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"gitHead":"06406a18fd503d01c1f5289de035b13244fb5f9b","scripts":{"test":"vitest","build":"tsc","clean":"rm -rf dist","prepack":"npm run build","changelog":"git log --oneline --pretty=format:'- %s (%h)' --grep='^feat\\|^fix\\|^docs\\|^style\\|^refactor\\|^perf\\|^test\\|^chore\\|^ci\\|^build\\|^revert'","build:watch":"tsc --watch","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"connyscode","email":"concode@outlook.de"},"repository":{"url":"git+ssh://git@github.com/byte5digital/payload-assist.git","type":"git"},"_npmVersion":"10.8.2","description":"A TypeScript library providing DTO utilities and validation hooks for Payload CMS","directories":{},"_nodeVersion":"20.19.5","dependencies":{"reflect-metadata":"^0.2.2","class-transformer":"^0.5.1"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","react":"^19.1.1","vitest":"^3.2.4","payload":"^3.0.0","typescript":"^5.7.3"},"peerDependencies":{"next":"^15.0.0","payload":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/payload-assist_1.2.6_1759309297299_0.36910619529622424","host":"s3://npm-registry-packages-npm-production"}},"1.2.7":{"name":"@byte5digital/payload-assist","version":"1.2.7","keywords":["payload","cms","dto","typescript","validation","config"],"author":{"name":"byte5"},"license":"MIT","_id":"@byte5digital/payload-assist@1.2.7","maintainers":[{"name":"connyscode","email":"concode@outlook.de"}],"homepage":"https://github.com/byte5digital/payload-assist#readme","bugs":{"url":"https://github.com/byte5digital/payload-assist/issues"},"dist":{"shasum":"50c3b637fd94007eb794c374cb6d9ae62b939968","tarball":"https://registry.npmjs.org/@byte5digital/payload-assist/-/payload-assist-1.2.7.tgz","fileCount":55,"integrity":"sha512-lHttigD7XhylYQyL0GO64sjxydiELXLzWy8hqjiBwZUt6GrHbKaO5nn4O4d/S0Gn2NDtL63htBcZFNyIdcW7eQ==","signatures":[{"sig":"MEQCIDaEaMDSLnIzQMp+NW/xLvzRDFRRJfRGsgGloHVO9y2XAiBd8ayDb97aLyx/NgeGJLMNdNcm+y8KDXdMmQCVjmp3GA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41160},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"gitHead":"1d5d8e0cde7b82f037afcc563c9a90ee095bfd25","scripts":{"test":"vitest","build":"tsc","clean":"rm -rf dist","prepack":"npm run build","changelog":"git log --oneline --pretty=format:'- %s (%h)' --grep='^feat\\|^fix\\|^docs\\|^style\\|^refactor\\|^perf\\|^test\\|^chore\\|^ci\\|^build\\|^revert'","build:watch":"tsc --watch","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"connyscode","email":"concode@outlook.de"},"repository":{"url":"git+ssh://git@github.com/byte5digital/payload-assist.git","type":"git"},"_npmVersion":"10.8.2","description":"A TypeScript library providing DTO utilities and validation hooks for Payload CMS","directories":{},"_nodeVersion":"20.19.5","dependencies":{"reflect-metadata":"^0.2.2","class-transformer":"^0.5.1"},"_hasShrinkwrap":false,"devDependencies":{"next":"^15.0.0","react":"^19.1.1","vitest":"^3.2.4","payload":"^3.0.0","typescript":"^5.7.3"},"peerDependencies":{"next":"^15.0.0","payload":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/payload-assist_1.2.7_1759399102030_0.6102722308314792","host":"s3://npm-registry-packages-npm-production"}},"1.2.8":{"name":"@byte5digital/payload-assist","version":"1.2.8","description":"A TypeScript library providing DTO utilities and validation hooks for Payload CMS","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsc","build:watch":"tsc --watch","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build","prepack":"npm run build","changelog":"git log --oneline --pretty=format:'- %s (%h)' --grep='^feat\\|^fix\\|^docs\\|^style\\|^refactor\\|^perf\\|^test\\|^chore\\|^ci\\|^build\\|^revert'","test":"vitest"},"repository":{"type":"git","url":"git+ssh://git@github.com/byte5digital/payload-assist.git"},"keywords":["payload","cms","dto","typescript","validation","config"],"author":{"name":"byte5"},"license":"MIT","type":"module","exports":{".":{"import":"./dist/index.js","require":"./dist/index.js","types":"./dist/index.d.ts"}},"peerDependencies":{"next":"^15.0.0","payload":"^3.0.0"},"dependencies":{"class-transformer":"^0.5.1","reflect-metadata":"^0.2.2"},"devDependencies":{"next":"^15.0.0","payload":"^3.0.0","react":"^19.1.1","typescript":"^5.7.3","vitest":"^3.2.4"},"engines":{"node":">=20.0.0"},"_id":"@byte5digital/payload-assist@1.2.8","gitHead":"4fd1789d2bf61d0fe5bf458ecde2b15114bab2c3","bugs":{"url":"https://github.com/byte5digital/payload-assist/issues"},"homepage":"https://github.com/byte5digital/payload-assist#readme","_nodeVersion":"24.3.0","_npmVersion":"11.4.2","dist":{"integrity":"sha512-77CflNUsphS1S/ehJNz3C2GEqo0u87zNn9Y0Lv8I2UqBTkGbyZhiB6qEK3FOlupyJfProFnei4c7ooq2qW9GNg==","shasum":"b889d48ee3fefac2eaac1fb188a0b070a5cffaea","tarball":"https://registry.npmjs.org/@byte5digital/payload-assist/-/payload-assist-1.2.8.tgz","fileCount":55,"unpackedSize":41294,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIELz/jKUfQfWpjBQcKctsLswL2A6H0CEte1hAnCX1P6DAiAtag5+Xxp5LLmGBHUu2BxKEaNcJJJ0le1I8UhnVmGzxQ=="}]},"_npmUser":{"name":"connyscode","email":"concode@outlook.de"},"directories":{},"maintainers":[{"name":"connyscode","email":"concode@outlook.de"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/payload-assist_1.2.8_1777295876106_0.6290435028725294"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-05T16:19:51.636Z","modified":"2026-04-27T13:17:56.442Z","1.0.0":"2025-09-05T16:19:51.971Z","1.1.0":"2025-09-25T10:52:54.834Z","1.2.0":"2025-09-29T11:57:18.260Z","1.2.1":"2025-09-29T12:22:03.852Z","1.2.2":"2025-09-29T12:30:13.637Z","1.2.3":"2025-09-29T12:35:49.085Z","1.2.4":"2025-09-30T08:51:15.389Z","1.2.5":"2025-09-30T11:10:36.815Z","1.2.6":"2025-10-01T09:01:37.490Z","1.2.7":"2025-10-02T09:58:22.269Z","1.2.8":"2026-04-27T13:17:56.239Z"},"bugs":{"url":"https://github.com/byte5digital/payload-assist/issues"},"author":{"name":"byte5"},"license":"MIT","homepage":"https://github.com/byte5digital/payload-assist#readme","keywords":["payload","cms","dto","typescript","validation","config"],"repository":{"type":"git","url":"git+ssh://git@github.com/byte5digital/payload-assist.git"},"description":"A TypeScript library providing DTO utilities and validation hooks for Payload CMS","maintainers":[{"name":"connyscode","email":"concode@outlook.de"}],"readme":"<picture>\n  <source media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/byte5digital/payload-assist/master/.github/assets/gh-banner-light.png\">\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/byte5digital/payload-assist/master/.github/assets/gh-banner-dark.png\">\n  <img alt=\"Assist for Payload\" src=\"https://raw.githubusercontent.com/byte5digital/payload-assist/master/.github/assets/gh-banner-light.png\">\n</picture>\n<div align=\"center\" style=\"display: flex; flex-direction: row; justify-content: center; align-items: center; gap: 12px;\">\n<a href=\"https://www.npmjs.com/@byte5digital/payload-assist\"><picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.npmjs.org%2F@byte5digital%2Fpayload-assist&query=%24%5B%22dist-tags%22%5D.latest&prefix=v&label=NPM&style=for-the-badge&labelColor=ffffff&color=373E45\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.npmjs.org%2F@byte5digital%2Fpayload-assist&query=%24%5B%22dist-tags%22%5D.latest&prefix=v&label=NPM&style=for-the-badge&labelColor=002634&color=E5E9EB\"><img alt=\"Assist for Payload\" src=\"https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.npmjs.org%2F@byte5digital%2Fpayload-assist&query=%24%5B%22dist-tags%22%5D.latest&prefix=v&label=NPM&style=for-the-badge&labelColor=002634&color=E5E9EB\"></picture></a>\n  <picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://img.shields.io/badge/TESTS-PASSING-empty?style=for-the-badge&labelColor=ffffff&color=373E45\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://img.shields.io/badge/TESTS-PASSING-empty?style=for-the-badge&labelColor=002634&color=E5E9EB\"><img alt=\"Tests passing\" src=\"https://img.shields.io/badge/TESTS-PASSING-empty?style=for-the-badge&labelColor=002634&color=E5E9EB\"></picture>\n  <picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://img.shields.io/badge/LICENSE-MIT-empty?style=for-the-badge&labelColor=ffffff&color=373E45\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://img.shields.io/badge/LICENSE-MIT-empty?style=for-the-badge&labelColor=002634&color=E5E9EB\"><img alt=\"License MIT\" src=\"https://img.shields.io/badge/LICENSE-MIT-empty?style=for-the-badge&labelColor=002634&color=E5E9EB\"></picture>\n</div>\n\n# Assist for Payload\n\nUtilities to add guardrails, DTO tooling, and ergonomic rules to Payload CMS projects.\n\n- **Rules**: Validate your Payload config at boot (e.g., kebab-case slugs).\n- **DTOs**: First-class helpers to define, transform, validate, and enforce DTO-only responses.\n- **Ergonomics**: Thin wrappers to keep endpoints and collection reads consistent and secure.\n\n## Installation\n\n```bash\nyarn add @byte5digital/payload-assist\n# or\nnpm install @byte5digital/payload-assist\n```\n\nPeer deps: Payload v3+, Next v15+. Dependencies `class-transformer` and `reflect-metadata` are included in the package.\n\n## API overview\n\n- `payloadAssist(payloadConfig, options?)`: Main function that initializes Assist for Payload, validates your payload config against defined rules, and returns the built config.\n- `defaultConfig`: Default config with built-in rules and transformAndValidate function (can be spread/overridden).\n- `Dto`: Base abstract class for response DTOs.\n- `transformAndValidate(Dto, data)`: Validate Payload data and transform to DTO. Uses the configured transformer/validator.\n- `withResponse(handler)`: Enforce DTO-only JSON responses in your custom payload endpoints.\n- `withDtoReadHook([{ dto, condition }, { dto }])`: Attach to collections to return DTOs from read operations with conditional DTO selection.\n\n## Helper Types\n\n### AccessControl\n\nA comprehensive type for Payload collection access control that includes all available access control methods.\n\n```ts\nimport { AccessControl } from \"@byte5digital/payload-assist\";\n\nexport const MyCollection: CollectionConfig = {\n  slug: \"my-collection\",\n  access: {\n    admin: ({ req }) => req.user?.role === \"admin\",\n    create: ({ req }) => req.user?.role === \"admin\",\n    read: ({ req }) => true, // public read\n    update: ({ req }) => req.user?.role === \"admin\",\n    delete: ({ req }) => req.user?.role === \"admin\",\n  } satisfies AccessControl,\n  // ...fields\n};\n```\n\n## Usage\n\n### Initialize Assist for Payload\n\nThe 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.\npayloadAssist 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.\n\n- **ruleSet**: An object map of named rules; merge defaults with your own, if required. Deactivate a default rule by setting the rule to `false`.\n- **rules**: `(config: payloadConfig) => boolean | void`; throw to fail with an actionable message and return true if the rule is satisfied.\n- **transformAndValidate**: `(dto: Dto, data: unknown) => Dto` Turn raw Payload data into typed DTOs.\n\n**Built-in rules:**\n\n- `disableQraphQL`: Ensures GraphQL is disabled in your config\n- `collectionsEndpointsUseWithResponse`: Ensures all collection endpoints use `withResponse`\n- `collectionsUseWithDtoReadHook`: Ensures all collections use `withDtoReadHook` in their afterRead hooks\n\n```ts\nimport { buildConfig } from \"payload\";\nimport payloadAssist, {\n  defaultConfig,\n  PayloadAssistError,\n} from \"@byte5digital/payload-assist\";\n\nexport default payloadAssist(\n  {\n    // your Payload config\n  },\n  {\n    ruleSet: {\n      ...defaultConfig.ruleSet,\n\n      // add/override rules here\n      secretIsSet: (config) => {\n        if (config.secret?.length > 0) return true;\n        throw new PayloadAssistError(\"A secret needs to be set\");\n      },\n    },\n  }\n);\n```\n\n---\n\n### DTOs: Purpose and usage\n\nDefine exactly what leaves your API by modeling responses as DTOs. Only explicitly exposed fields and nested DTOs are serialized.\nIt is important that all DTOs extend the `Dto` class. The example below shows the usage with the default `transformAndValidate`.\n\n```ts\nimport { Dto, Expose, Type } from \"@byte5digital/payload-assist\";\n\nexport class MediaResponse extends Dto {\n  @Expose() url: string;\n  @Expose() mimeType: string;\n}\n\nexport class UserResponse extends Dto {\n  @Expose() id: number;\n  @Expose() name: string;\n}\n\nexport class MyCollectionDto extends Dto {\n  @Expose() name: string;\n  @Expose() @Type(() => MediaResponse) image: MediaResponse;\n  @Expose() @Type(() => UserResponse) owner: UserResponse;\n}\n```\n\n---\n\nTransform any raw Payload doc into a DTO. By default `transformAndValidate` uses `class-transformer`, but it can be configured through the payloadAssist options.\n\n```ts\nimport { transformAndValidate } from \"@byte5digital/payload-assist\";\n\nconst payloadDoc = await getPayloadDoc();\nconst dto = transformAndValidate(MyCollectionDto, payloadDoc);\n```\n\n---\n\n### Enforcing DTO-only responses in endpoints\n\nUse `withResponse` to guarantee your endpoints return DTOs (and nothing else). It centralizes transform/serialize and standardizes error responses. The transformation strategy is configurable.\n\n```ts\nimport payload from \"payload\";\nimport {\n  withResponse,\n  transformAndValidate,\n} from \"@byte5digital/payload-assist\";\nimport { MyDataDto } from \"path/to/dtos\";\n\nexport const MyCollection: CollectionConfig = {\n  slug: \"my-collection\",\n  endpoints: [\n    {\n      path: \"/my-custom-endpoint\",\n      method: \"get\",\n      handler: withResponse(async (req: PayloadRequest) => {\n        const myData = await req.payload.find({\n          collection: \"my-collection\",\n          // ...additional filter logic\n        });\n\n        const myDataDto = transformAndValidate(MyDataDto, myData);\n        return {\n          response: myDataDto,\n          status: 200,\n        };\n      }),\n    },\n  ],\n\n  // ...fields\n};\n```\n\n---\n\n### Enforcing DTO-only responses from collections\n\nAttach `withDtoReadHook` to your collections afterReadHooks to transform read results automatically to the given DTOs.\nMultiple objects with DTOs can be passed, when they include a condition, only the last item can be without a condition.\nThe 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.\nSo the order of the given DTOs should be: More specific first, default last.\n\n```ts\n// src/collections/MyCollection.ts\nimport { CollectionConfig } from \"payload/types\";\nimport { withDtoReadHook } from \"@byte5digital/payload-assist\";\nimport { MyCollectionDto, MyCollectionAdminDto } from \"path/to/dtos\";\n\nexport const MyCollection: CollectionConfig = {\n  slug: \"my-collection\",\n  hooks: {\n    afterRead: [\n      withDtoReadHook(\n        {\n          dto: MyCollectionAdminDto,\n          condition: ({ req: { user } }) => user?.role === \"admin\",\n        },\n        {\n          dto: MyCollectionDto,\n        }\n      ),\n    ],\n  },\n  // ...fields\n};\n```\n\n## License\n\nMIT\n\n## About byte5\n\nWe'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.\n\nWe 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.\n\nIf you love building smart solutions with real impact — we should talk.\n\n**Connect with us:**\n\n- [Website](https://byte5.net)\n- [LinkedIn](https://www.linkedin.com/company/byte5-gmbh)\n- [Email](mailto:info@byte5.de)\n\n## Support\n\n- [Issue Tracker](https://github.com/byte5digital/payload-assist/issues)\n- [Email Support](mailto:support@byte5.de)\n\n---\n\n**Built with 🩵 by [byte5](https://byte5.net)**\n","readmeFilename":"README.md"}