@open-mercato/webhooks 0.4.9-canary-8c762104f0
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/CLAUDE.md +1 -0
- package/build.mjs +69 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/modules/webhooks/acl.js +14 -0
- package/dist/modules/webhooks/acl.js.map +7 -0
- package/dist/modules/webhooks/api/openapi.js +8 -0
- package/dist/modules/webhooks/api/openapi.js.map +7 -0
- package/dist/modules/webhooks/api/webhook-deliveries/route.js +118 -0
- package/dist/modules/webhooks/api/webhook-deliveries/route.js.map +7 -0
- package/dist/modules/webhooks/api/webhooks/route.js +268 -0
- package/dist/modules/webhooks/api/webhooks/route.js.map +7 -0
- package/dist/modules/webhooks/backend/webhooks/[id]/page.meta.js +17 -0
- package/dist/modules/webhooks/backend/webhooks/[id]/page.meta.js.map +7 -0
- package/dist/modules/webhooks/backend/webhooks/create/page.meta.js +17 -0
- package/dist/modules/webhooks/backend/webhooks/create/page.meta.js.map +7 -0
- package/dist/modules/webhooks/backend/webhooks/page.meta.js +24 -0
- package/dist/modules/webhooks/backend/webhooks/page.meta.js.map +7 -0
- package/dist/modules/webhooks/data/entities.js +196 -0
- package/dist/modules/webhooks/data/entities.js.map +7 -0
- package/dist/modules/webhooks/data/validators.js +39 -0
- package/dist/modules/webhooks/data/validators.js.map +7 -0
- package/dist/modules/webhooks/events.js +18 -0
- package/dist/modules/webhooks/events.js.map +7 -0
- package/dist/modules/webhooks/index.js +14 -0
- package/dist/modules/webhooks/index.js.map +7 -0
- package/dist/modules/webhooks/setup.js +12 -0
- package/dist/modules/webhooks/setup.js.map +7 -0
- package/dist/modules/webhooks/subscribers/outbound-dispatch.js +67 -0
- package/dist/modules/webhooks/subscribers/outbound-dispatch.js.map +7 -0
- package/dist/modules/webhooks/workers/webhook-delivery.js +129 -0
- package/dist/modules/webhooks/workers/webhook-delivery.js.map +7 -0
- package/generated/entities/webhook_delivery_entity/index.ts +22 -0
- package/generated/entities/webhook_entity/index.ts +26 -0
- package/generated/entities.ids.generated.ts +12 -0
- package/generated/entity-fields-registry.ts +13 -0
- package/jest.config.cjs +20 -0
- package/package.json +77 -0
- package/src/index.ts +1 -0
- package/src/modules/webhooks/acl.ts +10 -0
- package/src/modules/webhooks/api/openapi.ts +5 -0
- package/src/modules/webhooks/api/webhook-deliveries/route.ts +131 -0
- package/src/modules/webhooks/api/webhooks/route.ts +288 -0
- package/src/modules/webhooks/backend/webhooks/[id]/page.meta.ts +13 -0
- package/src/modules/webhooks/backend/webhooks/[id]/page.tsx +262 -0
- package/src/modules/webhooks/backend/webhooks/create/page.meta.ts +13 -0
- package/src/modules/webhooks/backend/webhooks/create/page.tsx +75 -0
- package/src/modules/webhooks/backend/webhooks/page.meta.ts +20 -0
- package/src/modules/webhooks/backend/webhooks/page.tsx +206 -0
- package/src/modules/webhooks/data/entities.ts +157 -0
- package/src/modules/webhooks/data/validators.ts +40 -0
- package/src/modules/webhooks/events.ts +15 -0
- package/src/modules/webhooks/i18n/en.json +73 -0
- package/src/modules/webhooks/index.ts +12 -0
- package/src/modules/webhooks/setup.ts +10 -0
- package/src/modules/webhooks/subscribers/outbound-dispatch.ts +79 -0
- package/src/modules/webhooks/workers/webhook-delivery.ts +158 -0
- package/tsconfig.build.json +13 -0
- package/tsconfig.json +9 -0
- package/watch.mjs +6 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
const webhookIcon = React.createElement(
|
|
3
|
+
"svg",
|
|
4
|
+
{ width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" },
|
|
5
|
+
React.createElement("path", { d: "M18 16.98h1a2 2 0 0 0 2-2v-1a2 2 0 0 0-4 0v4a2 2 0 0 1-4 0v-1a2 2 0 0 1 2-2h1" }),
|
|
6
|
+
React.createElement("path", { d: "M2 12a10 10 0 0 1 18-6" }),
|
|
7
|
+
React.createElement("path", { d: "M12 2a10 10 0 0 1 6 18" })
|
|
8
|
+
);
|
|
9
|
+
const metadata = {
|
|
10
|
+
requireAuth: true,
|
|
11
|
+
requireFeatures: ["webhooks.view"],
|
|
12
|
+
pageTitle: "Webhooks",
|
|
13
|
+
pageTitleKey: "webhooks.nav.title",
|
|
14
|
+
pageGroup: "Integrations",
|
|
15
|
+
pageGroupKey: "webhooks.nav.group",
|
|
16
|
+
pageOrder: 1,
|
|
17
|
+
icon: webhookIcon,
|
|
18
|
+
pageContext: "settings",
|
|
19
|
+
breadcrumb: [{ label: "Webhooks", labelKey: "webhooks.nav.title" }]
|
|
20
|
+
};
|
|
21
|
+
export {
|
|
22
|
+
metadata
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=page.meta.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/webhooks/backend/webhooks/page.meta.ts"],
|
|
4
|
+
"sourcesContent": ["import React from 'react'\n\nconst webhookIcon = React.createElement('svg', { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' },\n React.createElement('path', { d: 'M18 16.98h1a2 2 0 0 0 2-2v-1a2 2 0 0 0-4 0v4a2 2 0 0 1-4 0v-1a2 2 0 0 1 2-2h1' }),\n React.createElement('path', { d: 'M2 12a10 10 0 0 1 18-6' }),\n React.createElement('path', { d: 'M12 2a10 10 0 0 1 6 18' }),\n)\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['webhooks.view'],\n pageTitle: 'Webhooks',\n pageTitleKey: 'webhooks.nav.title',\n pageGroup: 'Integrations',\n pageGroupKey: 'webhooks.nav.group',\n pageOrder: 1,\n icon: webhookIcon,\n pageContext: 'settings' as const,\n breadcrumb: [{ label: 'Webhooks', labelKey: 'webhooks.nav.title' }],\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,WAAW;AAElB,MAAM,cAAc,MAAM;AAAA,EAAc;AAAA,EAAO,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,aAAa,MAAM,QAAQ,QAAQ,gBAAgB,aAAa,GAAG,eAAe,SAAS,gBAAgB,QAAQ;AAAA,EAClM,MAAM,cAAc,QAAQ,EAAE,GAAG,gFAAgF,CAAC;AAAA,EAClH,MAAM,cAAc,QAAQ,EAAE,GAAG,yBAAyB,CAAC;AAAA,EAC3D,MAAM,cAAc,QAAQ,EAAE,GAAG,yBAAyB,CAAC;AAC7D;AAEO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,eAAe;AAAA,EACjC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY,CAAC,EAAE,OAAO,YAAY,UAAU,qBAAqB,CAAC;AACpE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
import { Entity, PrimaryKey, Property, Index } from "@mikro-orm/core";
|
|
12
|
+
let WebhookEntity = class {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.httpMethod = "POST";
|
|
15
|
+
this.isActive = true;
|
|
16
|
+
this.deliveryStrategy = "http";
|
|
17
|
+
this.maxRetries = 10;
|
|
18
|
+
this.timeoutMs = 15e3;
|
|
19
|
+
this.rateLimitPerMinute = 0;
|
|
20
|
+
this.consecutiveFailures = 0;
|
|
21
|
+
this.autoDisableThreshold = 100;
|
|
22
|
+
this.createdAt = /* @__PURE__ */ new Date();
|
|
23
|
+
this.updatedAt = /* @__PURE__ */ new Date();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
__decorateClass([
|
|
27
|
+
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
28
|
+
], WebhookEntity.prototype, "id", 2);
|
|
29
|
+
__decorateClass([
|
|
30
|
+
Property({ type: "text" })
|
|
31
|
+
], WebhookEntity.prototype, "name", 2);
|
|
32
|
+
__decorateClass([
|
|
33
|
+
Property({ name: "description", type: "text", nullable: true })
|
|
34
|
+
], WebhookEntity.prototype, "description", 2);
|
|
35
|
+
__decorateClass([
|
|
36
|
+
Property({ name: "url", type: "text" })
|
|
37
|
+
], WebhookEntity.prototype, "url", 2);
|
|
38
|
+
__decorateClass([
|
|
39
|
+
Property({ name: "secret", type: "text" })
|
|
40
|
+
], WebhookEntity.prototype, "secret", 2);
|
|
41
|
+
__decorateClass([
|
|
42
|
+
Property({ name: "previous_secret", type: "text", nullable: true })
|
|
43
|
+
], WebhookEntity.prototype, "previousSecret", 2);
|
|
44
|
+
__decorateClass([
|
|
45
|
+
Property({ name: "previous_secret_set_at", type: Date, nullable: true })
|
|
46
|
+
], WebhookEntity.prototype, "previousSecretSetAt", 2);
|
|
47
|
+
__decorateClass([
|
|
48
|
+
Property({ name: "subscribed_events", type: "json" })
|
|
49
|
+
], WebhookEntity.prototype, "subscribedEvents", 2);
|
|
50
|
+
__decorateClass([
|
|
51
|
+
Property({ name: "http_method", type: "text", default: "'POST'" })
|
|
52
|
+
], WebhookEntity.prototype, "httpMethod", 2);
|
|
53
|
+
__decorateClass([
|
|
54
|
+
Property({ name: "custom_headers", type: "json", nullable: true })
|
|
55
|
+
], WebhookEntity.prototype, "customHeaders", 2);
|
|
56
|
+
__decorateClass([
|
|
57
|
+
Property({ name: "is_active", type: "boolean", default: true })
|
|
58
|
+
], WebhookEntity.prototype, "isActive", 2);
|
|
59
|
+
__decorateClass([
|
|
60
|
+
Property({ name: "delivery_strategy", type: "text", default: "'http'" })
|
|
61
|
+
], WebhookEntity.prototype, "deliveryStrategy", 2);
|
|
62
|
+
__decorateClass([
|
|
63
|
+
Property({ name: "strategy_config", type: "json", nullable: true })
|
|
64
|
+
], WebhookEntity.prototype, "strategyConfig", 2);
|
|
65
|
+
__decorateClass([
|
|
66
|
+
Property({ name: "max_retries", type: "int", default: 10 })
|
|
67
|
+
], WebhookEntity.prototype, "maxRetries", 2);
|
|
68
|
+
__decorateClass([
|
|
69
|
+
Property({ name: "timeout_ms", type: "int", default: 15e3 })
|
|
70
|
+
], WebhookEntity.prototype, "timeoutMs", 2);
|
|
71
|
+
__decorateClass([
|
|
72
|
+
Property({ name: "rate_limit_per_minute", type: "int", default: 0 })
|
|
73
|
+
], WebhookEntity.prototype, "rateLimitPerMinute", 2);
|
|
74
|
+
__decorateClass([
|
|
75
|
+
Property({ name: "consecutive_failures", type: "int", default: 0 })
|
|
76
|
+
], WebhookEntity.prototype, "consecutiveFailures", 2);
|
|
77
|
+
__decorateClass([
|
|
78
|
+
Property({ name: "auto_disable_threshold", type: "int", default: 100 })
|
|
79
|
+
], WebhookEntity.prototype, "autoDisableThreshold", 2);
|
|
80
|
+
__decorateClass([
|
|
81
|
+
Property({ name: "last_success_at", type: Date, nullable: true })
|
|
82
|
+
], WebhookEntity.prototype, "lastSuccessAt", 2);
|
|
83
|
+
__decorateClass([
|
|
84
|
+
Property({ name: "last_failure_at", type: Date, nullable: true })
|
|
85
|
+
], WebhookEntity.prototype, "lastFailureAt", 2);
|
|
86
|
+
__decorateClass([
|
|
87
|
+
Property({ name: "integration_id", type: "text", nullable: true })
|
|
88
|
+
], WebhookEntity.prototype, "integrationId", 2);
|
|
89
|
+
__decorateClass([
|
|
90
|
+
Property({ name: "organization_id", type: "uuid" })
|
|
91
|
+
], WebhookEntity.prototype, "organizationId", 2);
|
|
92
|
+
__decorateClass([
|
|
93
|
+
Property({ name: "tenant_id", type: "uuid" })
|
|
94
|
+
], WebhookEntity.prototype, "tenantId", 2);
|
|
95
|
+
__decorateClass([
|
|
96
|
+
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
97
|
+
], WebhookEntity.prototype, "createdAt", 2);
|
|
98
|
+
__decorateClass([
|
|
99
|
+
Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
|
|
100
|
+
], WebhookEntity.prototype, "updatedAt", 2);
|
|
101
|
+
__decorateClass([
|
|
102
|
+
Property({ name: "deleted_at", type: Date, nullable: true })
|
|
103
|
+
], WebhookEntity.prototype, "deletedAt", 2);
|
|
104
|
+
WebhookEntity = __decorateClass([
|
|
105
|
+
Entity({ tableName: "webhooks" }),
|
|
106
|
+
Index({ properties: ["organizationId", "tenantId", "isActive"] }),
|
|
107
|
+
Index({ properties: ["organizationId", "tenantId", "deletedAt"] })
|
|
108
|
+
], WebhookEntity);
|
|
109
|
+
let WebhookDeliveryEntity = class {
|
|
110
|
+
constructor() {
|
|
111
|
+
this.status = "pending";
|
|
112
|
+
this.attemptNumber = 0;
|
|
113
|
+
this.maxAttempts = 10;
|
|
114
|
+
this.enqueuedAt = /* @__PURE__ */ new Date();
|
|
115
|
+
this.createdAt = /* @__PURE__ */ new Date();
|
|
116
|
+
this.updatedAt = /* @__PURE__ */ new Date();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
__decorateClass([
|
|
120
|
+
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
121
|
+
], WebhookDeliveryEntity.prototype, "id", 2);
|
|
122
|
+
__decorateClass([
|
|
123
|
+
Property({ name: "webhook_id", type: "uuid" })
|
|
124
|
+
], WebhookDeliveryEntity.prototype, "webhookId", 2);
|
|
125
|
+
__decorateClass([
|
|
126
|
+
Property({ name: "event_type", type: "text" })
|
|
127
|
+
], WebhookDeliveryEntity.prototype, "eventType", 2);
|
|
128
|
+
__decorateClass([
|
|
129
|
+
Property({ name: "message_id", type: "text" })
|
|
130
|
+
], WebhookDeliveryEntity.prototype, "messageId", 2);
|
|
131
|
+
__decorateClass([
|
|
132
|
+
Property({ name: "payload", type: "json" })
|
|
133
|
+
], WebhookDeliveryEntity.prototype, "payload", 2);
|
|
134
|
+
__decorateClass([
|
|
135
|
+
Property({ name: "status", type: "text", default: "'pending'" })
|
|
136
|
+
], WebhookDeliveryEntity.prototype, "status", 2);
|
|
137
|
+
__decorateClass([
|
|
138
|
+
Property({ name: "response_status", type: "int", nullable: true })
|
|
139
|
+
], WebhookDeliveryEntity.prototype, "responseStatus", 2);
|
|
140
|
+
__decorateClass([
|
|
141
|
+
Property({ name: "response_body", type: "text", nullable: true })
|
|
142
|
+
], WebhookDeliveryEntity.prototype, "responseBody", 2);
|
|
143
|
+
__decorateClass([
|
|
144
|
+
Property({ name: "response_headers", type: "json", nullable: true })
|
|
145
|
+
], WebhookDeliveryEntity.prototype, "responseHeaders", 2);
|
|
146
|
+
__decorateClass([
|
|
147
|
+
Property({ name: "error_message", type: "text", nullable: true })
|
|
148
|
+
], WebhookDeliveryEntity.prototype, "errorMessage", 2);
|
|
149
|
+
__decorateClass([
|
|
150
|
+
Property({ name: "attempt_number", type: "int", default: 0 })
|
|
151
|
+
], WebhookDeliveryEntity.prototype, "attemptNumber", 2);
|
|
152
|
+
__decorateClass([
|
|
153
|
+
Property({ name: "max_attempts", type: "int", default: 10 })
|
|
154
|
+
], WebhookDeliveryEntity.prototype, "maxAttempts", 2);
|
|
155
|
+
__decorateClass([
|
|
156
|
+
Property({ name: "next_retry_at", type: Date, nullable: true })
|
|
157
|
+
], WebhookDeliveryEntity.prototype, "nextRetryAt", 2);
|
|
158
|
+
__decorateClass([
|
|
159
|
+
Property({ name: "duration_ms", type: "int", nullable: true })
|
|
160
|
+
], WebhookDeliveryEntity.prototype, "durationMs", 2);
|
|
161
|
+
__decorateClass([
|
|
162
|
+
Property({ name: "target_url", type: "text" })
|
|
163
|
+
], WebhookDeliveryEntity.prototype, "targetUrl", 2);
|
|
164
|
+
__decorateClass([
|
|
165
|
+
Property({ name: "enqueued_at", type: Date })
|
|
166
|
+
], WebhookDeliveryEntity.prototype, "enqueuedAt", 2);
|
|
167
|
+
__decorateClass([
|
|
168
|
+
Property({ name: "last_attempt_at", type: Date, nullable: true })
|
|
169
|
+
], WebhookDeliveryEntity.prototype, "lastAttemptAt", 2);
|
|
170
|
+
__decorateClass([
|
|
171
|
+
Property({ name: "delivered_at", type: Date, nullable: true })
|
|
172
|
+
], WebhookDeliveryEntity.prototype, "deliveredAt", 2);
|
|
173
|
+
__decorateClass([
|
|
174
|
+
Property({ name: "organization_id", type: "uuid" })
|
|
175
|
+
], WebhookDeliveryEntity.prototype, "organizationId", 2);
|
|
176
|
+
__decorateClass([
|
|
177
|
+
Property({ name: "tenant_id", type: "uuid" })
|
|
178
|
+
], WebhookDeliveryEntity.prototype, "tenantId", 2);
|
|
179
|
+
__decorateClass([
|
|
180
|
+
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
181
|
+
], WebhookDeliveryEntity.prototype, "createdAt", 2);
|
|
182
|
+
__decorateClass([
|
|
183
|
+
Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
|
|
184
|
+
], WebhookDeliveryEntity.prototype, "updatedAt", 2);
|
|
185
|
+
WebhookDeliveryEntity = __decorateClass([
|
|
186
|
+
Entity({ tableName: "webhook_deliveries" }),
|
|
187
|
+
Index({ properties: ["webhookId", "status"] }),
|
|
188
|
+
Index({ properties: ["organizationId", "tenantId", "createdAt"] }),
|
|
189
|
+
Index({ properties: ["webhookId", "createdAt"] }),
|
|
190
|
+
Index({ properties: ["eventType", "organizationId"] })
|
|
191
|
+
], WebhookDeliveryEntity);
|
|
192
|
+
export {
|
|
193
|
+
WebhookDeliveryEntity,
|
|
194
|
+
WebhookEntity
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=entities.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/webhooks/data/entities.ts"],
|
|
4
|
+
"sourcesContent": ["import { Entity, PrimaryKey, Property, Index } from '@mikro-orm/core'\n\n@Entity({ tableName: 'webhooks' })\n@Index({ properties: ['organizationId', 'tenantId', 'isActive'] })\n@Index({ properties: ['organizationId', 'tenantId', 'deletedAt'] })\nexport class WebhookEntity {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ type: 'text' })\n name!: string\n\n @Property({ name: 'description', type: 'text', nullable: true })\n description?: string | null\n\n @Property({ name: 'url', type: 'text' })\n url!: string\n\n @Property({ name: 'secret', type: 'text' })\n secret!: string\n\n @Property({ name: 'previous_secret', type: 'text', nullable: true })\n previousSecret?: string | null\n\n @Property({ name: 'previous_secret_set_at', type: Date, nullable: true })\n previousSecretSetAt?: Date | null\n\n @Property({ name: 'subscribed_events', type: 'json' })\n subscribedEvents!: string[]\n\n @Property({ name: 'http_method', type: 'text', default: \"'POST'\" })\n httpMethod: string = 'POST'\n\n @Property({ name: 'custom_headers', type: 'json', nullable: true })\n customHeaders?: Record<string, string> | null\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'delivery_strategy', type: 'text', default: \"'http'\" })\n deliveryStrategy: string = 'http'\n\n @Property({ name: 'strategy_config', type: 'json', nullable: true })\n strategyConfig?: Record<string, unknown> | null\n\n @Property({ name: 'max_retries', type: 'int', default: 10 })\n maxRetries: number = 10\n\n @Property({ name: 'timeout_ms', type: 'int', default: 15000 })\n timeoutMs: number = 15000\n\n @Property({ name: 'rate_limit_per_minute', type: 'int', default: 0 })\n rateLimitPerMinute: number = 0\n\n @Property({ name: 'consecutive_failures', type: 'int', default: 0 })\n consecutiveFailures: number = 0\n\n @Property({ name: 'auto_disable_threshold', type: 'int', default: 100 })\n autoDisableThreshold: number = 100\n\n @Property({ name: 'last_success_at', type: Date, nullable: true })\n lastSuccessAt?: Date | null\n\n @Property({ name: 'last_failure_at', type: Date, nullable: true })\n lastFailureAt?: Date | null\n\n @Property({ name: 'integration_id', type: 'text', nullable: true })\n integrationId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid' })\n organizationId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'webhook_deliveries' })\n@Index({ properties: ['webhookId', 'status'] })\n@Index({ properties: ['organizationId', 'tenantId', 'createdAt'] })\n@Index({ properties: ['webhookId', 'createdAt'] })\n@Index({ properties: ['eventType', 'organizationId'] })\nexport class WebhookDeliveryEntity {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'webhook_id', type: 'uuid' })\n webhookId!: string\n\n @Property({ name: 'event_type', type: 'text' })\n eventType!: string\n\n @Property({ name: 'message_id', type: 'text' })\n messageId!: string\n\n @Property({ name: 'payload', type: 'json' })\n payload!: Record<string, unknown>\n\n @Property({ name: 'status', type: 'text', default: \"'pending'\" })\n status: string = 'pending'\n\n @Property({ name: 'response_status', type: 'int', nullable: true })\n responseStatus?: number | null\n\n @Property({ name: 'response_body', type: 'text', nullable: true })\n responseBody?: string | null\n\n @Property({ name: 'response_headers', type: 'json', nullable: true })\n responseHeaders?: Record<string, string> | null\n\n @Property({ name: 'error_message', type: 'text', nullable: true })\n errorMessage?: string | null\n\n @Property({ name: 'attempt_number', type: 'int', default: 0 })\n attemptNumber: number = 0\n\n @Property({ name: 'max_attempts', type: 'int', default: 10 })\n maxAttempts: number = 10\n\n @Property({ name: 'next_retry_at', type: Date, nullable: true })\n nextRetryAt?: Date | null\n\n @Property({ name: 'duration_ms', type: 'int', nullable: true })\n durationMs?: number | null\n\n @Property({ name: 'target_url', type: 'text' })\n targetUrl!: string\n\n @Property({ name: 'enqueued_at', type: Date })\n enqueuedAt: Date = new Date()\n\n @Property({ name: 'last_attempt_at', type: Date, nullable: true })\n lastAttemptAt?: Date | null\n\n @Property({ name: 'delivered_at', type: Date, nullable: true })\n deliveredAt?: Date | null\n\n @Property({ name: 'organization_id', type: 'uuid' })\n organizationId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const webhookCreateSchema = z.object({
|
|
3
|
+
name: z.string().min(1).max(255),
|
|
4
|
+
description: z.string().max(1e3).optional().nullable(),
|
|
5
|
+
url: z.string().url(),
|
|
6
|
+
subscribedEvents: z.array(z.string().min(1)).min(1),
|
|
7
|
+
httpMethod: z.enum(["POST", "PUT", "PATCH"]).default("POST"),
|
|
8
|
+
customHeaders: z.record(z.string(), z.string()).optional().nullable(),
|
|
9
|
+
deliveryStrategy: z.literal("http").default("http"),
|
|
10
|
+
strategyConfig: z.record(z.string(), z.unknown()).optional().nullable(),
|
|
11
|
+
maxRetries: z.number().int().min(0).max(30).default(10),
|
|
12
|
+
timeoutMs: z.number().int().min(1e3).max(6e4).default(15e3),
|
|
13
|
+
rateLimitPerMinute: z.number().int().min(0).max(1e4).default(0),
|
|
14
|
+
autoDisableThreshold: z.number().int().min(0).max(1e3).default(100),
|
|
15
|
+
integrationId: z.string().optional().nullable()
|
|
16
|
+
});
|
|
17
|
+
const webhookUpdateSchema = webhookCreateSchema.partial().extend({
|
|
18
|
+
isActive: z.boolean().optional()
|
|
19
|
+
});
|
|
20
|
+
const webhookListQuerySchema = z.object({
|
|
21
|
+
page: z.string().optional(),
|
|
22
|
+
pageSize: z.string().optional(),
|
|
23
|
+
search: z.string().optional(),
|
|
24
|
+
isActive: z.string().optional()
|
|
25
|
+
});
|
|
26
|
+
const webhookDeliveryQuerySchema = z.object({
|
|
27
|
+
page: z.coerce.number().min(1).default(1),
|
|
28
|
+
pageSize: z.coerce.number().min(1).max(100).default(50),
|
|
29
|
+
webhookId: z.string().uuid().optional(),
|
|
30
|
+
eventType: z.string().optional(),
|
|
31
|
+
status: z.enum(["pending", "sending", "delivered", "failed", "expired"]).optional()
|
|
32
|
+
});
|
|
33
|
+
export {
|
|
34
|
+
webhookCreateSchema,
|
|
35
|
+
webhookDeliveryQuerySchema,
|
|
36
|
+
webhookListQuerySchema,
|
|
37
|
+
webhookUpdateSchema
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/webhooks/data/validators.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\n\nexport const webhookCreateSchema = z.object({\n name: z.string().min(1).max(255),\n description: z.string().max(1000).optional().nullable(),\n url: z.string().url(),\n subscribedEvents: z.array(z.string().min(1)).min(1),\n httpMethod: z.enum(['POST', 'PUT', 'PATCH'] as const).default('POST'),\n customHeaders: z.record(z.string(), z.string()).optional().nullable(),\n deliveryStrategy: z.literal('http').default('http'),\n strategyConfig: z.record(z.string(), z.unknown()).optional().nullable(),\n maxRetries: z.number().int().min(0).max(30).default(10),\n timeoutMs: z.number().int().min(1000).max(60000).default(15000),\n rateLimitPerMinute: z.number().int().min(0).max(10000).default(0),\n autoDisableThreshold: z.number().int().min(0).max(1000).default(100),\n integrationId: z.string().optional().nullable(),\n})\n\nexport type WebhookCreateInput = z.infer<typeof webhookCreateSchema>\n\nexport const webhookUpdateSchema = webhookCreateSchema.partial().extend({\n isActive: z.boolean().optional(),\n})\n\nexport type WebhookUpdateInput = z.infer<typeof webhookUpdateSchema>\n\nexport const webhookListQuerySchema = z.object({\n page: z.string().optional(),\n pageSize: z.string().optional(),\n search: z.string().optional(),\n isActive: z.string().optional(),\n})\n\nexport const webhookDeliveryQuerySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n webhookId: z.string().uuid().optional(),\n eventType: z.string().optional(),\n status: z.enum(['pending', 'sending', 'delivered', 'failed', 'expired'] as const).optional(),\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAEX,MAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC/B,aAAa,EAAE,OAAO,EAAE,IAAI,GAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACtD,KAAK,EAAE,OAAO,EAAE,IAAI;AAAA,EACpB,kBAAkB,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;AAAA,EAClD,YAAY,EAAE,KAAK,CAAC,QAAQ,OAAO,OAAO,CAAU,EAAE,QAAQ,MAAM;AAAA,EACpE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,EACpE,kBAAkB,EAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM;AAAA,EAClD,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,EACtE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE;AAAA,EACtD,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,IAAI,GAAK,EAAE,QAAQ,IAAK;AAAA,EAC9D,oBAAoB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAK,EAAE,QAAQ,CAAC;AAAA,EAChE,sBAAsB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAI,EAAE,QAAQ,GAAG;AAAA,EACnE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAChD,CAAC;AAIM,MAAM,sBAAsB,oBAAoB,QAAQ,EAAE,OAAO;AAAA,EACtE,UAAU,EAAE,QAAQ,EAAE,SAAS;AACjC,CAAC;AAIM,MAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAEM,MAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACxC,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EACtD,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACtC,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQ,EAAE,KAAK,CAAC,WAAW,WAAW,aAAa,UAAU,SAAS,CAAU,EAAE,SAAS;AAC7F,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createModuleEvents } from "@open-mercato/shared/modules/events";
|
|
2
|
+
const events = [
|
|
3
|
+
{ id: "webhooks.webhook.created", label: "Webhook Created", entity: "webhook", category: "crud" },
|
|
4
|
+
{ id: "webhooks.webhook.updated", label: "Webhook Updated", entity: "webhook", category: "crud" },
|
|
5
|
+
{ id: "webhooks.webhook.deleted", label: "Webhook Deleted", entity: "webhook", category: "crud" },
|
|
6
|
+
{ id: "webhooks.delivery.succeeded", label: "Webhook Delivery Succeeded", entity: "delivery", category: "lifecycle" },
|
|
7
|
+
{ id: "webhooks.delivery.failed", label: "Webhook Delivery Failed", entity: "delivery", category: "lifecycle" },
|
|
8
|
+
{ id: "webhooks.webhook.disabled", label: "Webhook Auto-Disabled", entity: "webhook", category: "lifecycle" }
|
|
9
|
+
];
|
|
10
|
+
const eventsConfig = createModuleEvents({ moduleId: "webhooks", events });
|
|
11
|
+
const emitWebhooksEvent = eventsConfig.emit;
|
|
12
|
+
var events_default = eventsConfig;
|
|
13
|
+
export {
|
|
14
|
+
events_default as default,
|
|
15
|
+
emitWebhooksEvent,
|
|
16
|
+
eventsConfig
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/webhooks/events.ts"],
|
|
4
|
+
"sourcesContent": ["import { createModuleEvents } from '@open-mercato/shared/modules/events'\n\nconst events = [\n { id: 'webhooks.webhook.created', label: 'Webhook Created', entity: 'webhook', category: 'crud' as const },\n { id: 'webhooks.webhook.updated', label: 'Webhook Updated', entity: 'webhook', category: 'crud' as const },\n { id: 'webhooks.webhook.deleted', label: 'Webhook Deleted', entity: 'webhook', category: 'crud' as const },\n { id: 'webhooks.delivery.succeeded', label: 'Webhook Delivery Succeeded', entity: 'delivery', category: 'lifecycle' as const },\n { id: 'webhooks.delivery.failed', label: 'Webhook Delivery Failed', entity: 'delivery', category: 'lifecycle' as const },\n { id: 'webhooks.webhook.disabled', label: 'Webhook Auto-Disabled', entity: 'webhook', category: 'lifecycle' as const },\n] as const\n\nexport const eventsConfig = createModuleEvents({ moduleId: 'webhooks', events })\nexport const emitWebhooksEvent = eventsConfig.emit\nexport type WebhooksEventId = typeof events[number]['id']\nexport default eventsConfig\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,0BAA0B;AAEnC,MAAM,SAAS;AAAA,EACb,EAAE,IAAI,4BAA4B,OAAO,mBAAmB,QAAQ,WAAW,UAAU,OAAgB;AAAA,EACzG,EAAE,IAAI,4BAA4B,OAAO,mBAAmB,QAAQ,WAAW,UAAU,OAAgB;AAAA,EACzG,EAAE,IAAI,4BAA4B,OAAO,mBAAmB,QAAQ,WAAW,UAAU,OAAgB;AAAA,EACzG,EAAE,IAAI,+BAA+B,OAAO,8BAA8B,QAAQ,YAAY,UAAU,YAAqB;AAAA,EAC7H,EAAE,IAAI,4BAA4B,OAAO,2BAA2B,QAAQ,YAAY,UAAU,YAAqB;AAAA,EACvH,EAAE,IAAI,6BAA6B,OAAO,yBAAyB,QAAQ,WAAW,UAAU,YAAqB;AACvH;AAEO,MAAM,eAAe,mBAAmB,EAAE,UAAU,YAAY,OAAO,CAAC;AACxE,MAAM,oBAAoB,aAAa;AAE9C,IAAO,iBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const metadata = {
|
|
2
|
+
name: "webhooks",
|
|
3
|
+
title: "Webhooks",
|
|
4
|
+
version: "0.1.0",
|
|
5
|
+
description: "Standard Webhooks compliant outbound webhook delivery for platform events.",
|
|
6
|
+
author: "Open Mercato Team",
|
|
7
|
+
license: "Proprietary"
|
|
8
|
+
};
|
|
9
|
+
import { features } from "./acl.js";
|
|
10
|
+
export {
|
|
11
|
+
features,
|
|
12
|
+
metadata
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/webhooks/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleInfo } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: ModuleInfo = {\n name: 'webhooks',\n title: 'Webhooks',\n version: '0.1.0',\n description: 'Standard Webhooks compliant outbound webhook delivery for platform events.',\n author: 'Open Mercato Team',\n license: 'Proprietary',\n}\n\nexport { features } from './acl'\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,WAAuB;AAAA,EAClC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,SAAS;AACX;AAEA,SAAS,gBAAgB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/webhooks/setup.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n admin: ['webhooks.*'],\n employee: ['webhooks.view', 'webhooks.deliveries.view'],\n },\n}\n\nexport default setup\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,OAAO,CAAC,YAAY;AAAA,IACpB,UAAU,CAAC,iBAAiB,0BAA0B;AAAA,EACxD;AACF;AAEA,IAAO,gBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { WebhookEntity } from "../data/entities.js";
|
|
2
|
+
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
3
|
+
const metadata = {
|
|
4
|
+
event: "*",
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: "webhooks:outbound-dispatch"
|
|
7
|
+
};
|
|
8
|
+
async function handler(payload, ctx) {
|
|
9
|
+
const eventId = ctx.eventId ?? payload.eventId ?? payload.type;
|
|
10
|
+
if (!eventId) return;
|
|
11
|
+
const tenantId = payload.tenantId;
|
|
12
|
+
const organizationId = payload.organizationId;
|
|
13
|
+
if (!tenantId) return;
|
|
14
|
+
if (eventId.startsWith("webhooks.")) return;
|
|
15
|
+
const em = ctx.container.resolve("em").fork();
|
|
16
|
+
const webhooks = await findWithDecryption(
|
|
17
|
+
em,
|
|
18
|
+
WebhookEntity,
|
|
19
|
+
{
|
|
20
|
+
isActive: true,
|
|
21
|
+
deletedAt: null,
|
|
22
|
+
tenantId,
|
|
23
|
+
...organizationId ? { organizationId } : {}
|
|
24
|
+
},
|
|
25
|
+
{},
|
|
26
|
+
{ tenantId, organizationId: organizationId ?? "" }
|
|
27
|
+
);
|
|
28
|
+
if (!webhooks.length) return;
|
|
29
|
+
const matchingWebhooks = webhooks.filter(
|
|
30
|
+
(webhook) => webhook.subscribedEvents.some((pattern) => eventMatchesPattern(eventId, pattern))
|
|
31
|
+
);
|
|
32
|
+
if (!matchingWebhooks.length) return;
|
|
33
|
+
const queue = ctx.container.resolve("queueService");
|
|
34
|
+
for (const webhook of matchingWebhooks) {
|
|
35
|
+
try {
|
|
36
|
+
await queue.enqueueJob({
|
|
37
|
+
queue: "webhook-deliveries",
|
|
38
|
+
data: {
|
|
39
|
+
webhookId: webhook.id,
|
|
40
|
+
eventId,
|
|
41
|
+
payload,
|
|
42
|
+
tenantId,
|
|
43
|
+
organizationId: organizationId ?? webhook.organizationId
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function eventMatchesPattern(eventId, pattern) {
|
|
51
|
+
if (pattern === "*") return true;
|
|
52
|
+
if (pattern === eventId) return true;
|
|
53
|
+
if (pattern.endsWith(".*")) {
|
|
54
|
+
const prefix = pattern.slice(0, -2);
|
|
55
|
+
return eventId.startsWith(prefix + ".");
|
|
56
|
+
}
|
|
57
|
+
if (pattern.endsWith("*")) {
|
|
58
|
+
const prefix = pattern.slice(0, -1);
|
|
59
|
+
return eventId.startsWith(prefix);
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
handler as default,
|
|
65
|
+
metadata
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=outbound-dispatch.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/webhooks/subscribers/outbound-dispatch.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { WebhookEntity } from '../data/entities'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nexport const metadata = {\n event: '*',\n persistent: true,\n id: 'webhooks:outbound-dispatch',\n}\n\nexport default async function handler(\n payload: Record<string, unknown>,\n ctx: { container: { resolve: <T = unknown>(name: string) => T }; eventId?: string },\n) {\n const eventId = ctx.eventId ?? (payload.eventId as string) ?? (payload.type as string)\n if (!eventId) return\n\n const tenantId = payload.tenantId as string | undefined\n const organizationId = payload.organizationId as string | undefined\n if (!tenantId) return\n\n if (eventId.startsWith('webhooks.')) return\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n const webhooks = await findWithDecryption(\n em,\n WebhookEntity,\n {\n isActive: true,\n deletedAt: null,\n tenantId,\n ...(organizationId ? { organizationId } : {}),\n },\n {},\n { tenantId, organizationId: organizationId ?? '' },\n )\n\n if (!webhooks.length) return\n\n const matchingWebhooks = webhooks.filter((webhook) =>\n webhook.subscribedEvents.some((pattern) => eventMatchesPattern(eventId, pattern)),\n )\n\n if (!matchingWebhooks.length) return\n\n const queue = ctx.container.resolve<{ enqueueJob: (data: unknown) => Promise<unknown> }>('queueService')\n\n for (const webhook of matchingWebhooks) {\n try {\n await queue.enqueueJob({\n queue: 'webhook-deliveries',\n data: {\n webhookId: webhook.id,\n eventId,\n payload,\n tenantId,\n organizationId: organizationId ?? webhook.organizationId,\n },\n })\n } catch {\n // Don't fail the event pipeline if queue is unavailable\n }\n }\n}\n\nfunction eventMatchesPattern(eventId: string, pattern: string): boolean {\n if (pattern === '*') return true\n if (pattern === eventId) return true\n if (pattern.endsWith('.*')) {\n const prefix = pattern.slice(0, -2)\n return eventId.startsWith(prefix + '.')\n }\n if (pattern.endsWith('*')) {\n const prefix = pattern.slice(0, -1)\n return eventId.startsWith(prefix)\n }\n return false\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,qBAAqB;AAC9B,SAAS,0BAA0B;AAE5B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,QACL,SACA,KACA;AACA,QAAM,UAAU,IAAI,WAAY,QAAQ,WAAuB,QAAQ;AACvE,MAAI,CAAC,QAAS;AAEd,QAAM,WAAW,QAAQ;AACzB,QAAM,iBAAiB,QAAQ;AAC/B,MAAI,CAAC,SAAU;AAEf,MAAI,QAAQ,WAAW,WAAW,EAAG;AAErC,QAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAE/D,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,MACE,UAAU;AAAA,MACV,WAAW;AAAA,MACX;AAAA,MACA,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,IAC7C;AAAA,IACA,CAAC;AAAA,IACD,EAAE,UAAU,gBAAgB,kBAAkB,GAAG;AAAA,EACnD;AAEA,MAAI,CAAC,SAAS,OAAQ;AAEtB,QAAM,mBAAmB,SAAS;AAAA,IAAO,CAAC,YACxC,QAAQ,iBAAiB,KAAK,CAAC,YAAY,oBAAoB,SAAS,OAAO,CAAC;AAAA,EAClF;AAEA,MAAI,CAAC,iBAAiB,OAAQ;AAE9B,QAAM,QAAQ,IAAI,UAAU,QAA6D,cAAc;AAEvG,aAAW,WAAW,kBAAkB;AACtC,QAAI;AACF,YAAM,MAAM,WAAW;AAAA,QACrB,OAAO;AAAA,QACP,MAAM;AAAA,UACJ,WAAW,QAAQ;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA,gBAAgB,kBAAkB,QAAQ;AAAA,QAC5C;AAAA,MACF,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,SAAiB,SAA0B;AACtE,MAAI,YAAY,IAAK,QAAO;AAC5B,MAAI,YAAY,QAAS,QAAO;AAChC,MAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,UAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;AAClC,WAAO,QAAQ,WAAW,SAAS,GAAG;AAAA,EACxC;AACA,MAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,UAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;AAClC,WAAO,QAAQ,WAAW,MAAM;AAAA,EAClC;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { WebhookEntity, WebhookDeliveryEntity } from "../data/entities.js";
|
|
2
|
+
import { buildWebhookHeaders, generateMessageId } from "@open-mercato/shared/lib/webhooks";
|
|
3
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
4
|
+
const metadata = {
|
|
5
|
+
queue: "webhook-deliveries",
|
|
6
|
+
id: "webhooks:delivery-worker",
|
|
7
|
+
concurrency: 10
|
|
8
|
+
};
|
|
9
|
+
async function handler(job, ctx) {
|
|
10
|
+
const { webhookId, eventId, payload, tenantId, organizationId } = job.data;
|
|
11
|
+
const em = ctx.resolve("em").fork();
|
|
12
|
+
const webhook = await findOneWithDecryption(
|
|
13
|
+
em,
|
|
14
|
+
WebhookEntity,
|
|
15
|
+
{ id: webhookId, isActive: true, deletedAt: null },
|
|
16
|
+
{},
|
|
17
|
+
{ tenantId, organizationId }
|
|
18
|
+
);
|
|
19
|
+
if (!webhook) return;
|
|
20
|
+
const messageId = generateMessageId();
|
|
21
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
22
|
+
const body = JSON.stringify({
|
|
23
|
+
type: eventId,
|
|
24
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25
|
+
data: payload
|
|
26
|
+
});
|
|
27
|
+
const now = /* @__PURE__ */ new Date();
|
|
28
|
+
const delivery = em.create(WebhookDeliveryEntity, {
|
|
29
|
+
webhookId: webhook.id,
|
|
30
|
+
eventType: eventId,
|
|
31
|
+
messageId,
|
|
32
|
+
payload: JSON.parse(body),
|
|
33
|
+
status: "sending",
|
|
34
|
+
attemptNumber: 0,
|
|
35
|
+
maxAttempts: webhook.maxRetries,
|
|
36
|
+
targetUrl: webhook.url,
|
|
37
|
+
organizationId: webhook.organizationId,
|
|
38
|
+
tenantId: webhook.tenantId,
|
|
39
|
+
enqueuedAt: now,
|
|
40
|
+
createdAt: now,
|
|
41
|
+
updatedAt: now
|
|
42
|
+
});
|
|
43
|
+
await em.flush();
|
|
44
|
+
const headers = buildWebhookHeaders(
|
|
45
|
+
messageId,
|
|
46
|
+
timestamp,
|
|
47
|
+
body,
|
|
48
|
+
webhook.secret,
|
|
49
|
+
webhook.previousSecret
|
|
50
|
+
);
|
|
51
|
+
const startTime = Date.now();
|
|
52
|
+
try {
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timeoutId = setTimeout(() => controller.abort(), webhook.timeoutMs);
|
|
55
|
+
const response = await fetch(webhook.url, {
|
|
56
|
+
method: webhook.httpMethod,
|
|
57
|
+
headers: {
|
|
58
|
+
"content-type": "application/json",
|
|
59
|
+
...headers,
|
|
60
|
+
...webhook.customHeaders ?? {}
|
|
61
|
+
},
|
|
62
|
+
body,
|
|
63
|
+
signal: controller.signal
|
|
64
|
+
});
|
|
65
|
+
clearTimeout(timeoutId);
|
|
66
|
+
const durationMs = Date.now() - startTime;
|
|
67
|
+
const responseBody = await response.text().catch(() => "");
|
|
68
|
+
delivery.responseStatus = response.status;
|
|
69
|
+
delivery.responseBody = responseBody.slice(0, 4096);
|
|
70
|
+
delivery.durationMs = durationMs;
|
|
71
|
+
delivery.lastAttemptAt = /* @__PURE__ */ new Date();
|
|
72
|
+
delivery.attemptNumber += 1;
|
|
73
|
+
if (response.ok) {
|
|
74
|
+
delivery.status = "delivered";
|
|
75
|
+
delivery.deliveredAt = /* @__PURE__ */ new Date();
|
|
76
|
+
webhook.consecutiveFailures = 0;
|
|
77
|
+
webhook.lastSuccessAt = /* @__PURE__ */ new Date();
|
|
78
|
+
} else {
|
|
79
|
+
const shouldRetry = shouldRetryStatus(response.status) && delivery.attemptNumber < delivery.maxAttempts;
|
|
80
|
+
if (shouldRetry) {
|
|
81
|
+
delivery.status = "pending";
|
|
82
|
+
delivery.nextRetryAt = calculateNextRetry(delivery.attemptNumber);
|
|
83
|
+
} else {
|
|
84
|
+
delivery.status = "failed";
|
|
85
|
+
}
|
|
86
|
+
webhook.consecutiveFailures += 1;
|
|
87
|
+
webhook.lastFailureAt = /* @__PURE__ */ new Date();
|
|
88
|
+
if (webhook.autoDisableThreshold > 0 && webhook.consecutiveFailures >= webhook.autoDisableThreshold) {
|
|
89
|
+
webhook.isActive = false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
const durationMs = Date.now() - startTime;
|
|
94
|
+
delivery.durationMs = durationMs;
|
|
95
|
+
delivery.lastAttemptAt = /* @__PURE__ */ new Date();
|
|
96
|
+
delivery.attemptNumber += 1;
|
|
97
|
+
delivery.errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
98
|
+
const shouldRetry = delivery.attemptNumber < delivery.maxAttempts;
|
|
99
|
+
if (shouldRetry) {
|
|
100
|
+
delivery.status = "pending";
|
|
101
|
+
delivery.nextRetryAt = calculateNextRetry(delivery.attemptNumber);
|
|
102
|
+
} else {
|
|
103
|
+
delivery.status = "failed";
|
|
104
|
+
}
|
|
105
|
+
webhook.consecutiveFailures += 1;
|
|
106
|
+
webhook.lastFailureAt = /* @__PURE__ */ new Date();
|
|
107
|
+
if (webhook.autoDisableThreshold > 0 && webhook.consecutiveFailures >= webhook.autoDisableThreshold) {
|
|
108
|
+
webhook.isActive = false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
await em.flush();
|
|
112
|
+
}
|
|
113
|
+
function shouldRetryStatus(status) {
|
|
114
|
+
if (status >= 200 && status < 300) return false;
|
|
115
|
+
if (status === 408 || status === 429) return true;
|
|
116
|
+
if (status >= 500) return true;
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
function calculateNextRetry(attemptNumber) {
|
|
120
|
+
const baseDelay = 1e3;
|
|
121
|
+
const delayMs = baseDelay * Math.pow(2, attemptNumber - 1);
|
|
122
|
+
const jitter = Math.random() * 1e3;
|
|
123
|
+
return new Date(Date.now() + delayMs + jitter);
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
handler as default,
|
|
127
|
+
metadata
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=webhook-delivery.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/webhooks/workers/webhook-delivery.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { WebhookEntity, WebhookDeliveryEntity } from '../data/entities'\nimport { buildWebhookHeaders, generateMessageId } from '@open-mercato/shared/lib/webhooks'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nexport const metadata = {\n queue: 'webhook-deliveries',\n id: 'webhooks:delivery-worker',\n concurrency: 10,\n}\n\ninterface WebhookDeliveryJob {\n webhookId: string\n eventId: string\n payload: Record<string, unknown>\n tenantId: string\n organizationId: string\n}\n\nexport default async function handler(\n job: { data: WebhookDeliveryJob },\n ctx: { resolve: <T = unknown>(name: string) => T },\n) {\n const { webhookId, eventId, payload, tenantId, organizationId } = job.data\n const em = (ctx.resolve('em') as EntityManager).fork()\n\n const webhook = await findOneWithDecryption(\n em,\n WebhookEntity,\n { id: webhookId, isActive: true, deletedAt: null },\n {},\n { tenantId, organizationId },\n )\n\n if (!webhook) return\n\n const messageId = generateMessageId()\n const timestamp = Math.floor(Date.now() / 1000)\n const body = JSON.stringify({\n type: eventId,\n timestamp: new Date().toISOString(),\n data: payload,\n })\n\n const now = new Date()\n const delivery = em.create(WebhookDeliveryEntity, {\n webhookId: webhook.id,\n eventType: eventId,\n messageId,\n payload: JSON.parse(body),\n status: 'sending',\n attemptNumber: 0,\n maxAttempts: webhook.maxRetries,\n targetUrl: webhook.url,\n organizationId: webhook.organizationId,\n tenantId: webhook.tenantId,\n enqueuedAt: now,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.flush()\n\n const headers = buildWebhookHeaders(\n messageId,\n timestamp,\n body,\n webhook.secret,\n webhook.previousSecret,\n )\n\n const startTime = Date.now()\n\n try {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), webhook.timeoutMs)\n\n const response = await fetch(webhook.url, {\n method: webhook.httpMethod,\n headers: {\n 'content-type': 'application/json',\n ...headers,\n ...(webhook.customHeaders ?? {}),\n },\n body,\n signal: controller.signal,\n })\n\n clearTimeout(timeoutId)\n\n const durationMs = Date.now() - startTime\n const responseBody = await response.text().catch(() => '')\n\n delivery.responseStatus = response.status\n delivery.responseBody = responseBody.slice(0, 4096)\n delivery.durationMs = durationMs\n delivery.lastAttemptAt = new Date()\n delivery.attemptNumber += 1\n\n if (response.ok) {\n delivery.status = 'delivered'\n delivery.deliveredAt = new Date()\n webhook.consecutiveFailures = 0\n webhook.lastSuccessAt = new Date()\n } else {\n const shouldRetry = shouldRetryStatus(response.status) && delivery.attemptNumber < delivery.maxAttempts\n if (shouldRetry) {\n delivery.status = 'pending'\n delivery.nextRetryAt = calculateNextRetry(delivery.attemptNumber)\n } else {\n delivery.status = 'failed'\n }\n webhook.consecutiveFailures += 1\n webhook.lastFailureAt = new Date()\n\n if (webhook.autoDisableThreshold > 0 && webhook.consecutiveFailures >= webhook.autoDisableThreshold) {\n webhook.isActive = false\n }\n }\n } catch (error) {\n const durationMs = Date.now() - startTime\n delivery.durationMs = durationMs\n delivery.lastAttemptAt = new Date()\n delivery.attemptNumber += 1\n delivery.errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\n const shouldRetry = delivery.attemptNumber < delivery.maxAttempts\n if (shouldRetry) {\n delivery.status = 'pending'\n delivery.nextRetryAt = calculateNextRetry(delivery.attemptNumber)\n } else {\n delivery.status = 'failed'\n }\n\n webhook.consecutiveFailures += 1\n webhook.lastFailureAt = new Date()\n\n if (webhook.autoDisableThreshold > 0 && webhook.consecutiveFailures >= webhook.autoDisableThreshold) {\n webhook.isActive = false\n }\n }\n\n await em.flush()\n}\n\nfunction shouldRetryStatus(status: number): boolean {\n if (status >= 200 && status < 300) return false\n if (status === 408 || status === 429) return true\n if (status >= 500) return true\n return false\n}\n\nfunction calculateNextRetry(attemptNumber: number): Date {\n const baseDelay = 1000\n const delayMs = baseDelay * Math.pow(2, attemptNumber - 1)\n const jitter = Math.random() * 1000\n return new Date(Date.now() + delayMs + jitter)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,eAAe,6BAA6B;AACrD,SAAS,qBAAqB,yBAAyB;AACvD,SAAS,6BAA6B;AAE/B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,IAAI;AAAA,EACJ,aAAa;AACf;AAUA,eAAO,QACL,KACA,KACA;AACA,QAAM,EAAE,WAAW,SAAS,SAAS,UAAU,eAAe,IAAI,IAAI;AACtE,QAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AAErD,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,EAAE,IAAI,WAAW,UAAU,MAAM,WAAW,KAAK;AAAA,IACjD,CAAC;AAAA,IACD,EAAE,UAAU,eAAe;AAAA,EAC7B;AAEA,MAAI,CAAC,QAAS;AAEd,QAAM,YAAY,kBAAkB;AACpC,QAAM,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAC9C,QAAM,OAAO,KAAK,UAAU;AAAA,IAC1B,MAAM;AAAA,IACN,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,MAAM;AAAA,EACR,CAAC;AAED,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,WAAW,GAAG,OAAO,uBAAuB;AAAA,IAChD,WAAW,QAAQ;AAAA,IACnB,WAAW;AAAA,IACX;AAAA,IACA,SAAS,KAAK,MAAM,IAAI;AAAA,IACxB,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,aAAa,QAAQ;AAAA,IACrB,WAAW,QAAQ;AAAA,IACnB,gBAAgB,QAAQ;AAAA,IACxB,UAAU,QAAQ;AAAA,IAClB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC;AAED,QAAM,GAAG,MAAM;AAEf,QAAM,UAAU;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AAEA,QAAM,YAAY,KAAK,IAAI;AAE3B,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,QAAQ,SAAS;AAExE,UAAM,WAAW,MAAM,MAAM,QAAQ,KAAK;AAAA,MACxC,QAAQ,QAAQ;AAAA,MAChB,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,QACH,GAAI,QAAQ,iBAAiB,CAAC;AAAA,MAChC;AAAA,MACA;AAAA,MACA,QAAQ,WAAW;AAAA,IACrB,CAAC;AAED,iBAAa,SAAS;AAEtB,UAAM,aAAa,KAAK,IAAI,IAAI;AAChC,UAAM,eAAe,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AAEzD,aAAS,iBAAiB,SAAS;AACnC,aAAS,eAAe,aAAa,MAAM,GAAG,IAAI;AAClD,aAAS,aAAa;AACtB,aAAS,gBAAgB,oBAAI,KAAK;AAClC,aAAS,iBAAiB;AAE1B,QAAI,SAAS,IAAI;AACf,eAAS,SAAS;AAClB,eAAS,cAAc,oBAAI,KAAK;AAChC,cAAQ,sBAAsB;AAC9B,cAAQ,gBAAgB,oBAAI,KAAK;AAAA,IACnC,OAAO;AACL,YAAM,cAAc,kBAAkB,SAAS,MAAM,KAAK,SAAS,gBAAgB,SAAS;AAC5F,UAAI,aAAa;AACf,iBAAS,SAAS;AAClB,iBAAS,cAAc,mBAAmB,SAAS,aAAa;AAAA,MAClE,OAAO;AACL,iBAAS,SAAS;AAAA,MACpB;AACA,cAAQ,uBAAuB;AAC/B,cAAQ,gBAAgB,oBAAI,KAAK;AAEjC,UAAI,QAAQ,uBAAuB,KAAK,QAAQ,uBAAuB,QAAQ,sBAAsB;AACnG,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,aAAa,KAAK,IAAI,IAAI;AAChC,aAAS,aAAa;AACtB,aAAS,gBAAgB,oBAAI,KAAK;AAClC,aAAS,iBAAiB;AAC1B,aAAS,eAAe,iBAAiB,QAAQ,MAAM,UAAU;AAEjE,UAAM,cAAc,SAAS,gBAAgB,SAAS;AACtD,QAAI,aAAa;AACf,eAAS,SAAS;AAClB,eAAS,cAAc,mBAAmB,SAAS,aAAa;AAAA,IAClE,OAAO;AACL,eAAS,SAAS;AAAA,IACpB;AAEA,YAAQ,uBAAuB;AAC/B,YAAQ,gBAAgB,oBAAI,KAAK;AAEjC,QAAI,QAAQ,uBAAuB,KAAK,QAAQ,uBAAuB,QAAQ,sBAAsB;AACnG,cAAQ,WAAW;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,GAAG,MAAM;AACjB;AAEA,SAAS,kBAAkB,QAAyB;AAClD,MAAI,UAAU,OAAO,SAAS,IAAK,QAAO;AAC1C,MAAI,WAAW,OAAO,WAAW,IAAK,QAAO;AAC7C,MAAI,UAAU,IAAK,QAAO;AAC1B,SAAO;AACT;AAEA,SAAS,mBAAmB,eAA6B;AACvD,QAAM,YAAY;AAClB,QAAM,UAAU,YAAY,KAAK,IAAI,GAAG,gBAAgB,CAAC;AACzD,QAAM,SAAS,KAAK,OAAO,IAAI;AAC/B,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,UAAU,MAAM;AAC/C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|