@endora-commerce/mod-webhooks 0.100.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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/index.d.ts +34 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +45 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/WebhooksPage.d.ts +3 -0
- package/dist/admin/pages/WebhooksPage.d.ts.map +1 -0
- package/dist/admin/pages/WebhooksPage.js +220 -0
- package/dist/admin/pages/WebhooksPage.js.map +1 -0
- package/dist/backend/entities/webhook-delivery.entity.d.ts +29 -0
- package/dist/backend/entities/webhook-delivery.entity.d.ts.map +1 -0
- package/dist/backend/entities/webhook-delivery.entity.js +108 -0
- package/dist/backend/entities/webhook-delivery.entity.js.map +1 -0
- package/dist/backend/entities/webhook.entity.d.ts +33 -0
- package/dist/backend/entities/webhook.entity.d.ts.map +1 -0
- package/dist/backend/entities/webhook.entity.js +91 -0
- package/dist/backend/entities/webhook.entity.js.map +1 -0
- package/dist/backend/index.d.ts +85 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +129 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.d.ts +26 -0
- package/dist/backend/routes.d.ts.map +1 -0
- package/dist/backend/routes.js +84 -0
- package/dist/backend/routes.js.map +1 -0
- package/dist/backend/services/event-bridge.d.ts +54 -0
- package/dist/backend/services/event-bridge.d.ts.map +1 -0
- package/dist/backend/services/event-bridge.js +43 -0
- package/dist/backend/services/event-bridge.js.map +1 -0
- package/dist/backend/services/webhook-delivery-worker.d.ts +34 -0
- package/dist/backend/services/webhook-delivery-worker.d.ts.map +1 -0
- package/dist/backend/services/webhook-delivery-worker.js +70 -0
- package/dist/backend/services/webhook-delivery-worker.js.map +1 -0
- package/dist/backend/services/webhook-queue.d.ts +24 -0
- package/dist/backend/services/webhook-queue.d.ts.map +1 -0
- package/dist/backend/services/webhook-queue.js +31 -0
- package/dist/backend/services/webhook-queue.js.map +1 -0
- package/dist/backend/services/webhook-service.d.ts +82 -0
- package/dist/backend/services/webhook-service.d.ts.map +1 -0
- package/dist/backend/services/webhook-service.js +176 -0
- package/dist/backend/services/webhook-service.js.map +1 -0
- package/dist/manifest.d.ts +169 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +122 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260425T091359_webhooks_us7_init.d.ts +22 -0
- package/dist/migrations/20260425T091359_webhooks_us7_init.d.ts.map +1 -0
- package/dist/migrations/20260425T091359_webhooks_us7_init.js +86 -0
- package/dist/migrations/20260425T091359_webhooks_us7_init.js.map +1 -0
- package/dist/migrations/20260724T203140_webhooks_org_filter.d.ts +17 -0
- package/dist/migrations/20260724T203140_webhooks_org_filter.d.ts.map +1 -0
- package/dist/migrations/20260724T203140_webhooks_org_filter.js +30 -0
- package/dist/migrations/20260724T203140_webhooks_org_filter.js.map +1 -0
- package/dist/migrations/20260727T200555_webhooks_drop_external_integrations.d.ts +28 -0
- package/dist/migrations/20260727T200555_webhooks_drop_external_integrations.d.ts.map +1 -0
- package/dist/migrations/20260727T200555_webhooks_drop_external_integrations.js +49 -0
- package/dist/migrations/20260727T200555_webhooks_drop_external_integrations.js.map +1 -0
- package/dist/migrations/index.d.ts +29 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +33 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/webhooks.md +50 -0
- package/i18n/en.json +6 -0
- package/i18n/pl.json +6 -0
- package/package.json +97 -0
- package/tailwind.css +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
|
|
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,59 @@
|
|
|
1
|
+
<!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
|
|
2
|
+
|
|
3
|
+
# @endora-commerce/mod-webhooks
|
|
4
|
+
|
|
5
|
+
Outbound webhook subscription registry and dispatcher.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
An **Endora Commerce module package**. Its module id is `webhooks` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
|
|
10
|
+
|
|
11
|
+
A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
|
|
12
|
+
|
|
13
|
+
## Entry points
|
|
14
|
+
|
|
15
|
+
| Import | Contents |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@endora-commerce/mod-webhooks` | the module manifest — its id, version, dependencies, settings and activation |
|
|
18
|
+
| `@endora-commerce/mod-webhooks/admin` | the Admin UI contribution: the screens, navigation and palette actions it adds |
|
|
19
|
+
| `@endora-commerce/mod-webhooks/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
|
|
20
|
+
| `@endora-commerce/mod-webhooks/migrations` | the module’s own schema migrations, in the order the platform runs them |
|
|
21
|
+
| `@endora-commerce/mod-webhooks/tailwind.css` | the Tailwind source declaration for the admin code above |
|
|
22
|
+
|
|
23
|
+
## Depends on
|
|
24
|
+
|
|
25
|
+
Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
|
|
26
|
+
|
|
27
|
+
**Endora packages**
|
|
28
|
+
|
|
29
|
+
- `@endora-commerce/admin-kit` — *optional*
|
|
30
|
+
- `@endora-commerce/contracts`
|
|
31
|
+
- `@endora-commerce/platform`
|
|
32
|
+
|
|
33
|
+
**Third-party**
|
|
34
|
+
|
|
35
|
+
- `@mikro-orm/core` ^6
|
|
36
|
+
- `@mikro-orm/migrations` ^6
|
|
37
|
+
- `@mikro-orm/postgresql` ^6
|
|
38
|
+
- `bullmq` ^5
|
|
39
|
+
- `fastify` ^5
|
|
40
|
+
- `ioredis` ^5
|
|
41
|
+
- `lucide-react` ^1 — *optional*
|
|
42
|
+
- `react` ^19 — *optional*
|
|
43
|
+
|
|
44
|
+
## What the tarball carries
|
|
45
|
+
|
|
46
|
+
- `dist/` — the compiled JavaScript and its type declarations
|
|
47
|
+
- `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
|
|
48
|
+
- `docs/` — the package’s own pages in the Endora Commerce documentation site
|
|
49
|
+
- `tailwind.css` — the Tailwind source declaration
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm add @endora-commerce/mod-webhooks
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Licence
|
|
58
|
+
|
|
59
|
+
MIT — the text is in `LICENSE`, beside this file.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `webhooks`' admin surface — one route and one sidebar entry, declared by the
|
|
3
|
+
* module that owns them (feature 091, Phase 4, the plan's batch 6;
|
|
4
|
+
* `specs/091-module-owned-admin-surfaces/contracts/admin-contribution.md`).
|
|
5
|
+
*
|
|
6
|
+
* **The batch this module belongs to was unblocked by P2 rather than chosen by
|
|
7
|
+
* size.** `plan.md`'s sequence table records this module's drain as **1**, and
|
|
8
|
+
* that one key was `WebhooksPage.tsx`'s reach into `admin/src/components/
|
|
9
|
+
* organization-picker` — a Group A entry in
|
|
10
|
+
* `backend/scripts/ledgers/admin-surface.ts`, retired when the picker became
|
|
11
|
+
* `@endora-commerce/admin-kit/components`'. The screen names the published
|
|
12
|
+
* component now, so this batch pays no reach of its own and its
|
|
13
|
+
* `check:module-boundary` line is unchanged on both sides — which is the
|
|
14
|
+
* measurement a zero-drain batch must produce, and which is only honest because
|
|
15
|
+
* the reach was drained in a merge request of its own first.
|
|
16
|
+
*
|
|
17
|
+
* **The permission the screen is gated on is shared with `api_keys`.**
|
|
18
|
+
* `integrations:manage` guards every route in both modules' admin surfaces and
|
|
19
|
+
* both manifests declare it (issue #213), so the code stays grantable while
|
|
20
|
+
* either surface is on. That is why this entry names the same code the API
|
|
21
|
+
* enforces rather than a `webhooks:`-prefixed one that does not exist.
|
|
22
|
+
*
|
|
23
|
+
* **This entry exports data and nothing else** (R2), like every `./admin`
|
|
24
|
+
* layer: `check:module-boundary`'s D-171 rule designates a subpath as contract
|
|
25
|
+
* surface when it emits no runtime binding, and `./admin` deliberately does not
|
|
26
|
+
* qualify, so a consumer reaching into another module's `./admin` stays a
|
|
27
|
+
* counted boundary reach.
|
|
28
|
+
*
|
|
29
|
+
* **The component is a dynamic-import factory** (R6), so Vite has a split point
|
|
30
|
+
* whether or not anybody remembers to ask for one.
|
|
31
|
+
*/
|
|
32
|
+
import type { AdminContributions } from '@endora-commerce/admin-kit/contributions';
|
|
33
|
+
export declare const contributions: AdminContributions;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAcnF,eAAO,MAAM,aAAa,EAAE,kBAiC3B,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** The module's only route: the subscription registry and its delivery log. */
|
|
2
|
+
const ROUTE_PATH = '/webhooks';
|
|
3
|
+
/**
|
|
4
|
+
* The code every route of this module's admin API enforces —
|
|
5
|
+
* `requireAdmin('integrations:manage')` on `GET /api/v1/admin/webhooks` and on
|
|
6
|
+
* each of its siblings. It is the same code the module's `open-webhooks`
|
|
7
|
+
* palette action declares, which `check:action-route-permissions` holds to this
|
|
8
|
+
* very route.
|
|
9
|
+
*/
|
|
10
|
+
const PERMISSION = 'integrations:manage';
|
|
11
|
+
export const contributions = {
|
|
12
|
+
routes: [
|
|
13
|
+
{
|
|
14
|
+
path: ROUTE_PATH,
|
|
15
|
+
component: () => import('./pages/WebhooksPage.js'),
|
|
16
|
+
requiredPermission: PERMISSION,
|
|
17
|
+
index: true,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
nav: [
|
|
21
|
+
{
|
|
22
|
+
to: ROUTE_PATH,
|
|
23
|
+
// Module-relative (R8), resolved in this module's own namespace out of
|
|
24
|
+
// `packages/modules/webhooks/i18n/`. It was `appShell.nav.webhooks` in
|
|
25
|
+
// the shared `_i18n` bundle, one of the four shared files a module author
|
|
26
|
+
// had to edit.
|
|
27
|
+
labelKey: 'nav.webhooks.label',
|
|
28
|
+
// The glyph `AppShell.tsx` rendered by hand. A nav entry names its icon,
|
|
29
|
+
// so `Webhook` joins `KnownIconNameSchema` and the kit's `icon-map.ts` in
|
|
30
|
+
// this merge request rather than the sidebar quietly changing to a name
|
|
31
|
+
// that happened to be on the allowlist.
|
|
32
|
+
icon: 'Webhook',
|
|
33
|
+
section: 'system',
|
|
34
|
+
// The hand-written position in *System* times a hundred, which is batch
|
|
35
|
+
// four's convention: `/webhooks` was the eighth row of that section
|
|
36
|
+
// before the drain began. *System* still holds host-declared entries, so
|
|
37
|
+
// `composeNav` appends every registry row after all of them whatever the
|
|
38
|
+
// weight says — what the weight can still do is keep the converted rows
|
|
39
|
+
// in the order the hand-written table had.
|
|
40
|
+
weight: 800,
|
|
41
|
+
requiredPermission: PERMISSION,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAiCA,+EAA+E;AAC/E,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,UAAU,GAAG,qBAAqB,CAAC;AAEzC,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC;YAClD,kBAAkB,EAAE,UAAU;YAC9B,KAAK,EAAE,IAAI;SACZ;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,uEAAuE;YACvE,0EAA0E;YAC1E,eAAe;YACf,QAAQ,EAAE,oBAAoB;YAC9B,yEAAyE;YACzE,0EAA0E;YAC1E,wEAAwE;YACxE,wCAAwC;YACxC,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,QAAQ;YACjB,wEAAwE;YACxE,oEAAoE;YACpE,yEAAyE;YACzE,yEAAyE;YACzE,wEAAwE;YACxE,2CAA2C;YAC3C,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,UAAU;SAC/B;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebhooksPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/WebhooksPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAoDzF,MAAM,CAAC,OAAO,UAAU,YAAY,IAAI,SAAS,CAkZhD"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import { Check, Copy, Pause, Play, RefreshCw, Trash2 } from 'lucide-react';
|
|
4
|
+
import { ApiError, apiClient, formatDateTime } from '@endora-commerce/admin-kit/lib';
|
|
5
|
+
import { useTranslation } from '@endora-commerce/admin-kit/i18n';
|
|
6
|
+
import { Alert, AlertDescription, Badge, Button, Card, CardContent, CardHeader, CardTitle, Checkbox, Input, Label, PageHeader, Select, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@endora-commerce/admin-kit/ui';
|
|
7
|
+
import { OrganizationPicker } from '@endora-commerce/admin-kit/components';
|
|
8
|
+
const KNOWN_EVENT_TYPES = [
|
|
9
|
+
'product.created.v1',
|
|
10
|
+
'product.updated.v1',
|
|
11
|
+
'product.archived.v1',
|
|
12
|
+
'rfq.created.v1',
|
|
13
|
+
'rfq.quoted.v1',
|
|
14
|
+
'rfq.accepted.v1',
|
|
15
|
+
'rfq.expired.v1',
|
|
16
|
+
'order.created.v1',
|
|
17
|
+
'order.status_changed.v1',
|
|
18
|
+
'order.cancelled.v1',
|
|
19
|
+
'payment.settled.v1',
|
|
20
|
+
'credit_limit.adjusted.v1',
|
|
21
|
+
'credit_limit.reservation_released.v1',
|
|
22
|
+
];
|
|
23
|
+
export default function WebhooksPage() {
|
|
24
|
+
const t = useTranslation('core');
|
|
25
|
+
const [webhooks, setWebhooks] = useState([]);
|
|
26
|
+
const [deliveries, setDeliveries] = useState([]);
|
|
27
|
+
const [loadingHooks, setLoadingHooks] = useState(true);
|
|
28
|
+
const [loadingDeliveries, setLoadingDeliveries] = useState(false);
|
|
29
|
+
const [filter, setFilter] = useState('all');
|
|
30
|
+
const [error, setError] = useState(null);
|
|
31
|
+
const [info, setInfo] = useState(null);
|
|
32
|
+
const [revealedSecret, setRevealedSecret] = useState(null);
|
|
33
|
+
const [copied, setCopied] = useState(false);
|
|
34
|
+
// Feature 062 — best-effort id → name lookup for the org-scope column.
|
|
35
|
+
const [orgNames, setOrgNames] = useState(new Map());
|
|
36
|
+
const copySecret = useCallback(async (secret) => {
|
|
37
|
+
try {
|
|
38
|
+
await navigator.clipboard.writeText(secret);
|
|
39
|
+
setCopied(true);
|
|
40
|
+
window.setTimeout(() => setCopied(false), 2000);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* clipboard unavailable — the input is selectable as a fallback */
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const refreshWebhooks = useCallback(async () => {
|
|
47
|
+
setLoadingHooks(true);
|
|
48
|
+
setError(null);
|
|
49
|
+
try {
|
|
50
|
+
const res = await apiClient.get('/api/v1/admin/webhooks');
|
|
51
|
+
setWebhooks(res.data);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('webhooks.error.load'));
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
setLoadingHooks(false);
|
|
58
|
+
}
|
|
59
|
+
}, [t]);
|
|
60
|
+
const refreshDeliveries = useCallback(async () => {
|
|
61
|
+
setLoadingDeliveries(true);
|
|
62
|
+
try {
|
|
63
|
+
const qs = filter === 'all' ? '?limit=50' : `?status=${filter}&limit=50`;
|
|
64
|
+
const res = await apiClient.get(`/api/v1/admin/webhooks/deliveries${qs}`);
|
|
65
|
+
setDeliveries(res.data);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('webhooks.error.loadDeliveries'));
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
setLoadingDeliveries(false);
|
|
72
|
+
}
|
|
73
|
+
}, [filter, t]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
void refreshWebhooks();
|
|
76
|
+
}, [refreshWebhooks]);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
void refreshDeliveries();
|
|
79
|
+
}, [refreshDeliveries]);
|
|
80
|
+
// Resolve organization names for org-bound subscriptions (feature 062).
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
const missing = Array.from(new Set(webhooks
|
|
83
|
+
.map((w) => w.organizationId)
|
|
84
|
+
.filter((id) => typeof id === 'string' && !orgNames.has(id))));
|
|
85
|
+
if (missing.length === 0)
|
|
86
|
+
return;
|
|
87
|
+
void (async () => {
|
|
88
|
+
const entries = await Promise.all(missing.map(async (id) => {
|
|
89
|
+
try {
|
|
90
|
+
const res = await apiClient.get(`/api/v1/admin/organizations/${id}`);
|
|
91
|
+
return [id, res.data.name];
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return [id, id];
|
|
95
|
+
}
|
|
96
|
+
}));
|
|
97
|
+
setOrgNames((prev) => {
|
|
98
|
+
const next = new Map(prev);
|
|
99
|
+
for (const [id, name] of entries)
|
|
100
|
+
next.set(id, name);
|
|
101
|
+
return next;
|
|
102
|
+
});
|
|
103
|
+
})();
|
|
104
|
+
}, [webhooks, orgNames]);
|
|
105
|
+
const handleCreate = useCallback(async (input) => {
|
|
106
|
+
try {
|
|
107
|
+
const res = await apiClient.post('/api/v1/admin/webhooks', {
|
|
108
|
+
name: input.name,
|
|
109
|
+
url: input.url,
|
|
110
|
+
eventTypes: input.eventTypes,
|
|
111
|
+
...(input.organizationId ? { organizationId: input.organizationId } : {}),
|
|
112
|
+
});
|
|
113
|
+
setInfo(t('webhooks.create.success'));
|
|
114
|
+
if (res.data.secret) {
|
|
115
|
+
setRevealedSecret({ name: input.name, secret: res.data.secret });
|
|
116
|
+
setCopied(false);
|
|
117
|
+
}
|
|
118
|
+
await refreshWebhooks();
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('webhooks.error.create'));
|
|
122
|
+
}
|
|
123
|
+
}, [refreshWebhooks, t]);
|
|
124
|
+
const handleToggleStatus = useCallback(async (w) => {
|
|
125
|
+
const next = w.status === 'active' ? 'paused' : 'active';
|
|
126
|
+
try {
|
|
127
|
+
await apiClient.patch(`/api/v1/admin/webhooks/${w.id}`, { status: next });
|
|
128
|
+
await refreshWebhooks();
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('webhooks.error.update'));
|
|
132
|
+
}
|
|
133
|
+
}, [refreshWebhooks, t]);
|
|
134
|
+
const handleDelete = useCallback(async (id) => {
|
|
135
|
+
if (!confirm(t('webhooks.action.deleteConfirm'))) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
await apiClient.delete(`/api/v1/admin/webhooks/${id}`);
|
|
140
|
+
await refreshWebhooks();
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('webhooks.error.delete'));
|
|
144
|
+
}
|
|
145
|
+
}, [refreshWebhooks, t]);
|
|
146
|
+
const handleReplay = useCallback(async (deliveryId) => {
|
|
147
|
+
try {
|
|
148
|
+
await apiClient.post(`/api/v1/admin/webhooks/deliveries/${deliveryId}/replay`);
|
|
149
|
+
setInfo(t('webhooks.delivery.replayQueued'));
|
|
150
|
+
await refreshDeliveries();
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('webhooks.error.replay'));
|
|
154
|
+
}
|
|
155
|
+
}, [refreshDeliveries, t]);
|
|
156
|
+
const webhookNameById = new Map(webhooks.map((w) => [w.id, w.name]));
|
|
157
|
+
return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: t('webhooks.page.title'), description: t('webhooks.page.description') }), error ? (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })) : null, info ? (_jsx(Alert, { variant: "success", className: "mb-4", children: _jsx(AlertDescription, { children: info }) })) : null, revealedSecret ? (_jsxs(Card, { className: "mb-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('webhooks.revealed.title') }) }), _jsxs(CardContent, { children: [_jsx("p", { className: "text-xs text-muted-foreground", children: revealedSecret.name }), _jsxs("div", { className: "mt-2 flex items-center gap-2", children: [_jsx(Input, { readOnly: true, value: revealedSecret.secret, className: "flex-1 bg-muted font-mono text-sm text-foreground", onFocus: (e) => e.currentTarget.select(), "aria-label": t('webhooks.revealed.title') }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "shrink-0", onClick: () => void copySecret(revealedSecret.secret), children: [copied ? _jsx(Check, { className: "mr-1 h-4 w-4" }) : _jsx(Copy, { className: "mr-1 h-4 w-4" }), copied ? t('webhooks.revealed.copied') : t('webhooks.revealed.copy')] })] }), _jsx(Button, { variant: "outline", size: "sm", className: "mt-3", onClick: () => {
|
|
158
|
+
setRevealedSecret(null);
|
|
159
|
+
setCopied(false);
|
|
160
|
+
}, children: t('webhooks.revealed.confirm') })] })] })) : null, _jsxs(Card, { className: "mb-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('webhooks.create.title') }) }), _jsx(CardContent, { children: _jsx(CreateWebhookForm, { onSubmit: handleCreate }) })] }), _jsxs(Card, { className: "mb-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('webhooks.list.title') }) }), _jsx(CardContent, { children: loadingHooks ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('common.state.loading') })) : webhooks.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('webhooks.empty') })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: t('webhooks.column.name') }), _jsx(TableHead, { children: t('webhooks.column.url') }), _jsx(TableHead, { children: t('webhooks.column.events') }), _jsx(TableHead, { children: t('webhooks.column.organization') }), _jsx(TableHead, { children: t('webhooks.column.status') }), _jsx(TableHead, {})] }) }), _jsx(TableBody, { children: webhooks.map((w) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: w.name }), _jsx(TableCell, { className: "font-mono text-xs", children: w.url }), _jsx(TableCell, { children: _jsx("div", { className: "flex flex-wrap gap-1", children: w.eventTypes.map((e) => (_jsx(Badge, { variant: "outline", className: "font-mono text-xs", children: e }, e))) }) }), _jsx(TableCell, { children: w.organizationId ? (_jsx(Badge, { variant: "outline", children: orgNames.get(w.organizationId) ?? w.organizationId })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: t('webhooks.organization.platformWide') })) }), _jsx(TableCell, { children: _jsx(Badge, { variant: w.status === 'active' ? 'success' : 'warning', children: t(`webhooks.status.${w.status}`) }) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
161
|
+
void handleToggleStatus(w);
|
|
162
|
+
}, children: [w.status === 'active' ? _jsx(Pause, {}) : _jsx(Play, {}), w.status === 'active' ? t('webhooks.action.pause') : t('webhooks.action.resume')] }), _jsxs(Button, { variant: "destructive", size: "sm", onClick: () => {
|
|
163
|
+
void handleDelete(w.id);
|
|
164
|
+
}, children: [_jsx(Trash2, {}), t('webhooks.action.delete')] })] }) })] }, w.id))) })] })) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex-row items-center justify-between", children: [_jsx(CardTitle, { children: t('webhooks.deliveries.title') }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Select, { className: "w-auto", value: filter, onChange: (e) => setFilter(e.target.value), children: [_jsx("option", { value: "all", children: t('webhooks.deliveries.filter.all') }), _jsx("option", { value: "failed", children: t('webhooks.deliveries.filter.failed') }), _jsx("option", { value: "dead_lettered", children: t('webhooks.deliveries.filter.deadLettered') })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
165
|
+
void refreshDeliveries();
|
|
166
|
+
}, children: [_jsx(RefreshCw, {}), t('webhooks.action.refresh')] })] })] }), _jsx(CardContent, { children: loadingDeliveries ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('common.state.loading') })) : deliveries.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('webhooks.deliveries.empty') })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: t('webhooks.deliveries.column.webhook') }), _jsx(TableHead, { children: t('webhooks.deliveries.column.event') }), _jsx(TableHead, { children: t('webhooks.deliveries.column.status') }), _jsx(TableHead, { children: t('webhooks.deliveries.column.attempts') }), _jsx(TableHead, { children: t('webhooks.deliveries.column.lastResponse') }), _jsx(TableHead, { children: t('webhooks.deliveries.column.lastError') }), _jsx(TableHead, { children: t('webhooks.deliveries.column.created') }), _jsx(TableHead, {})] }) }), _jsx(TableBody, { children: deliveries.map((d) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: webhookNameById.get(d.webhookId) ?? d.webhookId }), _jsxs(TableCell, { children: [_jsx("div", { children: d.eventType }), _jsx("div", { className: "font-mono text-xs text-muted-foreground", children: d.eventId })] }), _jsx(TableCell, { children: _jsx(DeliveryStatusBadge, { status: d.status }) }), _jsx(TableCell, { children: d.attemptCount }), _jsx(TableCell, { children: d.lastResponseStatus ?? '—' }), _jsx(TableCell, { className: "max-w-[240px] truncate text-xs text-muted-foreground", children: d.lastError ?? '—' }), _jsx(TableCell, { children: formatDateTime(d.createdAt) }), _jsx(TableCell, { children: d.status === 'failed' || d.status === 'dead_lettered' ? (_jsx(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
167
|
+
void handleReplay(d.id);
|
|
168
|
+
}, children: t('webhooks.action.replay') })) : null })] }, d.id))) })] })) })] })] }));
|
|
169
|
+
}
|
|
170
|
+
function DeliveryStatusBadge({ status }) {
|
|
171
|
+
const variant = status === 'succeeded'
|
|
172
|
+
? 'success'
|
|
173
|
+
: status === 'failed' || status === 'dead_lettered'
|
|
174
|
+
? 'destructive'
|
|
175
|
+
: 'warning';
|
|
176
|
+
return _jsx(Badge, { variant: variant, children: status });
|
|
177
|
+
}
|
|
178
|
+
function CreateWebhookForm(props) {
|
|
179
|
+
const t = useTranslation('core');
|
|
180
|
+
const [name, setName] = useState('');
|
|
181
|
+
const [url, setUrl] = useState('');
|
|
182
|
+
const [events, setEvents] = useState(new Set());
|
|
183
|
+
const [organizationId, setOrganizationId] = useState(null);
|
|
184
|
+
const [submitting, setSubmitting] = useState(false);
|
|
185
|
+
const toggle = (event) => {
|
|
186
|
+
setEvents((prev) => {
|
|
187
|
+
const next = new Set(prev);
|
|
188
|
+
if (next.has(event))
|
|
189
|
+
next.delete(event);
|
|
190
|
+
else
|
|
191
|
+
next.add(event);
|
|
192
|
+
return next;
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
const onSubmit = async (event) => {
|
|
196
|
+
event.preventDefault();
|
|
197
|
+
if (!name.trim() || !url.trim() || events.size === 0)
|
|
198
|
+
return;
|
|
199
|
+
setSubmitting(true);
|
|
200
|
+
try {
|
|
201
|
+
await props.onSubmit({
|
|
202
|
+
name: name.trim(),
|
|
203
|
+
url: url.trim(),
|
|
204
|
+
eventTypes: Array.from(events),
|
|
205
|
+
organizationId,
|
|
206
|
+
});
|
|
207
|
+
setName('');
|
|
208
|
+
setUrl('');
|
|
209
|
+
setEvents(new Set());
|
|
210
|
+
setOrganizationId(null);
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
setSubmitting(false);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
return (_jsxs("form", { className: "space-y-4", onSubmit: (e) => {
|
|
217
|
+
void onSubmit(e);
|
|
218
|
+
}, children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "webhook-name", children: t('webhooks.create.nameLabel') }), _jsx(Input, { id: "webhook-name", value: name, onChange: (e) => setName(e.target.value), placeholder: t('webhooks.create.namePlaceholder'), required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "webhook-url", children: t('webhooks.create.urlLabel') }), _jsx(Input, { id: "webhook-url", type: "url", value: url, onChange: (e) => setUrl(e.target.value), placeholder: t('webhooks.create.urlPlaceholder'), required: true })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "webhook-organization", children: t('webhooks.create.organizationLabel') }), _jsx(OrganizationPicker, { id: "webhook-organization", value: organizationId, onChange: setOrganizationId, ariaLabel: t('webhooks.create.organizationLabel') }), _jsx("p", { className: "text-xs text-muted-foreground", children: t('webhooks.create.organizationHelp') })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: t('webhooks.create.eventsLabel') }), _jsx("div", { className: "flex flex-wrap gap-3", children: KNOWN_EVENT_TYPES.map((event) => (_jsxs("label", { className: "inline-flex items-center gap-2 rounded-md border bg-background px-3 py-1.5 text-xs", children: [_jsx(Checkbox, { checked: events.has(event), onChange: () => toggle(event) }), _jsx("code", { className: "font-mono", children: event })] }, event))) })] }), _jsx(Button, { type: "submit", disabled: submitting || !name.trim() || !url.trim() || events.size === 0, children: submitting ? t('webhooks.create.submitting') : t('webhooks.create.submit') })] }));
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=WebhooksPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebhooksPage.js","sourceRoot":"","sources":["../../../src/admin/pages/WebhooksPage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { OptionalProps } from '@mikro-orm/core';
|
|
2
|
+
/**
|
|
3
|
+
* Persistent record of an outbound webhook attempt — used by the admin panel's
|
|
4
|
+
* delivery viewer + the dead-letter replay button. The transport layer
|
|
5
|
+
* (BullMQ via webhook-delivery-worker) drives this row through state.
|
|
6
|
+
*
|
|
7
|
+
* `dispatchedAt` is set when the worker picks the job up; `lastResponse` and
|
|
8
|
+
* `attemptCount` are bumped on every retry.
|
|
9
|
+
*/
|
|
10
|
+
export declare class WebhookDelivery {
|
|
11
|
+
[OptionalProps]?: 'id' | 'createdAt' | 'updatedAt' | 'attemptCount' | 'dispatchedAt' | 'lastResponseStatus' | 'lastResponseBody' | 'lastError' | 'completedAt' | 'deadLetteredAt';
|
|
12
|
+
id: string;
|
|
13
|
+
webhookId: string;
|
|
14
|
+
eventId: string;
|
|
15
|
+
eventType: string;
|
|
16
|
+
payload: unknown;
|
|
17
|
+
status: 'pending' | 'in_flight' | 'succeeded' | 'failed' | 'dead_lettered';
|
|
18
|
+
attemptCount: number;
|
|
19
|
+
dispatchedAt?: Date | null;
|
|
20
|
+
lastResponseStatus?: number | null;
|
|
21
|
+
lastResponseBody?: string | null;
|
|
22
|
+
lastError?: string | null;
|
|
23
|
+
completedAt?: Date | null;
|
|
24
|
+
deadLetteredAt?: Date | null;
|
|
25
|
+
createdAt: Date;
|
|
26
|
+
updatedAt: Date;
|
|
27
|
+
}
|
|
28
|
+
declare module 'fastify' { }
|
|
29
|
+
//# sourceMappingURL=webhook-delivery.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-delivery.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/webhook-delivery.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAIrF;;;;;;;GAOG;AACH,qBAEa,eAAe;IAC1B,CAAC,aAAa,CAAC,CAAC,EACZ,IAAI,GACJ,WAAW,GACX,WAAW,GACX,cAAc,GACd,cAAc,GACd,oBAAoB,GACpB,kBAAkB,GAClB,WAAW,GACX,aAAa,GACb,gBAAgB,CAAC;IAGrB,EAAE,EAAE,MAAM,CAAgB;IAI1B,SAAS,EAAG,MAAM,CAAC;IAInB,OAAO,EAAG,MAAM,CAAC;IAIjB,SAAS,EAAG,MAAM,CAAC;IAGnB,OAAO,EAAG,OAAO,CAAC;IAIlB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,eAAe,CAAa;IAGvF,YAAY,EAAE,MAAM,CAAK;IAGzB,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAG3B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGnC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1B,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAG1B,cAAc,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAG7B,SAAS,EAAE,IAAI,CAAc;IAG7B,SAAS,EAAE,IAAI,CAAc;CAC9B;AAED,OAAO,QAAQ,SAAS,CAAC,GAAE"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Entity, Index, OptionalProps, PrimaryKey, Property } from '@mikro-orm/core';
|
|
11
|
+
import { GlobalEntity } from '@endora-commerce/platform/tenancy';
|
|
12
|
+
import { randomUUID } from 'crypto';
|
|
13
|
+
/**
|
|
14
|
+
* Persistent record of an outbound webhook attempt — used by the admin panel's
|
|
15
|
+
* delivery viewer + the dead-letter replay button. The transport layer
|
|
16
|
+
* (BullMQ via webhook-delivery-worker) drives this row through state.
|
|
17
|
+
*
|
|
18
|
+
* `dispatchedAt` is set when the worker picks the job up; `lastResponse` and
|
|
19
|
+
* `attemptCount` are bumped on every retry.
|
|
20
|
+
*/
|
|
21
|
+
let WebhookDelivery = class WebhookDelivery {
|
|
22
|
+
[OptionalProps];
|
|
23
|
+
id = randomUUID();
|
|
24
|
+
webhookId;
|
|
25
|
+
eventId;
|
|
26
|
+
eventType;
|
|
27
|
+
payload;
|
|
28
|
+
status = 'pending';
|
|
29
|
+
attemptCount = 0;
|
|
30
|
+
dispatchedAt;
|
|
31
|
+
lastResponseStatus;
|
|
32
|
+
lastResponseBody;
|
|
33
|
+
lastError;
|
|
34
|
+
completedAt;
|
|
35
|
+
deadLetteredAt;
|
|
36
|
+
createdAt = new Date();
|
|
37
|
+
updatedAt = new Date();
|
|
38
|
+
};
|
|
39
|
+
__decorate([
|
|
40
|
+
PrimaryKey({ type: 'uuid' }),
|
|
41
|
+
__metadata("design:type", String)
|
|
42
|
+
], WebhookDelivery.prototype, "id", void 0);
|
|
43
|
+
__decorate([
|
|
44
|
+
Property({ type: 'uuid' }),
|
|
45
|
+
Index(),
|
|
46
|
+
__metadata("design:type", String)
|
|
47
|
+
], WebhookDelivery.prototype, "webhookId", void 0);
|
|
48
|
+
__decorate([
|
|
49
|
+
Property({ type: 'string', length: 64 }),
|
|
50
|
+
Index(),
|
|
51
|
+
__metadata("design:type", String)
|
|
52
|
+
], WebhookDelivery.prototype, "eventId", void 0);
|
|
53
|
+
__decorate([
|
|
54
|
+
Property({ type: 'string', length: 64 }),
|
|
55
|
+
Index(),
|
|
56
|
+
__metadata("design:type", String)
|
|
57
|
+
], WebhookDelivery.prototype, "eventType", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
Property({ type: 'json' }),
|
|
60
|
+
__metadata("design:type", Object)
|
|
61
|
+
], WebhookDelivery.prototype, "payload", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
Property({ type: 'string', length: 16 }),
|
|
64
|
+
Index(),
|
|
65
|
+
__metadata("design:type", String)
|
|
66
|
+
], WebhookDelivery.prototype, "status", void 0);
|
|
67
|
+
__decorate([
|
|
68
|
+
Property({ type: 'integer' }),
|
|
69
|
+
__metadata("design:type", Number)
|
|
70
|
+
], WebhookDelivery.prototype, "attemptCount", void 0);
|
|
71
|
+
__decorate([
|
|
72
|
+
Property({ type: 'datetime', nullable: true }),
|
|
73
|
+
__metadata("design:type", Object)
|
|
74
|
+
], WebhookDelivery.prototype, "dispatchedAt", void 0);
|
|
75
|
+
__decorate([
|
|
76
|
+
Property({ type: 'integer', nullable: true }),
|
|
77
|
+
__metadata("design:type", Object)
|
|
78
|
+
], WebhookDelivery.prototype, "lastResponseStatus", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
Property({ type: 'string', length: 4000, nullable: true }),
|
|
81
|
+
__metadata("design:type", Object)
|
|
82
|
+
], WebhookDelivery.prototype, "lastResponseBody", void 0);
|
|
83
|
+
__decorate([
|
|
84
|
+
Property({ type: 'string', length: 4000, nullable: true }),
|
|
85
|
+
__metadata("design:type", Object)
|
|
86
|
+
], WebhookDelivery.prototype, "lastError", void 0);
|
|
87
|
+
__decorate([
|
|
88
|
+
Property({ type: 'datetime', nullable: true }),
|
|
89
|
+
__metadata("design:type", Object)
|
|
90
|
+
], WebhookDelivery.prototype, "completedAt", void 0);
|
|
91
|
+
__decorate([
|
|
92
|
+
Property({ type: 'datetime', nullable: true }),
|
|
93
|
+
__metadata("design:type", Object)
|
|
94
|
+
], WebhookDelivery.prototype, "deadLetteredAt", void 0);
|
|
95
|
+
__decorate([
|
|
96
|
+
Property({ type: 'datetime', onCreate: () => new Date() }),
|
|
97
|
+
__metadata("design:type", Date)
|
|
98
|
+
], WebhookDelivery.prototype, "createdAt", void 0);
|
|
99
|
+
__decorate([
|
|
100
|
+
Property({ type: 'datetime', onUpdate: () => new Date() }),
|
|
101
|
+
__metadata("design:type", Date)
|
|
102
|
+
], WebhookDelivery.prototype, "updatedAt", void 0);
|
|
103
|
+
WebhookDelivery = __decorate([
|
|
104
|
+
GlobalEntity(),
|
|
105
|
+
Entity({ tableName: 'webhook_deliveries' })
|
|
106
|
+
], WebhookDelivery);
|
|
107
|
+
export { WebhookDelivery };
|
|
108
|
+
//# sourceMappingURL=webhook-delivery.entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-delivery.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/webhook-delivery.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;;;;;GAOG;AAGI,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B,CAAC,aAAa,CAAC,CAUM;IAGrB,EAAE,GAAW,UAAU,EAAE,CAAC;IAI1B,SAAS,CAAU;IAInB,OAAO,CAAU;IAIjB,SAAS,CAAU;IAGnB,OAAO,CAAW;IAIlB,MAAM,GAAuE,SAAS,CAAC;IAGvF,YAAY,GAAW,CAAC,CAAC;IAGzB,YAAY,CAAe;IAG3B,kBAAkB,CAAiB;IAGnC,gBAAgB,CAAiB;IAGjC,SAAS,CAAiB;IAG1B,WAAW,CAAe;IAG1B,cAAc,CAAe;IAG7B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;IAG7B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;CAC9B,CAAA;AA/CC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;2CACH;AAI1B;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE;;kDACW;AAInB;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxC,KAAK,EAAE;;gDACS;AAIjB;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxC,KAAK,EAAE;;kDACW;AAGnB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;gDACT;AAIlB;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxC,KAAK,EAAE;;+CAC+E;AAGvF;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;qDACL;AAGzB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qDACpB;AAG3B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;2DACX;AAGnC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;yDAC1B;AAGjC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDACjC;AAG1B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACrB;AAG1B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;uDAClB;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;kDAAc;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;kDAAc;AA5DlB,eAAe;IAF3B,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC;GAC/B,eAAe,CA6D3B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { OptionalProps } from '@mikro-orm/core';
|
|
2
|
+
/**
|
|
3
|
+
* Outbound webhook subscription (FR-121).
|
|
4
|
+
*
|
|
5
|
+
* - `eventTypes` array gates which events trigger a delivery for this row.
|
|
6
|
+
* - `secret` is shared with the receiver so they can verify the HMAC the
|
|
7
|
+
* delivery worker stamps on every POST body.
|
|
8
|
+
* - `status='paused'` stops new deliveries without deleting historical
|
|
9
|
+
* WebhookDelivery rows.
|
|
10
|
+
*/
|
|
11
|
+
export declare class Webhook {
|
|
12
|
+
[OptionalProps]?: 'id' | 'createdAt' | 'updatedAt' | 'status' | 'eventTypes' | 'createdByAdminUserId' | 'organizationId';
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
url: string;
|
|
16
|
+
/** Shared secret, stored plaintext (already at rest in the DB; the HMAC is
|
|
17
|
+
* what protects payload integrity in transit). 64 hex chars by default. */
|
|
18
|
+
secret: string;
|
|
19
|
+
eventTypes: string[];
|
|
20
|
+
status: 'active' | 'paused';
|
|
21
|
+
createdByAdminUserId?: string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Feature 062 — delivery filter (data-model.md §3). NULL = platform-wide
|
|
24
|
+
* subscription (legacy semantics); a value restricts delivery to events
|
|
25
|
+
* whose payload `organizationId` matches. Evaluated in the event-bridge
|
|
26
|
+
* lookup; the row itself stays `@GlobalEntity()` (admin-managed platform
|
|
27
|
+
* configuration — research §R12).
|
|
28
|
+
*/
|
|
29
|
+
organizationId?: string | null;
|
|
30
|
+
createdAt: Date;
|
|
31
|
+
updatedAt: Date;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=webhook.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/webhook.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAIrF;;;;;;;;GAQG;AACH,qBAEa,OAAO;IAClB,CAAC,aAAa,CAAC,CAAC,EACZ,IAAI,GACJ,WAAW,GACX,WAAW,GACX,QAAQ,GACR,YAAY,GACZ,sBAAsB,GACtB,gBAAgB,CAAC;IAGrB,EAAE,EAAE,MAAM,CAAgB;IAG1B,IAAI,EAAG,MAAM,CAAC;IAGd,GAAG,EAAG,MAAM,CAAC;IAEb;gFAC4E;IAE5E,MAAM,EAAG,MAAM,CAAC;IAGhB,UAAU,EAAE,MAAM,EAAE,CAAM;IAI1B,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAY;IAGvC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC;;;;;;OAMG;IAGH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG/B,SAAS,EAAE,IAAI,CAAc;IAG7B,SAAS,EAAE,IAAI,CAAc;CAC9B"}
|