@voltro/plugin-webhooks 0.22.1 → 0.24.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
@@ -1,16 +1,16 @@
1
1
  import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "./signing-BOUxHdAo.js";
2
2
  import { WebhookDeliveryNotFound as u, WebhookPayloadInvalid as d, WebhookPayloadUnrepresentable as f, WebhookPayloadVersionInvalid as p, WebhookSubscribeInvalid as m } from "./errors.js";
3
- import { webhookTables as h } from "./mixin.js";
4
- import { randomBytes as g, randomUUID as _ } from "node:crypto";
5
- import { Context as v, Effect as y, Either as b, Schema as x } from "effect";
6
- import { and as S, eq as C } from "@voltro/database";
7
- import { assertPublicUrl as w } from "@voltro/integration-http";
8
- import { publishServerError as ee } from "@voltro/protocol";
9
- import { createLogger as T } from "@voltro/logger";
10
- import { Activity as E, DurableClock as D, Workflow as te } from "@effect/workflow";
3
+ import { _voltroWebhookDeliveriesTable as h, _voltroWebhookRateWindowsTable as g, _voltroWebhookTargetsTable as _, webhookTables as v } from "./mixin.js";
4
+ import { randomBytes as y, randomUUID as b } from "node:crypto";
5
+ import { Context as ee, Effect as x, Either as te, Schema as S } from "effect";
6
+ import { and as C, eq as w } from "@voltro/database";
7
+ import { assertPublicUrl as T } from "@voltro/integration-http";
8
+ import { publishServerError as ne } from "@voltro/protocol";
9
+ import { createLogger as re } from "@voltro/logger";
10
+ import { Activity as E, DurableClock as D, Workflow as ie } from "@effect/workflow";
11
11
  //#region src/retry.ts
12
- var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
13
- let t = ne.exec(e);
12
+ var ae = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
13
+ let t = ae.exec(e);
14
14
  if (!t) throw Error(`invalid duration literal: ${e}`);
15
15
  let n = Number(t[1]), r = t[2] ?? "s";
16
16
  switch (r) {
@@ -64,7 +64,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
64
64
  retryOn: k,
65
65
  honourRetryAfter: !0,
66
66
  jitter: "full"
67
- }), re = () => ({
67
+ }), oe = () => ({
68
68
  strategy: "fixed",
69
69
  maxAttempts: 120,
70
70
  initialDelay: "30s",
@@ -72,7 +72,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
72
72
  retryOn: k,
73
73
  honourRetryAfter: !0,
74
74
  jitter: "full"
75
- }), M = class extends v.Tag("@voltro/webhooks/WebhooksService")() {}, ie = 32, N = 32, P = () => g(ie).toString("hex"), F = (e) => {
75
+ }), M = class extends ee.Tag("@voltro/webhooks/WebhooksService")() {}, se = 32, N = 32, P = () => y(se).toString("hex"), F = (e) => {
76
76
  let t;
77
77
  try {
78
78
  t = new URL(e.url);
@@ -87,7 +87,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
87
87
  reason: `url protocol must be http or https, got ${t.protocol}`
88
88
  });
89
89
  if (process.env.NODE_ENV === "production") try {
90
- w(e.url);
90
+ T(e.url);
91
91
  } catch (e) {
92
92
  throw new m({
93
93
  field: "url",
@@ -121,7 +121,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
121
121
  reason: `autoDisableAfter must be a positive integer, got ${e.autoDisableAfter}`
122
122
  });
123
123
  }, I = (e, t) => ({
124
- id: _(),
124
+ id: b(),
125
125
  event: e.event,
126
126
  url: e.url,
127
127
  secret: e.secret ?? P(),
@@ -138,19 +138,19 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
138
138
  autoDisableReason: null,
139
139
  payloadVersion: e.payloadVersion ?? t?.version ?? 1,
140
140
  description: e.description ?? null
141
- }), ae = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", L = (e, t) => {
141
+ }), ce = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", L = (e, t) => {
142
142
  if (e === null) return !0;
143
143
  let n = { payload: t };
