@voltro/plugin-webhooks 0.27.0 → 0.29.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
@@ -7,9 +7,9 @@ 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
9
  import { createLogger as T } from "@voltro/logger";
10
- import { Activity as E, DurableClock as re, Workflow as ie } from "@effect/workflow";
10
+ import { Activity as E, DurableClock as D, Workflow as re } from "@effect/workflow";
11
11
  //#region src/eventAudience.ts
12
- var ae = (e) => e.webhook !== void 0, D = (e) => {
12
+ var ie = (e) => e.webhook !== void 0, O = (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
- }, oe = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
23
- let t = oe.exec(e);
22
+ }, ae = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, k = (e) => {
23
+ let t = ae.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
- }, k = [
34
+ }, A = [
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
- ], se = (e, t, n) => {
43
- if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ?? k).includes(n.status)) return null;
42
+ ], oe = (e, t, n) => {
43
+ if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ?? A).includes(n.status)) return null;
44
44
  if (e.honourRetryAfter !== !1 && n?.retryAfterSeconds !== void 0) {
45
- let t = n.retryAfterSeconds * 1e3, r = O(e.maxDelay), i = Math.min(t, r);
45
+ let t = n.retryAfterSeconds * 1e3, r = k(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 = O(e.initialDelay), i = O(e.maxDelay), a;
51
+ let r = k(e.initialDelay), i = k(e.maxDelay), a;
52
52
  switch (e.strategy) {
53
53
  case "fixed":
54
54
  a = r;
@@ -66,12 +66,12 @@ 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
- }, A = () => ({
69
+ }, se = () => ({
70
70
  strategy: "exponential",
71
71
  maxAttempts: 8,
72
72
  initialDelay: "5s",
73
73
  maxDelay: "1h",
74
- retryOn: k,
74
+ retryOn: A,
75
75
  honourRetryAfter: !0,
76
76
  jitter: "full"
77
77
  }), ce = () => ({
@@ -79,7 +79,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
79
79
  maxAttempts: 120,
80
80
  initialDelay: "30s",
81
81
  maxDelay: "30s",
82
- retryOn: k,
82
+ retryOn: A,
83
83
  honourRetryAfter: !0,
84
84
  jitter: "full"
85
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) => {
@@ -149,7 +149,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
149
149
  url: e.url,
150
150
  secret: r ?? e.secret ?? N(),
151
151
  signing: e.signing ?? t?.defaultSigning ?? c(),
152
- retry: e.retry ?? t?.defaultRetry ?? A(),
152
+ retry: e.retry ?? t?.defaultRetry ?? se(),
153
153
  filter: e.filter ?? null,
154
154
  scope: e.scope ?? null,
155
155
  headers: e.headers ?? null,
@@ -206,59 +206,72 @@ 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
- }, he = (e, t, n = {}) => {
209
+ }, B = (e, t) => e !== null && Object.entries(t).every(([t, n]) => e[t] === n), V = 500, H = 200, U = async (e, t) => {
210
+ let n = [];
211
+ for (let r = 0; r < H; r += 1) {
212
+ let i = await e.store.query({
213
+ table: "_voltro_webhook_targets",
214
+ predicate: t,
215
+ order: [{
216
+ column: "id",
217
+ direction: "asc"
218
+ }],
219
+ take: V,
220
+ skip: r === 0 ? void 0 : r * V,
221
+ projection: void 0
222
+ });
223
+ if (n.push(...i), i.length < V) return n;
224
+ }
225
+ throw Error(`webhooks: more than ${H * V} 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.`);
226
+ }, he = async (e, t) => {
227
+ let n = (await U(e)).filter((e) => B(e.scope, t));
228
+ if (n.length === 0) return;
229
+ let r = new Set(n.map((e) => e.secret));
230
+ 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.`);
231
+ return [...r][0];
232
+ }, ge = (e, t, n = {}) => {
210
233
  let r = new Map((n.events ?? []).map((e) => [e.id, e])), i = {
211
234
  subscribe: async (t) => {
212
235
  F(t);
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", {
236
+ let n = P(t), i = t.secret === void 0 && t.scope !== void 0 ? await he(e, t.scope) : void 0, a = t.secret ?? i ?? N(), o = n.map((e) => I(t, r.get(e), e, a));
237
+ for (let t of o) await e.store.insert("_voltro_webhook_targets", {
215
238
  ...t,
216
239
  createdAt: /* @__PURE__ */ new Date(),
217
240
  updatedAt: /* @__PURE__ */ new Date()
218
241
  });
219
- let o = a[0];
242
+ let s = o[0];
220
243
  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) => ({
244
+ id: s.id,
245
+ event: s.event,
246
+ url: s.url,
247
+ secret: s.secret,
248
+ signing: s.signing,
249
+ retry: s.retry,
250
+ ...o.length > 1 ? { targets: o.map((e) => ({
228
251
  id: e.id,
229
252
  event: e.event
230
253
  })) } : {}
231
254
  };
232
255
  },
233
- emit: async (n, i) => {
234
- let a = typeof n == "object" && n.kind === "event" ? D(n) : void 0, o = typeof n == "string" ? r.get(n) : a ?? n, s = typeof n == "string" ? n : n.id ?? n.name;
235
- if (o !== void 0) {
236
- let e = x.decodeUnknownEither(o.payload)(i, { errors: "all" });
256
+ emit: async (n, i, a) => {
257
+ let o = typeof n == "object" && n.kind === "event" ? O(n) : void 0, s = typeof n == "string" ? r.get(n) : o ?? n, c = typeof n == "string" ? n : n.id ?? n.name;
258
+ if (s !== void 0) {
259
+ let e = x.decodeUnknownEither(s.payload)(i, { errors: "all" });
237
260
  if (te.isLeft(e)) throw new u({
238
- event: s,
261
+ event: c,
239
262
  issues: e.left.message
240
263
  });
241
264
  }
242
- let c = y(), l = (await e.store.query({
243
- table: "_voltro_webhook_targets",
244
- predicate: C("event", s),
245
- order: [{
246
- column: "createdAt",
247
- direction: "asc"
248
- }],
249
- take: 1e3,
250
- skip: void 0,
251
- projection: void 0
252
- })).filter((e) => z(e.filter, i)), d = [], f = JSON.stringify(i);
253
- for (let n of l) {
265
+ let l = y(), d = a?.tenantId, f = (await U(e, d == null ? C("event", c) : S(C("event", c), C("tenantId", d)))).filter((e) => z(e.filter, i)), p = [], m = JSON.stringify(i);
266
+ for (let n of f) {
254
267
  let r = y();
255
268
  n.active ? (await t({
256
269
  deliveryId: r,
257
270
  targetId: n.id,
258
- event: s,
259
- eventId: c,
260
- payloadJson: f
261
- }), d.push({
271
+ event: c,
272
+ eventId: l,
273
+ payloadJson: m
274
+ }), p.push({
262
275
  targetId: n.id,
263
276
  deliveryId: r,
264
277
  status: "dispatched"
@@ -267,23 +280,23 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
267
280
  deliveryId: r,
268
281
  targetId: n.id,
269
282
  tenantId: n.tenantId ?? null,
270
- event: s,
271
- eventId: c,
283
+ event: c,
284
+ eventId: l,
272
285
  attempt: 1,
273
286
  status: "pending",
274
- payload: f,
287
+ payload: m,
275
288
  scheduledAt: /* @__PURE__ */ new Date(),
276
289
  createdAt: /* @__PURE__ */ new Date(),
277
290
  updatedAt: /* @__PURE__ */ new Date()
278
- }), d.push({
291
+ }), p.push({
279
292
  targetId: n.id,
280
293
  deliveryId: r,
281
294
  status: "queued"
282
295
  }));
283
296
  }
284
297
  return {
285
- eventId: c,
286
- deliveries: d
298
+ eventId: l,
299
+ deliveries: p
287
300
  };
288
301
  },
289
302
  replay: async (n) => {
@@ -310,14 +323,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
310
323
  },
311
324
  resolveTargets: async (t) => {
312
325
  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);
326
+ let n = (await U(e)).filter((e) => B(e.scope, t.scope)).map((e) => e.id);
321
327
  if (n.length === 0) throw Error(`webhooks: no target matches scope ${JSON.stringify(t.scope)} — the operation would have silently done nothing`);
322
328
  return n;
323
329
  },
@@ -487,15 +493,15 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
487
493
  }
488
494
  };
489
495
  return i;
490
- }, ge = b.gen(function* () {
496
+ }, _e = b.gen(function* () {
491
497
  return yield* j;
492
- }), _e = (e) => {
498
+ }), ve = (e) => {
493
499
  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
500
  return e.webhooks;
495
- }, ve = 1e4, B = class {
501
+ }, ye = 1e4, W = class {
496
502
  capacity;
497
503
  cache = /* @__PURE__ */ new Map();
498
- constructor(e = ve) {
504
+ constructor(e = ye) {
499
505
  this.capacity = e;
500
506
  }
501
507
  evictExpired() {
@@ -530,19 +536,19 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
530
536
  clear() {
531
537
  this.cache.clear();
532
538
  }
533
- }, V = null, H = () => (V === null && (V = new B()), V), U = {
539
+ }, G = null, K = () => (G === null && (G = new W()), G), q = {
534
540
  "5m": 5 * 6e4,
535
541
  "1h": 60 * 6e4,
536
542
  "6h": 360 * 6e4,
537
543
  "1d": 1440 * 6e4,
538
544
  "7d": 10080 * 6e4,
539
545
  "30d": 720 * 60 * 6e4
540
- }, W = (e) => e === void 0 ? U["7d"] : U[e] ?? U["7d"], G = (e, t) => ({
546
+ }, J = (e) => e === void 0 ? q["7d"] : q[e] ?? q["7d"], Y = (e, t) => ({
541
547
  status: e,
542
548
  contentType: "application/json; charset=utf-8",
543
549
  body: JSON.stringify(t)
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) => {
550
+ }), be = (e, t) => {
551
+ 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 ?? K(), c = J(i?.ttl), l = t.log ?? ((e) => {
546
552
  T({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
547
553
  status: e.status,
548
554
  signatureOk: e.signatureOk,
@@ -554,7 +560,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
554
560
  return async (n) => {
555
561
  let u = Date.now();
556
562
  if (n.method !== "POST") {
557
- let t = G(405, {
563
+ let t = Y(405, {
558
564
  error: "method not allowed",
559
565
  expected: "POST"
560
566
  });
@@ -575,7 +581,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
575
581
  r._tag === "custom" && n.headers["x-slack-request-timestamp"] && (o = `${n.headers["x-slack-request-timestamp"]}|${t ?? ""}`);
576
582
  let s = a(r, n.rawBody, i, o);
577
583
  if (d = s.ok, !s.ok) {
578
- let t = G(401, {
584
+ let t = Y(401, {
579
585
  error: "invalid signature",
580
586
  reason: s.reason
581
587
  });
@@ -601,7 +607,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
601
607
  f = r;
602
608
  } else f = n.rawBody;
603
609
  } catch (t) {
604
- let n = G(400, {
610
+ let n = Y(400, {
605
611
  error: "malformed body",
606
612
  reason: t.message
607
613
  });
@@ -618,7 +624,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
618
624
  try {
619
625
  p = x.decodeUnknownSync(e.payload)(f);
620
626
  } catch (t) {
621
- let n = G(422, {
627
+ let n = Y(422, {
622
628
  error: "schema validation failed",
623
629
  reason: t.message
624
630
  });
@@ -637,7 +643,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
637
643
  if (m = typeof t == "string" ? n.headers[t.toLowerCase()] : t(n.headers, n.rawBody), m !== void 0 && m.length > 0) {
638
644
  let t = s.claim(m, c);
639
645
  if (h = t, t === "duplicate") {
640
- let t = G(200, {
646
+ let t = Y(200, {
641
647
  received: !0,
642
648
  duplicate: !0
643
649
  });
@@ -650,7 +656,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
650
656
  }), t;
651
657
  }
652
658
  if (t === "inflight") {
653
- let t = G(409, {
659
+ let t = Y(409, {
654
660
  error: "request already in flight",
655
661
  idempotencyKey: m
656
662
  });
@@ -673,7 +679,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
673
679
  idempotencyKey: m ?? "",
674
680
  ...r ? { workflows: r } : {}
675
681
  }), m !== void 0 && s.commit(m);
676
- let i = G(200, { received: !0 });
682
+ let i = Y(200, { received: !0 });
677
683
  return l({
678
684
  webhookId: e.id,
679
685
  status: 200,
@@ -683,7 +689,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
683
689
  }), i;
684
690
  } catch (t) {
685
691
  m !== void 0 && s.release(m);
686
- let n = G(500, {
692
+ let n = Y(500, {
687
693
  error: "handler threw",
688
694
  reason: t.message
689
695
  });
@@ -702,20 +708,20 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
702
708
  }), n;
703
709
  }
704
710
  };
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({
711
+ }, xe = (e) => `/webhooks/${e}`, X = "_voltro_webhook_rate_windows", Se = 6e4, Ce = (e, t) => `${e}@${t}`, we = async (e, t, n) => (await e.query({
706
712
  table: "_voltro_webhook_rate_windows",
707
713
  predicate: S(C("scope", t), C("bucket", n)),
708
714
  order: [],
709
715
  take: 1,
710
716
  skip: void 0,
711
717
  projection: void 0
712
- }))[0] ?? null, Y = 32, X = async (e, t, n) => {
713
- for (let r = 0; r < Y; r++) {
718
+ }))[0] ?? null, Z = 32, Te = async (e, t, n) => {
719
+ for (let r = 0; r < Z; r++) {
714
720
  r > 0 && await new Promise((e) => setTimeout(e, r));
715
- let i = await J(e, t.key, n);
721
+ let i = await we(e, t.key, n);
716
722
  if (i === null) {
717
- await e.insertIgnore(K, {
718
- id: xe(t.key, n),
723
+ await e.insertIgnore(X, {
724
+ id: Ce(t.key, n),
719
725
  scope: t.key,
720
726
  bucket: n,
721
727
  count: 0,
@@ -730,29 +736,29 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
730
736
  updatedAt: /* @__PURE__ */ new Date()
731
737
  }, { where: S(C("id", i.id), C("count", i.count)) }) === 1) return !0;
732
738
  }
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++) {
739
+ throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${Z} attempts`);
740
+ }, Ee = async (e, t, n) => {
741
+ for (let r = 0; r < Z; r++) {
736
742
  r > 0 && await new Promise((e) => setTimeout(e, r));
737
- let i = await J(e, t, n);
743
+ let i = await we(e, t, n);
738
744
  if (i === null || i.count <= 0 || await e.updateMany("_voltro_webhook_rate_windows", {
739
745
  count: i.count - 1,
740
746
  updatedAt: /* @__PURE__ */ new Date()
741
747
  }, { where: S(C("id", i.id), C("count", i.count)) }) === 1) return;
742
748
  }
743
- throw Error(`webhook rate window: release contention on (${t}) exceeded ${Y} attempts`);
744
- }, Se = async (e, t, n, r = q) => {
749
+ throw Error(`webhook rate window: release contention on (${t}) exceeded ${Z} attempts`);
750
+ }, De = async (e, t, n, r = Se) => {
745
751
  if (t.length === 0) return {
746
752
  acquired: !0,
747
753
  retryInMs: 0
748
754
  };
749
755
  let i = Math.floor(n / r), a = [];
750
756
  for (let o of t) {
751
- if (await X(e, o, i)) {
757
+ if (await Te(e, o, i)) {
752
758
  a.push(o);
753
759
  continue;
754
760
  }
755
- for (let t of a) await Z(e, t.key, i);
761
+ for (let t of a) await Ee(e, t.key, i);
756
762
  return {
757
763
  acquired: !1,
758
764
  retryInMs: (i + 1) * r - n
@@ -762,7 +768,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
762
768
  acquired: !0,
763
769
  retryInMs: 0
764
770
  };
765
- }, Ce = (e, t) => {
771
+ }, Oe = (e, t) => {
766
772
  if (e === "json") return {
767
773
  contentType: "application/json",
768
774
  bytes: Buffer.from(t, "utf8")
@@ -778,15 +784,15 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
778
784
  }
779
785
  return e === "form" ? {
780
786
  contentType: "application/x-www-form-urlencoded",
781
- bytes: Buffer.from(we(n), "utf8")
787
+ bytes: Buffer.from(ke(n), "utf8")
782
788
  } : {
783
789
  contentType: "application/xml",
784
- bytes: Buffer.from(Ee(n), "utf8")
790
+ bytes: Buffer.from(je(n), "utf8")
785
791
  };
786
- }, we = (e) => {
792
+ }, ke = (e) => {
787
793
  if (typeof e != "object" || !e || Array.isArray(e)) throw new d({
788
794
  format: "form",
789
- reason: `form encoding requires a JSON object at the top level, got ${ke(e)}`
795
+ reason: `form encoding requires a JSON object at the top level, got ${Pe(e)}`
790
796
  });
791
797
  let t = new URLSearchParams();
792
798
  for (let [n, r] of Object.entries(e)) Q(t, n, r);
@@ -805,13 +811,13 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
805
811
  return;
806
812
  }
807
813
  e.append(t, String(n));
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({
814
+ }, Ae = /^[A-Za-z_][A-Za-z0-9_.-]*$/, je = (e) => `<?xml version="1.0" encoding="UTF-8"?>${$("webhook", e)}`, $ = (e, t) => {
815
+ if (!Ae.test(e)) throw new d({
810
816
  format: "xml",
811
817
  reason: `object key ${JSON.stringify(e)} is not a valid XML element name`
812
818
  });
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) => {
819
+ return `<${e}>${Me(e, t)}</${e}>`;
820
+ }, Me = (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("") : Ne(String(t)), Ne = (e) => e.replace(/[&<>"']/g, (e) => {
815
821
  switch (e) {
816
822
  case "&": return "&amp;";
817
823
  case "<": return "&lt;";
@@ -819,17 +825,17 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
819
825
  case "\"": return "&quot;";
820
826
  default: return "&apos;";
821
827
  }
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({
828
+ }), Pe = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, Fe = "_voltro_webhook_targets", Ie = 32, Le = async (e, t) => (await e.query({
823
829
  table: "_voltro_webhook_targets",
824
830
  predicate: C("id", t),
825
831
  order: [],
826
832
  take: 1,
827
833
  skip: void 0,
828
834
  projection: void 0
829
- }))[0] ?? null, Ne = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
830
- for (let a = 0; a < je; a++) {
835
+ }))[0] ?? null, Re = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
836
+ for (let a = 0; a < Ie; a++) {
831
837
  a > 0 && await new Promise((e) => setTimeout(e, a));
832
- let o = await Me(e, t);
838
+ let o = await Le(e, t);
833
839
  if (o === null) return {
834
840
  consecutiveFailures: 0,
835
841
  autoDisabled: !1
@@ -854,24 +860,24 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
854
860
  autoDisabled: u
855
861
  };
856
862
  }
857
- throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${je} attempts`);
858
- }, Pe = x.Struct({
863
+ throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${Ie} attempts`);
864
+ }, ze = x.Struct({
859
865
  status: x.Number,
860
866
  body: x.String,
861
867
  latencyMs: x.Number,
862
868
  retryAfterSec: x.Union(x.Number, x.Undefined),
863
869
  transportError: x.Union(x.String, x.Undefined),
864
870
  encodeError: x.Union(x.String, x.Undefined)
865
- }), Fe = x.Struct({
871
+ }), Be = x.Struct({
866
872
  outcome: x.Literal("succeeded", "failed", "retry"),
867
873
  delayMs: x.Union(x.Number, x.Undefined),
868
874
  reason: x.Union(x.String, x.Undefined),
869
875
  autoDisabled: x.Union(x.Boolean, x.Undefined),
870
876
  consecutiveFailures: x.Union(x.Number, x.Undefined)
871
- }), Ie = x.Struct({
877
+ }), Ve = x.Struct({
872
878
  acquired: x.Boolean,
873
879
  retryInMs: x.Number
874
- }), Le = ie.make({
880
+ }), He = re.make({
875
881
  name: "voltro.deliverWebhook",
876
882
  payload: {
877
883
  deliveryId: x.String,
@@ -886,7 +892,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
886
892
  attempts: x.Number
887
893
  }),
888
894
  idempotencyKey: ({ deliveryId: e, attemptEpoch: t }) => `voltro.deliverWebhook:${e}:${t ?? 0}`
889
- }), Re = (e, t = {}) => (n, r) => {
895
+ }), Ue = (e, t = {}) => (n, r) => {
890
896
  let { deliveryId: i, targetId: a, event: s, eventId: c, payloadJson: l } = n, u = T({ scope: `webhook:${i}` });
891
897
  return b.gen(function* () {
892
898
  let n = yield* E.make({
@@ -972,9 +978,9 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
972
978
  if (v.length > 0) for (let n = 0;; n++) {
973
979
  let i = yield* E.make({
974
980
  name: `rate-acquire-${t}-${n}`,
975
- success: Ie,
981
+ success: Ve,
976
982
  execute: b.tryPromise({
977
- try: () => Se(e.store, v, Date.now(), g),
983
+ try: () => De(e.store, v, Date.now(), g),
978
984
  catch: (e) => (u.debug("rate-acquire raw error", {
979
985
  targetId: a,
980
986
  event: s,
@@ -994,7 +1000,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
994
1000
  }),
995
1001
  catch: (e) => /* @__PURE__ */ Error(`record-rate-deferral failed: ${e.message}`)
996
1002
  }).pipe(b.orDie)
997
- }), yield* re.sleep({
1003
+ }), yield* D.sleep({
998
1004
  name: `rate-window-sleep-${t}-${n}`,
999
1005
  duration: `${i.retryInMs} millis`
1000
1006
  });
@@ -1013,11 +1019,11 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
1013
1019
  });
1014
1020
  let _ = yield* E.make({
1015
1021
  name: `sign-and-post-${t}`,
1016
- success: Pe,
1022
+ success: ze,
1017
1023
  execute: b.promise(async () => {
1018
1024
  let e = Date.now(), r;
1019
1025
  try {
1020
- r = Ce(n.format, l);
1026
+ r = Oe(n.format, l);
1021
1027
  } catch (t) {
1022
1028
  if (t instanceof d) return {
1023
1029
  status: 0,
@@ -1067,10 +1073,10 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
1067
1073
  })
1068
1074
  }), y = yield* E.make({
1069
1075
  name: `classify-and-record-${t}`,
1070
- success: Fe,
1076
+ success: Be,
1071
1077
  execute: b.tryPromise({
1072
1078
  try: async () => {
1073
- let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = (t, n) => Ne(e.store, a, t, n);
1079
+ let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = (t, n) => Re(e.store, a, t, n);
1074
1080
  if (r) {
1075
1081
  await e.store.update("_voltro_webhook_deliveries", f, {
1076
1082
  status: "succeeded",
@@ -1088,7 +1094,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
1088
1094
  consecutiveFailures: t.consecutiveFailures
1089
1095
  };
1090
1096
  }
1091
- let c = o ? null : se(p, t, {
1097
+ let c = o ? null : oe(p, t, {
1092
1098
  ...i ? {} : { status: _.status },
1093
1099
  ..._.retryAfterSec === void 0 ? {} : { retryAfterSeconds: _.retryAfterSec }
1094
1100
  });
@@ -1148,7 +1154,7 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
1148
1154
  finalStatus: "failed",
1149
1155
  attempts: t
1150
1156
  };
1151
- y.delayMs !== void 0 && (yield* re.sleep({
1157
+ y.delayMs !== void 0 && (yield* D.sleep({
1152
1158
  name: `retry-sleep-${t}`,
1153
1159
  duration: `${y.delayMs} millis`
1154
1160
  }));
@@ -1160,4 +1166,4 @@ var ae = (e) => e.webhook !== void 0, D = (e) => {
1160
1166
  });
1161
1167
  };
1162
1168
  //#endregion
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 };
1169
+ export { W as IdempotencyCache, Se as RATE_WINDOW_MS, X as RATE_WINDOW_TABLE, Fe 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, De as acquireRateSlots, O as asOutgoingEvent, Ue as buildDeliverWebhookExecute, ge as buildWebhooksService, fe as compareVersions, Te as consumeRateSlot, xe as defaultIncomingPath, c as defaultOutgoingSignature, se as defaultRetryPolicy, s as defineIncomingWebhook, t as defineWebhookProvider, He as deliverWebhookWorkflow, Oe as encodePayload, P as eventsOf, ce as fastRetryPolicy, N as generateSecret, K as getIdempotencyCache, i as githubSignature, ie as hasWebhookAudience, r as isWebhookDescriptor, z as matchesFilter, be as mountIncomingWebhook, oe as nextRetry, k as parseDuration, J as parseTtl, Re as recordDeliveryOutcome, Ee as releaseRateSlot, I as resolveSubscribe, o as signPayload, n as slackSignature, e as stripeSignature, ve as useWebhooks, _e as useWebhooksEffect, F as validateSubscribe, a as verifySignature, _ as webhookTables };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-webhooks",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "description": "Webhooks plugin — first-class outgoing (multi-target, durable-workflow delivery, HMAC signing, retry policies, rate limits) + incoming (signature verification, idempotency, provider templates for Stripe / GitHub / Slack / generic).",
5
5
  "keywords": [
6
6
  "voltro",
@@ -48,12 +48,12 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@effect/workflow": "^0.19.0",
51
- "@voltro/database": "0.27.0",
52
- "@voltro/integration-http": "0.27.0",
53
- "@voltro/logger": "0.27.0",
54
- "@voltro/plugin-multitenancy": "0.27.0",
55
- "@voltro/protocol": "0.27.0",
56
- "@voltro/runtime": "0.27.0"
51
+ "@voltro/database": "0.29.0",
52
+ "@voltro/integration-http": "0.29.0",
53
+ "@voltro/logger": "0.29.0",
54
+ "@voltro/plugin-multitenancy": "0.29.0",
55
+ "@voltro/protocol": "0.29.0",
56
+ "@voltro/runtime": "0.29.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "effect": "^3.22.0"