@voltro/plugin-webhooks 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +235 -0
- package/dist/index.d.ts +52 -7
- package/dist/index.js +241 -225
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./signing-DUG4JWwk.js";
|
|
2
2
|
import { WebhookDeliveryNotFound as l, WebhookPayloadInvalid as u, WebhookPayloadUnrepresentable as d, WebhookPayloadVersionInvalid as f, WebhookSubscribeInvalid as p } from "./errors.js";
|
|
3
|
-
import { _voltroWebhookDeliveriesTable as m, _voltroWebhookRateWindowsTable as h, _voltroWebhookTargetsTable as
|
|
4
|
-
import { randomBytes as
|
|
5
|
-
import { Context as
|
|
6
|
-
import { and as
|
|
7
|
-
import { assertPublicUrl as
|
|
8
|
-
import { publishServerError as
|
|
9
|
-
import { createLogger as
|
|
10
|
-
import { Activity as
|
|
3
|
+
import { _voltroWebhookDeliveriesTable as m, _voltroWebhookRateWindowsTable as h, _voltroWebhookTargetsTable as ee, webhookTables as g } from "./mixin.js";
|
|
4
|
+
import { randomBytes as _, randomUUID as v } from "node:crypto";
|
|
5
|
+
import { Context as te, Effect as y, Either as ne, Schema as b } from "effect";
|
|
6
|
+
import { and as x, eq as S } from "@voltro/database";
|
|
7
|
+
import { assertPublicUrl as C } from "@voltro/integration-http";
|
|
8
|
+
import { publishServerError as re } from "@voltro/protocol";
|
|
9
|
+
import { createLogger as ie } from "@voltro/logger";
|
|
10
|
+
import { Activity as w, DurableClock as T, Workflow as ae } from "@effect/workflow";
|
|
11
11
|
//#region src/eventAudience.ts
|
|
12
|
-
var
|
|
12
|
+
var oe = (e) => e.webhook !== void 0, E = (e) => {
|
|
13
13
|
let t = e.webhook;
|
|
14
14
|
if (t !== void 0) return {
|
|
15
15
|
_tag: "outgoingEvent",
|
|
@@ -19,8 +19,8 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
19
19
|
...t.version === void 0 ? {} : { version: t.version },
|
|
20
20
|
...t.rateLimit === void 0 ? {} : { globalRateLimit: t.rateLimit }
|
|
21
21
|
};
|
|
22
|
-
},
|
|
23
|
-
let t =
|
|
22
|
+
}, se = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, D = (e) => {
|
|
23
|
+
let t = se.exec(e);
|
|
24
24
|
if (!t) throw Error(`invalid duration literal: ${e}`);
|
|
25
25
|
let n = Number(t[1]), r = t[2] ?? "s";
|
|
26
26
|
switch (r) {
|
|
@@ -31,7 +31,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
31
31
|
case "d": return n * 864e5;
|
|
32
32
|
default: throw Error(`unreachable unit: ${r}`);
|
|
33
33
|
}
|
|
34
|
-
},
|
|
34
|
+
}, O = [
|
|
35
35
|
408,
|
|
36
36
|
425,
|
|
37
37
|
429,
|
|
@@ -39,16 +39,16 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
39
39
|
502,
|
|
40
40
|
503,
|
|
41
41
|
504
|
|
42
|
-
],
|
|
43
|
-
if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ??
|
|
42
|
+
], k = (e, t, n) => {
|
|
43
|
+
if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ?? O).includes(n.status)) return null;
|
|
44
44
|
if (e.honourRetryAfter !== !1 && n?.retryAfterSeconds !== void 0) {
|
|
45
|
-
let t = n.retryAfterSeconds * 1e3, r =
|
|
45
|
+
let t = n.retryAfterSeconds * 1e3, r = D(e.maxDelay), i = Math.min(t, r);
|
|
46
46
|
return {
|
|
47
47
|
delayMs: i,
|
|
48
48
|
baseDelayMs: i
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
let r =
|
|
51
|
+
let r = D(e.initialDelay), i = D(e.maxDelay), a;
|
|
52
52
|
switch (e.strategy) {
|
|
53
53
|
case "fixed":
|
|
54
54
|
a = r;
|
|
@@ -71,7 +71,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
71
71
|
maxAttempts: 8,
|
|
72
72
|
initialDelay: "5s",
|
|
73
73
|
maxDelay: "1h",
|
|
74
|
-
retryOn:
|
|
74
|
+
retryOn: O,
|
|
75
75
|
honourRetryAfter: !0,
|
|
76
76
|
jitter: "full"
|
|
77
77
|
}), ce = () => ({
|
|
@@ -79,10 +79,10 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
79
79
|
maxAttempts: 120,
|
|
80
80
|
initialDelay: "30s",
|
|
81
81
|
maxDelay: "30s",
|
|
82
|
-
retryOn:
|
|
82
|
+
retryOn: O,
|
|
83
83
|
honourRetryAfter: !0,
|
|
84
84
|
jitter: "full"
|
|
85
|
-
}), j = class extends
|
|
85
|
+
}), j = class extends te.Tag("@voltro/webhooks/WebhooksService")() {}, le = 32, ue = 32, M = () => _(le).toString("hex"), N = (e) => e.events ?? (e.event === void 0 ? [] : [e.event]), P = (e) => {
|
|
86
86
|
let t;
|
|
87
87
|
try {
|
|
88
88
|
t = new URL(e.url);
|
|
@@ -97,14 +97,14 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
97
97
|
reason: `url protocol must be http or https, got ${t.protocol}`
|
|
98
98
|
});
|
|
99
99
|
if (process.env.NODE_ENV === "production") try {
|
|
100
|
-
|
|
100
|
+
C(e.url);
|
|
101
101
|
} catch (e) {
|
|
102
102
|
throw new p({
|
|
103
103
|
field: "url",
|
|
104
104
|
reason: e.message
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
|
-
let n =
|
|
107
|
+
let n = N(e);
|
|
108
108
|
if (n.length === 0) throw new p({
|
|
109
109
|
field: "event",
|
|
110
110
|
reason: "event id required"
|
|
@@ -121,9 +121,9 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
121
121
|
field: "events",
|
|
122
122
|
reason: "duplicate event — one row per event, so a repeat would deliver twice"
|
|
123
123
|
});
|
|
124
|
-
if (e.secret !== void 0 && e.secret.length <
|
|
124
|
+
if (e.secret !== void 0 && e.secret.length < ue) throw new p({
|
|
125
125
|
field: "secret",
|
|
126
|
-
reason: `secret must be at least ${
|
|
126
|
+
reason: `secret must be at least ${ue} chars`
|
|
127
127
|
});
|
|
128
128
|
if (e.retry !== void 0) {
|
|
129
129
|
if (e.retry.maxAttempts < 1) throw new p({
|
|
@@ -143,11 +143,11 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
143
143
|
field: "autoDisableAfter",
|
|
144
144
|
reason: `autoDisableAfter must be a positive integer, got ${e.autoDisableAfter}`
|
|
145
145
|
});
|
|
146
|
-
},
|
|
147
|
-
id:
|
|
146
|
+
}, F = (e, t, n, r) => ({
|
|
147
|
+
id: v(),
|
|
148
148
|
event: n ?? e.event ?? "",
|
|
149
149
|
url: e.url,
|
|
150
|
-
secret: r ?? e.secret ??
|
|
150
|
+
secret: r ?? e.secret ?? M(),
|
|
151
151
|
signing: e.signing ?? t?.defaultSigning ?? c(),
|
|
152
152
|
retry: e.retry ?? t?.defaultRetry ?? A(),
|
|
153
153
|
filter: e.filter ?? null,
|
|
@@ -162,14 +162,14 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
162
162
|
autoDisableReason: null,
|
|
163
163
|
payloadVersion: e.payloadVersion ?? t?.version ?? 1,
|
|
164
164
|
description: e.description ?? null
|
|
165
|
-
}),
|
|
165
|
+
}), de = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : 0, I = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : null, fe = (e) => {
|
|
166
166
|
if (typeof e != "string") return e;
|
|
167
167
|
try {
|
|
168
168
|
return JSON.parse(e);
|
|
169
169
|
} catch {
|
|
170
170
|
return e;
|
|
171
171
|
}
|
|
172
|
-
},
|
|
172
|
+
}, L = (e) => ({
|
|
173
173
|
id: String(e.id),
|
|
174
174
|
deliveryId: String(e.deliveryId),
|
|
175
175
|
targetId: String(e.targetId),
|
|
@@ -180,22 +180,22 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
180
180
|
responseStatus: e.responseStatus ?? null,
|
|
181
181
|
errorMessage: e.errorMessage ?? null,
|
|
182
182
|
latencyMs: e.latencyMs ?? null,
|
|
183
|
-
scheduledAt:
|
|
184
|
-
nextAttemptAt:
|
|
185
|
-
createdAt:
|
|
186
|
-
}),
|
|
183
|
+
scheduledAt: I(e.scheduledAt),
|
|
184
|
+
nextAttemptAt: I(e.nextAttemptAt),
|
|
185
|
+
createdAt: I(e.createdAt)
|
|
186
|
+
}), pe = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", R = (e, t) => {
|
|
187
187
|
if (e === null) return !0;
|
|
188
188
|
let n = { payload: t };
|
|
189
|
-
for (let [t, r] of Object.entries(e)) if (!me(
|
|
189
|
+
for (let [t, r] of Object.entries(e)) if (!he(me(n, t), r)) return !1;
|
|
190
190
|
return !0;
|
|
191
|
-
},
|
|
191
|
+
}, me = (e, t) => {
|
|
192
192
|
let n = t.split("."), r = e;
|
|
193
193
|
for (let e of n) {
|
|
194
194
|
if (typeof r != "object" || !r) return;
|
|
195
195
|
r = r[e];
|
|
196
196
|
}
|
|
197
197
|
return r;
|
|
198
|
-
},
|
|
198
|
+
}, he = (e, t) => {
|
|
199
199
|
if (typeof t == "object" && t && !Array.isArray(t)) {
|
|
200
200
|
let n = t;
|
|
201
201
|
if ("eq" in n) return e === n.eq;
|
|
@@ -206,42 +206,58 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
206
206
|
if ("in" in n && Array.isArray(n.in)) return n.in.includes(e);
|
|
207
207
|
}
|
|
208
208
|
return e === t;
|
|
209
|
-
},
|
|
209
|
+
}, z = (e, t) => e !== null && Object.entries(t).every(([t, n]) => e[t] === n), ge = async (e, t) => {
|
|
210
|
+
let n = (await e.store.query({
|
|
211
|
+
table: "_voltro_webhook_targets",
|
|
212
|
+
predicate: void 0,
|
|
213
|
+
order: [{
|
|
214
|
+
column: "createdAt",
|
|
215
|
+
direction: "asc"
|
|
216
|
+
}],
|
|
217
|
+
take: 1e3,
|
|
218
|
+
skip: void 0,
|
|
219
|
+
projection: void 0
|
|
220
|
+
})).filter((e) => z(e.scope, t));
|
|
221
|
+
if (n.length === 0) return;
|
|
222
|
+
let r = new Set(n.map((e) => e.secret));
|
|
223
|
+
if (r.size > 1) throw Error(`webhooks.subscribe: the scope ${JSON.stringify(t)} matches ${n.length} targets with ${r.size} different secrets, so it is not one endpoint. Pass \`secret\` explicitly, or narrow the scope.`);
|
|
224
|
+
return [...r][0];
|
|
225
|
+
}, _e = (e, t, n = {}) => {
|
|
210
226
|
let r = new Map((n.events ?? []).map((e) => [e.id, e])), i = {
|
|
211
227
|
subscribe: async (t) => {
|
|
212
|
-
|
|
213
|
-
let n =
|
|
214
|
-
for (let t of
|
|
228
|
+
P(t);
|
|
229
|
+
let n = N(t), i = t.secret === void 0 && t.scope !== void 0 ? await ge(e, t.scope) : void 0, a = t.secret ?? i ?? M(), o = n.map((e) => F(t, r.get(e), e, a));
|
|
230
|
+
for (let t of o) await e.store.insert("_voltro_webhook_targets", {
|
|
215
231
|
...t,
|
|
216
232
|
createdAt: /* @__PURE__ */ new Date(),
|
|
217
233
|
updatedAt: /* @__PURE__ */ new Date()
|
|
218
234
|
});
|
|
219
|
-
let
|
|
235
|
+
let s = o[0];
|
|
220
236
|
return {
|
|
221
|
-
id:
|
|
222
|
-
event:
|
|
223
|
-
url:
|
|
224
|
-
secret:
|
|
225
|
-
signing:
|
|
226
|
-
retry:
|
|
227
|
-
...
|
|
237
|
+
id: s.id,
|
|
238
|
+
event: s.event,
|
|
239
|
+
url: s.url,
|
|
240
|
+
secret: s.secret,
|
|
241
|
+
signing: s.signing,
|
|
242
|
+
retry: s.retry,
|
|
243
|
+
...o.length > 1 ? { targets: o.map((e) => ({
|
|
228
244
|
id: e.id,
|
|
229
245
|
event: e.event
|
|
230
246
|
})) } : {}
|
|
231
247
|
};
|
|
232
248
|
},
|
|
233
|
-
emit: async (n, i) => {
|
|
234
|
-
let
|
|
235
|
-
if (
|
|
236
|
-
let e =
|
|
237
|
-
if (
|
|
238
|
-
event:
|
|
249
|
+
emit: async (n, i, a) => {
|
|
250
|
+
let o = typeof n == "object" && n.kind === "event" ? E(n) : void 0, s = typeof n == "string" ? r.get(n) : o ?? n, c = typeof n == "string" ? n : n.id ?? n.name;
|
|
251
|
+
if (s !== void 0) {
|
|
252
|
+
let e = b.decodeUnknownEither(s.payload)(i, { errors: "all" });
|
|
253
|
+
if (ne.isLeft(e)) throw new u({
|
|
254
|
+
event: c,
|
|
239
255
|
issues: e.left.message
|
|
240
256
|
});
|
|
241
257
|
}
|
|
242
|
-
let
|
|
258
|
+
let l = v(), d = a?.tenantId, f = (await e.store.query({
|
|
243
259
|
table: "_voltro_webhook_targets",
|
|
244
|
-
predicate:
|
|
260
|
+
predicate: d == null ? S("event", c) : x(S("event", c), S("tenantId", d)),
|
|
245
261
|
order: [{
|
|
246
262
|
column: "createdAt",
|
|
247
263
|
direction: "asc"
|
|
@@ -249,16 +265,16 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
249
265
|
take: 1e3,
|
|
250
266
|
skip: void 0,
|
|
251
267
|
projection: void 0
|
|
252
|
-
})).filter((e) =>
|
|
253
|
-
for (let n of
|
|
254
|
-
let r =
|
|
268
|
+
})).filter((e) => R(e.filter, i)), p = [], m = JSON.stringify(i);
|
|
269
|
+
for (let n of f) {
|
|
270
|
+
let r = v();
|
|
255
271
|
n.active ? (await t({
|
|
256
272
|
deliveryId: r,
|
|
257
273
|
targetId: n.id,
|
|
258
|
-
event:
|
|
259
|
-
eventId:
|
|
260
|
-
payloadJson:
|
|
261
|
-
}),
|
|
274
|
+
event: c,
|
|
275
|
+
eventId: l,
|
|
276
|
+
payloadJson: m
|
|
277
|
+
}), p.push({
|
|
262
278
|
targetId: n.id,
|
|
263
279
|
deliveryId: r,
|
|
264
280
|
status: "dispatched"
|
|
@@ -267,29 +283,29 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
267
283
|
deliveryId: r,
|
|
268
284
|
targetId: n.id,
|
|
269
285
|
tenantId: n.tenantId ?? null,
|
|
270
|
-
event:
|
|
271
|
-
eventId:
|
|
286
|
+
event: c,
|
|
287
|
+
eventId: l,
|
|
272
288
|
attempt: 1,
|
|
273
289
|
status: "pending",
|
|
274
|
-
payload:
|
|
290
|
+
payload: m,
|
|
275
291
|
scheduledAt: /* @__PURE__ */ new Date(),
|
|
276
292
|
createdAt: /* @__PURE__ */ new Date(),
|
|
277
293
|
updatedAt: /* @__PURE__ */ new Date()
|
|
278
|
-
}),
|
|
294
|
+
}), p.push({
|
|
279
295
|
targetId: n.id,
|
|
280
296
|
deliveryId: r,
|
|
281
297
|
status: "queued"
|
|
282
298
|
}));
|
|
283
299
|
}
|
|
284
300
|
return {
|
|
285
|
-
eventId:
|
|
286
|
-
deliveries:
|
|
301
|
+
eventId: l,
|
|
302
|
+
deliveries: p
|
|
287
303
|
};
|
|
288
304
|
},
|
|
289
305
|
replay: async (n) => {
|
|
290
306
|
let r = (await e.store.query({
|
|
291
307
|
table: "_voltro_webhook_deliveries",
|
|
292
|
-
predicate:
|
|
308
|
+
predicate: S("deliveryId", n),
|
|
293
309
|
order: [{
|
|
294
310
|
column: "attempt",
|
|
295
311
|
direction: "asc"
|
|
@@ -303,7 +319,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
303
319
|
deliveryId: r.deliveryId,
|
|
304
320
|
targetId: r.targetId,
|
|
305
321
|
event: r.event,
|
|
306
|
-
eventId: r.eventId ??
|
|
322
|
+
eventId: r.eventId ?? v(),
|
|
307
323
|
payloadJson: typeof r.payload == "string" ? r.payload : JSON.stringify(r.payload),
|
|
308
324
|
attemptEpoch: Date.now()
|
|
309
325
|
});
|
|
@@ -317,7 +333,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
317
333
|
take: 1e3,
|
|
318
334
|
skip: void 0,
|
|
319
335
|
projection: void 0
|
|
320
|
-
})).filter((e) => e.scope
|
|
336
|
+
})).filter((e) => z(e.scope, t.scope)).map((e) => e.id);
|
|
321
337
|
if (n.length === 0) throw Error(`webhooks: no target matches scope ${JSON.stringify(t.scope)} — the operation would have silently done nothing`);
|
|
322
338
|
return n;
|
|
323
339
|
},
|
|
@@ -338,7 +354,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
338
354
|
});
|
|
339
355
|
let n = await e.store.query({
|
|
340
356
|
table: "_voltro_webhook_deliveries",
|
|
341
|
-
predicate: S(
|
|
357
|
+
predicate: x(S("targetId", r), S("status", "pending")),
|
|
342
358
|
order: [{
|
|
343
359
|
column: "createdAt",
|
|
344
360
|
direction: "asc"
|
|
@@ -351,17 +367,17 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
351
367
|
deliveryId: e.deliveryId,
|
|
352
368
|
targetId: r,
|
|
353
369
|
event: e.event,
|
|
354
|
-
eventId: e.eventId ??
|
|
370
|
+
eventId: e.eventId ?? v(),
|
|
355
371
|
payloadJson: typeof e.payload == "string" ? e.payload : JSON.stringify(e.payload),
|
|
356
372
|
attemptEpoch: i
|
|
357
373
|
});
|
|
358
374
|
}
|
|
359
375
|
},
|
|
360
376
|
deleteTarget: async (t) => {
|
|
361
|
-
for (let n of await i.resolveTargets(t)) await e.store.delete("_voltro_webhook_targets", n), await e.store.deleteMany("_voltro_webhook_deliveries", { where: S(
|
|
377
|
+
for (let n of await i.resolveTargets(t)) await e.store.delete("_voltro_webhook_targets", n), await e.store.deleteMany("_voltro_webhook_deliveries", { where: x(S("targetId", n), S("status", "pending")) });
|
|
362
378
|
},
|
|
363
379
|
rotateSecret: async (t) => {
|
|
364
|
-
let n =
|
|
380
|
+
let n = M();
|
|
365
381
|
for (let r of await i.resolveTargets(t)) await e.store.update("_voltro_webhook_targets", r, {
|
|
366
382
|
secret: n,
|
|
367
383
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -369,7 +385,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
369
385
|
return { secret: n };
|
|
370
386
|
},
|
|
371
387
|
updateTarget: async (t, n) => {
|
|
372
|
-
if (n.url !== void 0 &&
|
|
388
|
+
if (n.url !== void 0 && P({
|
|
373
389
|
event: "x",
|
|
374
390
|
url: n.url
|
|
375
391
|
}), n.rateLimitPerMinute !== void 0 && n.rateLimitPerMinute !== null && (!Number.isInteger(n.rateLimitPerMinute) || n.rateLimitPerMinute < 1)) throw Error("updateTarget: rateLimitPerMinute must be a positive integer or null");
|
|
@@ -389,14 +405,14 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
389
405
|
testTarget: async (n, r) => {
|
|
390
406
|
let i = (await e.store.query({
|
|
391
407
|
table: "_voltro_webhook_targets",
|
|
392
|
-
predicate:
|
|
408
|
+
predicate: S("id", n),
|
|
393
409
|
order: void 0,
|
|
394
410
|
take: 1,
|
|
395
411
|
skip: void 0,
|
|
396
412
|
projection: void 0
|
|
397
413
|
}))[0];
|
|
398
414
|
if (i === void 0) throw Error(`testTarget: no target ${n}`);
|
|
399
|
-
let a =
|
|
415
|
+
let a = v(), o = JSON.stringify(r ?? {
|
|
400
416
|
test: !0,
|
|
401
417
|
targetId: n,
|
|
402
418
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -405,7 +421,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
405
421
|
deliveryId: a,
|
|
406
422
|
targetId: i.id,
|
|
407
423
|
event: i.event,
|
|
408
|
-
eventId:
|
|
424
|
+
eventId: v(),
|
|
409
425
|
payloadJson: o
|
|
410
426
|
}) : await e.store.insert("_voltro_webhook_deliveries", {
|
|
411
427
|
id: `${a}:1`,
|
|
@@ -425,7 +441,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
425
441
|
listDeliveries: async (t) => {
|
|
426
442
|
let n = t?.scope === void 0 ? void 0 : new Set(await i.resolveTargets({ scope: t.scope })), r = await e.store.query({
|
|
427
443
|
table: "_voltro_webhook_deliveries",
|
|
428
|
-
predicate: t?.targetId === void 0 ? void 0 :
|
|
444
|
+
predicate: t?.targetId === void 0 ? void 0 : S("targetId", t.targetId),
|
|
429
445
|
order: [{
|
|
430
446
|
column: "createdAt",
|
|
431
447
|
direction: "desc"
|
|
@@ -434,20 +450,20 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
434
450
|
skip: void 0,
|
|
435
451
|
projection: void 0
|
|
436
452
|
}), a = t?.since?.getTime();
|
|
437
|
-
return r.filter((e) => n === void 0 || n.has(String(e.targetId))).filter((e) => t?.status === void 0 || e.status === t.status).filter((e) => a === void 0 ||
|
|
453
|
+
return r.filter((e) => n === void 0 || n.has(String(e.targetId))).filter((e) => t?.status === void 0 || e.status === t.status).filter((e) => a === void 0 || de(e.createdAt) >= a).slice(0, t?.limit ?? 200).map(L);
|
|
438
454
|
},
|
|
439
455
|
getDelivery: async (t) => {
|
|
440
456
|
let n = (await e.store.query({
|
|
441
457
|
table: "_voltro_webhook_deliveries",
|
|
442
|
-
predicate:
|
|
458
|
+
predicate: S("id", t),
|
|
443
459
|
order: void 0,
|
|
444
460
|
take: 1,
|
|
445
461
|
skip: void 0,
|
|
446
462
|
projection: void 0
|
|
447
463
|
}))[0];
|
|
448
464
|
return n === void 0 ? null : {
|
|
449
|
-
...
|
|
450
|
-
payload:
|
|
465
|
+
...L(n),
|
|
466
|
+
payload: fe(n.payload),
|
|
451
467
|
responseBody: n.responseBody ?? null
|
|
452
468
|
};
|
|
453
469
|
},
|
|
@@ -461,7 +477,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
461
477
|
listTargets: async (t, n) => {
|
|
462
478
|
let r = await e.store.query({
|
|
463
479
|
table: "_voltro_webhook_targets",
|
|
464
|
-
predicate: t === void 0 ? void 0 :
|
|
480
|
+
predicate: t === void 0 ? void 0 : S("event", t),
|
|
465
481
|
order: [{
|
|
466
482
|
column: "createdAt",
|
|
467
483
|
direction: "desc"
|
|
@@ -487,15 +503,15 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
487
503
|
}
|
|
488
504
|
};
|
|
489
505
|
return i;
|
|
490
|
-
},
|
|
506
|
+
}, ve = y.gen(function* () {
|
|
491
507
|
return yield* j;
|
|
492
|
-
}),
|
|
508
|
+
}), ye = (e) => {
|
|
493
509
|
if (e.webhooks === void 0) throw Error("useWebhooks: `ctx.webhooks` is not set. Add @voltro/plugin-webhooks to your app.config.ts plugin list and declare at least one *.webhook.tsx file.");
|
|
494
510
|
return e.webhooks;
|
|
495
|
-
},
|
|
511
|
+
}, be = 1e4, B = class {
|
|
496
512
|
capacity;
|
|
497
513
|
cache = /* @__PURE__ */ new Map();
|
|
498
|
-
constructor(e =
|
|
514
|
+
constructor(e = be) {
|
|
499
515
|
this.capacity = e;
|
|
500
516
|
}
|
|
501
517
|
evictExpired() {
|
|
@@ -541,9 +557,9 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
541
557
|
status: e,
|
|
542
558
|
contentType: "application/json; charset=utf-8",
|
|
543
559
|
body: JSON.stringify(t)
|
|
544
|
-
}),
|
|
560
|
+
}), xe = (e, t) => {
|
|
545
561
|
let n = e.provider, r = e.signature ?? n?.signature ?? null, i = e.idempotency ?? n?.idempotency ?? null, o = e.bodyType ?? n?.bodyType ?? "json", s = t.idempotencyCache ?? H(), c = W(i?.ttl), l = t.log ?? ((e) => {
|
|
546
|
-
|
|
562
|
+
ie({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
|
|
547
563
|
status: e.status,
|
|
548
564
|
signatureOk: e.signatureOk,
|
|
549
565
|
idempotency: e.idempotency,
|
|
@@ -616,7 +632,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
616
632
|
}
|
|
617
633
|
let p;
|
|
618
634
|
try {
|
|
619
|
-
p =
|
|
635
|
+
p = b.decodeUnknownSync(e.payload)(f);
|
|
620
636
|
} catch (t) {
|
|
621
637
|
let n = G(422, {
|
|
622
638
|
error: "schema validation failed",
|
|
@@ -694,7 +710,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
694
710
|
idempotency: h,
|
|
695
711
|
durationMs: Date.now() - u,
|
|
696
712
|
errorMessage: t.message
|
|
697
|
-
}),
|
|
713
|
+
}), re({
|
|
698
714
|
error: t,
|
|
699
715
|
source: "webhook",
|
|
700
716
|
name: e.id,
|
|
@@ -702,9 +718,9 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
702
718
|
}), n;
|
|
703
719
|
}
|
|
704
720
|
};
|
|
705
|
-
},
|
|
721
|
+
}, Se = (e) => `/webhooks/${e}`, K = "_voltro_webhook_rate_windows", q = 6e4, Ce = (e, t) => `${e}@${t}`, J = async (e, t, n) => (await e.query({
|
|
706
722
|
table: "_voltro_webhook_rate_windows",
|
|
707
|
-
predicate: S(
|
|
723
|
+
predicate: x(S("scope", t), S("bucket", n)),
|
|
708
724
|
order: [],
|
|
709
725
|
take: 1,
|
|
710
726
|
skip: void 0,
|
|
@@ -715,7 +731,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
715
731
|
let i = await J(e, t.key, n);
|
|
716
732
|
if (i === null) {
|
|
717
733
|
await e.insertIgnore(K, {
|
|
718
|
-
id:
|
|
734
|
+
id: Ce(t.key, n),
|
|
719
735
|
scope: t.key,
|
|
720
736
|
bucket: n,
|
|
721
737
|
count: 0,
|
|
@@ -728,20 +744,20 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
728
744
|
if (await e.updateMany("_voltro_webhook_rate_windows", {
|
|
729
745
|
count: i.count + 1,
|
|
730
746
|
updatedAt: /* @__PURE__ */ new Date()
|
|
731
|
-
}, { where: S(
|
|
747
|
+
}, { where: x(S("id", i.id), S("count", i.count)) }) === 1) return !0;
|
|
732
748
|
}
|
|
733
749
|
throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${Y} attempts`);
|
|
734
|
-
},
|
|
750
|
+
}, we = async (e, t, n) => {
|
|
735
751
|
for (let r = 0; r < Y; r++) {
|
|
736
752
|
r > 0 && await new Promise((e) => setTimeout(e, r));
|
|
737
753
|
let i = await J(e, t, n);
|
|
738
754
|
if (i === null || i.count <= 0 || await e.updateMany("_voltro_webhook_rate_windows", {
|
|
739
755
|
count: i.count - 1,
|
|
740
756
|
updatedAt: /* @__PURE__ */ new Date()
|
|
741
|
-
}, { where: S(
|
|
757
|
+
}, { where: x(S("id", i.id), S("count", i.count)) }) === 1) return;
|
|
742
758
|
}
|
|
743
759
|
throw Error(`webhook rate window: release contention on (${t}) exceeded ${Y} attempts`);
|
|
744
|
-
},
|
|
760
|
+
}, Te = async (e, t, n, r = q) => {
|
|
745
761
|
if (t.length === 0) return {
|
|
746
762
|
acquired: !0,
|
|
747
763
|
retryInMs: 0
|
|
@@ -752,7 +768,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
752
768
|
a.push(o);
|
|
753
769
|
continue;
|
|
754
770
|
}
|
|
755
|
-
for (let t of a) await
|
|
771
|
+
for (let t of a) await we(e, t.key, i);
|
|
756
772
|
return {
|
|
757
773
|
acquired: !1,
|
|
758
774
|
retryInMs: (i + 1) * r - n
|
|
@@ -762,7 +778,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
762
778
|
acquired: !0,
|
|
763
779
|
retryInMs: 0
|
|
764
780
|
};
|
|
765
|
-
},
|
|
781
|
+
}, Ee = (e, t) => {
|
|
766
782
|
if (e === "json") return {
|
|
767
783
|
contentType: "application/json",
|
|
768
784
|
bytes: Buffer.from(t, "utf8")
|
|
@@ -778,40 +794,40 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
778
794
|
}
|
|
779
795
|
return e === "form" ? {
|
|
780
796
|
contentType: "application/x-www-form-urlencoded",
|
|
781
|
-
bytes: Buffer.from(
|
|
797
|
+
bytes: Buffer.from(De(n), "utf8")
|
|
782
798
|
} : {
|
|
783
799
|
contentType: "application/xml",
|
|
784
|
-
bytes: Buffer.from(
|
|
800
|
+
bytes: Buffer.from(ke(n), "utf8")
|
|
785
801
|
};
|
|
786
|
-
},
|
|
802
|
+
}, De = (e) => {
|
|
787
803
|
if (typeof e != "object" || !e || Array.isArray(e)) throw new d({
|
|
788
804
|
format: "form",
|
|
789
|
-
reason: `form encoding requires a JSON object at the top level, got ${
|
|
805
|
+
reason: `form encoding requires a JSON object at the top level, got ${Me(e)}`
|
|
790
806
|
});
|
|
791
807
|
let t = new URLSearchParams();
|
|
792
|
-
for (let [n, r] of Object.entries(e))
|
|
808
|
+
for (let [n, r] of Object.entries(e)) Z(t, n, r);
|
|
793
809
|
return t.toString();
|
|
794
|
-
},
|
|
810
|
+
}, Z = (e, t, n) => {
|
|
795
811
|
if (n === null) {
|
|
796
812
|
e.append(t, "");
|
|
797
813
|
return;
|
|
798
814
|
}
|
|
799
815
|
if (Array.isArray(n)) {
|
|
800
|
-
n.forEach((n, r) =>
|
|
816
|
+
n.forEach((n, r) => Z(e, `${t}[${r}]`, n));
|
|
801
817
|
return;
|
|
802
818
|
}
|
|
803
819
|
if (typeof n == "object") {
|
|
804
|
-
for (let [r, i] of Object.entries(n))
|
|
820
|
+
for (let [r, i] of Object.entries(n)) Z(e, `${t}[${r}]`, i);
|
|
805
821
|
return;
|
|
806
822
|
}
|
|
807
823
|
e.append(t, String(n));
|
|
808
|
-
},
|
|
809
|
-
if (!
|
|
824
|
+
}, Oe = /^[A-Za-z_][A-Za-z0-9_.-]*$/, ke = (e) => `<?xml version="1.0" encoding="UTF-8"?>${Q("webhook", e)}`, Q = (e, t) => {
|
|
825
|
+
if (!Oe.test(e)) throw new d({
|
|
810
826
|
format: "xml",
|
|
811
827
|
reason: `object key ${JSON.stringify(e)} is not a valid XML element name`
|
|
812
828
|
});
|
|
813
|
-
return `<${e}>${
|
|
814
|
-
},
|
|
829
|
+
return `<${e}>${Ae(e, t)}</${e}>`;
|
|
830
|
+
}, Ae = (e, t) => t == null ? "" : Array.isArray(t) ? t.map((e) => Q("item", e)).join("") : typeof t == "object" ? Object.entries(t).map(([e, t]) => Q(e, t)).join("") : je(String(t)), je = (e) => e.replace(/[&<>"']/g, (e) => {
|
|
815
831
|
switch (e) {
|
|
816
832
|
case "&": return "&";
|
|
817
833
|
case "<": return "<";
|
|
@@ -819,17 +835,17 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
819
835
|
case "\"": return """;
|
|
820
836
|
default: return "'";
|
|
821
837
|
}
|
|
822
|
-
}),
|
|
838
|
+
}), Me = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, Ne = "_voltro_webhook_targets", Pe = 32, Fe = async (e, t) => (await e.query({
|
|
823
839
|
table: "_voltro_webhook_targets",
|
|
824
|
-
predicate:
|
|
840
|
+
predicate: S("id", t),
|
|
825
841
|
order: [],
|
|
826
842
|
take: 1,
|
|
827
843
|
skip: void 0,
|
|
828
844
|
projection: void 0
|
|
829
|
-
}))[0] ?? null,
|
|
830
|
-
for (let a = 0; a <
|
|
845
|
+
}))[0] ?? null, $ = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
|
|
846
|
+
for (let a = 0; a < Pe; a++) {
|
|
831
847
|
a > 0 && await new Promise((e) => setTimeout(e, a));
|
|
832
|
-
let o = await
|
|
848
|
+
let o = await Fe(e, t);
|
|
833
849
|
if (o === null) return {
|
|
834
850
|
consecutiveFailures: 0,
|
|
835
851
|
autoDisabled: !1
|
|
@@ -839,7 +855,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
839
855
|
if (s === 0 || await e.updateMany("_voltro_webhook_targets", {
|
|
840
856
|
consecutiveFailures: 0,
|
|
841
857
|
updatedAt: i
|
|
842
|
-
}, { where: S(
|
|
858
|
+
}, { where: x(S("id", t), S("consecutiveFailures", s)) }) === 1) return {
|
|
843
859
|
consecutiveFailures: 0,
|
|
844
860
|
autoDisabled: !1
|
|
845
861
|
};
|
|
@@ -849,68 +865,68 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
849
865
|
consecutiveFailures: c,
|
|
850
866
|
updatedAt: i
|
|
851
867
|
};
|
|
852
|
-
if (u && (d.active = !1, d.autoDisabledAt = i, d.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", d, { where: S(
|
|
868
|
+
if (u && (d.active = !1, d.autoDisabledAt = i, d.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", d, { where: x(S("id", t), S("consecutiveFailures", s)) }) === 1) return {
|
|
853
869
|
consecutiveFailures: c,
|
|
854
870
|
autoDisabled: u
|
|
855
871
|
};
|
|
856
872
|
}
|
|
857
|
-
throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${
|
|
858
|
-
},
|
|
859
|
-
status:
|
|
860
|
-
body:
|
|
861
|
-
latencyMs:
|
|
862
|
-
retryAfterSec:
|
|
863
|
-
transportError:
|
|
864
|
-
encodeError:
|
|
865
|
-
}),
|
|
866
|
-
outcome:
|
|
867
|
-
delayMs:
|
|
868
|
-
reason:
|
|
869
|
-
autoDisabled:
|
|
870
|
-
consecutiveFailures:
|
|
871
|
-
}),
|
|
872
|
-
acquired:
|
|
873
|
-
retryInMs:
|
|
874
|
-
}),
|
|
873
|
+
throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${Pe} attempts`);
|
|
874
|
+
}, Ie = b.Struct({
|
|
875
|
+
status: b.Number,
|
|
876
|
+
body: b.String,
|
|
877
|
+
latencyMs: b.Number,
|
|
878
|
+
retryAfterSec: b.Union(b.Number, b.Undefined),
|
|
879
|
+
transportError: b.Union(b.String, b.Undefined),
|
|
880
|
+
encodeError: b.Union(b.String, b.Undefined)
|
|
881
|
+
}), Le = b.Struct({
|
|
882
|
+
outcome: b.Literal("succeeded", "failed", "retry"),
|
|
883
|
+
delayMs: b.Union(b.Number, b.Undefined),
|
|
884
|
+
reason: b.Union(b.String, b.Undefined),
|
|
885
|
+
autoDisabled: b.Union(b.Boolean, b.Undefined),
|
|
886
|
+
consecutiveFailures: b.Union(b.Number, b.Undefined)
|
|
887
|
+
}), Re = b.Struct({
|
|
888
|
+
acquired: b.Boolean,
|
|
889
|
+
retryInMs: b.Number
|
|
890
|
+
}), ze = ae.make({
|
|
875
891
|
name: "voltro.deliverWebhook",
|
|
876
892
|
payload: {
|
|
877
|
-
deliveryId:
|
|
878
|
-
targetId:
|
|
879
|
-
event:
|
|
880
|
-
eventId:
|
|
881
|
-
payloadJson:
|
|
882
|
-
attemptEpoch:
|
|
893
|
+
deliveryId: b.String,
|
|
894
|
+
targetId: b.String,
|
|
895
|
+
event: b.String,
|
|
896
|
+
eventId: b.String,
|
|
897
|
+
payloadJson: b.String,
|
|
898
|
+
attemptEpoch: b.optionalWith(b.Number, { default: () => 0 })
|
|
883
899
|
},
|
|
884
|
-
success:
|
|
885
|
-
finalStatus:
|
|
886
|
-
attempts:
|
|
900
|
+
success: b.Struct({
|
|
901
|
+
finalStatus: b.Literal("succeeded", "failed", "deferred"),
|
|
902
|
+
attempts: b.Number
|
|
887
903
|
}),
|
|
888
904
|
idempotencyKey: ({ deliveryId: e, attemptEpoch: t }) => `voltro.deliverWebhook:${e}:${t ?? 0}`
|
|
889
|
-
}),
|
|
890
|
-
let { deliveryId: i, targetId: a, event: s, eventId: c, payloadJson: l } = n, u =
|
|
891
|
-
return
|
|
892
|
-
let n = yield*
|
|
905
|
+
}), Be = (e, t = {}) => (n, r) => {
|
|
906
|
+
let { deliveryId: i, targetId: a, event: s, eventId: c, payloadJson: l } = n, u = ie({ scope: `webhook:${i}` });
|
|
907
|
+
return y.gen(function* () {
|
|
908
|
+
let n = yield* w.make({
|
|
893
909
|
name: "fetch-target",
|
|
894
|
-
success:
|
|
895
|
-
id:
|
|
896
|
-
event:
|
|
897
|
-
url:
|
|
898
|
-
secret:
|
|
899
|
-
signing:
|
|
900
|
-
retry:
|
|
901
|
-
headers:
|
|
902
|
-
key:
|
|
903
|
-
value:
|
|
904
|
-
}),
|
|
905
|
-
rateLimitPerMinute:
|
|
906
|
-
active:
|
|
907
|
-
format:
|
|
908
|
-
tenantId:
|
|
910
|
+
success: b.Union(b.Null, b.Struct({
|
|
911
|
+
id: b.String,
|
|
912
|
+
event: b.String,
|
|
913
|
+
url: b.String,
|
|
914
|
+
secret: b.String,
|
|
915
|
+
signing: b.Any,
|
|
916
|
+
retry: b.Any,
|
|
917
|
+
headers: b.Union(b.Record({
|
|
918
|
+
key: b.String,
|
|
919
|
+
value: b.String
|
|
920
|
+
}), b.Null),
|
|
921
|
+
rateLimitPerMinute: b.Union(b.Number, b.Null),
|
|
922
|
+
active: b.Boolean,
|
|
923
|
+
format: b.Literal("json", "form", "xml"),
|
|
924
|
+
tenantId: b.Union(b.String, b.Null)
|
|
909
925
|
})),
|
|
910
|
-
execute:
|
|
926
|
+
execute: y.tryPromise({
|
|
911
927
|
try: async () => (await e.store.query({
|
|
912
928
|
table: "_voltro_webhook_targets",
|
|
913
|
-
predicate:
|
|
929
|
+
predicate: S("id", a),
|
|
914
930
|
order: [{
|
|
915
931
|
column: "createdAt",
|
|
916
932
|
direction: "asc"
|
|
@@ -924,7 +940,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
924
940
|
event: s,
|
|
925
941
|
cause: String(e)
|
|
926
942
|
}), /* @__PURE__ */ Error(`fetch-target failed: ${e.message}`))
|
|
927
|
-
}).pipe(
|
|
943
|
+
}).pipe(y.orDie)
|
|
928
944
|
});
|
|
929
945
|
if (n === null) return {
|
|
930
946
|
finalStatus: "failed",
|
|
@@ -949,75 +965,75 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
949
965
|
...o
|
|
950
966
|
});
|
|
951
967
|
};
|
|
952
|
-
if (n.active !== !0) return yield*
|
|
968
|
+
if (n.active !== !0) return yield* w.make({
|
|
953
969
|
name: "record-paused-pending",
|
|
954
|
-
success:
|
|
955
|
-
execute:
|
|
970
|
+
success: b.Void,
|
|
971
|
+
execute: y.tryPromise({
|
|
956
972
|
try: () => r(`${i}:1`, 1, { status: "pending" }),
|
|
957
973
|
catch: (e) => /* @__PURE__ */ Error(`record-paused-pending failed: ${e.message}`)
|
|
958
|
-
}).pipe(
|
|
974
|
+
}).pipe(y.orDie)
|
|
959
975
|
}), {
|
|
960
976
|
finalStatus: "deferred",
|
|
961
977
|
attempts: 0
|
|
962
978
|
};
|
|
963
|
-
let f = (e) => typeof e == "string" ? JSON.parse(e) : e, p = f(n.retry), m = f(n.signing), h = n.headers === null ? null : f(n.headers),
|
|
979
|
+
let f = (e) => typeof e == "string" ? JSON.parse(e) : e, p = f(n.retry), m = f(n.signing), h = n.headers === null ? null : f(n.headers), ee = t.rateWindowMs ?? 6e4, g = t.events?.find((e) => e.id === s)?.globalRateLimit, _ = [...typeof n.rateLimitPerMinute == "number" && n.rateLimitPerMinute > 0 ? [{
|
|
964
980
|
key: `target:${n.id}`,
|
|
965
981
|
limit: n.rateLimitPerMinute
|
|
966
|
-
}] : [], ...
|
|
982
|
+
}] : [], ...g !== void 0 && g.perMinute > 0 ? [{
|
|
967
983
|
key: `event:${s}`,
|
|
968
|
-
limit:
|
|
984
|
+
limit: g.perMinute
|
|
969
985
|
}] : []];
|
|
970
986
|
for (let t = 1; t <= p.maxAttempts; t++) {
|
|
971
987
|
let f = `${i}:${t}`;
|
|
972
|
-
if (
|
|
973
|
-
let i = yield*
|
|
988
|
+
if (_.length > 0) for (let n = 0;; n++) {
|
|
989
|
+
let i = yield* w.make({
|
|
974
990
|
name: `rate-acquire-${t}-${n}`,
|
|
975
|
-
success:
|
|
976
|
-
execute:
|
|
977
|
-
try: () =>
|
|
991
|
+
success: Re,
|
|
992
|
+
execute: y.tryPromise({
|
|
993
|
+
try: () => Te(e.store, _, Date.now(), ee),
|
|
978
994
|
catch: (e) => (u.debug("rate-acquire raw error", {
|
|
979
995
|
targetId: a,
|
|
980
996
|
event: s,
|
|
981
997
|
attempt: t,
|
|
982
998
|
cause: String(e)
|
|
983
999
|
}), /* @__PURE__ */ Error(`rate-acquire failed: ${e.message}`))
|
|
984
|
-
}).pipe(
|
|
1000
|
+
}).pipe(y.orDie)
|
|
985
1001
|
});
|
|
986
1002
|
if (i.acquired) break;
|
|
987
|
-
yield*
|
|
1003
|
+
yield* w.make({
|
|
988
1004
|
name: `record-rate-deferral-${t}-${n}`,
|
|
989
|
-
success:
|
|
990
|
-
execute:
|
|
1005
|
+
success: b.Void,
|
|
1006
|
+
execute: y.tryPromise({
|
|
991
1007
|
try: () => r(f, t, {
|
|
992
1008
|
status: "pending",
|
|
993
1009
|
nextAttemptAt: new Date(Date.now() + i.retryInMs)
|
|
994
1010
|
}),
|
|
995
1011
|
catch: (e) => /* @__PURE__ */ Error(`record-rate-deferral failed: ${e.message}`)
|
|
996
|
-
}).pipe(
|
|
997
|
-
}), yield*
|
|
1012
|
+
}).pipe(y.orDie)
|
|
1013
|
+
}), yield* T.sleep({
|
|
998
1014
|
name: `rate-window-sleep-${t}-${n}`,
|
|
999
1015
|
duration: `${i.retryInMs} millis`
|
|
1000
1016
|
});
|
|
1001
1017
|
}
|
|
1002
|
-
yield*
|
|
1018
|
+
yield* w.make({
|
|
1003
1019
|
name: `record-attempt-start-${t}`,
|
|
1004
|
-
success:
|
|
1005
|
-
execute:
|
|
1020
|
+
success: b.Void,
|
|
1021
|
+
execute: y.tryPromise({
|
|
1006
1022
|
try: () => r(f, t, {
|
|
1007
1023
|
status: "inFlight",
|
|
1008
1024
|
nextAttemptAt: null,
|
|
1009
1025
|
scheduledAt: /* @__PURE__ */ new Date()
|
|
1010
1026
|
}),
|
|
1011
1027
|
catch: (e) => /* @__PURE__ */ Error(`record-attempt-start failed: ${e.message}`)
|
|
1012
|
-
}).pipe(
|
|
1028
|
+
}).pipe(y.orDie)
|
|
1013
1029
|
});
|
|
1014
|
-
let
|
|
1030
|
+
let g = yield* w.make({
|
|
1015
1031
|
name: `sign-and-post-${t}`,
|
|
1016
|
-
success:
|
|
1017
|
-
execute:
|
|
1032
|
+
success: Ie,
|
|
1033
|
+
execute: y.promise(async () => {
|
|
1018
1034
|
let e = Date.now(), r;
|
|
1019
1035
|
try {
|
|
1020
|
-
r =
|
|
1036
|
+
r = Ee(n.format, l);
|
|
1021
1037
|
} catch (t) {
|
|
1022
1038
|
if (t instanceof d) return {
|
|
1023
1039
|
status: 0,
|
|
@@ -1030,7 +1046,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
1030
1046
|
throw t;
|
|
1031
1047
|
}
|
|
1032
1048
|
let a = Buffer.from(r.bytes), { headerName: u, headerValue: f } = o(m, a, n.secret);
|
|
1033
|
-
process.env.NODE_ENV === "production" &&
|
|
1049
|
+
process.env.NODE_ENV === "production" && C(n.url);
|
|
1034
1050
|
try {
|
|
1035
1051
|
let o = await fetch(n.url, {
|
|
1036
1052
|
method: "POST",
|
|
@@ -1065,18 +1081,18 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
1065
1081
|
};
|
|
1066
1082
|
}
|
|
1067
1083
|
})
|
|
1068
|
-
}),
|
|
1084
|
+
}), v = yield* w.make({
|
|
1069
1085
|
name: `classify-and-record-${t}`,
|
|
1070
|
-
success:
|
|
1071
|
-
execute:
|
|
1086
|
+
success: Le,
|
|
1087
|
+
execute: y.tryPromise({
|
|
1072
1088
|
try: async () => {
|
|
1073
|
-
let r =
|
|
1089
|
+
let r = g.status >= 200 && g.status < 300, i = g.transportError !== void 0, o = g.encodeError !== void 0, s = (t, n) => $(e.store, a, t, n);
|
|
1074
1090
|
if (r) {
|
|
1075
1091
|
await e.store.update("_voltro_webhook_deliveries", f, {
|
|
1076
1092
|
status: "succeeded",
|
|
1077
|
-
responseStatus:
|
|
1078
|
-
responseBody:
|
|
1079
|
-
latencyMs:
|
|
1093
|
+
responseStatus: g.status,
|
|
1094
|
+
responseBody: g.body,
|
|
1095
|
+
latencyMs: g.latencyMs,
|
|
1080
1096
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1081
1097
|
});
|
|
1082
1098
|
let t = await s(!0, "");
|
|
@@ -1088,18 +1104,18 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
1088
1104
|
consecutiveFailures: t.consecutiveFailures
|
|
1089
1105
|
};
|
|
1090
1106
|
}
|
|
1091
|
-
let c = o ? null :
|
|
1092
|
-
...i ? {} : { status:
|
|
1093
|
-
...
|
|
1107
|
+
let c = o ? null : k(p, t, {
|
|
1108
|
+
...i ? {} : { status: g.status },
|
|
1109
|
+
...g.retryAfterSec === void 0 ? {} : { retryAfterSeconds: g.retryAfterSec }
|
|
1094
1110
|
});
|
|
1095
1111
|
if (c === null) {
|
|
1096
|
-
let t = o ? `encode (${n.format}): ${
|
|
1112
|
+
let t = o ? `encode (${n.format}): ${g.encodeError}` : i ? `transport: ${g.transportError}` : `http ${g.status}: ${g.body.slice(0, 200)}`;
|
|
1097
1113
|
await e.store.update("_voltro_webhook_deliveries", f, {
|
|
1098
1114
|
status: "failed",
|
|
1099
|
-
responseStatus: i || o ? null :
|
|
1100
|
-
responseBody: i || o ? null :
|
|
1101
|
-
errorMessage: o ? t :
|
|
1102
|
-
latencyMs:
|
|
1115
|
+
responseStatus: i || o ? null : g.status,
|
|
1116
|
+
responseBody: i || o ? null : g.body,
|
|
1117
|
+
errorMessage: o ? t : g.transportError ?? null,
|
|
1118
|
+
latencyMs: g.latencyMs,
|
|
1103
1119
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1104
1120
|
});
|
|
1105
1121
|
let r = await s(!1, t);
|
|
@@ -1113,10 +1129,10 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
1113
1129
|
}
|
|
1114
1130
|
return await e.store.update("_voltro_webhook_deliveries", f, {
|
|
1115
1131
|
status: "retryScheduled",
|
|
1116
|
-
responseStatus: i ? null :
|
|
1117
|
-
responseBody: i ? null :
|
|
1118
|
-
errorMessage:
|
|
1119
|
-
latencyMs:
|
|
1132
|
+
responseStatus: i ? null : g.status,
|
|
1133
|
+
responseBody: i ? null : g.body,
|
|
1134
|
+
errorMessage: g.transportError ?? null,
|
|
1135
|
+
latencyMs: g.latencyMs,
|
|
1120
1136
|
nextAttemptAt: new Date(Date.now() + c.delayMs),
|
|
1121
1137
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1122
1138
|
}), {
|
|
@@ -1133,24 +1149,24 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
1133
1149
|
attempt: t,
|
|
1134
1150
|
cause: String(e)
|
|
1135
1151
|
}), /* @__PURE__ */ Error(`classify-and-record failed: ${e.message}`))
|
|
1136
|
-
}).pipe(
|
|
1152
|
+
}).pipe(y.orDie)
|
|
1137
1153
|
});
|
|
1138
|
-
if (
|
|
1154
|
+
if (v.autoDisabled === !0 && u.warn("target auto-disabled after consecutive failures", {
|
|
1139
1155
|
targetId: a,
|
|
1140
1156
|
event: s,
|
|
1141
|
-
consecutiveFailures:
|
|
1142
|
-
reason:
|
|
1143
|
-
}),
|
|
1157
|
+
consecutiveFailures: v.consecutiveFailures ?? null,
|
|
1158
|
+
reason: v.reason ?? null
|
|
1159
|
+
}), v.outcome === "succeeded") return {
|
|
1144
1160
|
finalStatus: "succeeded",
|
|
1145
1161
|
attempts: t
|
|
1146
1162
|
};
|
|
1147
|
-
if (
|
|
1163
|
+
if (v.outcome === "failed") return {
|
|
1148
1164
|
finalStatus: "failed",
|
|
1149
1165
|
attempts: t
|
|
1150
1166
|
};
|
|
1151
|
-
|
|
1167
|
+
v.delayMs !== void 0 && (yield* T.sleep({
|
|
1152
1168
|
name: `retry-sleep-${t}`,
|
|
1153
|
-
duration: `${
|
|
1169
|
+
duration: `${v.delayMs} millis`
|
|
1154
1170
|
}));
|
|
1155
1171
|
}
|
|
1156
1172
|
return {
|
|
@@ -1160,4 +1176,4 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
|
|
|
1160
1176
|
});
|
|
1161
1177
|
};
|
|
1162
1178
|
//#endregion
|
|
1163
|
-
export { B as IdempotencyCache, q as RATE_WINDOW_MS, K as RATE_WINDOW_TABLE,
|
|
1179
|
+
export { B as IdempotencyCache, q as RATE_WINDOW_MS, K as RATE_WINDOW_TABLE, Ne as TARGETS_TABLE, l as WebhookDeliveryNotFound, u as WebhookPayloadInvalid, d as WebhookPayloadUnrepresentable, f as WebhookPayloadVersionInvalid, p as WebhookSubscribeInvalid, j as WebhooksService, m as _voltroWebhookDeliveriesTable, h as _voltroWebhookRateWindowsTable, ee as _voltroWebhookTargetsTable, Te as acquireRateSlots, E as asOutgoingEvent, Be as buildDeliverWebhookExecute, _e as buildWebhooksService, pe as compareVersions, X as consumeRateSlot, Se as defaultIncomingPath, c as defaultOutgoingSignature, A as defaultRetryPolicy, s as defineIncomingWebhook, t as defineWebhookProvider, ze as deliverWebhookWorkflow, Ee as encodePayload, N as eventsOf, ce as fastRetryPolicy, M as generateSecret, H as getIdempotencyCache, i as githubSignature, oe as hasWebhookAudience, r as isWebhookDescriptor, R as matchesFilter, xe as mountIncomingWebhook, k as nextRetry, D as parseDuration, W as parseTtl, $ as recordDeliveryOutcome, we as releaseRateSlot, F as resolveSubscribe, o as signPayload, n as slackSignature, e as stripeSignature, ye as useWebhooks, ve as useWebhooksEffect, P as validateSubscribe, a as verifySignature, g as webhookTables };
|