diff --git a/99 Daily/2026-05-15.md b/99 Daily/2026-05-15.md index 4362d2c..2c20ec2 100644 --- a/99 Daily/2026-05-15.md +++ b/99 Daily/2026-05-15.md @@ -78,3 +78,4 @@ tags: [daily] - 15:38 — session ended | `ai_leed` - 15:42 — session ended | `ai_leed` - 15:44 — session ended | `ai_leed` +- 15:53 (6min) — session ended | `Shumiland` diff --git a/raw/hooks__overview.md b/raw/_processed/hooks__overview.md similarity index 100% rename from raw/hooks__overview.md rename to raw/_processed/hooks__overview.md diff --git a/wiki/payloadcms/_index.md b/wiki/payloadcms/_index.md index 60b89e4..6f23af6 100644 --- a/wiki/payloadcms/_index.md +++ b/wiki/payloadcms/_index.md @@ -60,7 +60,7 @@ | [[wiki/payloadcms/fields-basic\|PayloadCMS — Fields: Basic]] | Scalar (basic) fields store a single value per document. They map directly to database columns and d | https://payloadcms.com/docs/fields/overview | 2026-05-15 | | [[wiki/payloadcms/fields-complex\|PayloadCMS — Fields: Complex]] | Complex fields define structure, layout, or relations between documents. Some are data-bearing (Arra | https://payloadcms.com/docs/fields/array | 2026-05-15 | | [[wiki/payloadcms/getting-started\|PayloadCMS — Getting Started]] | Payload is a code-first, open-source Next.js fullstack framework that acts as a CMS, enterprise tool | getting-started__what-is-payload.md | 2026-05-15 | -| [[wiki/payloadcms/hooks\|PayloadCMS — Hooks]] | - Hooks execute side effects at precise moments in the Document lifecycle | https://payloadcms.com/docs/hooks/overview | 2026-05-15 | +| [[wiki/payloadcms/hooks\|PayloadCMS — Hooks]] | All hook types (Root/Collection/Global/Field), awaited vs fire-and-forget, APIError, performance (avoid read hooks), context caching, jobs offload | raw/hooks__overview.md | 2026-05-15 | | [[wiki/payloadcms/live-preview\|PayloadCMS — Live Preview]] | - Renders your frontend inside an iframe directly in the Admin Panel | https://payloadcms.com/docs/live-preview/overview | 2026-05-15 | | [[wiki/payloadcms/rich-text\|PayloadCMS — Rich Text (Lexical)]] | - Rich text is powered by **Lexical** (Meta's framework), exposed via `@payloadcms/richtext-lexical` | https://payloadcms.com/docs/rich-text/overview | 2026-05-15 | | [[wiki/payloadcms/examples-overview\|Examples Overview]] | 9 official starter examples (auth, draft-preview, multi-tenant, tailwind-shadcn, whitelabel…) — `npx create-payload-app --example ` | raw/examples__overview.md | 2026-05-15 | diff --git a/wiki/payloadcms/hooks.md b/wiki/payloadcms/hooks.md index 85311ce..6997274 100644 --- a/wiki/payloadcms/hooks.md +++ b/wiki/payloadcms/hooks.md @@ -2,6 +2,7 @@ tags: [payloadcms, tech-patterns] topic: payloadcms sources: + - raw/hooks__overview.md - https://payloadcms.com/docs/hooks/overview - https://payloadcms.com/docs/hooks/collections - https://payloadcms.com/docs/hooks/globals @@ -231,6 +232,68 @@ declare module 'payload' { } ``` +## Custom Error Messages + +Throw `APIError` from any hook to return structured errors to REST or GraphQL callers: + +```ts +import { APIError, type CollectionBeforeChangeHook } from 'payload' + +const beforeChangeHook: CollectionBeforeChangeHook = async ({ data }) => { + if (rateLimitExceeded) { + throw new APIError('You have sent too many requests', 429) + } + return data +} +``` + +## Performance + +### Avoid expensive logic in read hooks + +`beforeRead` / `afterRead` run on **every** read request — query-time operations here multiply with list view page sizes. + +```ts +// BAD — runs on every find/findByID +hooks: { beforeRead: [async () => { await doSomethingExpensive() }] } + +// BETTER — only on create/update +hooks: { beforeChange: [async () => { await doSomethingExpensive() }] } +``` + +### Use Hook Context to cache across hooks + +```ts +hooks: { + beforeChange: [ + async ({ context, data }) => { + context.enriched = await fetchExpensiveData(data.userId) + return { ...data, profile: context.enriched } + }, + ], + afterChange: [ + async ({ context, doc }) => { + // reuse what beforeChange already fetched — no second DB call + await syncToCRM(doc.id, context.enriched) + }, + ], +} +``` + +Full context API → [[wiki/payloadcms/hooks-context|Hooks — Context]] + +### Offload long-running tasks + +```ts +afterChange: [ + async ({ doc, req }) => { + await req.payload.jobs.queue({ task: 'processReport', input: { id: doc.id } }) + }, +] +``` + +→ [[wiki/payloadcms/jobs-queue|Jobs Queue]] + ## Gotchas - **`data` on `beforeChange`/`beforeValidate`** — contains only changed fields (delta), not the full document. Use `originalDoc` for unchanged fields. `id` is NOT in `data` on create — use `afterChange` if you need it.