@voltro/plugin-webhooks 0.25.0 → 0.27.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/dist/index.js CHANGED
@@ -6,8 +6,8 @@ import { Context as ee, Effect as b, Either as te, Schema as x } from "effect";
6
6
  import { and as S, eq as C } from "@voltro/database";
7
7
  import { assertPublicUrl as w } from "@voltro/integration-http";
8
8
  import { publishServerError as ne } from "@voltro/protocol";
9
- import { createLogger as re } from "@voltro/logger";
10
- import { Activity as T, DurableClock as E, Workflow as ie } from "@effect/workflow";
9
+ import { createLogger as T } from "@voltro/logger";
10
+ import { Activity as E, DurableClock as re, Workflow as ie } from "@effect/workflow";
11
11
  //#region src/eventAudience.ts
12
12
  var ae = (e) => e.webhook !== void 0, D = (e) => {
13
13
  let t = e.webhook;
@@ -39,7 +39,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
39
39
  502,
40
40
  503,
41
41
  504
42
- ], A = (e, t, n) => {
42
+ ], se = (e, t, n) => {
43
43
  if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ?? k).includes(n.status)) return null;
44
44
  if (e.honourRetryAfter !== !1 && n?.retryAfterSeconds !== void 0) {
45
45
  let t = n.retryAfterSeconds * 1e3, r = O(e.maxDelay), i = Math.min(t, r);
@@ -66,7 +66,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
66
66
  delayMs: Math.max(1, Math.floor(o)),
67
67
  baseDelayMs: a
68
68
  };
69
- }, j = () => ({
69
+ }, A = () => ({
70
70
  strategy: "exponential",
71
71
  maxAttempts: 8,
72
72
  initialDelay: "5s",
@@ -74,7 +74,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
74
74
  retryOn: k,
75
75
  honourRetryAfter: !0,
76
76
  jitter: "full"
77
- }), se = () => ({
77
+ }), ce = () => ({
78
78
  strategy: "fixed",
79
79
  maxAttempts: 120,
80
80
  initialDelay: "30s",
@@ -82,7 +82,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
82
82
  retryOn: k,
83
83
  honourRetryAfter: !0,
84
84
  jitter: "full"
85
- }), M = class extends ee.Tag("@voltro/webhooks/WebhooksService")() {}, ce = 32, N = 32, P = () => v(ce).toString("hex"), F = (e) => {
85
+ }), j = class extends ee.Tag("@voltro/webhooks/WebhooksService")() {}, le = 32, M = 32, N = () => v(le).toString("hex"), P = (e) => e.events ?? (e.event === void 0 ? [] : [e.event]), F = (e) => {
86
86
  let t;
87
87
  try {
88
88
  t = new URL(e.url);
@@ -104,13 +104,26 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
104
104
  reason: e.message
105
105
  });
106
106
  }