144
- for (let [t, r] of Object.entries(e)) if (!se(oe(n, t), r)) return !1;
144
+ for (let [t, r] of Object.entries(e)) if (!ue(le(n, t), r)) return !1;
145
145
  return !0;
146
- }, oe = (e, t) => {
146
+ }, le = (e, t) => {
147
147
  let n = t.split("."), r = e;
148
148
  for (let e of n) {
149
149
  if (typeof r != "object" || !r) return;
150
150
  r = r[e];
151
151
  }
152
152
  return r;
153
- }, se = (e, t) => {
153
+ }, ue = (e, t) => {
154
154
  if (typeof t == "object" && t && !Array.isArray(t)) {
155
155
  let n = t;
156
156
  if ("eq" in n) return e === n.eq;
@@ -161,7 +161,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
161
161
  if ("in" in n && Array.isArray(n.in)) return n.in.includes(e);
162
162
  }
163
163
  return e === t;
164
- }, ce = (e, t, n = {}) => {
164
+ }, de = (e, t, n = {}) => {
165
165
  let r = new Map((n.events ?? []).map((e) => [e.id, e]));
166
166
  return {
167
167
  subscribe: async (t) => {
@@ -183,15 +183,15 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
183
183
  emit: async (n, i) => {
184
184
  let a = typeof n == "string" ? r.get(n) : n, o = typeof n == "string" ? n : n.id;
185
185
  if (a !== void 0) {
186
- let e = x.decodeUnknownEither(a.payload)(i, { errors: "all" });
187
- if (b.isLeft(e)) throw new d({
186
+ let e = S.decodeUnknownEither(a.payload)(i, { errors: "all" });
187
+ if (te.isLeft(e)) throw new d({
188
188
  event: o,
189
189
  issues: e.left.message
190
190
  });
191
191
  }
192
- let s = _(), c = (await e.store.query({
192
+ let s = b(), c = (await e.store.query({
193
193
  table: "_voltro_webhook_targets",
194
- predicate: C("event", o),
194
+ predicate: w("event", o),
195
195
  order: [{
196
196
  column: "createdAt",
197
197
  direction: "asc"
@@ -201,7 +201,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
201
201
  projection: void 0
202
202
  })).filter((e) => L(e.filter, i)), l = [], u = JSON.stringify(i);
203
203
  for (let n of c) {
204
- let r = _();
204
+ let r = b();
205
205
  n.active ? (await t({
206
206
  deliveryId: r,
207
207
  targetId: n.id,
@@ -239,7 +239,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
239
239
  replay: async (n) => {
240
240
  let r = (await e.store.query({
241
241
  table: "_voltro_webhook_deliveries",
242
- predicate: C("deliveryId", n),
242
+ predicate: w("deliveryId", n),
243
243
  order: [{
244
244
  column: "attempt",
245
245
  direction: "asc"
@@ -253,7 +253,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
253
253
  deliveryId: r.deliveryId,
254
254
  targetId: r.targetId,
255
255
  event: r.event,
256
- eventId: r.eventId ?? _(),
256
+ eventId: r.eventId ?? b(),
257
257
  payloadJson: typeof r.payload == "string" ? r.payload : JSON.stringify(r.payload),
258
258
  attemptEpoch: Date.now()
259
259
  });
@@ -274,7 +274,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
274
274
  });
275
275
  let r = await e.store.query({
276
276
  table: "_voltro_webhook_deliveries",
277
- predicate: S(C("targetId", n), C("status", "pending")),
277
+ predicate: C(w("targetId", n), w("status", "pending")),
278
278
  order: [{
279
279
  column: "createdAt",
280
280
  direction: "asc"
@@ -287,13 +287,13 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
287
287
  deliveryId: e.deliveryId,
288
288
  targetId: n,
289
289
  event: e.event,
290
- eventId: e.eventId ?? _(),
290
+ eventId: e.eventId ?? b(),
291
291
  payloadJson: typeof e.payload == "string" ? e.payload : JSON.stringify(e.payload),
292
292
  attemptEpoch: i
293
293
  });
294
294
  },
295
295
  deleteTarget: async (t) => {
296
- await e.store.delete("_voltro_webhook_targets", t), await e.store.deleteMany("_voltro_webhook_deliveries", { where: S(C("targetId", t), C("status", "pending")) });
296
+ await e.store.delete("_voltro_webhook_targets", t), await e.store.deleteMany("_voltro_webhook_deliveries", { where: C(w("targetId", t), w("status", "pending")) });
297
297
  },
298
298
  rotateSecret: async (t) => {
299
299
  let n = P();
@@ -311,7 +311,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
311
311
  },
312
312
  listTargets: async (t) => (await e.store.query({
313
313
  table: "_voltro_webhook_targets",
314
- predicate: t === void 0 ? void 0 : C("event", t),
314
+ predicate: t === void 0 ? void 0 : w("event", t),
315
315
  order: [{
316
316
  column: "createdAt",
317
317
  direction: "desc"
@@ -333,15 +333,15 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
333
333
  autoDisableReason: e.autoDisableReason
334
334
  }))
335
335
  };
336
- }, le = y.gen(function* () {
336
+ }, fe = x.gen(function* () {
337
337
  return yield* M;
338
- }), ue = (e) => {
338
+ }), pe = (e) => {
339
339
  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.");
340
340
  return e.webhooks;
341
- }, de = 1e4, R = class {
341
+ }, me = 1e4, R = class {
342
342
  capacity;
343
343
  cache = /* @__PURE__ */ new Map();
344
- constructor(e = de) {
344
+ constructor(e = me) {
345
345
  this.capacity = e;
346
346
  }
347
347
  evictExpired() {
@@ -387,9 +387,9 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
387
387
  status: e,
388
388
  contentType: "application/json; charset=utf-8",
389
389
  body: JSON.stringify(t)
390
- }), fe = (e, t) => {
390
+ }), he = (e, t) => {
391
391
  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) => {
392
- T({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
392
+ re({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
393
393
  status: e.status,
394
394
  signatureOk: e.signatureOk,
395
395
  idempotency: e.idempotency,
@@ -462,7 +462,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
462
462
  }
463
463
  let p;
464
464
  try {
465
- p = x.decodeUnknownSync(e.payload)(f);
465
+ p = S.decodeUnknownSync(e.payload)(f);
466
466
  } catch (t) {
467
467
  let n = U(422, {
468
468
  error: "schema validation failed",
@@ -540,7 +540,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
540
540
  idempotency: h,
541
541
  durationMs: Date.now() - u,
542
542
  errorMessage: t.message
543
- }), ee({
543
+ }), ne({
544
544
  error: t,
545
545
  source: "webhook",
546
546
  name: e.id,
@@ -548,9 +548,9 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
548
548
  }), n;
549
549
  }
550
550
  };
551
- }, pe = (e) => `/webhooks/${e}`, W = "_voltro_webhook_rate_windows", G = 6e4, me = (e, t) => `${e}@${t}`, K = async (e, t, n) => (await e.query({
551
+ }, ge = (e) => `/webhooks/${e}`, W = "_voltro_webhook_rate_windows", G = 6e4, _e = (e, t) => `${e}@${t}`, K = async (e, t, n) => (await e.query({
552
552
  table: "_voltro_webhook_rate_windows",
553
- predicate: S(C("scope", t), C("bucket", n)),
553
+ predicate: C(w("scope", t), w("bucket", n)),
554
554
  order: [],
555
555
  take: 1,
556
556
  skip: void 0,
@@ -561,7 +561,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
561
561
  let i = await K(e, t.key, n);
562
562
  if (i === null) {
563
563
  await e.insertIgnore(W, {
564
- id: me(t.key, n),
564
+ id: _e(t.key, n),
565
565
  scope: t.key,
566
566
  bucket: n,
567
567
  count: 0,
@@ -574,7 +574,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
574
574
  if (await e.updateMany("_voltro_webhook_rate_windows", {
575
575
  count: i.count + 1,
576
576
  updatedAt: /* @__PURE__ */ new Date()
577
- }, { where: S(C("id", i.id), C("count", i.count)) }) === 1) return !0;
577
+ }, { where: C(w("id", i.id), w("count", i.count)) }) === 1) return !0;
578
578
  }
579
579
  throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${q} attempts`);
580
580
  }, Y = async (e, t, n) => {
@@ -584,7 +584,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
584
584
  if (i === null || i.count <= 0 || await e.updateMany("_voltro_webhook_rate_windows", {
585
585
  count: i.count - 1,
586
586
  updatedAt: /* @__PURE__ */ new Date()
587
- }, { where: S(C("id", i.id), C("count", i.count)) }) === 1) return;
587
+ }, { where: C(w("id", i.id), w("count", i.count)) }) === 1) return;
588
588
  }
589
589
  throw Error(`webhook rate window: release contention on (${t}) exceeded ${q} attempts`);
590
590
  }, X = async (e, t, n, r = G) => {
@@ -624,15 +624,15 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
624
624
  }
625
625
  return e === "form" ? {
626
626
  contentType: "application/x-www-form-urlencoded",
627
- bytes: Buffer.from(he(n), "utf8")
627
+ bytes: Buffer.from(ve(n), "utf8")
628
628
  } : {
629
629
  contentType: "application/xml",
630
- bytes: Buffer.from(_e(n), "utf8")
630
+ bytes: Buffer.from(be(n), "utf8")
631
631
  };
632
- }, he = (e) => {
632
+ }, ve = (e) => {
633
633
  if (typeof e != "object" || !e || Array.isArray(e)) throw new f({
634
634
  format: "form",
635
- reason: `form encoding requires a JSON object at the top level, got ${be(e)}`
635
+ reason: `form encoding requires a JSON object at the top level, got ${Ce(e)}`
636
636
  });
637
637
  let t = new URLSearchParams();
638
638
  for (let [n, r] of Object.entries(e)) Q(t, n, r);
@@ -651,13 +651,13 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
651
651
  return;
652
652
  }
653
653
  e.append(t, String(n));
654
- }, ge = /^[A-Za-z_][A-Za-z0-9_.-]*$/, _e = (e) => `<?xml version="1.0" encoding="UTF-8"?>${$("webhook", e)}`, $ = (e, t) => {
655
- if (!ge.test(e)) throw new f({
654
+ }, ye = /^[A-Za-z_][A-Za-z0-9_.-]*$/, be = (e) => `<?xml version="1.0" encoding="UTF-8"?>${$("webhook", e)}`, $ = (e, t) => {
655
+ if (!ye.test(e)) throw new f({
656
656
  format: "xml",
657
657
  reason: `object key ${JSON.stringify(e)} is not a valid XML element name`
658
658
  });
659
- return `<${e}>${ve(e, t)}</${e}>`;
660
- }, ve = (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("") : ye(String(t)), ye = (e) => e.replace(/[&<>"']/g, (e) => {
659
+ return `<${e}>${xe(e, t)}</${e}>`;
660
+ }, xe = (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("") : Se(String(t)), Se = (e) => e.replace(/[&<>"']/g, (e) => {
661
661
  switch (e) {
662
662
  case "&": return "&amp;";
663
663
  case "<": return "&lt;";
@@ -665,17 +665,17 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
665
665
  case "\"": return "&quot;";
666
666
  default: return "&apos;";
667
667
  }
668
- }), be = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, xe = "_voltro_webhook_targets", Se = 32, Ce = async (e, t) => (await e.query({
668
+ }), Ce = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, we = "_voltro_webhook_targets", Te = 32, Ee = async (e, t) => (await e.query({
669
669
  table: "_voltro_webhook_targets",
670
- predicate: C("id", t),
670
+ predicate: w("id", t),
671
671
  order: [],
672
672
  take: 1,
673
673
  skip: void 0,
674
674
  projection: void 0
675
- }))[0] ?? null, we = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
676
- for (let a = 0; a < Se; a++) {
675
+ }))[0] ?? null, De = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
676
+ for (let a = 0; a < Te; a++) {
677
677
  a > 0 && await new Promise((e) => setTimeout(e, a));
678
- let o = await Ce(e, t);
678
+ let o = await Ee(e, t);
679
679
  if (o === null) return {
680
680
  consecutiveFailures: 0,
681
681
  autoDisabled: !1
@@ -685,7 +685,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
685
685
  if (s === 0 || await e.updateMany("_voltro_webhook_targets", {
686
686
  consecutiveFailures: 0,
687
687
  updatedAt: i
688
- }, { where: S(C("id", t), C("consecutiveFailures", s)) }) === 1) return {
688
+ }, { where: C(w("id", t), w("consecutiveFailures", s)) }) === 1) return {
689
689
  consecutiveFailures: 0,
690
690
  autoDisabled: !1
691
691
  };
@@ -695,68 +695,68 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
695
695
  consecutiveFailures: c,
696
696
  updatedAt: i
697
697
  };
698
- if (u && (d.active = !1, d.autoDisabledAt = i, d.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", d, { where: S(C("id", t), C("consecutiveFailures", s)) }) === 1) return {
698
+ if (u && (d.active = !1, d.autoDisabledAt = i, d.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", d, { where: C(w("id", t), w("consecutiveFailures", s)) }) === 1) return {
699
699
  consecutiveFailures: c,
700
700
  autoDisabled: u
701
701
  };
702
702
  }
703
- throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${Se} attempts`);
704
- }, Te = x.Struct({
705
- status: x.Number,
706
- body: x.String,
707
- latencyMs: x.Number,
708
- retryAfterSec: x.Union(x.Number, x.Undefined),
709
- transportError: x.Union(x.String, x.Undefined),
710
- encodeError: x.Union(x.String, x.Undefined)
711
- }), Ee = x.Struct({
712
- outcome: x.Literal("succeeded", "failed", "retry"),
713
- delayMs: x.Union(x.Number, x.Undefined),
714
- reason: x.Union(x.String, x.Undefined),
715
- autoDisabled: x.Union(x.Boolean, x.Undefined),
716
- consecutiveFailures: x.Union(x.Number, x.Undefined)
717
- }), De = x.Struct({
718
- acquired: x.Boolean,
719
- retryInMs: x.Number
720
- }), Oe = te.make({
703
+ throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${Te} attempts`);
704
+ }, Oe = S.Struct({
705
+ status: S.Number,
706
+ body: S.String,
707
+ latencyMs: S.Number,
708
+ retryAfterSec: S.Union(S.Number, S.Undefined),
709
+ transportError: S.Union(S.String, S.Undefined),
710
+ encodeError: S.Union(S.String, S.Undefined)
711
+ }), ke = S.Struct({
712
+ outcome: S.Literal("succeeded", "failed", "retry"),
713
+ delayMs: S.Union(S.Number, S.Undefined),
714
+ reason: S.Union(S.String, S.Undefined),
715
+ autoDisabled: S.Union(S.Boolean, S.Undefined),
716
+ consecutiveFailures: S.Union(S.Number, S.Undefined)
717
+ }), Ae = S.Struct({
718
+ acquired: S.Boolean,
719
+ retryInMs: S.Number
720
+ }), je = ie.make({
721
721
  name: "voltro.deliverWebhook",
722
722
  payload: {
723
- deliveryId: x.String,
724
- targetId: x.String,
725
- event: x.String,
726
- eventId: x.String,
727
- payloadJson: x.String,
728
- attemptEpoch: x.optionalWith(x.Number, { default: () => 0 })
723
+ deliveryId: S.String,
724
+ targetId: S.String,
725
+ event: S.String,
726
+ eventId: S.String,
727
+ payloadJson: S.String,
728
+ attemptEpoch: S.optionalWith(S.Number, { default: () => 0 })
729
729
  },
730
- success: x.Struct({
731
- finalStatus: x.Literal("succeeded", "failed", "deferred"),
732
- attempts: x.Number
730
+ success: S.Struct({
731
+ finalStatus: S.Literal("succeeded", "failed", "deferred"),
732
+ attempts: S.Number
733
733
  }),
734
734
  idempotencyKey: ({ deliveryId: e, attemptEpoch: t }) => `voltro.deliverWebhook:${e}:${t ?? 0}`
735
- }), ke = (e, t = {}) => (n, r) => {
736
- let { deliveryId: i, targetId: a, event: s, eventId: c, payloadJson: l } = n, u = T({ scope: `webhook:${i}` });
737
- return y.gen(function* () {
735
+ }), Me = (e, t = {}) => (n, r) => {
736
+ let { deliveryId: i, targetId: a, event: s, eventId: c, payloadJson: l } = n, u = re({ scope: `webhook:${i}` });
737
+ return x.gen(function* () {
738
738
  let n = yield* E.make({
739
739
  name: "fetch-target",
740
- success: x.Union(x.Null, x.Struct({
741
- id: x.String,
742
- event: x.String,
743
- url: x.String,
744
- secret: x.String,
745
- signing: x.Any,
746
- retry: x.Any,
747
- headers: x.Union(x.Record({
748
- key: x.String,
749
- value: x.String
750
- }), x.Null),
751
- rateLimitPerMinute: x.Union(x.Number, x.Null),
752
- active: x.Boolean,
753
- format: x.Literal("json", "form", "xml"),
754
- tenantId: x.Union(x.String, x.Null)
740
+ success: S.Union(S.Null, S.Struct({
741
+ id: S.String,
742
+ event: S.String,
743
+ url: S.String,
744
+ secret: S.String,
745
+ signing: S.Any,
746
+ retry: S.Any,
747
+ headers: S.Union(S.Record({
748
+ key: S.String,
749
+ value: S.String
750
+ }), S.Null),
751
+ rateLimitPerMinute: S.Union(S.Number, S.Null),
752
+ active: S.Boolean,
753
+ format: S.Literal("json", "form", "xml"),
754
+ tenantId: S.Union(S.String, S.Null)
755
755
  })),
756
- execute: y.tryPromise({
756
+ execute: x.tryPromise({
757
757
  try: async () => (await e.store.query({
758
758
  table: "_voltro_webhook_targets",
759
- predicate: C("id", a),
759
+ predicate: w("id", a),
760
760
  order: [{
761
761
  column: "createdAt",
762
762
  direction: "asc"
@@ -770,7 +770,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
770
770
  event: s,
771
771
  cause: String(e)
772
772
  }), /* @__PURE__ */ Error(`fetch-target failed: ${e.message}`))
773
- }).pipe(y.orDie)
773
+ }).pipe(x.orDie)
774
774
  });
775
775
  if (n === null) return {
776
776
  finalStatus: "failed",
@@ -797,11 +797,11 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
797
797
  };
798
798
  if (n.active !== !0) return yield* E.make({
799
799
  name: "record-paused-pending",
800
- success: x.Void,
801
- execute: y.tryPromise({
800
+ success: S.Void,
801
+ execute: x.tryPromise({
802
802
  try: () => r(`${i}:1`, 1, { status: "pending" }),
803
803
  catch: (e) => /* @__PURE__ */ Error(`record-paused-pending failed: ${e.message}`)
804
- }).pipe(y.orDie)
804
+ }).pipe(x.orDie)
805
805
  }), {
806
806
  finalStatus: "deferred",
807
807
  attempts: 0
@@ -818,8 +818,8 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
818
818
  if (v.length > 0) for (let n = 0;; n++) {
819
819
  let i = yield* E.make({
820
820
  name: `rate-acquire-${t}-${n}`,
821
- success: De,
822
- execute: y.tryPromise({
821
+ success: Ae,
822
+ execute: x.tryPromise({
823
823
  try: () => X(e.store, v, Date.now(), g),
824
824
  catch: (e) => (u.debug("rate-acquire raw error", {
825
825
  targetId: a,
@@ -827,19 +827,19 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
827
827
  attempt: t,
828
828
  cause: String(e)
829
829
  }), /* @__PURE__ */ Error(`rate-acquire failed: ${e.message}`))
830
- }).pipe(y.orDie)
830
+ }).pipe(x.orDie)
831
831
  });
832
832
  if (i.acquired) break;
833
833
  yield* E.make({
834
834
  name: `record-rate-deferral-${t}-${n}`,
835
- success: x.Void,
836
- execute: y.tryPromise({
835
+ success: S.Void,
836
+ execute: x.tryPromise({
837
837
  try: () => r(d, t, {
838
838
  status: "pending",
839
839
  nextAttemptAt: new Date(Date.now() + i.retryInMs)
840
840
  }),
841
841
  catch: (e) => /* @__PURE__ */ Error(`record-rate-deferral failed: ${e.message}`)
842
- }).pipe(y.orDie)
842
+ }).pipe(x.orDie)
843
843
  }), yield* D.sleep({
844
844
  name: `rate-window-sleep-${t}-${n}`,
845
845
  duration: `${i.retryInMs} millis`
@@ -847,20 +847,20 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
847
847
  }
848
848
  yield* E.make({
849
849
  name: `record-attempt-start-${t}`,
850
- success: x.Void,
851
- execute: y.tryPromise({
850
+ success: S.Void,
851
+ execute: x.tryPromise({
852
852
  try: () => r(d, t, {
853
853
  status: "inFlight",
854
854
  nextAttemptAt: null,
855
855
  scheduledAt: /* @__PURE__ */ new Date()
856
856
  }),
857
857
  catch: (e) => /* @__PURE__ */ Error(`record-attempt-start failed: ${e.message}`)
858
- }).pipe(y.orDie)
858
+ }).pipe(x.orDie)
859
859
  });
860
860
  let _ = yield* E.make({
861
861
  name: `sign-and-post-${t}`,
862
- success: Te,
863
- execute: y.promise(async () => {
862
+ success: Oe,
863
+ execute: x.promise(async () => {
864
864
  let e = Date.now(), r;
865
865
  try {
866
866
  r = Z(n.format, l);
@@ -876,7 +876,7 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
876
876
  throw t;
877
877
  }
878
878
  let a = Buffer.from(r.bytes), { headerName: u, headerValue: d } = o(m, a, n.secret);
879
- process.env.NODE_ENV === "production" && w(n.url);
879
+ process.env.NODE_ENV === "production" && T(n.url);
880
880
  try {
881
881
  let o = await fetch(n.url, {
882
882
  method: "POST",
@@ -911,12 +911,12 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
911
911
  };
912
912
  }
913
913
  })
914
- }), b = yield* E.make({
914
+ }), y = yield* E.make({
915
915
  name: `classify-and-record-${t}`,
916
- success: Ee,
917
- execute: y.tryPromise({
916
+ success: ke,
917
+ execute: x.tryPromise({
918
918
  try: async () => {
919
- let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = (t, n) => we(e.store, a, t, n);
919
+ let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = (t, n) => De(e.store, a, t, n);
920
920
  if (r) {
921
921
  await e.store.update("_voltro_webhook_deliveries", d, {
922
922
  status: "succeeded",
@@ -979,24 +979,24 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
979
979
  attempt: t,
980
980
  cause: String(e)
981
981
  }), /* @__PURE__ */ Error(`classify-and-record failed: ${e.message}`))
982
- }).pipe(y.orDie)
982
+ }).pipe(x.orDie)
983
983
  });
984
- if (b.autoDisabled === !0 && u.warn("target auto-disabled after consecutive failures", {
984
+ if (y.autoDisabled === !0 && u.warn("target auto-disabled after consecutive failures", {
985
985
  targetId: a,
986
986
  event: s,
987
- consecutiveFailures: b.consecutiveFailures ?? null,
988
- reason: b.reason ?? null
989
- }), b.outcome === "succeeded") return {
987
+ consecutiveFailures: y.consecutiveFailures ?? null,
988
+ reason: y.reason ?? null
989
+ }), y.outcome === "succeeded") return {
990
990
  finalStatus: "succeeded",
991
991
  attempts: t
992
992
  };
993
- if (b.outcome === "failed") return {
993
+ if (y.outcome === "failed") return {
994
994
  finalStatus: "failed",
995
995
  attempts: t
996
996
  };
997
- b.delayMs !== void 0 && (yield* D.sleep({
997
+ y.delayMs !== void 0 && (yield* D.sleep({
998
998
  name: `retry-sleep-${t}`,
999
- duration: `${b.delayMs} millis`
999
+ duration: `${y.delayMs} millis`
1000
1000
  }));
1001
1001
  }
1002
1002
  return {
@@ -1006,4 +1006,4 @@ var ne = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, O = (e) => {
1006
1006
  });
1007
1007
  };
1008
1008
  //#endregion
1009
- export { R as IdempotencyCache, G as RATE_WINDOW_MS, W as RATE_WINDOW_TABLE, xe as TARGETS_TABLE, u as WebhookDeliveryNotFound, d as WebhookPayloadInvalid, f as WebhookPayloadUnrepresentable, p as WebhookPayloadVersionInvalid, m as WebhookSubscribeInvalid, M as WebhooksService, X as acquireRateSlots, ke as buildDeliverWebhookExecute, ce as buildWebhooksService, ae as compareVersions, J as consumeRateSlot, pe as defaultIncomingPath, c as defaultOutgoingSignature, j as defaultRetryPolicy, s as defineIncomingWebhook, t as defineOutgoingEvent, r as defineWebhookProvider, Oe as deliverWebhookWorkflow, Z as encodePayload, re as fastRetryPolicy, P as generateSecret, B as getIdempotencyCache, i as githubSignature, l as isWebhookDescriptor, L as matchesFilter, fe as mountIncomingWebhook, A as nextRetry, O as parseDuration, H as parseTtl, we as recordDeliveryOutcome, Y as releaseRateSlot, I as resolveSubscribe, o as signPayload, n as slackSignature, e as stripeSignature, ue as useWebhooks, le as useWebhooksEffect, F as validateSubscribe, a as verifySignature, h as webhookTables };
1009
+ export { R as IdempotencyCache, G as RATE_WINDOW_MS, W as RATE_WINDOW_TABLE, we as TARGETS_TABLE, u as WebhookDeliveryNotFound, d as WebhookPayloadInvalid, f as WebhookPayloadUnrepresentable, p as WebhookPayloadVersionInvalid, m as WebhookSubscribeInvalid, M as WebhooksService, h as _voltroWebhookDeliveriesTable, g as _voltroWebhookRateWindowsTable, _ as _voltroWebhookTargetsTable, X as acquireRateSlots, Me as buildDeliverWebhookExecute, de as buildWebhooksService, ce as compareVersions, J as consumeRateSlot, ge as defaultIncomingPath, c as defaultOutgoingSignature, j as defaultRetryPolicy, s as defineIncomingWebhook, t as defineOutgoingEvent, r as defineWebhookProvider, je as deliverWebhookWorkflow, Z as encodePayload, oe as fastRetryPolicy, P as generateSecret, B as getIdempotencyCache, i as githubSignature, l as isWebhookDescriptor, L as matchesFilter, he as mountIncomingWebhook, A as nextRetry, O as parseDuration, H as parseTtl, De as recordDeliveryOutcome, Y as releaseRateSlot, I as resolveSubscribe, o as signPayload, n as slackSignature, e as stripeSignature, pe as useWebhooks, fe as useWebhooksEffect, F as validateSubscribe, a as verifySignature, v as webhookTables };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-webhooks",
3
- "version": "0.22.1",
3
+ "version": "0.24.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.22.1",
52
- "@voltro/integration-http": "0.22.1",
53
- "@voltro/logger": "0.22.1",
54
- "@voltro/plugin-multitenancy": "0.22.1",
55
- "@voltro/protocol": "0.22.1",
56
- "@voltro/runtime": "0.22.1"
51
+ "@voltro/database": "0.24.0",
52
+ "@voltro/integration-http": "0.24.0",
53
+ "@voltro/logger": "0.24.0",
54
+ "@voltro/plugin-multitenancy": "0.24.0",
55
+ "@voltro/protocol": "0.24.0",
56
+ "@voltro/runtime": "0.24.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "effect": "^3.22.0"