@voltro/plugin-webhooks 0.75.0 → 0.77.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 +459 -0
- package/THIRD-PARTY-NOTICES.md +3 -3
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +3 -3
- package/dist/index.d.ts +10 -0
- package/dist/index.js +288 -277
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { C as e, E as t, S as n, T as r, _ as i, a, b as o, c as s, d as c, f as l, g as u, h as d, i as f, l as p, m, n as h, o as g, p as _, r as v, s as y, t as
|
|
2
|
-
import { WebhookDeliveryNotFound as
|
|
3
|
-
import { _voltroWebhookDeliveriesTable as
|
|
4
|
-
import { Context as
|
|
5
|
-
import { definePlugin as
|
|
6
|
-
import { randomBytes as
|
|
7
|
-
import { and as
|
|
8
|
-
import { assertPublicUrl as
|
|
9
|
-
import { createLogger as
|
|
10
|
-
import { Activity as
|
|
11
|
-
import { defineOutboxHandler as
|
|
1
|
+
import { C as e, E as t, S as n, T as r, _ as i, a, b as o, c as s, d as c, f as l, g as u, h as d, i as f, l as p, m, n as h, o as g, p as _, r as v, s as y, t as ee, u as te, v as ne, w as re, x as ie, y as ae } from "./signing-DeHObNv6.js";
|
|
2
|
+
import { WebhookDeliveryNotFound as b, WebhookPayloadInvalid as oe, WebhookPayloadUnrepresentable as x, WebhookPayloadVersionInvalid as se, WebhookSubscribeInvalid as S, WebhookTargetNotFound as C } from "./errors.js";
|
|
3
|
+
import { _voltroWebhookDeliveriesTable as ce, _voltroWebhookEventStatsTable as le, _voltroWebhookRateWindowsTable as ue, _voltroWebhookTargetsTable as de, webhookTables as fe } from "./mixin.js";
|
|
4
|
+
import { Context as pe, Effect as w, Either as me, Schema as T } from "effect";
|
|
5
|
+
import { definePlugin as he, publishServerError as ge } from "@voltro/protocol";
|
|
6
|
+
import { randomBytes as _e, randomUUID as E } from "node:crypto";
|
|
7
|
+
import { and as D, eq as O } from "@voltro/database";
|
|
8
|
+
import { assertPublicUrl as ve } from "@voltro/integration-http";
|
|
9
|
+
import { createLogger as k } from "@voltro/logger";
|
|
10
|
+
import { Activity as A, DurableClock as j, Workflow as ye } from "@effect/workflow";
|
|
11
|
+
import { defineOutboxHandler as be } from "@voltro/runtime";
|
|
12
12
|
//#region src/plugin.ts
|
|
13
|
-
var
|
|
13
|
+
var M = ["network:outbound:*"], xe = (e = {}) => he({
|
|
14
14
|
name: e.name ? `@voltro/plugin-webhooks#${e.name}` : "@voltro/plugin-webhooks",
|
|
15
15
|
description: "Outgoing webhooks (multi-target, durable-workflow delivery, HMAC signing, retry policies, rate limits) + incoming (signature verification, idempotency, provider templates). Declares wildcard outbound network access because targets are user-configured URLs.",
|
|
16
|
-
permissions:
|
|
17
|
-
onActivate: (e) =>
|
|
16
|
+
permissions: M,
|
|
17
|
+
onActivate: (e) => w.sync(() => {
|
|
18
18
|
e.logger.info("webhooks active", { outbound: "network:outbound:* (subscriber-configured target URLs — audit visibility, not a restriction)" });
|
|
19
19
|
})
|
|
20
|
-
}),
|
|
20
|
+
}), Se = (e) => e.webhook !== void 0, Ce = (e) => {
|
|
21
21
|
let t = e.webhook;
|
|
22
22
|
if (t !== void 0) return {
|
|
23
23
|
_tag: "outgoingEvent",
|
|
@@ -27,8 +27,8 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
27
27
|
...t.version === void 0 ? {} : { version: t.version },
|
|
28
28
|
...t.rateLimit === void 0 ? {} : { globalRateLimit: t.rateLimit }
|
|
29
29
|
};
|
|
30
|
-
},
|
|
31
|
-
let t =
|
|
30
|
+
}, we = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, N = (e) => {
|
|
31
|
+
let t = we.exec(e);
|
|
32
32
|
if (!t) throw Error(`invalid duration literal: ${e}`);
|
|
33
33
|
let n = Number(t[1]), r = t[2] ?? "s";
|
|
34
34
|
switch (r) {
|
|
@@ -39,7 +39,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
39
39
|
case "d": return n * 864e5;
|
|
40
40
|
default: throw Error(`unreachable unit: ${r}`);
|
|
41
41
|
}
|
|
42
|
-
},
|
|
42
|
+
}, P = [
|
|
43
43
|
408,
|
|
44
44
|
425,
|
|
45
45
|
429,
|
|
@@ -47,16 +47,16 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
47
47
|
502,
|
|
48
48
|
503,
|
|
49
49
|
504
|
|
50
|
-
],
|
|
51
|
-
if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ??
|
|
50
|
+
], Te = (e, t, n) => {
|
|
51
|
+
if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ?? P).includes(n.status)) return null;
|
|
52
52
|
if (e.honourRetryAfter !== !1 && n?.retryAfterSeconds !== void 0) {
|
|
53
|
-
let t = n.retryAfterSeconds * 1e3, r =
|
|
53
|
+
let t = n.retryAfterSeconds * 1e3, r = N(e.maxDelay), i = Math.min(t, r);
|
|
54
54
|
return {
|
|
55
55
|
delayMs: i,
|
|
56
56
|
baseDelayMs: i
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
-
let r =
|
|
59
|
+
let r = N(e.initialDelay), i = N(e.maxDelay), a;
|
|
60
60
|
switch (e.strategy) {
|
|
61
61
|
case "fixed":
|
|
62
62
|
a = r;
|
|
@@ -72,97 +72,98 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
72
72
|
delayMs: Math.max(1, Math.floor(o)),
|
|
73
73
|
baseDelayMs: a
|
|
74
74
|
};
|
|
75
|
-
},
|
|
75
|
+
}, Ee = () => ({
|
|
76
76
|
strategy: "exponential",
|
|
77
77
|
maxAttempts: 8,
|
|
78
78
|
initialDelay: "5s",
|
|
79
79
|
maxDelay: "1h",
|
|
80
|
-
retryOn:
|
|
80
|
+
retryOn: P,
|
|
81
81
|
honourRetryAfter: !0,
|
|
82
82
|
jitter: "full"
|
|
83
|
-
}),
|
|
83
|
+
}), De = () => ({
|
|
84
84
|
strategy: "fixed",
|
|
85
85
|
maxAttempts: 120,
|
|
86
86
|
initialDelay: "30s",
|
|
87
87
|
maxDelay: "30s",
|
|
88
|
-
retryOn:
|
|
88
|
+
retryOn: P,
|
|
89
89
|
honourRetryAfter: !0,
|
|
90
90
|
jitter: "full"
|
|
91
|
-
}),
|
|
91
|
+
}), Oe = class extends pe.Tag("@voltro/webhooks/WebhooksService")() {}, ke = 32, F = 32, I = () => _e(ke).toString("hex"), L = (e) => e.events ?? (e.event === void 0 ? [] : [e.event]), R = (e, t) => {
|
|
92
|
+
if (e !== void 0 && t?._tag === "standardWebhooks" && !ne(e)) throw new S({
|
|
93
|
+
field: "secret",
|
|
94
|
+
reason: "a standard-webhooks target needs the spec's secret serialization (\"whsec_\" + base64 of 24..64 random bytes) — mint one with generateStandardWebhooksSecret(), or omit `secret` and let subscribe mint it. If the incompatible key is inherited, rotate the endpoint secret and update the receiver before adding the event"
|
|
95
|
+
});
|
|
96
|
+
}, z = (e) => {
|
|
92
97
|
let t;
|
|
93
98
|
try {
|
|
94
99
|
t = new URL(e.url);
|
|
95
100
|
} catch (e) {
|
|
96
|
-
throw new
|
|
101
|
+
throw new S({
|
|
97
102
|
field: "url",
|
|
98
103
|
reason: `invalid subscriber url: ${e.message}`
|
|
99
104
|
});
|
|
100
105
|
}
|
|
101
|
-
if (t.protocol !== "http:" && t.protocol !== "https:") throw new
|
|
106
|
+
if (t.protocol !== "http:" && t.protocol !== "https:") throw new S({
|
|
102
107
|
field: "url",
|
|
103
108
|
reason: `url protocol must be http or https, got ${t.protocol}`
|
|
104
109
|
});
|
|
105
110
|
if (process.env.NODE_ENV === "production") try {
|
|
106
|
-
|
|
111
|
+
ve(e.url);
|
|
107
112
|
} catch (e) {
|
|
108
|
-
throw new
|
|
113
|
+
throw new S({
|
|
109
114
|
field: "url",
|
|
110
115
|
reason: e.message
|
|
111
116
|
});
|
|
112
117
|
}
|
|
113
|
-
let n =
|
|
114
|
-
if (n.length === 0) throw new
|
|
118
|
+
let n = L(e);
|
|
119
|
+
if (n.length === 0) throw new S({
|
|
115
120
|
field: "event",
|
|
116
121
|
reason: "event id required"
|
|
117
122
|
});
|
|
118
|
-
if (e.event !== void 0 && e.events !== void 0) throw new
|
|
123
|
+
if (e.event !== void 0 && e.events !== void 0) throw new S({
|
|
119
124
|
field: "event",
|
|
120
125
|
reason: "pass `event` OR `events`, not both — the row set would be ambiguous"
|
|
121
126
|
});
|
|
122
|
-
if (n.some((e) => e.length === 0)) throw new
|
|
127
|
+
if (n.some((e) => e.length === 0)) throw new S({
|
|
123
128
|
field: "events",
|
|
124
129
|
reason: "event id required"
|
|
125
130
|
});
|
|
126
|
-
if (new Set(n).size !== n.length) throw new
|
|
131
|
+
if (new Set(n).size !== n.length) throw new S({
|
|
127
132
|
field: "events",
|
|
128
133
|
reason: "duplicate event — one row per event, so a repeat would deliver twice"
|
|
129
134
|
});
|
|
130
|
-
if (e.secret !== void 0 && e.secret.length <
|
|
131
|
-
field: "secret",
|
|
132
|
-
reason: `secret must be at least ${Te} chars`
|
|
133
|
-
});
|
|
134
|
-
if (e.secret !== void 0 && e.signing?._tag === "standardWebhooks" && !te(e.secret)) throw new w({
|
|
135
|
+
if (e.secret !== void 0 && e.secret.length < F) throw new S({
|
|
135
136
|
field: "secret",
|
|
136
|
-
reason:
|
|
137
|
+
reason: `secret must be at least ${F} chars`
|
|
137
138
|
});
|
|
138
|
-
if (e.retry !== void 0) {
|
|
139
|
-
if (e.retry.maxAttempts < 1) throw new
|
|
139
|
+
if (R(e.secret, e.signing), e.retry !== void 0) {
|
|
140
|
+
if (e.retry.maxAttempts < 1) throw new S({
|
|
140
141
|
field: "retry",
|
|
141
142
|
reason: "retry.maxAttempts must be ≥ 1"
|
|
142
143
|
});
|
|
143
|
-
if (e.retry.maxAttempts > 1e3) throw new
|
|
144
|
+
if (e.retry.maxAttempts > 1e3) throw new S({
|
|
144
145
|
field: "retry",
|
|
145
146
|
reason: "retry.maxAttempts must be ≤ 1000"
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
|
-
if (e.rateLimitPerMinute !== void 0 && e.rateLimitPerMinute < 1) throw new
|
|
149
|
+
if (e.rateLimitPerMinute !== void 0 && e.rateLimitPerMinute < 1) throw new S({
|
|
149
150
|
field: "rateLimitPerMinute",
|
|
150
151
|
reason: "rateLimitPerMinute must be ≥ 1"
|
|
151
152
|
});
|
|
152
|
-
if (e.autoDisableAfter !== void 0 && (e.autoDisableAfter < 1 || !Number.isInteger(e.autoDisableAfter))) throw new
|
|
153
|
+
if (e.autoDisableAfter !== void 0 && (e.autoDisableAfter < 1 || !Number.isInteger(e.autoDisableAfter))) throw new S({
|
|
153
154
|
field: "autoDisableAfter",
|
|
154
155
|
reason: `autoDisableAfter must be a positive integer, got ${e.autoDisableAfter}`
|
|
155
156
|
});
|
|
156
|
-
},
|
|
157
|
-
let a = e.signing ?? t?.defaultSigning ??
|
|
158
|
-
return {
|
|
159
|
-
id:
|
|
157
|
+
}, B = (e, t, n, r) => {
|
|
158
|
+
let a = e.signing ?? t?.defaultSigning ?? ee(), o = a._tag === "standardWebhooks" ? i : I, s = r ?? e.secret ?? o();
|
|
159
|
+
return R(s, a), {
|
|
160
|
+
id: E(),
|
|
160
161
|
tenantId: e.tenantId ?? null,
|
|
161
162
|
event: n ?? e.event ?? "",
|
|
162
163
|
url: e.url,
|
|
163
|
-
secret:
|
|
164
|
+
secret: s,
|
|
164
165
|
signing: a,
|
|
165
|
-
retry: e.retry ?? t?.defaultRetry ??
|
|
166
|
+
retry: e.retry ?? t?.defaultRetry ?? Ee(),
|
|
166
167
|
filter: e.filter ?? null,
|
|
167
168
|
scope: e.scope ?? null,
|
|
168
169
|
headers: e.headers ?? null,
|
|
@@ -176,14 +177,14 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
176
177
|
payloadVersion: e.payloadVersion ?? t?.version ?? 1,
|
|
177
178
|
description: e.description ?? null
|
|
178
179
|
};
|
|
179
|
-
},
|
|
180
|
+
}, Ae = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : 0, V = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : null, je = (e) => {
|
|
180
181
|
if (typeof e != "string") return e;
|
|
181
182
|
try {
|
|
182
183
|
return JSON.parse(e);
|
|
183
184
|
} catch {
|
|
184
185
|
return e;
|
|
185
186
|
}
|
|
186
|
-
},
|
|
187
|
+
}, H = (e) => ({
|
|
187
188
|
id: String(e.id),
|
|
188
189
|
deliveryId: String(e.deliveryId),
|
|
189
190
|
targetId: String(e.targetId),
|
|
@@ -194,28 +195,28 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
194
195
|
responseStatus: e.responseStatus ?? null,
|
|
195
196
|
errorMessage: e.errorMessage ?? null,
|
|
196
197
|
latencyMs: e.latencyMs ?? null,
|
|
197
|
-
scheduledAt:
|
|
198
|
-
nextAttemptAt:
|
|
199
|
-
createdAt:
|
|
200
|
-
}),
|
|
198
|
+
scheduledAt: V(e.scheduledAt),
|
|
199
|
+
nextAttemptAt: V(e.nextAttemptAt),
|
|
200
|
+
createdAt: V(e.createdAt)
|
|
201
|
+
}), Me = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", Ne = (e, t) => {
|
|
201
202
|
if (e === null) return !0;
|
|
202
203
|
let n = { payload: t };
|
|
203
|
-
for (let [t, r] of Object.entries(e)) if (!
|
|
204
|
+
for (let [t, r] of Object.entries(e)) if (!Fe(Pe(n, t), r)) return !1;
|
|
204
205
|
return !0;
|
|
205
|
-
},
|
|
206
|
+
}, Pe = (e, t) => {
|
|
206
207
|
let n = t.split("."), r = e;
|
|
207
208
|
for (let e of n) {
|
|
208
209
|
if (typeof r != "object" || !r) return;
|
|
209
210
|
r = r[e];
|
|
210
211
|
}
|
|
211
212
|
return r;
|
|
212
|
-
},
|
|
213
|
+
}, U = (e, t) => {
|
|
213
214
|
if (typeof e == "number" && typeof t == "number") return e - t;
|
|
214
215
|
if (typeof e == "string" && typeof t == "string") return e < t ? -1 : +(e > t);
|
|
215
|
-
},
|
|
216
|
+
}, Fe = (e, t) => {
|
|
216
217
|
if (typeof t == "object" && t && !Array.isArray(t)) {
|
|
217
218
|
let n = t;
|
|
218
|
-
return "eq" in n && e !== n.eq || "in" in n && (!Array.isArray(n.in) || !n.in.includes(e)) || "gt" in n && !((
|
|
219
|
+
return "eq" in n && e !== n.eq || "in" in n && (!Array.isArray(n.in) || !n.in.includes(e)) || "gt" in n && !((U(e, n.gt) ?? 0) > 0) || "gte" in n && !((U(e, n.gte) ?? -1) >= 0) || "lt" in n && !((U(e, n.lt) ?? 0) < 0) || "lte" in n && !((U(e, n.lte) ?? 1) <= 0) ? !1 : [
|
|
219
220
|
"eq",
|
|
220
221
|
"in",
|
|
221
222
|
"gt",
|
|
@@ -225,9 +226,9 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
225
226
|
].some((e) => e in n);
|
|
226
227
|
}
|
|
227
228
|
return e === t;
|
|
228
|
-
},
|
|
229
|
+
}, Ie = (e, t) => e !== null && Object.entries(t).every(([t, n]) => e[t] === n), W = 500, Le = 200, G = async (e, t) => {
|
|
229
230
|
let n = [];
|
|
230
|
-
for (let r = 0; r <
|
|
231
|
+
for (let r = 0; r < Le; r += 1) {
|
|
231
232
|
let i = await e.store.query({
|
|
232
233
|
table: "_voltro_webhook_targets",
|
|
233
234
|
predicate: t,
|
|
@@ -235,24 +236,24 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
235
236
|
column: "id",
|
|
236
237
|
direction: "asc"
|
|
237
238
|
}],
|
|
238
|
-
take:
|
|
239
|
-
skip: r === 0 ? void 0 : r *
|
|
239
|
+
take: W,
|
|
240
|
+
skip: r === 0 ? void 0 : r * W,
|
|
240
241
|
projection: void 0
|
|
241
242
|
});
|
|
242
|
-
if (n.push(...i), i.length <
|
|
243
|
+
if (n.push(...i), i.length < W) return n;
|
|
243
244
|
}
|
|
244
|
-
throw Error(`webhooks: more than ${
|
|
245
|
-
},
|
|
246
|
-
let n = (await
|
|
245
|
+
throw Error(`webhooks: more than ${Le * W} rows in \`_voltro_webhook_targets\` — refusing to answer a scope lookup from a partial scan. A truncated scan mints a fresh secret for a live endpoint (breaking its signatures) or reports that a real scope matches nothing.`);
|
|
246
|
+
}, Re = async (e, t) => {
|
|
247
|
+
let n = (await G(e)).filter((e) => Ie(e.scope, t));
|
|
247
248
|
if (n.length === 0) return;
|
|
248
249
|
let r = new Set(n.map((e) => e.secret));
|
|
249
250
|
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.`);
|
|
250
251
|
return [...r][0];
|
|
251
|
-
},
|
|
252
|
+
}, ze = async (e, t) => {
|
|
252
253
|
try {
|
|
253
254
|
let n = await e.store.query({
|
|
254
255
|
table: "_voltro_webhook_event_stats",
|
|
255
|
-
predicate:
|
|
256
|
+
predicate: O("event", t),
|
|
256
257
|
order: [],
|
|
257
258
|
take: 1,
|
|
258
259
|
skip: void 0,
|
|
@@ -274,44 +275,44 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
274
275
|
updatedAt: r
|
|
275
276
|
});
|
|
276
277
|
} catch {}
|
|
277
|
-
},
|
|
278
|
-
let r = new Map((n.events ?? []).map((e) => [e.id, e])),
|
|
278
|
+
}, Be = (e, t, n = {}) => {
|
|
279
|
+
let r = new Map((n.events ?? []).map((e) => [e.id, e])), a = {
|
|
279
280
|
subscribe: async (t) => {
|
|
280
|
-
|
|
281
|
-
let n =
|
|
282
|
-
for (let t of
|
|
281
|
+
z(t);
|
|
282
|
+
let n = L(t), a = t.secret === void 0 && t.scope !== void 0 ? await Re(e, t.scope) : void 0, o = t.secret ?? a ?? i(), s = n.map((e) => B(t, r.get(e), e, o));
|
|
283
|
+
for (let t of s) await e.store.insert("_voltro_webhook_targets", {
|
|
283
284
|
...t,
|
|
284
285
|
createdAt: /* @__PURE__ */ new Date(),
|
|
285
286
|
updatedAt: /* @__PURE__ */ new Date()
|
|
286
287
|
});
|
|
287
|
-
let
|
|
288
|
+
let c = s[0];
|
|
288
289
|
return {
|
|
289
|
-
id:
|
|
290
|
-
event:
|
|
291
|
-
url:
|
|
292
|
-
secret:
|
|
293
|
-
signing:
|
|
294
|
-
retry:
|
|
295
|
-
...
|
|
290
|
+
id: c.id,
|
|
291
|
+
event: c.event,
|
|
292
|
+
url: c.url,
|
|
293
|
+
secret: c.secret,
|
|
294
|
+
signing: c.signing,
|
|
295
|
+
retry: c.retry,
|
|
296
|
+
...s.length > 1 ? { targets: s.map((e) => ({
|
|
296
297
|
id: e.id,
|
|
297
298
|
event: e.event
|
|
298
299
|
})) } : {}
|
|
299
300
|
};
|
|
300
301
|
},
|
|
301
302
|
emit: async (n, i, a) => {
|
|
302
|
-
let o = typeof n == "object" && n.kind === "event" ?
|
|
303
|
+
let o = typeof n == "object" && n.kind === "event" ? Ce(n) : void 0, s = typeof n == "string" ? r.get(n) : o ?? n, c = typeof n == "string" ? n : n.id ?? n.name;
|
|
303
304
|
if (s !== void 0) {
|
|
304
|
-
let e =
|
|
305
|
-
if (
|
|
305
|
+
let e = T.decodeUnknownEither(s.payload)(i, { errors: "all" });
|
|
306
|
+
if (me.isLeft(e)) throw new oe({
|
|
306
307
|
event: c,
|
|
307
308
|
issues: e.left.message
|
|
308
309
|
});
|
|
309
310
|
}
|
|
310
|
-
let l =
|
|
311
|
-
await
|
|
312
|
-
let f = d.filter((e) =>
|
|
311
|
+
let l = E(), u = a?.tenantId, d = await G(e, u == null ? O("event", c) : D(O("event", c), O("tenantId", u)));
|
|
312
|
+
await ze(e, c);
|
|
313
|
+
let f = d.filter((e) => Ne(e.filter, i)), p = [], m = JSON.stringify(i);
|
|
313
314
|
for (let n of f) {
|
|
314
|
-
let r =
|
|
315
|
+
let r = E();
|
|
315
316
|
n.active ? (await t({
|
|
316
317
|
deliveryId: r,
|
|
317
318
|
targetId: n.id,
|
|
@@ -349,7 +350,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
349
350
|
replay: async (n) => {
|
|
350
351
|
let r = (await e.store.query({
|
|
351
352
|
table: "_voltro_webhook_deliveries",
|
|
352
|
-
predicate:
|
|
353
|
+
predicate: O("deliveryId", n),
|
|
353
354
|
order: [{
|
|
354
355
|
column: "attempt",
|
|
355
356
|
direction: "asc"
|
|
@@ -358,30 +359,40 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
358
359
|
skip: void 0,
|
|
359
360
|
projection: void 0
|
|
360
361
|
}))[0];
|
|
361
|
-
if (r === void 0) throw new
|
|
362
|
+
if (r === void 0) throw new b({ deliveryId: n });
|
|
362
363
|
await t({
|
|
363
364
|
deliveryId: r.deliveryId,
|
|
364
365
|
targetId: r.targetId,
|
|
365
366
|
event: r.event,
|
|
366
|
-
eventId: r.eventId ??
|
|
367
|
+
eventId: r.eventId ?? E(),
|
|
367
368
|
payloadJson: typeof r.payload == "string" ? r.payload : JSON.stringify(r.payload),
|
|
368
369
|
attemptEpoch: Date.now()
|
|
369
370
|
});
|
|
370
371
|
},
|
|
371
372
|
resolveTargets: async (t) => {
|
|
372
|
-
if (typeof t == "string")
|
|
373
|
-
|
|
373
|
+
if (typeof t == "string") {
|
|
374
|
+
if ((await e.store.query({
|
|
375
|
+
table: "_voltro_webhook_targets",
|
|
376
|
+
predicate: O("id", t),
|
|
377
|
+
order: [],
|
|
378
|
+
take: 1,
|
|
379
|
+
skip: void 0,
|
|
380
|
+
projection: ["id"]
|
|
381
|
+
})).length === 0) throw new C({ targetId: t });
|
|
382
|
+
return [t];
|
|
383
|
+
}
|
|
384
|
+
let n = (await G(e)).filter((e) => Ie(e.scope, t.scope)).map((e) => e.id);
|
|
374
385
|
if (n.length === 0) throw Error(`webhooks: no target matches scope ${JSON.stringify(t.scope)} — the operation would have silently done nothing`);
|
|
375
386
|
return n;
|
|
376
387
|
},
|
|
377
388
|
pauseTarget: async (t) => {
|
|
378
|
-
for (let n of await
|
|
389
|
+
for (let n of await a.resolveTargets(t)) await e.store.update("_voltro_webhook_targets", n, {
|
|
379
390
|
active: !1,
|
|
380
391
|
updatedAt: /* @__PURE__ */ new Date()
|
|
381
392
|
});
|
|
382
393
|
},
|
|
383
394
|
resumeTarget: async (n) => {
|
|
384
|
-
for (let r of await
|
|
395
|
+
for (let r of await a.resolveTargets(n)) {
|
|
385
396
|
await e.store.update("_voltro_webhook_targets", r, {
|
|
386
397
|
active: !0,
|
|
387
398
|
consecutiveFailures: 0,
|
|
@@ -391,7 +402,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
391
402
|
});
|
|
392
403
|
let n = await e.store.query({
|
|
393
404
|
table: "_voltro_webhook_deliveries",
|
|
394
|
-
predicate: O(
|
|
405
|
+
predicate: D(O("targetId", r), O("status", "pending")),
|
|
395
406
|
order: [{
|
|
396
407
|
column: "createdAt",
|
|
397
408
|
direction: "asc"
|
|
@@ -404,25 +415,25 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
404
415
|
deliveryId: e.deliveryId,
|
|
405
416
|
targetId: r,
|
|
406
417
|
event: e.event,
|
|
407
|
-
eventId: e.eventId ??
|
|
418
|
+
eventId: e.eventId ?? E(),
|
|
408
419
|
payloadJson: typeof e.payload == "string" ? e.payload : JSON.stringify(e.payload),
|
|
409
420
|
attemptEpoch: i
|
|
410
421
|
});
|
|
411
422
|
}
|
|
412
423
|
},
|
|
413
424
|
deleteTarget: async (t) => {
|
|
414
|
-
for (let n of await
|
|
425
|
+
for (let n of await a.resolveTargets(t)) await e.store.delete("_voltro_webhook_targets", n), await e.store.deleteMany("_voltro_webhook_deliveries", { where: D(O("targetId", n), O("status", "pending")) });
|
|
415
426
|
},
|
|
416
427
|
rotateSecret: async (t) => {
|
|
417
|
-
let n =
|
|
418
|
-
for (let r of await
|
|
428
|
+
let n = i();
|
|
429
|
+
for (let r of await a.resolveTargets(t)) await e.store.update("_voltro_webhook_targets", r, {
|
|
419
430
|
secret: n,
|
|
420
431
|
updatedAt: /* @__PURE__ */ new Date()
|
|
421
432
|
});
|
|
422
433
|
return { secret: n };
|
|
423
434
|
},
|
|
424
435
|
updateTarget: async (t, n) => {
|
|
425
|
-
if (n.url !== void 0 &&
|
|
436
|
+
if (n.url !== void 0 && z({
|
|
426
437
|
event: "x",
|
|
427
438
|
url: n.url
|
|
428
439
|
}), 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");
|
|
@@ -437,19 +448,19 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
437
448
|
"autoDisableAfter",
|
|
438
449
|
"format"
|
|
439
450
|
]) n[e] !== void 0 && (r[e] = n[e]);
|
|
440
|
-
for (let n of await
|
|
451
|
+
for (let n of await a.resolveTargets(t)) await e.store.update("_voltro_webhook_targets", n, r);
|
|
441
452
|
},
|
|
442
453
|
testTarget: async (n, r) => {
|
|
443
454
|
let i = (await e.store.query({
|
|
444
455
|
table: "_voltro_webhook_targets",
|
|
445
|
-
predicate:
|
|
456
|
+
predicate: O("id", n),
|
|
446
457
|
order: [],
|
|
447
458
|
take: 1,
|
|
448
459
|
skip: void 0,
|
|
449
460
|
projection: void 0
|
|
450
461
|
}))[0];
|
|
451
|
-
if (i === void 0) throw
|
|
452
|
-
let a =
|
|
462
|
+
if (i === void 0) throw new C({ targetId: n });
|
|
463
|
+
let a = E(), o = JSON.stringify(r ?? {
|
|
453
464
|
test: !0,
|
|
454
465
|
targetId: n,
|
|
455
466
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -458,7 +469,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
458
469
|
deliveryId: a,
|
|
459
470
|
targetId: i.id,
|
|
460
471
|
event: i.event,
|
|
461
|
-
eventId:
|
|
472
|
+
eventId: E(),
|
|
462
473
|
payloadJson: o
|
|
463
474
|
}) : await e.store.insert("_voltro_webhook_deliveries", {
|
|
464
475
|
id: `${a}:1`,
|
|
@@ -476,9 +487,9 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
476
487
|
}), { deliveryId: a };
|
|
477
488
|
},
|
|
478
489
|
listDeliveries: async (t) => {
|
|
479
|
-
let n = t?.scope === void 0 ? void 0 : new Set(await
|
|
490
|
+
let n = t?.scope === void 0 ? void 0 : new Set(await a.resolveTargets({ scope: t.scope })), r = await e.store.query({
|
|
480
491
|
table: "_voltro_webhook_deliveries",
|
|
481
|
-
predicate: t?.targetId === void 0 ? void 0 :
|
|
492
|
+
predicate: t?.targetId === void 0 ? void 0 : O("targetId", t.targetId),
|
|
482
493
|
order: [{
|
|
483
494
|
column: "createdAt",
|
|
484
495
|
direction: "desc"
|
|
@@ -486,27 +497,27 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
486
497
|
take: Math.min((t?.limit ?? 200) * (t?.status !== void 0 || t?.since !== void 0 ? 10 : 1), 5e3),
|
|
487
498
|
skip: void 0,
|
|
488
499
|
projection: void 0
|
|
489
|
-
}),
|
|
490
|
-
return r.filter((e) => n === void 0 || n.has(String(e.targetId))).filter((e) => t?.status === void 0 || e.status === t.status).filter((e) =>
|
|
500
|
+
}), i = t?.since?.getTime();
|
|
501
|
+
return r.filter((e) => n === void 0 || n.has(String(e.targetId))).filter((e) => t?.status === void 0 || e.status === t.status).filter((e) => i === void 0 || Ae(e.createdAt) >= i).slice(0, t?.limit ?? 200).map(H);
|
|
491
502
|
},
|
|
492
503
|
getDelivery: async (t) => {
|
|
493
504
|
let n = (await e.store.query({
|
|
494
505
|
table: "_voltro_webhook_deliveries",
|
|
495
|
-
predicate:
|
|
506
|
+
predicate: O("id", t),
|
|
496
507
|
order: [],
|
|
497
508
|
take: 1,
|
|
498
509
|
skip: void 0,
|
|
499
510
|
projection: void 0
|
|
500
511
|
}))[0];
|
|
501
512
|
return n === void 0 ? null : {
|
|
502
|
-
...
|
|
503
|
-
payload:
|
|
513
|
+
...H(n),
|
|
514
|
+
payload: je(n.payload),
|
|
504
515
|
responseBody: n.responseBody ?? null
|
|
505
516
|
};
|
|
506
517
|
},
|
|
507
518
|
updateTargetPayloadVersion: async (t, n) => {
|
|
508
|
-
if (n < 1 || !Number.isInteger(n)) throw new
|
|
509
|
-
await e.store.update("_voltro_webhook_targets", t, {
|
|
519
|
+
if (n < 1 || !Number.isInteger(n)) throw new se({ version: n });
|
|
520
|
+
await a.resolveTargets(t), await e.store.update("_voltro_webhook_targets", t, {
|
|
510
521
|
payloadVersion: n,
|
|
511
522
|
updatedAt: /* @__PURE__ */ new Date()
|
|
512
523
|
});
|
|
@@ -514,7 +525,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
514
525
|
listTargets: async (t, n) => {
|
|
515
526
|
let r = await e.store.query({
|
|
516
527
|
table: "_voltro_webhook_targets",
|
|
517
|
-
predicate: t === void 0 ? void 0 :
|
|
528
|
+
predicate: t === void 0 ? void 0 : O("event", t),
|
|
518
529
|
order: [{
|
|
519
530
|
column: "createdAt",
|
|
520
531
|
direction: "desc"
|
|
@@ -539,16 +550,16 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
539
550
|
}));
|
|
540
551
|
}
|
|
541
552
|
};
|
|
542
|
-
return
|
|
543
|
-
},
|
|
544
|
-
return yield*
|
|
545
|
-
}),
|
|
553
|
+
return a;
|
|
554
|
+
}, Ve = w.gen(function* () {
|
|
555
|
+
return yield* Oe;
|
|
556
|
+
}), He = (e) => {
|
|
546
557
|
if (e.webhooks === void 0) throw Error("useWebhooks: `ctx.webhooks` is not set. Declare an outgoing event with a `webhook:` block in a *.event.ts file, or an incoming endpoint in a *.webhook.tsx file — the service is wired the moment the app has either.");
|
|
547
558
|
return e.webhooks;
|
|
548
|
-
},
|
|
559
|
+
}, Ue = 1e4, We = class {
|
|
549
560
|
capacity;
|
|
550
561
|
cache = /* @__PURE__ */ new Map();
|
|
551
|
-
constructor(e =
|
|
562
|
+
constructor(e = Ue) {
|
|
552
563
|
this.capacity = e;
|
|
553
564
|
}
|
|
554
565
|
evictExpired() {
|
|
@@ -583,36 +594,36 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
583
594
|
clear() {
|
|
584
595
|
this.cache.clear();
|
|
585
596
|
}
|
|
586
|
-
},
|
|
597
|
+
}, K = null, Ge = () => (K === null && (K = new We()), K), q = {
|
|
587
598
|
"5m": 3e5,
|
|
588
599
|
"1h": 36e5,
|
|
589
600
|
"6h": 216e5,
|
|
590
601
|
"1d": 864e5,
|
|
591
602
|
"7d": 6048e5,
|
|
592
603
|
"30d": 2592e6
|
|
593
|
-
},
|
|
604
|
+
}, Ke = (e) => e === void 0 ? q["7d"] : q[e] ?? q["7d"], J = (e, t) => ({
|
|
594
605
|
status: e,
|
|
595
606
|
contentType: "application/json; charset=utf-8",
|
|
596
607
|
body: JSON.stringify(t)
|
|
597
|
-
}),
|
|
608
|
+
}), qe = "voltroWebhookVerification", Je = class extends Error {
|
|
598
609
|
webhookId;
|
|
599
610
|
name = "UnverifiedIncomingWebhook";
|
|
600
611
|
constructor(e) {
|
|
601
612
|
super(`incoming webhook '${e}' declares no verification. It would be mounted as a public, unauthenticated POST that runs your application code, so the framework refuses to mount it. Pick one on the descriptor:\n · provider: stripeWebhookProvider() — a preset (HMAC scheme + idempotency + body type)\n · signature: { _tag: 'hmac', algorithm: 'hmacSha256', header: 'X-Signature', encoding: 'hex', includeTimestamp: true }\n · verification: 'provider' — the handler verifies with the provider's own SDK\n · verification: 'none' — deliberately public; a gateway / IP allow-list owns it\nA signature-verified webhook reads its shared secret from VOLTRO_WEBHOOK_SECRET_${e.toUpperCase().replace(/[^A-Z0-9]/g, "_")}. The framework never invents that value — the sender holds the other half of it.`), this.webhookId = e;
|
|
602
613
|
}
|
|
603
|
-
},
|
|
614
|
+
}, Ye = (e) => `VOLTRO_WEBHOOK_SECRET_${e.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`, Xe = (e) => {
|
|
604
615
|
let t = e.signature ?? e.provider?.signature ?? null;
|
|
605
616
|
return (e.verification === void 0 || e.verification === "signature") && t === null ? null : e.verification ?? "signature";
|
|
606
|
-
},
|
|
607
|
-
let n = e.provider, r = e.signature ?? n?.signature ?? null, i = e.idempotency ?? n?.idempotency ?? null, a = e.bodyType ?? n?.bodyType ?? "json", o =
|
|
608
|
-
if (o === null) throw new
|
|
617
|
+
}, Ze = (e, t) => {
|
|
618
|
+
let n = e.provider, r = e.signature ?? n?.signature ?? null, i = e.idempotency ?? n?.idempotency ?? null, a = e.bodyType ?? n?.bodyType ?? "json", o = Xe(e);
|
|
619
|
+
if (o === null) throw new Je(e.id);
|
|
609
620
|
let c = o;
|
|
610
|
-
c === "none" &&
|
|
621
|
+
c === "none" && k({ scope: `webhook:${e.id}` }).warn("incoming webhook mounted WITHOUT verification — anyone who can reach this URL can run its handler", {
|
|
611
622
|
webhookId: e.id,
|
|
612
623
|
verification: "none"
|
|
613
624
|
});
|
|
614
|
-
let l = t.idempotencyCache ??
|
|
615
|
-
|
|
625
|
+
let l = t.idempotencyCache ?? Ge(), u = Ke(i?.ttl), d = t.log ?? ((e) => {
|
|
626
|
+
k({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
|
|
616
627
|
status: e.status,
|
|
617
628
|
signatureOk: e.signatureOk,
|
|
618
629
|
idempotency: e.idempotency,
|
|
@@ -623,7 +634,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
623
634
|
return Object.assign(async (n) => {
|
|
624
635
|
let o = Date.now();
|
|
625
636
|
if (n.method !== "POST") {
|
|
626
|
-
let t =
|
|
637
|
+
let t = J(405, {
|
|
627
638
|
error: "method not allowed",
|
|
628
639
|
expected: "POST"
|
|
629
640
|
});
|
|
@@ -639,7 +650,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
639
650
|
if (r !== null && c === "signature") {
|
|
640
651
|
let i = await t.resolveSecret(e.id);
|
|
641
652
|
if (i === null) {
|
|
642
|
-
let t = `no signing secret configured — set ${
|
|
653
|
+
let t = `no signing secret configured — set ${Ye(e.id)}`, n = J(503, {
|
|
643
654
|
error: "webhook not configured",
|
|
644
655
|
reason: t
|
|
645
656
|
});
|
|
@@ -659,7 +670,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
659
670
|
headers: n.headers
|
|
660
671
|
});
|
|
661
672
|
if (f = t.ok, !t.ok) {
|
|
662
|
-
let n =
|
|
673
|
+
let n = J(401, {
|
|
663
674
|
error: "invalid signature",
|
|
664
675
|
reason: t.reason
|
|
665
676
|
});
|
|
@@ -685,7 +696,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
685
696
|
p = r;
|
|
686
697
|
} else p = n.rawBody;
|
|
687
698
|
} catch (t) {
|
|
688
|
-
let n =
|
|
699
|
+
let n = J(400, {
|
|
689
700
|
error: "malformed body",
|
|
690
701
|
reason: t.message
|
|
691
702
|
});
|
|
@@ -700,9 +711,9 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
700
711
|
}
|
|
701
712
|
let m;
|
|
702
713
|
try {
|
|
703
|
-
m =
|
|
714
|
+
m = T.decodeUnknownSync(e.payload)(p);
|
|
704
715
|
} catch (t) {
|
|
705
|
-
let n =
|
|
716
|
+
let n = J(422, {
|
|
706
717
|
error: "schema validation failed",
|
|
707
718
|
reason: t.message
|
|
708
719
|
});
|
|
@@ -721,7 +732,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
721
732
|
if (h = typeof t == "string" ? n.headers[t.toLowerCase()] : t(n.headers, n.rawBody), h !== void 0 && h.length > 0) {
|
|
722
733
|
let t = l.claim(h, u);
|
|
723
734
|
if (g = t, t === "duplicate") {
|
|
724
|
-
let t =
|
|
735
|
+
let t = J(200, {
|
|
725
736
|
received: !0,
|
|
726
737
|
duplicate: !0
|
|
727
738
|
});
|
|
@@ -734,7 +745,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
734
745
|
}), t;
|
|
735
746
|
}
|
|
736
747
|
if (t === "inflight") {
|
|
737
|
-
let t =
|
|
748
|
+
let t = J(409, {
|
|
738
749
|
error: "request already in flight",
|
|
739
750
|
idempotencyKey: h
|
|
740
751
|
});
|
|
@@ -757,7 +768,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
757
768
|
idempotencyKey: h ?? "",
|
|
758
769
|
...r ? { workflows: r } : {}
|
|
759
770
|
}), h !== void 0 && l.commit(h);
|
|
760
|
-
let i =
|
|
771
|
+
let i = J(200, { received: !0 });
|
|
761
772
|
return d({
|
|
762
773
|
webhookId: e.id,
|
|
763
774
|
status: 200,
|
|
@@ -767,7 +778,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
767
778
|
}), i;
|
|
768
779
|
} catch (t) {
|
|
769
780
|
h !== void 0 && l.release(h);
|
|
770
|
-
let n =
|
|
781
|
+
let n = J(500, {
|
|
771
782
|
error: "handler threw",
|
|
772
783
|
reason: t.message
|
|
773
784
|
});
|
|
@@ -778,28 +789,28 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
778
789
|
idempotency: g,
|
|
779
790
|
durationMs: Date.now() - o,
|
|
780
791
|
errorMessage: t.message
|
|
781
|
-
}),
|
|
792
|
+
}), ge({
|
|
782
793
|
error: t,
|
|
783
794
|
source: "webhook",
|
|
784
795
|
name: e.id,
|
|
785
796
|
fields: { status: 500 }
|
|
786
797
|
}), n;
|
|
787
798
|
}
|
|
788
|
-
}, { [
|
|
789
|
-
},
|
|
799
|
+
}, { [qe]: c });
|
|
800
|
+
}, Qe = (e) => `/webhooks/${e}`, $e = "_voltro_webhook_rate_windows", et = 6e4, tt = (e, t) => `${e}@${t}`, nt = async (e, t, n) => (await e.query({
|
|
790
801
|
table: "_voltro_webhook_rate_windows",
|
|
791
|
-
predicate: O(
|
|
802
|
+
predicate: D(O("scope", t), O("bucket", n)),
|
|
792
803
|
order: [],
|
|
793
804
|
take: 1,
|
|
794
805
|
skip: void 0,
|
|
795
806
|
projection: void 0
|
|
796
|
-
}))[0] ?? null,
|
|
797
|
-
for (let r = 0; r <
|
|
807
|
+
}))[0] ?? null, Y = 32, rt = async (e, t, n) => {
|
|
808
|
+
for (let r = 0; r < Y; r++) {
|
|
798
809
|
r > 0 && await new Promise((e) => setTimeout(e, r));
|
|
799
|
-
let i = await
|
|
810
|
+
let i = await nt(e, t.key, n);
|
|
800
811
|
if (i === null) {
|
|
801
|
-
await e.insertIgnore(
|
|
802
|
-
id:
|
|
812
|
+
await e.insertIgnore($e, {
|
|
813
|
+
id: tt(t.key, n),
|
|
803
814
|
scope: t.key,
|
|
804
815
|
bucket: n,
|
|
805
816
|
count: 0,
|
|
@@ -812,31 +823,31 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
812
823
|
if (await e.updateMany("_voltro_webhook_rate_windows", {
|
|
813
824
|
count: i.count + 1,
|
|
814
825
|
updatedAt: /* @__PURE__ */ new Date()
|
|
815
|
-
}, { where: O(
|
|
826
|
+
}, { where: D(O("id", i.id), O("count", i.count)) }) === 1) return !0;
|
|
816
827
|
}
|
|
817
|
-
throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${
|
|
818
|
-
},
|
|
819
|
-
for (let r = 0; r <
|
|
828
|
+
throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${Y} attempts`);
|
|
829
|
+
}, it = async (e, t, n) => {
|
|
830
|
+
for (let r = 0; r < Y; r++) {
|
|
820
831
|
r > 0 && await new Promise((e) => setTimeout(e, r));
|
|
821
|
-
let i = await
|
|
832
|
+
let i = await nt(e, t, n);
|
|
822
833
|
if (i === null || i.count <= 0 || await e.updateMany("_voltro_webhook_rate_windows", {
|
|
823
834
|
count: i.count - 1,
|
|
824
835
|
updatedAt: /* @__PURE__ */ new Date()
|
|
825
|
-
}, { where: O(
|
|
836
|
+
}, { where: D(O("id", i.id), O("count", i.count)) }) === 1) return;
|
|
826
837
|
}
|
|
827
|
-
throw Error(`webhook rate window: release contention on (${t}) exceeded ${
|
|
828
|
-
},
|
|
838
|
+
throw Error(`webhook rate window: release contention on (${t}) exceeded ${Y} attempts`);
|
|
839
|
+
}, at = async (e, t, n, r = et) => {
|
|
829
840
|
if (t.length === 0) return {
|
|
830
841
|
acquired: !0,
|
|
831
842
|
retryInMs: 0
|
|
832
843
|
};
|
|
833
844
|
let i = Math.floor(n / r), a = [];
|
|
834
845
|
for (let o of t) {
|
|
835
|
-
if (await
|
|
846
|
+
if (await rt(e, o, i)) {
|
|
836
847
|
a.push(o);
|
|
837
848
|
continue;
|
|
838
849
|
}
|
|
839
|
-
for (let t of a) await
|
|
850
|
+
for (let t of a) await it(e, t.key, i);
|
|
840
851
|
return {
|
|
841
852
|
acquired: !1,
|
|
842
853
|
retryInMs: (i + 1) * r - n
|
|
@@ -846,7 +857,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
846
857
|
acquired: !0,
|
|
847
858
|
retryInMs: 0
|
|
848
859
|
};
|
|
849
|
-
},
|
|
860
|
+
}, ot = (e, t) => {
|
|
850
861
|
if (e === "json") return {
|
|
851
862
|
contentType: "application/json",
|
|
852
863
|
bytes: Buffer.from(t, "utf8")
|
|
@@ -855,47 +866,47 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
855
866
|
try {
|
|
856
867
|
n = JSON.parse(t);
|
|
857
868
|
} catch (t) {
|
|
858
|
-
throw new
|
|
869
|
+
throw new x({
|
|
859
870
|
format: e,
|
|
860
871
|
reason: `payload is not valid JSON: ${t.message}`
|
|
861
872
|
});
|
|
862
873
|
}
|
|
863
874
|
return e === "form" ? {
|
|
864
875
|
contentType: "application/x-www-form-urlencoded",
|
|
865
|
-
bytes: Buffer.from(
|
|
876
|
+
bytes: Buffer.from(st(n), "utf8")
|
|
866
877
|
} : {
|
|
867
878
|
contentType: "application/xml",
|
|
868
|
-
bytes: Buffer.from(
|
|
879
|
+
bytes: Buffer.from(lt(n), "utf8")
|
|
869
880
|
};
|
|
870
|
-
},
|
|
871
|
-
if (typeof e != "object" || !e || Array.isArray(e)) throw new
|
|
881
|
+
}, st = (e) => {
|
|
882
|
+
if (typeof e != "object" || !e || Array.isArray(e)) throw new x({
|
|
872
883
|
format: "form",
|
|
873
|
-
reason: `form encoding requires a JSON object at the top level, got ${
|
|
884
|
+
reason: `form encoding requires a JSON object at the top level, got ${ft(e)}`
|
|
874
885
|
});
|
|
875
886
|
let t = new URLSearchParams();
|
|
876
|
-
for (let [n, r] of Object.entries(e))
|
|
887
|
+
for (let [n, r] of Object.entries(e)) X(t, n, r);
|
|
877
888
|
return t.toString();
|
|
878
|
-
},
|
|
889
|
+
}, X = (e, t, n) => {
|
|
879
890
|
if (n === null) {
|
|
880
891
|
e.append(t, "");
|
|
881
892
|
return;
|
|
882
893
|
}
|
|
883
894
|
if (Array.isArray(n)) {
|
|
884
|
-
n.forEach((n, r) =>
|
|
895
|
+
n.forEach((n, r) => X(e, `${t}[${r}]`, n));
|
|
885
896
|
return;
|
|
886
897
|
}
|
|
887
898
|
if (typeof n == "object") {
|
|
888
|
-
for (let [r, i] of Object.entries(n))
|
|
899
|
+
for (let [r, i] of Object.entries(n)) X(e, `${t}[${r}]`, i);
|
|
889
900
|
return;
|
|
890
901
|
}
|
|
891
902
|
e.append(t, String(n));
|
|
892
|
-
},
|
|
893
|
-
if (!
|
|
903
|
+
}, ct = /^[A-Za-z_][A-Za-z0-9_.-]*$/, lt = (e) => `<?xml version="1.0" encoding="UTF-8"?>${Z("webhook", e)}`, Z = (e, t) => {
|
|
904
|
+
if (!ct.test(e)) throw new x({
|
|
894
905
|
format: "xml",
|
|
895
906
|
reason: `object key ${JSON.stringify(e)} is not a valid XML element name`
|
|
896
907
|
});
|
|
897
|
-
return `<${e}>${
|
|
898
|
-
},
|
|
908
|
+
return `<${e}>${ut(e, t)}</${e}>`;
|
|
909
|
+
}, ut = (e, t) => t == null ? "" : Array.isArray(t) ? t.map((e) => Z("item", e)).join("") : typeof t == "object" ? Object.entries(t).map(([e, t]) => Z(e, t)).join("") : dt(String(t)), dt = (e) => e.replace(/[&<>"']/g, (e) => {
|
|
899
910
|
switch (e) {
|
|
900
911
|
case "&": return "&";
|
|
901
912
|
case "<": return "<";
|
|
@@ -903,17 +914,17 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
903
914
|
case "\"": return """;
|
|
904
915
|
default: return "'";
|
|
905
916
|
}
|
|
906
|
-
}),
|
|
917
|
+
}), ft = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, pt = "_voltro_webhook_targets", mt = 32, ht = async (e, t) => (await e.query({
|
|
907
918
|
table: "_voltro_webhook_targets",
|
|
908
|
-
predicate:
|
|
919
|
+
predicate: O("id", t),
|
|
909
920
|
order: [],
|
|
910
921
|
take: 1,
|
|
911
922
|
skip: void 0,
|
|
912
923
|
projection: void 0
|
|
913
|
-
}))[0] ?? null,
|
|
914
|
-
for (let o = 0; o <
|
|
924
|
+
}))[0] ?? null, Q = async (e, t, n, r, i = /* @__PURE__ */ new Date(), a = !1) => {
|
|
925
|
+
for (let o = 0; o < mt; o++) {
|
|
915
926
|
o > 0 && await new Promise((e) => setTimeout(e, o));
|
|
916
|
-
let s = await
|
|
927
|
+
let s = await ht(e, t);
|
|
917
928
|
if (s === null) return {
|
|
918
929
|
consecutiveFailures: 0,
|
|
919
930
|
autoDisabled: !1
|
|
@@ -923,7 +934,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
923
934
|
if (c === 0 || await e.updateMany("_voltro_webhook_targets", {
|
|
924
935
|
consecutiveFailures: 0,
|
|
925
936
|
updatedAt: i
|
|
926
|
-
}, { where: O(
|
|
937
|
+
}, { where: D(O("id", t), O("consecutiveFailures", c)) }) === 1) return {
|
|
927
938
|
consecutiveFailures: 0,
|
|
928
939
|
autoDisabled: !1
|
|
929
940
|
};
|
|
@@ -933,72 +944,72 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
933
944
|
consecutiveFailures: l,
|
|
934
945
|
updatedAt: i
|
|
935
946
|
};
|
|
936
|
-
if (d && (f.active = !1, f.autoDisabledAt = i, f.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", f, { where: O(
|
|
947
|
+
if (d && (f.active = !1, f.autoDisabledAt = i, f.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", f, { where: D(O("id", t), O("consecutiveFailures", c)) }) === 1) return {
|
|
937
948
|
consecutiveFailures: l,
|
|
938
949
|
autoDisabled: d
|
|
939
950
|
};
|
|
940
951
|
}
|
|
941
|
-
throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${
|
|
942
|
-
},
|
|
943
|
-
status:
|
|
944
|
-
body:
|
|
945
|
-
latencyMs:
|
|
946
|
-
retryAfterSec:
|
|
947
|
-
transportError:
|
|
948
|
-
encodeError:
|
|
949
|
-
}),
|
|
950
|
-
outcome:
|
|
951
|
-
delayMs:
|
|
952
|
-
reason:
|
|
953
|
-
autoDisabled:
|
|
954
|
-
consecutiveFailures:
|
|
955
|
-
}),
|
|
956
|
-
acquired:
|
|
957
|
-
retryInMs:
|
|
958
|
-
}),
|
|
959
|
-
deliveryId:
|
|
960
|
-
targetId:
|
|
961
|
-
event:
|
|
962
|
-
eventId:
|
|
963
|
-
payloadJson:
|
|
964
|
-
attemptEpoch:
|
|
965
|
-
},
|
|
952
|
+
throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${mt} attempts`);
|
|
953
|
+
}, gt = T.Struct({
|
|
954
|
+
status: T.Number,
|
|
955
|
+
body: T.String,
|
|
956
|
+
latencyMs: T.Number,
|
|
957
|
+
retryAfterSec: T.Union(T.Number, T.Undefined),
|
|
958
|
+
transportError: T.Union(T.String, T.Undefined),
|
|
959
|
+
encodeError: T.Union(T.String, T.Undefined)
|
|
960
|
+
}), _t = T.Struct({
|
|
961
|
+
outcome: T.Literal("succeeded", "failed", "retry"),
|
|
962
|
+
delayMs: T.Union(T.Number, T.Undefined),
|
|
963
|
+
reason: T.Union(T.String, T.Undefined),
|
|
964
|
+
autoDisabled: T.Union(T.Boolean, T.Undefined),
|
|
965
|
+
consecutiveFailures: T.Union(T.Number, T.Undefined)
|
|
966
|
+
}), vt = T.Struct({
|
|
967
|
+
acquired: T.Boolean,
|
|
968
|
+
retryInMs: T.Number
|
|
969
|
+
}), yt = {
|
|
970
|
+
deliveryId: T.String,
|
|
971
|
+
targetId: T.String,
|
|
972
|
+
event: T.String,
|
|
973
|
+
eventId: T.String,
|
|
974
|
+
payloadJson: T.String,
|
|
975
|
+
attemptEpoch: T.optionalWith(T.Number, { default: () => 0 })
|
|
976
|
+
}, bt = ye.make({
|
|
966
977
|
name: "voltro.deliverWebhook",
|
|
967
|
-
payload:
|
|
968
|
-
success:
|
|
969
|
-
finalStatus:
|
|
970
|
-
attempts:
|
|
978
|
+
payload: yt,
|
|
979
|
+
success: T.Struct({
|
|
980
|
+
finalStatus: T.Literal("succeeded", "failed", "deferred"),
|
|
981
|
+
attempts: T.Number
|
|
971
982
|
}),
|
|
972
983
|
idempotencyKey: ({ deliveryId: e, attemptEpoch: t }) => `voltro.deliverWebhook:${e}:${t ?? 0}`
|
|
973
|
-
}),
|
|
984
|
+
}), xt = 3e4, St = (e, t) => {
|
|
974
985
|
if (e !== void 0) return e;
|
|
975
986
|
let n = Number(t.VOLTRO_WEBHOOK_TIMEOUT_MS);
|
|
976
|
-
return Number.isFinite(n) && n > 0 ? n :
|
|
977
|
-
},
|
|
978
|
-
let { deliveryId: i, targetId: a, event: o, eventId: s, payloadJson: c } = n, l =
|
|
979
|
-
return
|
|
980
|
-
let n = yield*
|
|
987
|
+
return Number.isFinite(n) && n > 0 ? n : xt;
|
|
988
|
+
}, Ct = (e, t = {}) => (n, r) => {
|
|
989
|
+
let { deliveryId: i, targetId: a, event: o, eventId: s, payloadJson: c } = n, l = k({ scope: `webhook:${i}` });
|
|
990
|
+
return w.gen(function* () {
|
|
991
|
+
let n = yield* A.make({
|
|
981
992
|
name: "fetch-target",
|
|
982
|
-
success:
|
|
983
|
-
id:
|
|
984
|
-
event:
|
|
985
|
-
url:
|
|
986
|
-
secret:
|
|
987
|
-
signing:
|
|
988
|
-
retry:
|
|
989
|
-
headers:
|
|
990
|
-
key:
|
|
991
|
-
value:
|
|
992
|
-
}),
|
|
993
|
-
rateLimitPerMinute:
|
|
994
|
-
active:
|
|
995
|
-
format:
|
|
996
|
-
tenantId:
|
|
993
|
+
success: T.Union(T.Null, T.Struct({
|
|
994
|
+
id: T.String,
|
|
995
|
+
event: T.String,
|
|
996
|
+
url: T.String,
|
|
997
|
+
secret: T.String,
|
|
998
|
+
signing: T.Any,
|
|
999
|
+
retry: T.Any,
|
|
1000
|
+
headers: T.Union(T.Record({
|
|
1001
|
+
key: T.String,
|
|
1002
|
+
value: T.String
|
|
1003
|
+
}), T.Null),
|
|
1004
|
+
rateLimitPerMinute: T.Union(T.Number, T.Null),
|
|
1005
|
+
active: T.Boolean,
|
|
1006
|
+
format: T.Literal("json", "form", "xml"),
|
|
1007
|
+
tenantId: T.Union(T.String, T.Null)
|
|
997
1008
|
})),
|
|
998
|
-
execute:
|
|
1009
|
+
execute: w.tryPromise({
|
|
999
1010
|
try: async () => (await e.store.query({
|
|
1000
1011
|
table: "_voltro_webhook_targets",
|
|
1001
|
-
predicate:
|
|
1012
|
+
predicate: O("id", a),
|
|
1002
1013
|
order: [{
|
|
1003
1014
|
column: "createdAt",
|
|
1004
1015
|
direction: "asc"
|
|
@@ -1012,7 +1023,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1012
1023
|
event: o,
|
|
1013
1024
|
cause: String(e)
|
|
1014
1025
|
}), /* @__PURE__ */ Error(`fetch-target failed: ${e.message}`))
|
|
1015
|
-
}).pipe(
|
|
1026
|
+
}).pipe(w.orDie)
|
|
1016
1027
|
});
|
|
1017
1028
|
if (n === null) return {
|
|
1018
1029
|
finalStatus: "failed",
|
|
@@ -1037,18 +1048,18 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1037
1048
|
...l
|
|
1038
1049
|
});
|
|
1039
1050
|
};
|
|
1040
|
-
if (n.active !== !0) return yield*
|
|
1051
|
+
if (n.active !== !0) return yield* A.make({
|
|
1041
1052
|
name: "record-paused-pending",
|
|
1042
|
-
success:
|
|
1043
|
-
execute:
|
|
1053
|
+
success: T.Void,
|
|
1054
|
+
execute: w.tryPromise({
|
|
1044
1055
|
try: () => r(`${i}:1`, 1, { status: "pending" }),
|
|
1045
1056
|
catch: (e) => /* @__PURE__ */ Error(`record-paused-pending failed: ${e.message}`)
|
|
1046
|
-
}).pipe(
|
|
1057
|
+
}).pipe(w.orDie)
|
|
1047
1058
|
}), {
|
|
1048
1059
|
finalStatus: "deferred",
|
|
1049
1060
|
attempts: 0
|
|
1050
1061
|
};
|
|
1051
|
-
let u = (e) => typeof e == "string" ? JSON.parse(e) : e, d = u(n.retry), p = u(n.signing), m = n.headers === null ? null : u(n.headers), h = t.rateWindowMs ?? 6e4, g =
|
|
1062
|
+
let u = (e) => typeof e == "string" ? JSON.parse(e) : e, d = u(n.retry), p = u(n.signing), m = n.headers === null ? null : u(n.headers), h = t.rateWindowMs ?? 6e4, g = St(t.timeoutMs, process.env), _ = t.events?.find((e) => e.id === o)?.globalRateLimit, v = [...typeof n.rateLimitPerMinute == "number" && n.rateLimitPerMinute > 0 ? [{
|
|
1052
1063
|
key: `target:${n.id}`,
|
|
1053
1064
|
limit: n.rateLimitPerMinute
|
|
1054
1065
|
}] : [], ..._ !== void 0 && _.perMinute > 0 ? [{
|
|
@@ -1058,56 +1069,56 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1058
1069
|
for (let t = 1; t <= d.maxAttempts; t++) {
|
|
1059
1070
|
let u = `${i}:${t}`;
|
|
1060
1071
|
if (v.length > 0) for (let n = 0;; n++) {
|
|
1061
|
-
let i = yield*
|
|
1072
|
+
let i = yield* A.make({
|
|
1062
1073
|
name: `rate-acquire-${t}-${n}`,
|
|
1063
|
-
success:
|
|
1064
|
-
execute:
|
|
1065
|
-
try: () =>
|
|
1074
|
+
success: vt,
|
|
1075
|
+
execute: w.tryPromise({
|
|
1076
|
+
try: () => at(e.store, v, Date.now(), h),
|
|
1066
1077
|
catch: (e) => (l.debug("rate-acquire raw error", {
|
|
1067
1078
|
targetId: a,
|
|
1068
1079
|
event: o,
|
|
1069
1080
|
attempt: t,
|
|
1070
1081
|
cause: String(e)
|
|
1071
1082
|
}), /* @__PURE__ */ Error(`rate-acquire failed: ${e.message}`))
|
|
1072
|
-
}).pipe(
|
|
1083
|
+
}).pipe(w.orDie)
|
|
1073
1084
|
});
|
|
1074
1085
|
if (i.acquired) break;
|
|
1075
|
-
yield*
|
|
1086
|
+
yield* A.make({
|
|
1076
1087
|
name: `record-rate-deferral-${t}-${n}`,
|
|
1077
|
-
success:
|
|
1078
|
-
execute:
|
|
1088
|
+
success: T.Void,
|
|
1089
|
+
execute: w.tryPromise({
|
|
1079
1090
|
try: () => r(u, t, {
|
|
1080
1091
|
status: "pending",
|
|
1081
1092
|
nextAttemptAt: new Date(Date.now() + i.retryInMs)
|
|
1082
1093
|
}),
|
|
1083
1094
|
catch: (e) => /* @__PURE__ */ Error(`record-rate-deferral failed: ${e.message}`)
|
|
1084
|
-
}).pipe(
|
|
1085
|
-
}), yield*
|
|
1095
|
+
}).pipe(w.orDie)
|
|
1096
|
+
}), yield* j.sleep({
|
|
1086
1097
|
name: `rate-window-sleep-${t}-${n}`,
|
|
1087
1098
|
duration: `${i.retryInMs} millis`
|
|
1088
1099
|
});
|
|
1089
1100
|
}
|
|
1090
|
-
yield*
|
|
1101
|
+
yield* A.make({
|
|
1091
1102
|
name: `record-attempt-start-${t}`,
|
|
1092
|
-
success:
|
|
1093
|
-
execute:
|
|
1103
|
+
success: T.Void,
|
|
1104
|
+
execute: w.tryPromise({
|
|
1094
1105
|
try: () => r(u, t, {
|
|
1095
1106
|
status: "inFlight",
|
|
1096
1107
|
nextAttemptAt: null,
|
|
1097
1108
|
scheduledAt: /* @__PURE__ */ new Date()
|
|
1098
1109
|
}),
|
|
1099
1110
|
catch: (e) => /* @__PURE__ */ Error(`record-attempt-start failed: ${e.message}`)
|
|
1100
|
-
}).pipe(
|
|
1111
|
+
}).pipe(w.orDie)
|
|
1101
1112
|
});
|
|
1102
|
-
let _ = yield*
|
|
1113
|
+
let _ = yield* A.make({
|
|
1103
1114
|
name: `sign-and-post-${t}`,
|
|
1104
|
-
success:
|
|
1105
|
-
execute:
|
|
1115
|
+
success: gt,
|
|
1116
|
+
execute: w.promise(async () => {
|
|
1106
1117
|
let e = Date.now(), r;
|
|
1107
1118
|
try {
|
|
1108
|
-
r =
|
|
1119
|
+
r = ot(n.format, c);
|
|
1109
1120
|
} catch (t) {
|
|
1110
|
-
if (t instanceof
|
|
1121
|
+
if (t instanceof x) return {
|
|
1111
1122
|
status: 0,
|
|
1112
1123
|
body: "",
|
|
1113
1124
|
latencyMs: Date.now() - e,
|
|
@@ -1122,7 +1133,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1122
1133
|
secret: n.secret,
|
|
1123
1134
|
messageId: i
|
|
1124
1135
|
});
|
|
1125
|
-
process.env.NODE_ENV === "production" &&
|
|
1136
|
+
process.env.NODE_ENV === "production" && ve(n.url);
|
|
1126
1137
|
try {
|
|
1127
1138
|
let c = await fetch(n.url, {
|
|
1128
1139
|
method: "POST",
|
|
@@ -1159,12 +1170,12 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1159
1170
|
};
|
|
1160
1171
|
}
|
|
1161
1172
|
})
|
|
1162
|
-
}), y = yield*
|
|
1173
|
+
}), y = yield* A.make({
|
|
1163
1174
|
name: `classify-and-record-${t}`,
|
|
1164
|
-
success:
|
|
1165
|
-
execute:
|
|
1175
|
+
success: _t,
|
|
1176
|
+
execute: w.tryPromise({
|
|
1166
1177
|
try: async () => {
|
|
1167
|
-
let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = _.status === 410, c = (t, n) =>
|
|
1178
|
+
let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = _.status === 410, c = (t, n) => Q(e.store, a, t, n, /* @__PURE__ */ new Date(), !t && s);
|
|
1168
1179
|
if (r) {
|
|
1169
1180
|
await e.store.update("_voltro_webhook_deliveries", u, {
|
|
1170
1181
|
status: "succeeded",
|
|
@@ -1182,7 +1193,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1182
1193
|
consecutiveFailures: t.consecutiveFailures
|
|
1183
1194
|
};
|
|
1184
1195
|
}
|
|
1185
|
-
let l = o ? null :
|
|
1196
|
+
let l = o ? null : Te(d, t, {
|
|
1186
1197
|
...i ? {} : { status: _.status },
|
|
1187
1198
|
..._.retryAfterSec === void 0 ? {} : { retryAfterSeconds: _.retryAfterSec }
|
|
1188
1199
|
});
|
|
@@ -1227,7 +1238,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1227
1238
|
attempt: t,
|
|
1228
1239
|
cause: String(e)
|
|
1229
1240
|
}), /* @__PURE__ */ Error(`classify-and-record failed: ${e.message}`))
|
|
1230
|
-
}).pipe(
|
|
1241
|
+
}).pipe(w.orDie)
|
|
1231
1242
|
});
|
|
1232
1243
|
if (y.autoDisabled === !0 && l.warn("target auto-disabled after consecutive failures", {
|
|
1233
1244
|
targetId: a,
|
|
@@ -1242,7 +1253,7 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1242
1253
|
finalStatus: "failed",
|
|
1243
1254
|
attempts: t
|
|
1244
1255
|
};
|
|
1245
|
-
y.delayMs !== void 0 && (yield*
|
|
1256
|
+
y.delayMs !== void 0 && (yield* j.sleep({
|
|
1246
1257
|
name: `retry-sleep-${t}`,
|
|
1247
1258
|
duration: `${y.delayMs} millis`
|
|
1248
1259
|
}));
|
|
@@ -1252,15 +1263,15 @@ var N = ["network:outbound:*"], ye = (e = {}) => pe({
|
|
|
1252
1263
|
attempts: d.maxAttempts
|
|
1253
1264
|
};
|
|
1254
1265
|
});
|
|
1255
|
-
}, $ = "voltro.webhook.emit",
|
|
1266
|
+
}, $ = "voltro.webhook.emit", wt = (e) => typeof e.event == "string", Tt = (e) => be({
|
|
1256
1267
|
effect: $,
|
|
1257
1268
|
maxAttempts: 1,
|
|
1258
1269
|
handler: async ({ payload: t }) => {
|
|
1259
|
-
if (!
|
|
1270
|
+
if (!wt(t)) throw Error(`${$}: row payload has no \`event\` name — cannot resolve a descriptor. Got keys: ${Object.keys(t).join(", ") || "(none)"}`);
|
|
1260
1271
|
let n = e();
|
|
1261
1272
|
if (n === void 0) throw Error(`${$}: the outgoing-webhooks service is not available in this process. An emit was enqueued by a build that had the plugin registered; this one does not.`);
|
|
1262
1273
|
await n.emit(t.event, t.payload, { tenantId: t.tenantId });
|
|
1263
1274
|
}
|
|
1264
1275
|
});
|
|
1265
1276
|
//#endregion
|
|
1266
|
-
export {
|
|
1277
|
+
export { We as IdempotencyCache, et as RATE_WINDOW_MS, $e as RATE_WINDOW_TABLE, p as STANDARD_WEBHOOKS_DEFAULT_TOLERANCE_SECONDS, te as STANDARD_WEBHOOKS_ID_HEADER, c as STANDARD_WEBHOOKS_MAX_KEY_BYTES, l as STANDARD_WEBHOOKS_MIN_KEY_BYTES, _ as STANDARD_WEBHOOKS_SECRET_PREFIX, m as STANDARD_WEBHOOKS_SIGNATURE_HEADER, d as STANDARD_WEBHOOKS_TIMESTAMP_HEADER, u as STANDARD_WEBHOOKS_VERSION, pt as TARGETS_TABLE, Je as UnverifiedIncomingWebhook, M as WEBHOOKS_PLUGIN_PERMISSIONS, $ as WEBHOOK_EMIT_EFFECT, qe as WEBHOOK_VERIFICATION_PROPERTY, b as WebhookDeliveryNotFound, oe as WebhookPayloadInvalid, x as WebhookPayloadUnrepresentable, se as WebhookPayloadVersionInvalid, S as WebhookSubscribeInvalid, C as WebhookTargetNotFound, Oe as WebhooksService, ce as _voltroWebhookDeliveriesTable, le as _voltroWebhookEventStatsTable, ue as _voltroWebhookRateWindowsTable, de as _voltroWebhookTargetsTable, at as acquireRateSlots, Ce as asOutgoingEvent, Ct as buildDeliverWebhookExecute, Be as buildWebhooksService, Me as compareVersions, rt as consumeRateSlot, Qe as defaultIncomingPath, ee as defaultOutgoingSignature, Ee as defaultRetryPolicy, re as defineIncomingWebhook, r as defineWebhookProvider, bt as deliverWebhookWorkflow, ot as encodePayload, L as eventsOf, De as fastRetryPolicy, I as generateSecret, i as generateStandardWebhooksSecret, h as genericHmacSignature, Ge as getIdempotencyCache, v as githubSignature, Se as hasWebhookAudience, Xe as incomingWebhookVerification, ne as isStandardWebhooksSecret, t as isWebhookDescriptor, Tt as makeDeferredEmitHandler, Ne as matchesFilter, Ze as mountIncomingWebhook, Te as nextRetry, N as parseDuration, Ke as parseTtl, Q as recordDeliveryOutcome, it as releaseRateSlot, B as resolveSubscribe, f as signRequest, a as slackSignature, ae as standardWebhooksHeaders, o as standardWebhooksKey, g as standardWebhooksSignature, ie as standardWebhooksSignatureToken, n as standardWebhooksSignedContent, y as stripeSignature, He as useWebhooks, Ve as useWebhooksEffect, z as validateSubscribe, s as verifyRequest, e as verifyStandardWebhooks, fe as webhookTables, xe as webhooksPlugin };
|