107
- if (e.event.length === 0) throw new p({
107
+ let n = P(e);
108
+ if (n.length === 0) throw new p({
108
109
  field: "event",
109
110
  reason: "event id required"
110
111
  });
111
- if (e.secret !== void 0 && e.secret.length < N) throw new p({
112
+ if (e.event !== void 0 && e.events !== void 0) throw new p({
113
+ field: "event",
114
+ reason: "pass `event` OR `events`, not both — the row set would be ambiguous"
115
+ });
116
+ if (n.some((e) => e.length === 0)) throw new p({
117
+ field: "events",
118
+ reason: "event id required"
119
+ });
120
+ if (new Set(n).size !== n.length) throw new p({
121
+ field: "events",
122
+ reason: "duplicate event — one row per event, so a repeat would deliver twice"
123
+ });
124
+ if (e.secret !== void 0 && e.secret.length < M) throw new p({
112
125
  field: "secret",
113
- reason: `secret must be at least ${N} chars`
126
+ reason: `secret must be at least ${M} chars`
114
127
  });
115
128
  if (e.retry !== void 0) {
116
129
  if (e.retry.maxAttempts < 1) throw new p({
@@ -130,14 +143,15 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
130
143
  field: "autoDisableAfter",
131
144
  reason: `autoDisableAfter must be a positive integer, got ${e.autoDisableAfter}`
132
145
  });
133
- }, I = (e, t) => ({
146
+ }, I = (e, t, n, r) => ({
134
147
  id: y(),
135
- event: e.event,
148
+ event: n ?? e.event ?? "",
136
149
  url: e.url,
137
- secret: e.secret ?? P(),
150
+ secret: r ?? e.secret ?? N(),
138
151
  signing: e.signing ?? t?.defaultSigning ?? c(),
139
- retry: e.retry ?? t?.defaultRetry ?? j(),
152
+ retry: e.retry ?? t?.defaultRetry ?? A(),
140
153
  filter: e.filter ?? null,
154
+ scope: e.scope ?? null,
141
155
  headers: e.headers ?? null,
142
156
  rateLimitPerMinute: e.rateLimitPerMinute ?? null,
143
157
  active: !0,
@@ -148,19 +162,40 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
148
162
  autoDisableReason: null,
149
163
  payloadVersion: e.payloadVersion ?? t?.version ?? 1,
150
164
  description: e.description ?? null
151
- }), le = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", L = (e, t) => {
165
+ }), ue = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : 0, L = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : null, de = (e) => {
166
+ if (typeof e != "string") return e;
167
+ try {
168
+ return JSON.parse(e);
169
+ } catch {
170
+ return e;
171
+ }
172
+ }, R = (e) => ({
173
+ id: String(e.id),
174
+ deliveryId: String(e.deliveryId),
175
+ targetId: String(e.targetId),
176
+ event: String(e.event),
177
+ eventId: e.eventId ?? null,
178
+ attempt: Number(e.attempt ?? 0),
179
+ status: e.status,
180
+ responseStatus: e.responseStatus ?? null,
181
+ errorMessage: e.errorMessage ?? null,
182
+ latencyMs: e.latencyMs ?? null,
183
+ scheduledAt: L(e.scheduledAt),
184
+ nextAttemptAt: L(e.nextAttemptAt),
185
+ createdAt: L(e.createdAt)
186
+ }), fe = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", z = (e, t) => {
152
187
  if (e === null) return !0;
153
188
  let n = { payload: t };
154
- for (let [t, r] of Object.entries(e)) if (!de(ue(n, t), r)) return !1;
189
+ for (let [t, r] of Object.entries(e)) if (!me(pe(n, t), r)) return !1;
155
190
  return !0;
156
- }, ue = (e, t) => {
191
+ }, pe = (e, t) => {
157
192
  let n = t.split("."), r = e;
158
193
  for (let e of n) {
159
194
  if (typeof r != "object" || !r) return;
160
195
  r = r[e];
161
196
  }
162
197
  return r;
163
- }, de = (e, t) => {
198
+ }, me = (e, t) => {
164
199
  if (typeof t == "object" && t && !Array.isArray(t)) {
165
200
  let n = t;
166
201
  if ("eq" in n) return e === n.eq;
@@ -171,23 +206,28 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
171
206
  if ("in" in n && Array.isArray(n.in)) return n.in.includes(e);
172
207
  }
173
208
  return e === t;
174
- }, fe = (e, t, n = {}) => {
175
- let r = new Map((n.events ?? []).map((e) => [e.id, e]));
176
- return {
209
+ }, he = (e, t, n = {}) => {
210
+ let r = new Map((n.events ?? []).map((e) => [e.id, e])), i = {
177
211
  subscribe: async (t) => {
178
212
  F(t);
179
- let n = I(t, r.get(t.event));
180
- return await e.store.insert("_voltro_webhook_targets", {
181
- ...n,
213
+ let n = P(t), i = t.secret ?? N(), a = n.map((e) => I(t, r.get(e), e, i));
214
+ for (let t of a) await e.store.insert("_voltro_webhook_targets", {
215
+ ...t,
182
216
  createdAt: /* @__PURE__ */ new Date(),
183
217
  updatedAt: /* @__PURE__ */ new Date()
184
- }), {
185
- id: n.id,
186
- event: n.event,
187
- url: n.url,
188
- secret: n.secret,
189
- signing: n.signing,
190
- retry: n.retry
218
+ });
219
+ let o = a[0];
220
+ return {
221
+ id: o.id,
222
+ event: o.event,
223
+ url: o.url,
224
+ secret: o.secret,
225
+ signing: o.signing,
226
+ retry: o.retry,
227
+ ...a.length > 1 ? { targets: a.map((e) => ({
228
+ id: e.id,
229
+ event: e.event
230
+ })) } : {}
191
231
  };
192
232
  },
193
233
  emit: async (n, i) => {
@@ -209,7 +249,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
209
249
  take: 1e3,
210
250
  skip: void 0,
211
251
  projection: void 0
212
- })).filter((e) => L(e.filter, i)), d = [], f = JSON.stringify(i);
252
+ })).filter((e) => z(e.filter, i)), d = [], f = JSON.stringify(i);
213
253
  for (let n of l) {
214
254
  let r = y();
215
255
  n.active ? (await t({
@@ -268,49 +308,148 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
268
308
  attemptEpoch: Date.now()
269
309
  });
270
310
  },
311
+ resolveTargets: async (t) => {
312
+ if (typeof t == "string") return [t];
313
+ let n = (await e.store.query({
314
+ table: "_voltro_webhook_targets",
315
+ predicate: void 0,
316
+ order: void 0,
317
+ take: 1e3,
318
+ skip: void 0,
319
+ projection: void 0
320
+ })).filter((e) => e.scope !== null && Object.entries(t.scope).every(([t, n]) => e.scope?.[t] === n)).map((e) => e.id);
321
+ if (n.length === 0) throw Error(`webhooks: no target matches scope ${JSON.stringify(t.scope)} — the operation would have silently done nothing`);
322
+ return n;
323
+ },
271
324
  pauseTarget: async (t) => {
272
- await e.store.update("_voltro_webhook_targets", t, {
325
+ for (let n of await i.resolveTargets(t)) await e.store.update("_voltro_webhook_targets", n, {
273
326
  active: !1,
274
327
  updatedAt: /* @__PURE__ */ new Date()
275
328
  });
276
329
  },
277
330
  resumeTarget: async (n) => {
278
- await e.store.update("_voltro_webhook_targets", n, {
279
- active: !0,
280
- consecutiveFailures: 0,
281
- autoDisabledAt: null,
282
- autoDisableReason: null,
331
+ for (let r of await i.resolveTargets(n)) {
332
+ await e.store.update("_voltro_webhook_targets", r, {
333
+ active: !0,
334
+ consecutiveFailures: 0,
335
+ autoDisabledAt: null,
336
+ autoDisableReason: null,
337
+ updatedAt: /* @__PURE__ */ new Date()
338
+ });
339
+ let n = await e.store.query({
340
+ table: "_voltro_webhook_deliveries",
341
+ predicate: S(C("targetId", r), C("status", "pending")),
342
+ order: [{
343
+ column: "createdAt",
344
+ direction: "asc"
345
+ }],
346
+ take: 1e4,
347
+ skip: void 0,
348
+ projection: void 0
349
+ }), i = Date.now();
350
+ for (let e of n) await t({
351
+ deliveryId: e.deliveryId,
352
+ targetId: r,
353
+ event: e.event,
354
+ eventId: e.eventId ?? y(),
355
+ payloadJson: typeof e.payload == "string" ? e.payload : JSON.stringify(e.payload),
356
+ attemptEpoch: i
357
+ });
358
+ }
359
+ },
360
+ 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(C("targetId", n), C("status", "pending")) });
362
+ },
363
+ rotateSecret: async (t) => {
364
+ let n = N();
365
+ for (let r of await i.resolveTargets(t)) await e.store.update("_voltro_webhook_targets", r, {
366
+ secret: n,
283
367
  updatedAt: /* @__PURE__ */ new Date()
284
368
  });
285
- let r = await e.store.query({
369
+ return { secret: n };
370
+ },
371
+ updateTarget: async (t, n) => {
372
+ if (n.url !== void 0 && F({
373
+ event: "x",
374
+ url: n.url
375
+ }), 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");
376
+ let r = { updatedAt: /* @__PURE__ */ new Date() };
377
+ for (let e of [
378
+ "url",
379
+ "description",
380
+ "filter",
381
+ "scope",
382
+ "headers",
383
+ "rateLimitPerMinute",
384
+ "autoDisableAfter",
385
+ "format"
386
+ ]) n[e] !== void 0 && (r[e] = n[e]);
387
+ for (let n of await i.resolveTargets(t)) await e.store.update("_voltro_webhook_targets", n, r);
388
+ },
389
+ testTarget: async (n, r) => {
390
+ let i = (await e.store.query({
391
+ table: "_voltro_webhook_targets",
392
+ predicate: C("id", n),
393
+ order: void 0,
394
+ take: 1,
395
+ skip: void 0,
396
+ projection: void 0
397
+ }))[0];
398
+ if (i === void 0) throw Error(`testTarget: no target ${n}`);
399
+ let a = y(), o = JSON.stringify(r ?? {
400
+ test: !0,
401
+ targetId: n,
402
+ at: (/* @__PURE__ */ new Date()).toISOString()
403
+ });
404
+ return i.active ? await t({
405
+ deliveryId: a,
406
+ targetId: i.id,
407
+ event: i.event,
408
+ eventId: y(),
409
+ payloadJson: o
410
+ }) : await e.store.insert("_voltro_webhook_deliveries", {
411
+ id: `${a}:1`,
412
+ deliveryId: a,
413
+ targetId: i.id,
414
+ tenantId: i.tenantId ?? null,
415
+ event: i.event,
416
+ eventId: null,
417
+ attempt: 1,
418
+ status: "pending",
419
+ payload: o,
420
+ scheduledAt: /* @__PURE__ */ new Date(),
421
+ createdAt: /* @__PURE__ */ new Date(),
422
+ updatedAt: /* @__PURE__ */ new Date()
423
+ }), { deliveryId: a };
424
+ },
425
+ listDeliveries: async (t) => {
426
+ let n = t?.scope === void 0 ? void 0 : new Set(await i.resolveTargets({ scope: t.scope })), r = await e.store.query({
286
427
  table: "_voltro_webhook_deliveries",
287
- predicate: S(C("targetId", n), C("status", "pending")),
428
+ predicate: t?.targetId === void 0 ? void 0 : C("targetId", t.targetId),
288
429
  order: [{
289
430
  column: "createdAt",
290
- direction: "asc"
431
+ direction: "desc"
291
432
  }],
292
- take: 1e4,
433
+ take: Math.min((t?.limit ?? 200) * (t?.status !== void 0 || t?.since !== void 0 ? 10 : 1), 5e3),
293
434
  skip: void 0,
294
435
  projection: void 0
295
- }), i = Date.now();
296
- for (let e of r) await t({
297
- deliveryId: e.deliveryId,
298
- targetId: n,
299
- event: e.event,
300
- eventId: e.eventId ?? y(),
301
- payloadJson: typeof e.payload == "string" ? e.payload : JSON.stringify(e.payload),
302
- attemptEpoch: i
303
- });
436
+ }), 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 || ue(e.createdAt) >= a).slice(0, t?.limit ?? 200).map(R);
304
438
  },
305
- deleteTarget: async (t) => {
306
- await e.store.delete("_voltro_webhook_targets", t), await e.store.deleteMany("_voltro_webhook_deliveries", { where: S(C("targetId", t), C("status", "pending")) });
307
- },
308
- rotateSecret: async (t) => {
309
- let n = P();
310
- return await e.store.update("_voltro_webhook_targets", t, {
311
- secret: n,
312
- updatedAt: /* @__PURE__ */ new Date()
313
- }), { secret: n };
439
+ getDelivery: async (t) => {
440
+ let n = (await e.store.query({
441
+ table: "_voltro_webhook_deliveries",
442
+ predicate: C("id", t),
443
+ order: void 0,
444
+ take: 1,
445
+ skip: void 0,
446
+ projection: void 0
447
+ }))[0];
448
+ return n === void 0 ? null : {
449
+ ...R(n),
450
+ payload: de(n.payload),
451
+ responseBody: n.responseBody ?? null
452
+ };
314
453
  },
315
454
  updateTargetPayloadVersion: async (t, n) => {
316
455
  if (n < 1 || !Number.isInteger(n)) throw new f({ version: n });
@@ -319,39 +458,44 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
319
458
  updatedAt: /* @__PURE__ */ new Date()
320
459
  });
321
460
  },
322
- listTargets: async (t) => (await e.store.query({
323
- table: "_voltro_webhook_targets",
324
- predicate: t === void 0 ? void 0 : C("event", t),
325
- order: [{
326
- column: "createdAt",
327
- direction: "desc"
328
- }],
329
- take: 500,
330
- skip: void 0,
331
- projection: void 0
332
- })).map((e) => ({
333
- id: e.id,
334
- event: e.event,
335
- url: e.url,
336
- active: e.active,
337
- rateLimitPerMinute: e.rateLimitPerMinute,
338
- description: e.description,
339
- payloadVersion: e.payloadVersion,
340
- autoDisableAfter: e.autoDisableAfter,
341
- consecutiveFailures: e.consecutiveFailures ?? 0,
342
- autoDisabledAt: e.autoDisabledAt === null || e.autoDisabledAt === void 0 ? null : e.autoDisabledAt instanceof Date ? e.autoDisabledAt.toISOString() : String(e.autoDisabledAt),
343
- autoDisableReason: e.autoDisableReason
344
- }))
461
+ listTargets: async (t, n) => {
462
+ let r = await e.store.query({
463
+ table: "_voltro_webhook_targets",
464
+ predicate: t === void 0 ? void 0 : C("event", t),
465
+ order: [{
466
+ column: "createdAt",
467
+ direction: "desc"
468
+ }],
469
+ take: 500,
470
+ skip: void 0,
471
+ projection: void 0
472
+ });
473
+ return (n === void 0 ? r : r.filter((e) => e.scope !== null && Object.entries(n).every(([t, n]) => e.scope?.[t] === n))).map((e) => ({
474
+ id: e.id,
475
+ event: e.event,
476
+ url: e.url,
477
+ active: e.active,
478
+ rateLimitPerMinute: e.rateLimitPerMinute,
479
+ description: e.description,
480
+ payloadVersion: e.payloadVersion,
481
+ autoDisableAfter: e.autoDisableAfter,
482
+ consecutiveFailures: e.consecutiveFailures ?? 0,
483
+ autoDisabledAt: e.autoDisabledAt === null || e.autoDisabledAt === void 0 ? null : e.autoDisabledAt instanceof Date ? e.autoDisabledAt.toISOString() : String(e.autoDisabledAt),
484
+ autoDisableReason: e.autoDisableReason,
485
+ scope: e.scope
486
+ }));
487
+ }
345
488
  };
346
- }, pe = b.gen(function* () {
347
- return yield* M;
348
- }), me = (e) => {
489
+ return i;
490
+ }, ge = b.gen(function* () {
491
+ return yield* j;
492
+ }), _e = (e) => {
349
493
  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.");
350
494
  return e.webhooks;
351
- }, he = 1e4, R = class {
495
+ }, ve = 1e4, B = class {
352
496
  capacity;
353
497
  cache = /* @__PURE__ */ new Map();
354
- constructor(e = he) {
498
+ constructor(e = ve) {
355
499
  this.capacity = e;
356
500
  }
357
501
  evictExpired() {
@@ -386,20 +530,20 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
386
530
  clear() {
387
531
  this.cache.clear();
388
532
  }
389
- }, z = null, B = () => (z === null && (z = new R()), z), V = {
533
+ }, V = null, H = () => (V === null && (V = new B()), V), U = {
390
534
  "5m": 5 * 6e4,
391
535
  "1h": 60 * 6e4,
392
536
  "6h": 360 * 6e4,
393
537
  "1d": 1440 * 6e4,
394
538
  "7d": 10080 * 6e4,
395
539
  "30d": 720 * 60 * 6e4
396
- }, H = (e) => e === void 0 ? V["7d"] : V[e] ?? V["7d"], U = (e, t) => ({
540
+ }, W = (e) => e === void 0 ? U["7d"] : U[e] ?? U["7d"], G = (e, t) => ({
397
541
  status: e,
398
542
  contentType: "application/json; charset=utf-8",
399
543
  body: JSON.stringify(t)
400
- }), ge = (e, t) => {
401
- 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 ?? B(), c = H(i?.ttl), l = t.log ?? ((e) => {
402
- re({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
544
+ }), ye = (e, t) => {
545
+ 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
+ T({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
403
547
  status: e.status,
404
548
  signatureOk: e.signatureOk,
405
549
  idempotency: e.idempotency,
@@ -410,7 +554,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
410
554
  return async (n) => {
411
555
  let u = Date.now();
412
556
  if (n.method !== "POST") {
413
- let t = U(405, {
557
+ let t = G(405, {
414
558
  error: "method not allowed",
415
559
  expected: "POST"
416
560
  });
@@ -431,7 +575,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
431
575
  r._tag === "custom" && n.headers["x-slack-request-timestamp"] && (o = `${n.headers["x-slack-request-timestamp"]}|${t ?? ""}`);
432
576
  let s = a(r, n.rawBody, i, o);
433
577
  if (d = s.ok, !s.ok) {
434
- let t = U(401, {
578
+ let t = G(401, {
435
579
  error: "invalid signature",
436
580
  reason: s.reason
437
581
  });
@@ -457,7 +601,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
457
601
  f = r;
458
602
  } else f = n.rawBody;
459
603
  } catch (t) {
460
- let n = U(400, {
604
+ let n = G(400, {
461
605
  error: "malformed body",
462
606
  reason: t.message
463
607
  });
@@ -474,7 +618,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
474
618
  try {
475
619
  p = x.decodeUnknownSync(e.payload)(f);
476
620
  } catch (t) {
477
- let n = U(422, {
621
+ let n = G(422, {
478
622
  error: "schema validation failed",
479
623
  reason: t.message
480
624
  });
@@ -493,7 +637,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
493
637
  if (m = typeof t == "string" ? n.headers[t.toLowerCase()] : t(n.headers, n.rawBody), m !== void 0 && m.length > 0) {
494
638
  let t = s.claim(m, c);
495
639
  if (h = t, t === "duplicate") {
496
- let t = U(200, {
640
+ let t = G(200, {
497
641
  received: !0,
498
642
  duplicate: !0
499
643
  });
@@ -506,7 +650,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
506
650
  }), t;
507
651
  }
508
652
  if (t === "inflight") {
509
- let t = U(409, {
653
+ let t = G(409, {
510
654
  error: "request already in flight",
511
655
  idempotencyKey: m
512
656
  });
@@ -529,7 +673,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
529
673
  idempotencyKey: m ?? "",
530
674
  ...r ? { workflows: r } : {}
531
675
  }), m !== void 0 && s.commit(m);
532
- let i = U(200, { received: !0 });
676
+ let i = G(200, { received: !0 });
533
677
  return l({
534
678
  webhookId: e.id,
535
679
  status: 200,
@@ -539,7 +683,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
539
683
  }), i;
540
684
  } catch (t) {
541
685
  m !== void 0 && s.release(m);
542
- let n = U(500, {
686
+ let n = G(500, {
543
687
  error: "handler threw",
544
688
  reason: t.message
545
689
  });
@@ -558,20 +702,20 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
558
702
  }), n;
559
703
  }
560
704
  };
561
- }, _e = (e) => `/webhooks/${e}`, W = "_voltro_webhook_rate_windows", G = 6e4, ve = (e, t) => `${e}@${t}`, K = async (e, t, n) => (await e.query({
705
+ }, be = (e) => `/webhooks/${e}`, K = "_voltro_webhook_rate_windows", q = 6e4, xe = (e, t) => `${e}@${t}`, J = async (e, t, n) => (await e.query({
562
706
  table: "_voltro_webhook_rate_windows",
563
707
  predicate: S(C("scope", t), C("bucket", n)),
564
708
  order: [],
565
709
  take: 1,
566
710
  skip: void 0,
567
711
  projection: void 0
568
- }))[0] ?? null, q = 32, J = async (e, t, n) => {
569
- for (let r = 0; r < q; r++) {
712
+ }))[0] ?? null, Y = 32, X = async (e, t, n) => {
713
+ for (let r = 0; r < Y; r++) {
570
714
  r > 0 && await new Promise((e) => setTimeout(e, r));
571
- let i = await K(e, t.key, n);
715
+ let i = await J(e, t.key, n);
572
716
  if (i === null) {
573
- await e.insertIgnore(W, {
574
- id: ve(t.key, n),
717
+ await e.insertIgnore(K, {
718
+ id: xe(t.key, n),
575
719
  scope: t.key,
576
720
  bucket: n,
577
721
  count: 0,
@@ -586,29 +730,29 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
586
730
  updatedAt: /* @__PURE__ */ new Date()
587
731
  }, { where: S(C("id", i.id), C("count", i.count)) }) === 1) return !0;
588
732
  }
589
- throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${q} attempts`);
590
- }, Y = async (e, t, n) => {
591
- for (let r = 0; r < q; r++) {
733
+ throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${Y} attempts`);
734
+ }, Z = async (e, t, n) => {
735
+ for (let r = 0; r < Y; r++) {
592
736
  r > 0 && await new Promise((e) => setTimeout(e, r));
593
- let i = await K(e, t, n);
737
+ let i = await J(e, t, n);
594
738
  if (i === null || i.count <= 0 || await e.updateMany("_voltro_webhook_rate_windows", {
595
739
  count: i.count - 1,
596
740
  updatedAt: /* @__PURE__ */ new Date()
597
741
  }, { where: S(C("id", i.id), C("count", i.count)) }) === 1) return;
598
742
  }
599
- throw Error(`webhook rate window: release contention on (${t}) exceeded ${q} attempts`);
600
- }, X = async (e, t, n, r = G) => {
743
+ throw Error(`webhook rate window: release contention on (${t}) exceeded ${Y} attempts`);
744
+ }, Se = async (e, t, n, r = q) => {
601
745
  if (t.length === 0) return {
602
746
  acquired: !0,
603
747
  retryInMs: 0
604
748
  };
605
749
  let i = Math.floor(n / r), a = [];
606
750
  for (let o of t) {
607
- if (await J(e, o, i)) {
751
+ if (await X(e, o, i)) {
608
752
  a.push(o);
609
753
  continue;
610
754
  }
611
- for (let t of a) await Y(e, t.key, i);
755
+ for (let t of a) await Z(e, t.key, i);
612
756
  return {
613
757
  acquired: !1,
614
758
  retryInMs: (i + 1) * r - n
@@ -618,7 +762,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
618
762
  acquired: !0,
619
763
  retryInMs: 0
620
764
  };
621
- }, Z = (e, t) => {
765
+ }, Ce = (e, t) => {
622
766
  if (e === "json") return {
623
767
  contentType: "application/json",
624
768
  bytes: Buffer.from(t, "utf8")
@@ -634,15 +778,15 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
634
778
  }
635
779
  return e === "form" ? {
636
780
  contentType: "application/x-www-form-urlencoded",
637
- bytes: Buffer.from(ye(n), "utf8")
781
+ bytes: Buffer.from(we(n), "utf8")
638
782
  } : {
639
783
  contentType: "application/xml",
640
- bytes: Buffer.from(xe(n), "utf8")
784
+ bytes: Buffer.from(Ee(n), "utf8")
641
785
  };
642
- }, ye = (e) => {
786
+ }, we = (e) => {
643
787
  if (typeof e != "object" || !e || Array.isArray(e)) throw new d({
644
788
  format: "form",
645
- reason: `form encoding requires a JSON object at the top level, got ${we(e)}`
789
+ reason: `form encoding requires a JSON object at the top level, got ${ke(e)}`
646
790
  });
647
791
  let t = new URLSearchParams();
648
792
  for (let [n, r] of Object.entries(e)) Q(t, n, r);
@@ -661,13 +805,13 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
661
805
  return;
662
806
  }
663
807
  e.append(t, String(n));
664
- }, be = /^[A-Za-z_][A-Za-z0-9_.-]*$/, xe = (e) => `<?xml version="1.0" encoding="UTF-8"?>${$("webhook", e)}`, $ = (e, t) => {
665
- if (!be.test(e)) throw new d({
808
+ }, Te = /^[A-Za-z_][A-Za-z0-9_.-]*$/, Ee = (e) => `<?xml version="1.0" encoding="UTF-8"?>${$("webhook", e)}`, $ = (e, t) => {
809
+ if (!Te.test(e)) throw new d({
666
810
  format: "xml",
667
811
  reason: `object key ${JSON.stringify(e)} is not a valid XML element name`
668
812
  });
669
- return `<${e}>${Se(e, t)}</${e}>`;
670
- }, Se = (e, t) => t == null ? "" : Array.isArray(t) ? t.map((e) => $("item", e)).join("") : typeof t == "object" ? Object.entries(t).map(([e, t]) => $(e, t)).join("") : Ce(String(t)), Ce = (e) => e.replace(/[&<>"']/g, (e) => {
813
+ return `<${e}>${De(e, t)}</${e}>`;
814
+ }, De = (e, t) => t == null ? "" : Array.isArray(t) ? t.map((e) => $("item", e)).join("") : typeof t == "object" ? Object.entries(t).map(([e, t]) => $(e, t)).join("") : Oe(String(t)), Oe = (e) => e.replace(/[&<>"']/g, (e) => {
671
815
  switch (e) {
672
816
  case "&": return "&amp;";
673
817
  case "<": return "&lt;";
@@ -675,17 +819,17 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
675
819
  case "\"": return "&quot;";
676
820
  default: return "&apos;";
677
821
  }
678
- }), we = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, Te = "_voltro_webhook_targets", Ee = 32, De = async (e, t) => (await e.query({
822
+ }), ke = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, Ae = "_voltro_webhook_targets", je = 32, Me = async (e, t) => (await e.query({
679
823
  table: "_voltro_webhook_targets",
680
824
  predicate: C("id", t),
681
825
  order: [],
682
826
  take: 1,
683
827
  skip: void 0,
684
828
  projection: void 0
685
- }))[0] ?? null, Oe = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
686
- for (let a = 0; a < Ee; a++) {
829
+ }))[0] ?? null, Ne = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
830
+ for (let a = 0; a < je; a++) {
687
831
  a > 0 && await new Promise((e) => setTimeout(e, a));
688
- let o = await De(e, t);
832
+ let o = await Me(e, t);
689
833
  if (o === null) return {
690
834
  consecutiveFailures: 0,
691
835
  autoDisabled: !1
@@ -710,24 +854,24 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
710
854
  autoDisabled: u
711
855
  };
712
856
  }
713
- throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${Ee} attempts`);
714
- }, ke = x.Struct({
857
+ throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${je} attempts`);
858
+ }, Pe = x.Struct({
715
859
  status: x.Number,
716
860
  body: x.String,
717
861
  latencyMs: x.Number,
718
862
  retryAfterSec: x.Union(x.Number, x.Undefined),
719
863
  transportError: x.Union(x.String, x.Undefined),
720
864
  encodeError: x.Union(x.String, x.Undefined)
721
- }), Ae = x.Struct({
865
+ }), Fe = x.Struct({
722
866
  outcome: x.Literal("succeeded", "failed", "retry"),
723
867
  delayMs: x.Union(x.Number, x.Undefined),
724
868
  reason: x.Union(x.String, x.Undefined),
725
869
  autoDisabled: x.Union(x.Boolean, x.Undefined),
726
870
  consecutiveFailures: x.Union(x.Number, x.Undefined)
727
- }), je = x.Struct({
871
+ }), Ie = x.Struct({
728
872
  acquired: x.Boolean,
729
873
  retryInMs: x.Number
730
- }), Me = ie.make({
874
+ }), Le = ie.make({
731
875
  name: "voltro.deliverWebhook",
732
876
  payload: {
733
877
  deliveryId: x.String,
@@ -742,10 +886,10 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
742
886
  attempts: x.Number
743
887
  }),
744
888
  idempotencyKey: ({ deliveryId: e, attemptEpoch: t }) => `voltro.deliverWebhook:${e}:${t ?? 0}`
745
- }), Ne = (e, t = {}) => (n, r) => {
746
- let { deliveryId: i, targetId: a, event: s, eventId: c, payloadJson: l } = n, u = re({ scope: `webhook:${i}` });
889
+ }), Re = (e, t = {}) => (n, r) => {
890
+ let { deliveryId: i, targetId: a, event: s, eventId: c, payloadJson: l } = n, u = T({ scope: `webhook:${i}` });
747
891
  return b.gen(function* () {
748
- let n = yield* T.make({
892
+ let n = yield* E.make({
749
893
  name: "fetch-target",
750
894
  success: x.Union(x.Null, x.Struct({
751
895
  id: x.String,
@@ -805,7 +949,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
805
949
  ...o
806
950
  });
807
951
  };
808
- if (n.active !== !0) return yield* T.make({
952
+ if (n.active !== !0) return yield* E.make({
809
953
  name: "record-paused-pending",
810
954
  success: x.Void,
811
955
  execute: b.tryPromise({
@@ -826,11 +970,11 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
826
970
  for (let t = 1; t <= p.maxAttempts; t++) {
827
971
  let f = `${i}:${t}`;
828
972
  if (v.length > 0) for (let n = 0;; n++) {
829
- let i = yield* T.make({
973
+ let i = yield* E.make({
830
974
  name: `rate-acquire-${t}-${n}`,
831
- success: je,
975
+ success: Ie,
832
976
  execute: b.tryPromise({
833
- try: () => X(e.store, v, Date.now(), g),
977
+ try: () => Se(e.store, v, Date.now(), g),
834
978
  catch: (e) => (u.debug("rate-acquire raw error", {
835
979
  targetId: a,
836
980
  event: s,
@@ -840,7 +984,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
840
984
  }).pipe(b.orDie)
841
985
  });
842
986
  if (i.acquired) break;
843
- yield* T.make({
987
+ yield* E.make({
844
988
  name: `record-rate-deferral-${t}-${n}`,
845
989
  success: x.Void,
846
990
  execute: b.tryPromise({
@@ -850,12 +994,12 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
850
994
  }),
851
995
  catch: (e) => /* @__PURE__ */ Error(`record-rate-deferral failed: ${e.message}`)
852
996
  }).pipe(b.orDie)
853
- }), yield* E.sleep({
997
+ }), yield* re.sleep({
854
998
  name: `rate-window-sleep-${t}-${n}`,
855
999
  duration: `${i.retryInMs} millis`
856
1000
  });
857
1001
  }
858
- yield* T.make({
1002
+ yield* E.make({
859
1003
  name: `record-attempt-start-${t}`,
860
1004
  success: x.Void,
861
1005
  execute: b.tryPromise({
@@ -867,13 +1011,13 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
867
1011
  catch: (e) => /* @__PURE__ */ Error(`record-attempt-start failed: ${e.message}`)
868
1012
  }).pipe(b.orDie)
869
1013
  });
870
- let _ = yield* T.make({
1014
+ let _ = yield* E.make({
871
1015
  name: `sign-and-post-${t}`,
872
- success: ke,
1016
+ success: Pe,
873
1017
  execute: b.promise(async () => {
874
1018
  let e = Date.now(), r;
875
1019
  try {
876
- r = Z(n.format, l);
1020
+ r = Ce(n.format, l);
877
1021
  } catch (t) {
878
1022
  if (t instanceof d) return {
879
1023
  status: 0,
@@ -921,12 +1065,12 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
921
1065
  };
922
1066
  }
923
1067
  })
924
- }), y = yield* T.make({
1068
+ }), y = yield* E.make({
925
1069
  name: `classify-and-record-${t}`,
926
- success: Ae,
1070
+ success: Fe,
927
1071
  execute: b.tryPromise({
928
1072
  try: async () => {
929
- let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = (t, n) => Oe(e.store, a, t, n);
1073
+ let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = (t, n) => Ne(e.store, a, t, n);
930
1074
  if (r) {
931
1075
  await e.store.update("_voltro_webhook_deliveries", f, {
932
1076
  status: "succeeded",
@@ -944,7 +1088,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
944
1088
  consecutiveFailures: t.consecutiveFailures
945
1089
  };
946
1090
  }
947
- let c = o ? null : A(p, t, {
1091
+ let c = o ? null : se(p, t, {
948
1092
  ...i ? {} : { status: _.status },
949
1093
  ..._.retryAfterSec === void 0 ? {} : { retryAfterSeconds: _.retryAfterSec }
950
1094
  });
@@ -1004,7 +1148,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
1004
1148
  finalStatus: "failed",
1005
1149
  attempts: t
1006
1150
  };
1007
- y.delayMs !== void 0 && (yield* E.sleep({
1151
+ y.delayMs !== void 0 && (yield* re.sleep({
1008
1152
  name: `retry-sleep-${t}`,
1009
1153
  duration: `${y.delayMs} millis`
1010
1154
  }));
@@ -1016,4 +1160,4 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
1016
1160
  });
1017
1161
  };
1018
1162
  //#endregion
1019
- export { R as IdempotencyCache, G as RATE_WINDOW_MS, W as RATE_WINDOW_TABLE, Te as TARGETS_TABLE, l as WebhookDeliveryNotFound, u as WebhookPayloadInvalid, d as WebhookPayloadUnrepresentable, f as WebhookPayloadVersionInvalid, p as WebhookSubscribeInvalid, M as WebhooksService, m as _voltroWebhookDeliveriesTable, h as _voltroWebhookRateWindowsTable, g as _voltroWebhookTargetsTable, X as acquireRateSlots, D as asOutgoingEvent, Ne as buildDeliverWebhookExecute, fe as buildWebhooksService, le as compareVersions, J as consumeRateSlot, _e as defaultIncomingPath, c as defaultOutgoingSignature, j as defaultRetryPolicy, s as defineIncomingWebhook, t as defineWebhookProvider, Me as deliverWebhookWorkflow, Z as encodePayload, se as fastRetryPolicy, P as generateSecret, B as getIdempotencyCache, i as githubSignature, ae as hasWebhookAudience, r as isWebhookDescriptor, L as matchesFilter, ge as mountIncomingWebhook, A as nextRetry, O as parseDuration, H as parseTtl, Oe as recordDeliveryOutcome, Y as releaseRateSlot, I as resolveSubscribe, o as signPayload, n as slackSignature, e as stripeSignature, me as useWebhooks, pe as useWebhooksEffect, F as validateSubscribe, a as verifySignature, _ as webhookTables };
1163
+ export { B as IdempotencyCache, q as RATE_WINDOW_MS, K as RATE_WINDOW_TABLE, Ae 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, g as _voltroWebhookTargetsTable, Se as acquireRateSlots, D as asOutgoingEvent, Re as buildDeliverWebhookExecute, he as buildWebhooksService, fe as compareVersions, X as consumeRateSlot, be as defaultIncomingPath, c as defaultOutgoingSignature, A as defaultRetryPolicy, s as defineIncomingWebhook, t as defineWebhookProvider, Le as deliverWebhookWorkflow, Ce as encodePayload, P as eventsOf, ce as fastRetryPolicy, N as generateSecret, H as getIdempotencyCache, i as githubSignature, ae as hasWebhookAudience, r as isWebhookDescriptor, z as matchesFilter, ye as mountIncomingWebhook, se as nextRetry, O as parseDuration, W as parseTtl, Ne as recordDeliveryOutcome, Z as releaseRateSlot, I as resolveSubscribe, o as signPayload, n as slackSignature, e as stripeSignature, _e as useWebhooks, ge as useWebhooksEffect, F as validateSubscribe, a as verifySignature, _ as webhookTables };