@10x-media/webhooks 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # @10x-media/webhooks
2
+
3
+ ## 0.1.0-beta.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial beta of `@10x-media/webhooks`: outbound webhook subscriptions for Payload v3.
8
+
9
+ - **Subscriptions**: an admin-managed collection for registering endpoint URLs, selecting events, and storing per-subscription secrets. A 48-character hex secret is auto-generated on create.
10
+ - **Deliveries log**: an append-only collection with derived status, HTTP response code, and a redeliver button that replays the original payload to the original URL.
11
+ - **Event hooks**: opt any collection in with `collections: { posts: true }`. Emits `<slug>.created`, `<slug>.updated`, and `<slug>.deleted` events. Per-collection `operations`, `transform`, and `includePreviousData` options.
12
+ - **HMAC signing**: `X-Webhook-Signature: v1=<hex>` on every request when a subscription has a secret. Signed over `${timestamp}.${rawBody}`.
13
+ - **Delivery modes**: `inline` (awaited in the hook), `queue` (Payload jobs task with configurable retries and queue), and `auto` (queue when a runner is detected, inline otherwise).
14
+ - **Code subscriptions**: hard-coded subscriptions in plugin options, merged with admin-managed ones at delivery time.
15
+ - **Composable**: auto-detects `@10x-media/jobs` (uses its worker) and `@10x-media/automations` (registers a `webhook` trigger in the catalog).
16
+ - **Cross-DB**: tested on MongoDB and PostgreSQL via the matrix integration suite.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 10x Media GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # @10x-media/webhooks
2
+
3
+ Outbound webhook subscriptions for Payload v3. Opt any collection in, let subscribers register URLs in the admin panel, and deliver signed HTTP POSTs on every create/update/delete -- inline or via Payload's built-in jobs queue.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@10x-media/webhooks?style=flat-square)](https://www.npmjs.com/package/@10x-media/webhooks)
6
+
7
+ Part of the [@10x-media Payload plugins](https://github.com/10x-media/payload-plugins) collection. In beta: published under the `beta` dist-tag until a stable 1.0.
8
+
9
+ ## Requirements
10
+
11
+ - Payload v3 (peer: `payload@^3.82.0`)
12
+ - React 19 (peer)
13
+ - Node 22.18+
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add @10x-media/webhooks
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```ts
24
+ import { buildConfig } from 'payload'
25
+ import { webhooks } from '@10x-media/webhooks'
26
+
27
+ export default buildConfig({
28
+ plugins: [
29
+ webhooks({
30
+ collections: {
31
+ posts: true,
32
+ orders: { operations: ['create', 'delete'] },
33
+ },
34
+ }),
35
+ ],
36
+ })
37
+ ```
38
+
39
+ That is the minimum config. The plugin adds two collections to your admin panel:
40
+
41
+ - **Webhook Subscriptions** -- admins create endpoint records (URL, events, optional secret).
42
+ - **Webhook Deliveries** -- an append-only log with status, response code, and a redeliver button.
43
+
44
+ ## Options
45
+
46
+ | Option | Type | Default | Description |
47
+ |---|---|---|---|
48
+ | `disabled` | `boolean` | `false` | When `true`, returns the config unchanged. |
49
+ | `collections` | `Record<string, true \| CollectionWebhookConfig>` | `{}` | Collections that emit webhook events. |
50
+ | `subscriptions` | `CodeSubscription[]` | `[]` | Hard-coded subscriptions (no admin record needed). |
51
+ | `delivery` | `DeliveryMode \| DeliveryOptions` | `'auto'` | How deliveries are executed. |
52
+ | `subscriptionsCollection` | `{ slug?: string; hidden?: boolean }` | -- | Override the subscriptions collection slug or hide it from the admin panel. |
53
+ | `deliveriesLog` | `{ slug?: string; hidden?: boolean }` | -- | Override the deliveries collection slug or hide it from the admin panel. |
54
+
55
+ ### `CollectionWebhookConfig`
56
+
57
+ ```ts
58
+ type CollectionWebhookConfig = {
59
+ operations?: ('create' | 'update' | 'delete')[]
60
+ includePreviousData?: boolean
61
+ transform?: (args: {
62
+ doc: Record<string, unknown>
63
+ previousDoc?: Record<string, unknown>
64
+ operation: 'create' | 'update' | 'delete'
65
+ req: PayloadRequest
66
+ }) => unknown
67
+ }
68
+ ```
69
+
70
+ `true` is shorthand for all three operations with no transform.
71
+
72
+ `transform` lets you redact fields or reshape the payload before it is sent. Return `undefined` to suppress delivery for that document.
73
+
74
+ `includePreviousData` adds a `previousData` key to the body on `update` events.
75
+
76
+ ### Delivery modes
77
+
78
+ | Mode | Behavior |
79
+ |---|---|
80
+ | `'auto'` (default) | Queued when `config.jobs.autoRun` is set or `@10x-media/jobs` is installed; inline otherwise. |
81
+ | `'queue'` | Always enqueued as a Payload job. A worker must run `payload.jobs.run()`. |
82
+ | `'inline'` | Awaited in the `afterChange`/`afterDelete` hook. Simple but adds latency to every write. |
83
+
84
+ Pass a full `DeliveryOptions` object to tune the queue and timeout:
85
+
86
+ ```ts
87
+ webhooks({
88
+ collections: { posts: true },
89
+ delivery: {
90
+ mode: 'queue',
91
+ timeoutMs: 5_000,
92
+ retries: 3,
93
+ queue: 'webhooks',
94
+ },
95
+ })
96
+ ```
97
+
98
+ Defaults: `timeoutMs: 10000`, `retries: 4`, `queue: 'default'`.
99
+
100
+ ### Code subscriptions
101
+
102
+ Register subscriptions in code when you do not want them managed through the admin panel:
103
+
104
+ ```ts
105
+ webhooks({
106
+ collections: { orders: true },
107
+ subscriptions: [
108
+ {
109
+ id: 'my-crm',
110
+ url: 'https://crm.example.com/hooks/orders',
111
+ events: ['orders.created', 'orders.updated'],
112
+ secret: process.env.WEBHOOK_SECRET,
113
+ },
114
+ ],
115
+ })
116
+ ```
117
+
118
+ Code subscriptions are merged with admin-managed ones at delivery time.
119
+
120
+ ## Webhook payload
121
+
122
+ Every delivery POSTs a JSON body:
123
+
124
+ ```json
125
+ {
126
+ "id": "<delivery-id>",
127
+ "event": "posts.created",
128
+ "collection": "posts",
129
+ "operation": "create",
130
+ "occurredAt": "2025-01-01T00:00:00.000Z",
131
+ "data": { ... }
132
+ }
133
+ ```
134
+
135
+ `previousData` is included on `update` events when `includePreviousData: true`.
136
+
137
+ ## Signature verification
138
+
139
+ When a subscription has a `secret`, each request carries an `X-Webhook-Signature` header:
140
+
141
+ ```
142
+ X-Webhook-Signature: v1=<hex>
143
+ ```
144
+
145
+ The signature is HMAC-SHA256 over `${timestamp}.${rawBody}`, where `timestamp` is the Unix second from the `X-Webhook-Timestamp` header.
146
+
147
+ Verify in your receiver:
148
+
149
+ ```ts
150
+ import { createHmac } from 'node:crypto'
151
+
152
+ function verify(secret: string, timestamp: string, rawBody: string, signature: string): boolean {
153
+ const expected = createHmac('sha256', secret)
154
+ .update(`${timestamp}.${rawBody}`)
155
+ .digest('hex')
156
+ return signature === `v1=${expected}`
157
+ }
158
+ ```
159
+
160
+ Additional headers sent on every request: `X-Webhook-Id`, `X-Webhook-Event`, `X-Webhook-Timestamp`, `User-Agent: 10x-media-webhooks`. Subscriptions can inject extra headers via the admin panel's **Headers** array field.
161
+
162
+ ## Admin panel
163
+
164
+ The plugin adds a **Webhooks** group with two collections.
165
+
166
+ **Webhook Subscriptions**: create and manage endpoint records. A random 48-character hex secret is auto-generated on create and shown in full **exactly once** on that create response -- copy it to your receiver then. On every later read it is masked (`__redacted__`); the raw value is still used internally to sign deliveries but is never returned through the API or admin again. Rotate by deleting and recreating the record.
167
+
168
+ **Webhook Deliveries**: an append-only delivery log. Each row shows the event, subscription, status, HTTP response code, and a **Redeliver** button that replays the original payload to the original URL. Access requires a logged-in admin.
169
+
170
+ ## Composing with `@10x-media/jobs`
171
+
172
+ When `@10x-media/jobs` is installed, `delivery` mode auto-resolves to `'queue'` and the delivery task runs under the jobs worker. No extra config is needed -- the plugin detects the sibling plugin automatically.
173
+
174
+ ## Composing with `@10x-media/automations`
175
+
176
+ When `@10x-media/automations` is installed, the plugin contributes a `webhook` trigger slug to the automations catalog, reserving it for future inbound-webhook support. This plugin is outbound-only today and does not yet fire that trigger -- the contribution simply registers the slug so a later inbound phase can use it. No extra config is needed.
177
+
178
+ ## Security
179
+
180
+ - **Signing secrets are reveal-once.** A subscription's secret is shown in full only on the create response and masked (`__redacted__`) on every read thereafter; the raw value is used internally to sign deliveries and is never returned via REST, GraphQL, or the admin again. It is currently stored unencrypted at rest -- encryption-at-rest is planned.
181
+ - **Outbound requests target operator-supplied URLs (SSRF).** Deliveries POST to whatever URL a subscription specifies, including private or internal hosts. Subscriptions are created by authenticated admins, so treat that as a trusted operation; if your admins are not fully trusted, restrict outbound egress at the network layer or front your receivers with an allowlist.
182
+ - **Admin access is the trust boundary.** Both collections require a logged-in user, and the redeliver endpoint authorizes by login only (any authenticated user may redeliver any delivery). Tighten the collections with your own access control if you need finer-grained permissions.
183
+
184
+ ## License
185
+
186
+ [MIT](./LICENSE). Copyright 10x Media GmbH.
@@ -0,0 +1,14 @@
1
+ import { DefaultCellComponentProps } from "payload";
2
+
3
+ //#region src/delivery/DeliveryStatusCell.d.ts
4
+ /** List cell rendering a delivery's status as a native Payload Pill. */
5
+ declare const DeliveryStatusCell: ({
6
+ cellData
7
+ }: DefaultCellComponentProps) => import("react/jsx-runtime").JSX.Element;
8
+ //#endregion
9
+ //#region src/delivery/RedeliverButton.d.ts
10
+ /** Doc-view action that POSTs to the deliveries redeliver endpoint. */
11
+ declare const RedeliverButton: () => import("react/jsx-runtime").JSX.Element | null;
12
+ //#endregion
13
+ export { DeliveryStatusCell, RedeliverButton };
14
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,83 @@
1
+ "use client";
2
+ import { t as keys } from "../keys-BdNiD3rC.js";
3
+ import { Button, Pill, toast, useConfig, useDocumentInfo, useTranslation } from "@payloadcms/ui";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { useState } from "react";
6
+ //#region src/translations/useTranslation.ts
7
+ /**
8
+ * `useTranslation` bound to this plugin's keys, so `t(keys.X)` typechecks without
9
+ * a per-call `@ts-expect-error`. Returns Payload's `{ t, i18n }` unchanged.
10
+ */
11
+ const useTranslation$1 = () => useTranslation();
12
+ //#endregion
13
+ //#region src/delivery/DeliveryStatusCell.tsx
14
+ const META = {
15
+ pending: {
16
+ labelKey: keys.statusPending,
17
+ pillStyle: "light"
18
+ },
19
+ success: {
20
+ labelKey: keys.statusSuccess,
21
+ pillStyle: "success"
22
+ },
23
+ failed: {
24
+ labelKey: keys.statusFailed,
25
+ pillStyle: "warning"
26
+ },
27
+ dead: {
28
+ labelKey: keys.statusDead,
29
+ pillStyle: "error"
30
+ }
31
+ };
32
+ const FALLBACK = {
33
+ labelKey: keys.statusPending,
34
+ pillStyle: "light"
35
+ };
36
+ /** List cell rendering a delivery's status as a native Payload Pill. */
37
+ const DeliveryStatusCell = ({ cellData }) => {
38
+ const { t } = useTranslation$1();
39
+ const meta = META[String(cellData)] ?? FALLBACK;
40
+ return /* @__PURE__ */ jsx(Pill, {
41
+ pillStyle: meta.pillStyle,
42
+ size: "small",
43
+ children: t(meta.labelKey)
44
+ });
45
+ };
46
+ //#endregion
47
+ //#region src/delivery/RedeliverButton.tsx
48
+ /** Doc-view action that POSTs to the deliveries redeliver endpoint. */
49
+ const RedeliverButton = () => {
50
+ const { id, collectionSlug } = useDocumentInfo();
51
+ const { config } = useConfig();
52
+ const { t } = useTranslation$1();
53
+ const [busy, setBusy] = useState(false);
54
+ if (!id || !collectionSlug) return null;
55
+ const apiRoute = config.routes?.api ?? "/api";
56
+ const serverURL = config.serverURL ?? "";
57
+ const onClick = async () => {
58
+ setBusy(true);
59
+ try {
60
+ const res = await fetch(`${serverURL}${apiRoute}/${collectionSlug}/${encodeURIComponent(String(id))}/redeliver`, {
61
+ method: "POST",
62
+ credentials: "include"
63
+ });
64
+ if (!res.ok) throw new Error(String(res.status));
65
+ toast.success(t(keys.redeliverDone));
66
+ } catch {
67
+ toast.error(t(keys.redeliver));
68
+ } finally {
69
+ setBusy(false);
70
+ }
71
+ };
72
+ return /* @__PURE__ */ jsx(Button, {
73
+ buttonStyle: "secondary",
74
+ disabled: busy,
75
+ onClick,
76
+ size: "small",
77
+ children: t(keys.redeliver)
78
+ });
79
+ };
80
+ //#endregion
81
+ export { DeliveryStatusCell, RedeliverButton };
82
+
83
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["useTranslation","usePayloadTranslation","useTranslation","useTranslation"],"sources":["../../src/translations/useTranslation.ts","../../src/delivery/DeliveryStatusCell.tsx","../../src/delivery/RedeliverButton.tsx"],"sourcesContent":["'use client'\n\nimport { useTranslation as usePayloadTranslation } from '@payloadcms/ui'\n\nimport type { TranslationKey } from './keys'\n\n/**\n * `useTranslation` bound to this plugin's keys, so `t(keys.X)` typechecks without\n * a per-call `@ts-expect-error`. Returns Payload's `{ t, i18n }` unchanged.\n */\nexport const useTranslation = () => usePayloadTranslation<Record<string, never>, TranslationKey>()\n","'use client'\n\nimport { Pill } from '@payloadcms/ui'\nimport type { DefaultCellComponentProps } from 'payload'\n\nimport { keys, type TranslationKey } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\n\ntype MetaEntry = { labelKey: TranslationKey; pillStyle: 'error' | 'light' | 'success' | 'warning' }\n\nconst META: Record<string, MetaEntry> = {\n\tpending: { labelKey: keys.statusPending, pillStyle: 'light' },\n\tsuccess: { labelKey: keys.statusSuccess, pillStyle: 'success' },\n\tfailed: { labelKey: keys.statusFailed, pillStyle: 'warning' },\n\tdead: { labelKey: keys.statusDead, pillStyle: 'error' },\n}\n\nconst FALLBACK: MetaEntry = { labelKey: keys.statusPending, pillStyle: 'light' }\n\n/** List cell rendering a delivery's status as a native Payload Pill. */\nexport const DeliveryStatusCell = ({ cellData }: DefaultCellComponentProps) => {\n\tconst { t } = useTranslation()\n\tconst meta = META[String(cellData)] ?? FALLBACK\n\treturn (\n\t\t<Pill pillStyle={meta.pillStyle} size=\"small\">\n\t\t\t{t(meta.labelKey)}\n\t\t</Pill>\n\t)\n}\n","'use client'\n\nimport { Button, toast, useConfig, useDocumentInfo } from '@payloadcms/ui'\nimport { useState } from 'react'\n\nimport { keys } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\n\n/** Doc-view action that POSTs to the deliveries redeliver endpoint. */\nexport const RedeliverButton = () => {\n\tconst { id, collectionSlug } = useDocumentInfo()\n\tconst { config } = useConfig()\n\tconst { t } = useTranslation()\n\tconst [busy, setBusy] = useState(false)\n\n\tif (!id || !collectionSlug) {\n\t\treturn null\n\t}\n\n\tconst apiRoute = config.routes?.api ?? '/api'\n\tconst serverURL = config.serverURL ?? ''\n\n\tconst onClick = async () => {\n\t\tsetBusy(true)\n\t\ttry {\n\t\t\tconst res = await fetch(\n\t\t\t\t`${serverURL}${apiRoute}/${collectionSlug}/${encodeURIComponent(String(id))}/redeliver`,\n\t\t\t\t{ method: 'POST', credentials: 'include' }\n\t\t\t)\n\t\t\tif (!res.ok) {\n\t\t\t\tthrow new Error(String(res.status))\n\t\t\t}\n\t\t\ttoast.success(t(keys.redeliverDone))\n\t\t} catch {\n\t\t\ttoast.error(t(keys.redeliver))\n\t\t} finally {\n\t\t\tsetBusy(false)\n\t\t}\n\t}\n\n\treturn (\n\t\t<Button buttonStyle=\"secondary\" disabled={busy} onClick={onClick} size=\"small\">\n\t\t\t{t(keys.redeliver)}\n\t\t</Button>\n\t)\n}\n"],"mappings":";;;;;;;;;;AAUA,MAAaA,yBAAuBC,eAA6D;;;ACAjG,MAAM,OAAkC;CACvC,SAAS;EAAE,UAAU,KAAK;EAAe,WAAW;CAAQ;CAC5D,SAAS;EAAE,UAAU,KAAK;EAAe,WAAW;CAAU;CAC9D,QAAQ;EAAE,UAAU,KAAK;EAAc,WAAW;CAAU;CAC5D,MAAM;EAAE,UAAU,KAAK;EAAY,WAAW;CAAQ;AACvD;AAEA,MAAM,WAAsB;CAAE,UAAU,KAAK;CAAe,WAAW;AAAQ;;AAG/E,MAAa,sBAAsB,EAAE,eAA0C;CAC9E,MAAM,EAAE,MAAMC,iBAAe;CAC7B,MAAM,OAAO,KAAK,OAAO,QAAQ,MAAM;CACvC,OACC,oBAAC,MAAD;EAAM,WAAW,KAAK;EAAW,MAAK;YACpC,EAAE,KAAK,QAAQ;CACX,CAAA;AAER;;;;ACnBA,MAAa,wBAAwB;CACpC,MAAM,EAAE,IAAI,mBAAmB,gBAAgB;CAC/C,MAAM,EAAE,WAAW,UAAU;CAC7B,MAAM,EAAE,MAAMC,iBAAe;CAC7B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,IAAI,CAAC,MAAM,CAAC,gBACX,OAAO;CAGR,MAAM,WAAW,OAAO,QAAQ,OAAO;CACvC,MAAM,YAAY,OAAO,aAAa;CAEtC,MAAM,UAAU,YAAY;EAC3B,QAAQ,IAAI;EACZ,IAAI;GACH,MAAM,MAAM,MAAM,MACjB,GAAG,YAAY,SAAS,GAAG,eAAe,GAAG,mBAAmB,OAAO,EAAE,CAAC,EAAE,aAC5E;IAAE,QAAQ;IAAQ,aAAa;GAAU,CAC1C;GACA,IAAI,CAAC,IAAI,IACR,MAAM,IAAI,MAAM,OAAO,IAAI,MAAM,CAAC;GAEnC,MAAM,QAAQ,EAAE,KAAK,aAAa,CAAC;EACpC,QAAQ;GACP,MAAM,MAAM,EAAE,KAAK,SAAS,CAAC;EAC9B,UAAU;GACT,QAAQ,KAAK;EACd;CACD;CAEA,OACC,oBAAC,QAAD;EAAQ,aAAY;EAAY,UAAU;EAAe;EAAS,MAAK;YACrE,EAAE,KAAK,SAAS;CACV,CAAA;AAEV"}
@@ -0,0 +1,37 @@
1
+ //#region src/translations/keys.d.ts
2
+ /**
3
+ * Typed translation keys. Lookups must go through these constants, not string
4
+ * literals. Every key here must have a value in every locale (`en.ts`), or it is
5
+ * a type error.
6
+ */
7
+ declare const keys: {
8
+ readonly pluginName: "webhooks:pluginName";
9
+ readonly subscriptionSingular: "webhooks:subscriptionSingular";
10
+ readonly subscriptionPlural: "webhooks:subscriptionPlural";
11
+ readonly deliverySingular: "webhooks:deliverySingular";
12
+ readonly deliveryPlural: "webhooks:deliveryPlural";
13
+ readonly fieldName: "webhooks:fieldName";
14
+ readonly fieldUrl: "webhooks:fieldUrl";
15
+ readonly fieldEnabled: "webhooks:fieldEnabled";
16
+ readonly fieldEvents: "webhooks:fieldEvents";
17
+ readonly fieldSecret: "webhooks:fieldSecret";
18
+ readonly fieldSecretHelp: "webhooks:fieldSecretHelp";
19
+ readonly fieldHeaders: "webhooks:fieldHeaders";
20
+ readonly fieldDescription: "webhooks:fieldDescription";
21
+ readonly statusPending: "webhooks:statusPending";
22
+ readonly statusSuccess: "webhooks:statusSuccess";
23
+ readonly statusFailed: "webhooks:statusFailed";
24
+ readonly statusDead: "webhooks:statusDead";
25
+ readonly redeliver: "webhooks:redeliver";
26
+ readonly redeliverDone: "webhooks:redeliverDone";
27
+ };
28
+ type TranslationKey = (typeof keys)[keyof typeof keys];
29
+ //#endregion
30
+ //#region src/translations/index.d.ts
31
+ /** Per-locale messages merged into `config.i18n.translations`. English only for now. */
32
+ declare const translations: {
33
+ en: Record<string, Record<string, string>>;
34
+ };
35
+ //#endregion
36
+ export { type TranslationKey as WebhooksTranslationKeys, keys, translations };
37
+ //# sourceMappingURL=i18n.d.ts.map
@@ -0,0 +1,3 @@
1
+ import { t as keys } from "../keys-BdNiD3rC.js";
2
+ import { t as translations } from "../translations-CnkwrCJ3.js";
3
+ export { keys, translations };
@@ -0,0 +1,2 @@
1
+ import { r as WebhooksPluginOptions } from "../index-CpsTtHO1.js";
2
+ export type { WebhooksPluginOptions as PluginOptions, WebhooksPluginOptions };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import { PayloadRequest } from "payload";
2
+
3
+ //#region src/options.d.ts
4
+ type WebhookOperation = 'create' | 'update' | 'delete';
5
+ type CollectionWebhookConfig = {
6
+ operations?: WebhookOperation[];
7
+ includePreviousData?: boolean;
8
+ transform?: (args: {
9
+ doc: Record<string, unknown>;
10
+ previousDoc?: Record<string, unknown>;
11
+ operation: WebhookOperation;
12
+ req: PayloadRequest;
13
+ }) => unknown;
14
+ };
15
+ type CodeSubscription = {
16
+ id: string;
17
+ url: string;
18
+ events: string[];
19
+ secret?: string;
20
+ headers?: Record<string, string>;
21
+ enabled?: boolean;
22
+ };
23
+ type DeliveryMode = 'auto' | 'queue' | 'inline';
24
+ type DeliveryOptions = {
25
+ mode?: DeliveryMode;
26
+ timeoutMs?: number;
27
+ retries?: number;
28
+ queue?: string;
29
+ };
30
+ type WebhooksPluginOptions = {
31
+ disabled?: boolean;
32
+ collections?: Record<string, true | CollectionWebhookConfig>;
33
+ subscriptions?: CodeSubscription[];
34
+ delivery?: DeliveryMode | DeliveryOptions;
35
+ subscriptionsCollection?: {
36
+ slug?: string;
37
+ hidden?: boolean;
38
+ };
39
+ deliveriesLog?: {
40
+ slug?: string;
41
+ hidden?: boolean;
42
+ };
43
+ };
44
+ //#endregion
45
+ //#region src/index.d.ts
46
+ declare module 'payload' {
47
+ interface RegisteredPlugins {
48
+ '@10x-media/webhooks': WebhooksPluginOptions;
49
+ }
50
+ }
51
+ /** The trigger slug webhooks contributes to the automations catalog. */
52
+ declare const WEBHOOK_TRIGGER_SLUG: "webhook";
53
+ /**
54
+ * Webhooks plugin for Payload v3. Runs before automations (`order: 10`) so it can
55
+ * push its `webhook` trigger into automations when present, and builds outbound
56
+ * delivery: opt-in collections emit signed HTTP POSTs to subscribed endpoints,
57
+ * delivered via native Payload jobs or bounded-await inline.
58
+ */
59
+ declare const webhooks: (options: WebhooksPluginOptions) => import("payload").Plugin;
60
+ //#endregion
61
+ export { webhooks as n, WebhooksPluginOptions as r, WEBHOOK_TRIGGER_SLUG as t };
62
+ //# sourceMappingURL=index-CpsTtHO1.d.ts.map
@@ -0,0 +1,2 @@
1
+ import { n as webhooks, r as WebhooksPluginOptions, t as WEBHOOK_TRIGGER_SLUG } from "./index-CpsTtHO1.js";
2
+ export { type WebhooksPluginOptions as PluginOptions, type WebhooksPluginOptions, WEBHOOK_TRIGGER_SLUG, webhooks };