@voltro/plugin-webhooks 0.84.0 → 0.85.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,29 +1,29 @@
1
1
  import { C as e, E as t, S as n, T as r, _ as i, a, b as o, c as s, d as c, f as l, g as u, h as d, i as f, l as p, m, n as h, o as g, p as _, r as v, s as y, t as ee, u as te, v as ne, w as re, x as ie, y as ae } from "./signing-DeHObNv6.js";
2
- import { WebhookDeliveryNotFound as oe, WebhookPayloadInvalid as se, WebhookPayloadUnrepresentable as b, WebhookPayloadVersionInvalid as ce, WebhookSubscribeInvalid as x, WebhookTargetNotFound as S } from "./errors.js";
3
- import { _voltroWebhookDeliveriesTable as le, _voltroWebhookEventStatsTable as ue, _voltroWebhookRateWindowsTable as de, _voltroWebhookTargetsTable as fe, webhookTables as pe } from "./mixin.js";
4
- import { Context as me, Effect as C, Either as he, Schema as w } from "effect";
5
- import { definePlugin as ge, publishServerError as _e } from "@voltro/protocol";
6
- import { randomBytes as ve, randomUUID as T } from "node:crypto";
7
- import { and as E, eq as D } from "@voltro/database";
8
- import { assertPublicUrl as ye } from "@voltro/integration-http";
9
- import { createLogger as O } from "@voltro/logger";
10
- import { Activity as k, DurableClock as A, Workflow as be } from "@effect/workflow";
11
- import { defineOutboxHandler as xe } from "@voltro/runtime";
2
+ import { WebhookDeliveryNotFound as oe, WebhookPayloadInvalid as se, WebhookPayloadUnrepresentable as b, WebhookPayloadVersionInvalid as x, WebhookSubscribeInvalid as S, WebhookTargetNotFound as C } from "./errors.js";
3
+ import { _voltroWebhookDeliveriesTable as ce, _voltroWebhookEventStatsTable as le, _voltroWebhookRateWindowsTable as ue, _voltroWebhookTargetsTable as de, webhookTables as fe } from "./mixin.js";
4
+ import { Context as pe, Effect as w, Result as me, Schema as T } from "effect";
5
+ import { definePlugin as he, publishServerError as ge } from "@voltro/protocol";
6
+ import { randomBytes as _e, randomUUID as E } from "node:crypto";
7
+ import { and as D, eq as O } from "@voltro/database";
8
+ import { assertPublicUrl as k } from "@voltro/integration-http";
9
+ import { createLogger as A } from "@voltro/logger";
10
+ import { Activity as j, DurableClock as ve, Workflow as ye } from "effect/workflow";
11
+ import { defineOutboxHandler as be } from "@voltro/runtime";
12
12
  //#region src/plugin.ts
13
- var j = ["network:outbound:*"], M = [{
13
+ var xe = ["network:outbound:*"], M = [{
14
14
  destination: "runtime:registered webhook targets (_voltro_webhook_targets)",
15
15
  purpose: "event deliveries, HMAC-signed",
16
16
  data: ["content", "metadata"],
17
17
  disable: "remove or pause the targets; an emit then delivers nowhere"
18
- }], Se = (e = {}) => ge({
18
+ }], Se = (e = {}) => he({
19
19
  name: e.name ? `@voltro/plugin-webhooks#${e.name}` : "@voltro/plugin-webhooks",
20
20
  description: "Outgoing webhooks (multi-target, durable-workflow delivery, HMAC signing, retry policies, rate limits) + incoming (signature verification, idempotency, provider templates). Declares wildcard outbound network access because targets are user-configured URLs.",
21
- permissions: j,
21
+ permissions: xe,
22
22
  egress: M,
23
- onActivate: (e) => C.sync(() => {
23
+ onActivate: (e) => w.sync(() => {
24
24
  e.logger.info("webhooks active", { outbound: "network:outbound:* (subscriber-configured target URLs — audit visibility, not a restriction)" });
25
25
  })
26
- }), Ce = (e) => e.webhook !== void 0, we = (e) => {
26
+ }), Ce = (e) => e.webhook !== void 0, N = (e) => {
27
27
  let t = e.webhook;
28
28
  if (t !== void 0) return {
29
29
  _tag: "outgoingEvent",
@@ -33,8 +33,8 @@ var j = ["network:outbound:*"], M = [{
33
33
  ...t.version === void 0 ? {} : { version: t.version },
34
34
  ...t.rateLimit === void 0 ? {} : { globalRateLimit: t.rateLimit }
35
35
  };
36
- }, Te = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, N = (e) => {
37
- let t = Te.exec(e);
36
+ }, we = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, P = (e) => {
37
+ let t = we.exec(e);
38
38
  if (!t) throw Error(`invalid duration literal: ${e}`);
39
39
  let n = Number(t[1]), r = t[2] ?? "s";
40
40
  switch (r) {
@@ -45,7 +45,7 @@ var j = ["network:outbound:*"], M = [{
45
45
  case "d": return n * 864e5;
46
46
  default: throw Error(`unreachable unit: ${r}`);
47
47
  }
48
- }, P = [
48
+ }, F = [
49
49
  408,
50
50
  425,
51
51
  429,
@@ -53,16 +53,16 @@ var j = ["network:outbound:*"], M = [{
53
53
  502,
54
54
  503,
55
55
  504
56
- ], Ee = (e, t, n) => {
57
- if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ?? P).includes(n.status)) return null;
56
+ ], Te = (e, t, n) => {
57
+ if (t >= e.maxAttempts || n?.status !== void 0 && !(e.retryOn ?? F).includes(n.status)) return null;
58
58
  if (e.honourRetryAfter !== !1 && n?.retryAfterSeconds !== void 0) {
59
- let t = n.retryAfterSeconds * 1e3, r = N(e.maxDelay), i = Math.min(t, r);
59
+ let t = n.retryAfterSeconds * 1e3, r = P(e.maxDelay), i = Math.min(t, r);
60
60
  return {
61
61
  delayMs: i,
62
62
  baseDelayMs: i
63
63
  };
64
64
  }
65
- let r = N(e.initialDelay), i = N(e.maxDelay), a;
65
+ let r = P(e.initialDelay), i = P(e.maxDelay), a;
66
66
  switch (e.strategy) {
67
67
  case "fixed":
68
68
  a = r;
@@ -78,98 +78,98 @@ var j = ["network:outbound:*"], M = [{
78
78
  delayMs: Math.max(1, Math.floor(o)),
79
79
  baseDelayMs: a
80
80
  };
81
- }, De = () => ({
81
+ }, Ee = () => ({
82
82
  strategy: "exponential",
83
83
  maxAttempts: 8,
84
84
  initialDelay: "5s",
85
85
  maxDelay: "1h",
86
- retryOn: P,
86
+ retryOn: F,
87
87
  honourRetryAfter: !0,
88
88
  jitter: "full"
89
- }), Oe = () => ({
89
+ }), De = () => ({
90
90
  strategy: "fixed",
91
91
  maxAttempts: 120,
92
92
  initialDelay: "30s",
93
93
  maxDelay: "30s",
94
- retryOn: P,
94
+ retryOn: F,
95
95
  honourRetryAfter: !0,
96
96
  jitter: "full"
97
- }), ke = class extends me.Tag("@voltro/webhooks/WebhooksService")() {}, Ae = 32, je = 32, Me = () => ve(Ae).toString("hex"), F = (e) => e.events ?? (e.event === void 0 ? [] : [e.event]), I = (e, t) => {
98
- if (e !== void 0 && t?._tag === "standardWebhooks" && !ne(e)) throw new x({
97
+ }), Oe = class extends pe.Service()("@voltro/webhooks/WebhooksService") {}, ke = 32, Ae = 32, je = () => _e(ke).toString("hex"), I = (e) => e.events ?? (e.event === void 0 ? [] : [e.event]), L = (e, t) => {
98
+ if (e !== void 0 && t?._tag === "standardWebhooks" && !ne(e)) throw new S({
99
99
  field: "secret",
100
100
  reason: "a standard-webhooks target needs the spec's secret serialization (\"whsec_\" + base64 of 24..64 random bytes) — mint one with generateStandardWebhooksSecret(), or omit `secret` and let subscribe mint it. If the incompatible key is inherited, rotate the endpoint secret and update the receiver before adding the event"
101
101
  });
102
- }, L = (e) => {
102
+ }, R = (e) => {
103
103
  let t;
104
104
  try {
105
105
  t = new URL(e.url);
106
106
  } catch (e) {
107
- throw new x({
107
+ throw new S({
108
108
  field: "url",
109
109
  reason: `invalid subscriber url: ${e.message}`
110
110
  });
111
111
  }
112
- if (t.protocol !== "http:" && t.protocol !== "https:") throw new x({
112
+ if (t.protocol !== "http:" && t.protocol !== "https:") throw new S({
113
113
  field: "url",
114
114
  reason: `url protocol must be http or https, got ${t.protocol}`
115
115
  });
116
116
  if (process.env.NODE_ENV === "production") try {
117
- ye(e.url);
117
+ k(e.url);
118
118
  } catch (e) {
119
- throw new x({
119
+ throw new S({
120
120
  field: "url",
121
121
  reason: e.message
122
122
  });
123
123
  }
124
- let n = F(e);
125
- if (n.length === 0) throw new x({
124
+ let n = I(e);
125
+ if (n.length === 0) throw new S({
126
126
  field: "event",
127
127
  reason: "event id required"
128
128
  });
129
- if (e.event !== void 0 && e.events !== void 0) throw new x({
129
+ if (e.event !== void 0 && e.events !== void 0) throw new S({
130
130
  field: "event",
131
131
  reason: "pass `event` OR `events`, not both — the row set would be ambiguous"
132
132
  });
133
- if (n.some((e) => e.length === 0)) throw new x({
133
+ if (n.some((e) => e.length === 0)) throw new S({
134
134
  field: "events",
135
135
  reason: "event id required"
136
136
  });
137
- if (new Set(n).size !== n.length) throw new x({
137
+ if (new Set(n).size !== n.length) throw new S({
138
138
  field: "events",
139
139
  reason: "duplicate event — one row per event, so a repeat would deliver twice"
140
140
  });
141
- if (e.secret !== void 0 && e.secret.length < je) throw new x({
141
+ if (e.secret !== void 0 && e.secret.length < Ae) throw new S({
142
142
  field: "secret",
143
- reason: `secret must be at least ${je} chars`
143
+ reason: `secret must be at least ${Ae} chars`
144
144
  });
145
- if (I(e.secret, e.signing), e.retry !== void 0) {
146
- if (e.retry.maxAttempts < 1) throw new x({
145
+ if (L(e.secret, e.signing), e.retry !== void 0) {
146
+ if (e.retry.maxAttempts < 1) throw new S({
147
147
  field: "retry",
148
148
  reason: "retry.maxAttempts must be ≥ 1"
149
149
  });
150
- if (e.retry.maxAttempts > 1e3) throw new x({
150
+ if (e.retry.maxAttempts > 1e3) throw new S({
151
151
  field: "retry",
152
152
  reason: "retry.maxAttempts must be ≤ 1000"
153
153
  });
154
154
  }
155
- if (e.rateLimitPerMinute !== void 0 && e.rateLimitPerMinute < 1) throw new x({
155
+ if (e.rateLimitPerMinute !== void 0 && e.rateLimitPerMinute < 1) throw new S({
156
156
  field: "rateLimitPerMinute",
157
157
  reason: "rateLimitPerMinute must be ≥ 1"
158
158
  });
159
- if (e.autoDisableAfter !== void 0 && (e.autoDisableAfter < 1 || !Number.isInteger(e.autoDisableAfter))) throw new x({
159
+ if (e.autoDisableAfter !== void 0 && (e.autoDisableAfter < 1 || !Number.isInteger(e.autoDisableAfter))) throw new S({
160
160
  field: "autoDisableAfter",
161
161
  reason: `autoDisableAfter must be a positive integer, got ${e.autoDisableAfter}`
162
162
  });
163
- }, R = (e, t, n, r) => {
164
- let a = e.signing ?? t?.defaultSigning ?? ee(), o = a._tag === "standardWebhooks" ? i : Me, s = r ?? e.secret ?? o();
165
- return I(s, a), {
166
- id: T(),
163
+ }, z = (e, t, n, r) => {
164
+ let a = e.signing ?? t?.defaultSigning ?? ee(), o = a._tag === "standardWebhooks" ? i : je, s = r ?? e.secret ?? o();
165
+ return L(s, a), {
166
+ id: E(),
167
167
  tenantId: e.tenantId ?? null,
168
168
  event: n ?? e.event ?? "",
169
169
  url: e.url,
170
170
  secret: s,
171
171
  signing: a,
172
- retry: e.retry ?? t?.defaultRetry ?? De(),
172
+ retry: e.retry ?? t?.defaultRetry ?? Ee(),
173
173
  filter: e.filter ?? null,
174
174
  scope: e.scope ?? null,
175
175
  headers: e.headers ?? null,
@@ -183,14 +183,14 @@ var j = ["network:outbound:*"], M = [{
183
183
  payloadVersion: e.payloadVersion ?? t?.version ?? 1,
184
184
  description: e.description ?? null
185
185
  };
186
- }, Ne = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : 0, z = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : null, Pe = (e) => {
186
+ }, Me = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : 0, B = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : null, Ne = (e) => {
187
187
  if (typeof e != "string") return e;
188
188
  try {
189
189
  return JSON.parse(e);
190
190
  } catch {
191
191
  return e;
192
192
  }
193
- }, B = (e) => ({
193
+ }, V = (e) => ({
194
194
  id: String(e.id),
195
195
  deliveryId: String(e.deliveryId),
196
196
  targetId: String(e.targetId),
@@ -201,28 +201,28 @@ var j = ["network:outbound:*"], M = [{
201
201
  responseStatus: e.responseStatus ?? null,
202
202
  errorMessage: e.errorMessage ?? null,
203
203
  latencyMs: e.latencyMs ?? null,
204
- scheduledAt: z(e.scheduledAt),
205
- nextAttemptAt: z(e.nextAttemptAt),
206
- createdAt: z(e.createdAt)
207
- }), Fe = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", V = (e, t) => {
204
+ scheduledAt: B(e.scheduledAt),
205
+ nextAttemptAt: B(e.nextAttemptAt),
206
+ createdAt: B(e.createdAt)
207
+ }), Pe = (e, t) => e === t ? "current" : e < t ? "behind" : "ahead", H = (e, t) => {
208
208
  if (e === null) return !0;
209
209
  let n = { payload: t };
210
- for (let [t, r] of Object.entries(e)) if (!Le(Ie(n, t), r)) return !1;
210
+ for (let [t, r] of Object.entries(e)) if (!Ie(Fe(n, t), r)) return !1;
211
211
  return !0;
212
- }, Ie = (e, t) => {
212
+ }, Fe = (e, t) => {
213
213
  let n = t.split("."), r = e;
214
214
  for (let e of n) {
215
215
  if (typeof r != "object" || !r) return;
216
216
  r = r[e];
217
217
  }
218
218
  return r;
219
- }, H = (e, t) => {
219
+ }, U = (e, t) => {
220
220
  if (typeof e == "number" && typeof t == "number") return e - t;
221
221
  if (typeof e == "string" && typeof t == "string") return e < t ? -1 : +(e > t);
222
- }, Le = (e, t) => {
222
+ }, Ie = (e, t) => {
223
223
  if (typeof t == "object" && t && !Array.isArray(t)) {
224
224
  let n = t;
225
- return "eq" in n && e !== n.eq || "in" in n && (!Array.isArray(n.in) || !n.in.includes(e)) || "gt" in n && !((H(e, n.gt) ?? 0) > 0) || "gte" in n && !((H(e, n.gte) ?? -1) >= 0) || "lt" in n && !((H(e, n.lt) ?? 0) < 0) || "lte" in n && !((H(e, n.lte) ?? 1) <= 0) ? !1 : [
225
+ return "eq" in n && e !== n.eq || "in" in n && (!Array.isArray(n.in) || !n.in.includes(e)) || "gt" in n && !((U(e, n.gt) ?? 0) > 0) || "gte" in n && !((U(e, n.gte) ?? -1) >= 0) || "lt" in n && !((U(e, n.lt) ?? 0) < 0) || "lte" in n && !((U(e, n.lte) ?? 1) <= 0) ? !1 : [
226
226
  "eq",
227
227
  "in",
228
228
  "gt",
@@ -232,9 +232,9 @@ var j = ["network:outbound:*"], M = [{
232
232
  ].some((e) => e in n);
233
233
  }
234
234
  return e === t;
235
- }, U = (e, t) => e !== null && Object.entries(t).every(([t, n]) => e[t] === n), W = 500, Re = 200, G = async (e, t) => {
235
+ }, W = (e, t) => e !== null && Object.entries(t).every(([t, n]) => e[t] === n), G = 500, Le = 200, K = async (e, t) => {
236
236
  let n = [];
237
- for (let r = 0; r < Re; r += 1) {
237
+ for (let r = 0; r < Le; r += 1) {
238
238
  let i = await e.store.query({
239
239
  table: "_voltro_webhook_targets",
240
240
  predicate: t,
@@ -242,24 +242,24 @@ var j = ["network:outbound:*"], M = [{
242
242
  column: "id",
243
243
  direction: "asc"
244
244
  }],
245
- take: W,
246
- skip: r === 0 ? void 0 : r * W,
245
+ take: G,
246
+ skip: r === 0 ? void 0 : r * G,
247
247
  projection: void 0
248
248
  });
249
- if (n.push(...i), i.length < W) return n;
249
+ if (n.push(...i), i.length < G) return n;
250
250
  }
251
- throw Error(`webhooks: more than ${Re * W} rows in \`_voltro_webhook_targets\` — refusing to answer a scope lookup from a partial scan. A truncated scan mints a fresh secret for a live endpoint (breaking its signatures) or reports that a real scope matches nothing.`);
252
- }, ze = async (e, t) => {
253
- let n = (await G(e)).filter((e) => U(e.scope, t));
251
+ throw Error(`webhooks: more than ${Le * G} 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.`);
252
+ }, Re = async (e, t) => {
253
+ let n = (await K(e)).filter((e) => W(e.scope, t));
254
254
  if (n.length === 0) return;
255
255
  let r = new Set(n.map((e) => e.secret));
256
256
  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.`);
257
257
  return [...r][0];
258
- }, Be = async (e, t) => {
258
+ }, ze = async (e, t) => {
259
259
  try {
260
260
  let n = await e.store.query({
261
261
  table: "_voltro_webhook_event_stats",
262
- predicate: D("event", t),
262
+ predicate: O("event", t),
263
263
  order: [],
264
264
  take: 1,
265
265
  skip: void 0,
@@ -281,11 +281,11 @@ var j = ["network:outbound:*"], M = [{
281
281
  updatedAt: r
282
282
  });
283
283
  } catch {}
284
- }, Ve = (e, t, n = {}) => {
284
+ }, Be = (e, t, n = {}) => {
285
285
  let r = new Map((n.events ?? []).map((e) => [e.id, e])), a = {
286
286
  subscribe: async (t) => {
287
- L(t);
288
- let n = F(t), a = t.secret === void 0 && t.scope !== void 0 ? await ze(e, t.scope) : void 0, o = t.secret ?? a ?? i(), s = n.map((e) => R(t, r.get(e), e, o));
287
+ R(t);
288
+ let n = I(t), a = t.secret === void 0 && t.scope !== void 0 ? await Re(e, t.scope) : void 0, o = t.secret ?? a ?? i(), s = n.map((e) => z(t, r.get(e), e, o));
289
289
  for (let t of s) await e.store.insert("_voltro_webhook_targets", {
290
290
  ...t,
291
291
  createdAt: /* @__PURE__ */ new Date(),
@@ -306,32 +306,31 @@ var j = ["network:outbound:*"], M = [{
306
306
  };
307
307
  },
308
308
  emit: async (n, i, a) => {
309
- let o = typeof n == "object" && n.kind === "event" ? we(n) : void 0, s = typeof n == "string" ? r.get(n) : o ?? n, c = typeof n == "string" ? n : n.id ?? n.name;
309
+ let o = typeof n == "object" && n.kind === "event" ? N(n) : void 0, s = typeof n == "string" ? r.get(n) : o ?? n, c = typeof n == "string" ? n : n.id ?? n.name;
310
310
  if (s !== void 0) {
311
- let e = w.decodeUnknownEither(s.payload)(i, { errors: "all" });
312
- if (he.isLeft(e)) throw new se({
311
+ let e = T.decodeUnknownResult(s.payload)(i, { errors: "all" });
312
+ if (me.isFailure(e)) throw new se({
313
313
  event: c,
314
- issues: e.left.message
314
+ issues: e.failure.message
315
315
  });
316
316
  }
317
- let l = T(), u = a?.tenantId, d = await G(e, u == null ? D("event", c) : E(D("event", c), D("tenantId", u)));
318
- await Be(e, c);
319
- let f = d.filter((e) => V(e.filter, i)), p = [], m = JSON.stringify(i);
320
- for (let n of f) {
321
- let r = T();
317
+ let l = a?.eventId ?? E(), u = a?.tenantId, d = await K(e, u == null ? O("event", c) : D(O("event", c), O("tenantId", u)));
318
+ await ze(e, c);
319
+ let f = d.filter((e) => H(e.filter, i)), p = [], m = JSON.stringify(i), h = async (n, r) => {
320
+ let i = E();
322
321
  n.active ? (await t({
323
- deliveryId: r,
322
+ deliveryId: i,
324
323
  targetId: n.id,
325
324
  event: c,
326
325
  eventId: l,
327
326
  payloadJson: m
328
- }), p.push({
327
+ }), p[r] = {
329
328
  targetId: n.id,
330
- deliveryId: r,
329
+ deliveryId: i,
331
330
  status: "dispatched"
332
- })) : (await e.store.insert("_voltro_webhook_deliveries", {
333
- id: `${r}:1`,
334
- deliveryId: r,
331
+ }) : (await e.store.insert("_voltro_webhook_deliveries", {
332
+ id: `${i}:1`,
333
+ deliveryId: i,
335
334
  targetId: n.id,
336
335
  tenantId: n.tenantId ?? null,
337
336
  event: c,
@@ -342,12 +341,22 @@ var j = ["network:outbound:*"], M = [{
342
341
  scheduledAt: /* @__PURE__ */ new Date(),
343
342
  createdAt: /* @__PURE__ */ new Date(),
344
343
  updatedAt: /* @__PURE__ */ new Date()
345
- }), p.push({
344
+ }), p[r] = {
346
345
  targetId: n.id,
347
- deliveryId: r,
346
+ deliveryId: i,
348
347
  status: "queued"
349
- }));
350
- }
348
+ });
349
+ }, g = 0, _ = !1, v;
350
+ if (await Promise.all(Array.from({ length: Math.min(4, f.length) }, async () => {
351
+ for (; !_ && g < f.length;) {
352
+ let e = g++;
353
+ try {
354
+ await h(f[e], e);
355
+ } catch (e) {
356
+ _ || (_ = !0, v = e);
357
+ }
358
+ }
359
+ })), _) throw v;
351
360
  return {
352
361
  eventId: l,
353
362
  deliveries: p
@@ -356,7 +365,7 @@ var j = ["network:outbound:*"], M = [{
356
365
  replay: async (n) => {
357
366
  let r = (await e.store.query({
358
367
  table: "_voltro_webhook_deliveries",
359
- predicate: D("deliveryId", n),
368
+ predicate: O("deliveryId", n),
360
369
  order: [{
361
370
  column: "attempt",
362
371
  direction: "asc"
@@ -370,7 +379,7 @@ var j = ["network:outbound:*"], M = [{
370
379
  deliveryId: r.deliveryId,
371
380
  targetId: r.targetId,
372
381
  event: r.event,
373
- eventId: r.eventId ?? T(),
382
+ eventId: r.eventId ?? E(),
374
383
  payloadJson: typeof r.payload == "string" ? r.payload : JSON.stringify(r.payload),
375
384
  attemptEpoch: Date.now()
376
385
  });
@@ -379,15 +388,15 @@ var j = ["network:outbound:*"], M = [{
379
388
  if (typeof t == "string") {
380
389
  if ((await e.store.query({
381
390
  table: "_voltro_webhook_targets",
382
- predicate: D("id", t),
391
+ predicate: O("id", t),
383
392
  order: [],
384
393
  take: 1,
385
394
  skip: void 0,
386
395
  projection: ["id"]
387
- })).length === 0) throw new S({ targetId: t });
396
+ })).length === 0) throw new C({ targetId: t });
388
397
  return [t];
389
398
  }
390
- let n = (await G(e)).filter((e) => U(e.scope, t.scope)).map((e) => e.id);
399
+ let n = (await K(e)).filter((e) => W(e.scope, t.scope)).map((e) => e.id);
391
400
  if (n.length === 0) throw Error(`webhooks: no target matches scope ${JSON.stringify(t.scope)} — the operation would have silently done nothing`);
392
401
  return n;
393
402
  },
@@ -408,7 +417,7 @@ var j = ["network:outbound:*"], M = [{
408
417
  });
409
418
  let n = await e.store.query({
410
419
  table: "_voltro_webhook_deliveries",
411
- predicate: E(D("targetId", r), D("status", "pending")),
420
+ predicate: D(O("targetId", r), O("status", "pending")),
412
421
  order: [{
413
422
  column: "createdAt",
414
423
  direction: "asc"
@@ -421,14 +430,14 @@ var j = ["network:outbound:*"], M = [{
421
430
  deliveryId: e.deliveryId,
422
431
  targetId: r,
423
432
  event: e.event,
424
- eventId: e.eventId ?? T(),
433
+ eventId: e.eventId ?? E(),
425
434
  payloadJson: typeof e.payload == "string" ? e.payload : JSON.stringify(e.payload),
426
435
  attemptEpoch: i
427
436
  });
428
437
  }
429
438
  },
430
439
  deleteTarget: async (t) => {
431
- for (let n of await a.resolveTargets(t)) await e.store.delete("_voltro_webhook_targets", n), await e.store.deleteMany("_voltro_webhook_deliveries", { where: E(D("targetId", n), D("status", "pending")) });
440
+ for (let n of await a.resolveTargets(t)) await e.store.delete("_voltro_webhook_targets", n), await e.store.deleteMany("_voltro_webhook_deliveries", { where: D(O("targetId", n), O("status", "pending")) });
432
441
  },
433
442
  rotateSecret: async (t) => {
434
443
  let n = i();
@@ -439,7 +448,7 @@ var j = ["network:outbound:*"], M = [{
439
448
  return { secret: n };
440
449
  },
441
450
  updateTarget: async (t, n) => {
442
- if (n.url !== void 0 && L({
451
+ if (n.url !== void 0 && R({
443
452
  event: "x",
444
453
  url: n.url
445
454
  }), 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");
@@ -459,14 +468,14 @@ var j = ["network:outbound:*"], M = [{
459
468
  testTarget: async (n, r) => {
460
469
  let i = (await e.store.query({
461
470
  table: "_voltro_webhook_targets",
462
- predicate: D("id", n),
471
+ predicate: O("id", n),
463
472
  order: [],
464
473
  take: 1,
465
474
  skip: void 0,
466
475
  projection: void 0
467
476
  }))[0];
468
- if (i === void 0) throw new S({ targetId: n });
469
- let a = T(), o = JSON.stringify(r ?? {
477
+ if (i === void 0) throw new C({ targetId: n });
478
+ let a = E(), o = JSON.stringify(r ?? {
470
479
  test: !0,
471
480
  targetId: n,
472
481
  at: (/* @__PURE__ */ new Date()).toISOString()
@@ -475,7 +484,7 @@ var j = ["network:outbound:*"], M = [{
475
484
  deliveryId: a,
476
485
  targetId: i.id,
477
486
  event: i.event,
478
- eventId: T(),
487
+ eventId: E(),
479
488
  payloadJson: o
480
489
  }) : await e.store.insert("_voltro_webhook_deliveries", {
481
490
  id: `${a}:1`,
@@ -495,7 +504,7 @@ var j = ["network:outbound:*"], M = [{
495
504
  listDeliveries: async (t) => {
496
505
  let n = t?.scope === void 0 ? void 0 : new Set(await a.resolveTargets({ scope: t.scope })), r = await e.store.query({
497
506
  table: "_voltro_webhook_deliveries",
498
- predicate: t?.targetId === void 0 ? void 0 : D("targetId", t.targetId),
507
+ predicate: t?.targetId === void 0 ? void 0 : O("targetId", t.targetId),
499
508
  order: [{
500
509
  column: "createdAt",
501
510
  direction: "desc"
@@ -504,25 +513,25 @@ var j = ["network:outbound:*"], M = [{
504
513
  skip: void 0,
505
514
  projection: void 0
506
515
  }), i = t?.since?.getTime();
507
- return r.filter((e) => n === void 0 || n.has(String(e.targetId))).filter((e) => t?.status === void 0 || e.status === t.status).filter((e) => i === void 0 || Ne(e.createdAt) >= i).slice(0, t?.limit ?? 200).map(B);
516
+ return r.filter((e) => n === void 0 || n.has(String(e.targetId))).filter((e) => t?.status === void 0 || e.status === t.status).filter((e) => i === void 0 || Me(e.createdAt) >= i).slice(0, t?.limit ?? 200).map(V);
508
517
  },
509
518
  getDelivery: async (t) => {
510
519
  let n = (await e.store.query({
511
520
  table: "_voltro_webhook_deliveries",
512
- predicate: D("id", t),
521
+ predicate: O("id", t),
513
522
  order: [],
514
523
  take: 1,
515
524
  skip: void 0,
516
525
  projection: void 0
517
526
  }))[0];
518
527
  return n === void 0 ? null : {
519
- ...B(n),
520
- payload: Pe(n.payload),
528
+ ...V(n),
529
+ payload: Ne(n.payload),
521
530
  responseBody: n.responseBody ?? null
522
531
  };
523
532
  },
524
533
  updateTargetPayloadVersion: async (t, n) => {
525
- if (n < 1 || !Number.isInteger(n)) throw new ce({ version: n });
534
+ if (n < 1 || !Number.isInteger(n)) throw new x({ version: n });
526
535
  await a.resolveTargets(t), await e.store.update("_voltro_webhook_targets", t, {
527
536
  payloadVersion: n,
528
537
  updatedAt: /* @__PURE__ */ new Date()
@@ -531,7 +540,7 @@ var j = ["network:outbound:*"], M = [{
531
540
  listTargets: async (t, n) => {
532
541
  let r = await e.store.query({
533
542
  table: "_voltro_webhook_targets",
534
- predicate: t === void 0 ? void 0 : D("event", t),
543
+ predicate: t === void 0 ? void 0 : O("event", t),
535
544
  order: [{
536
545
  column: "createdAt",
537
546
  direction: "desc"
@@ -558,15 +567,15 @@ var j = ["network:outbound:*"], M = [{
558
567
  }
559
568
  };
560
569
  return a;
561
- }, He = C.gen(function* () {
562
- return yield* ke;
563
- }), Ue = (e) => {
570
+ }, Ve = w.gen(function* () {
571
+ return yield* Oe;
572
+ }), He = (e) => {
564
573
  if (e.webhooks === void 0) throw Error("useWebhooks: `ctx.webhooks` is not set. Declare an outgoing event with a `webhook:` block in a *.event.ts file, or an incoming endpoint in a *.webhook.tsx file — the service is wired the moment the app has either.");
565
574
  return e.webhooks;
566
- }, We = 1e4, Ge = class {
575
+ }, Ue = 1e4, We = class {
567
576
  capacity;
568
577
  cache = /* @__PURE__ */ new Map();
569
- constructor(e = We) {
578
+ constructor(e = Ue) {
570
579
  this.capacity = e;
571
580
  }
572
581
  evictExpired() {
@@ -601,36 +610,36 @@ var j = ["network:outbound:*"], M = [{
601
610
  clear() {
602
611
  this.cache.clear();
603
612
  }
604
- }, K = null, Ke = () => (K === null && (K = new Ge()), K), q = {
613
+ }, q = null, Ge = () => (q === null && (q = new We()), q), J = {
605
614
  "5m": 3e5,
606
615
  "1h": 36e5,
607
616
  "6h": 216e5,
608
617
  "1d": 864e5,
609
618
  "7d": 6048e5,
610
619
  "30d": 2592e6
611
- }, qe = (e) => e === void 0 ? q["7d"] : q[e] ?? q["7d"], J = (e, t) => ({
620
+ }, Ke = (e) => e === void 0 ? J["7d"] : J[e] ?? J["7d"], Y = (e, t) => ({
612
621
  status: e,
613
622
  contentType: "application/json; charset=utf-8",
614
623
  body: JSON.stringify(t)
615
- }), Je = "voltroWebhookVerification", Ye = class extends Error {
624
+ }), qe = "voltroWebhookVerification", Je = class extends Error {
616
625
  webhookId;
617
626
  name = "UnverifiedIncomingWebhook";
618
627
  constructor(e) {
619
628
  super(`incoming webhook '${e}' declares no verification. It would be mounted as a public, unauthenticated POST that runs your application code, so the framework refuses to mount it. Pick one on the descriptor:\n · provider: stripeWebhookProvider() — a preset (HMAC scheme + idempotency + body type)\n · signature: { _tag: 'hmac', algorithm: 'hmacSha256', header: 'X-Signature', encoding: 'hex', includeTimestamp: true }\n · verification: 'provider' — the handler verifies with the provider's own SDK\n · verification: 'none' — deliberately public; a gateway / IP allow-list owns it\nA signature-verified webhook reads its shared secret from VOLTRO_WEBHOOK_SECRET_${e.toUpperCase().replace(/[^A-Z0-9]/g, "_")}. The framework never invents that value — the sender holds the other half of it.`), this.webhookId = e;
620
629
  }
621
- }, Xe = (e) => `VOLTRO_WEBHOOK_SECRET_${e.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`, Ze = (e) => {
630
+ }, Ye = (e) => `VOLTRO_WEBHOOK_SECRET_${e.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`, Xe = (e) => {
622
631
  let t = e.signature ?? e.provider?.signature ?? null;
623
632
  return (e.verification === void 0 || e.verification === "signature") && t === null ? null : e.verification ?? "signature";
624
- }, Qe = (e, t) => {
625
- let n = e.provider, r = e.signature ?? n?.signature ?? null, i = e.idempotency ?? n?.idempotency ?? null, a = e.bodyType ?? n?.bodyType ?? "json", o = Ze(e);
626
- if (o === null) throw new Ye(e.id);
633
+ }, Ze = (e, t) => {
634
+ let n = e.provider, r = e.signature ?? n?.signature ?? null, i = e.idempotency ?? n?.idempotency ?? null, a = e.bodyType ?? n?.bodyType ?? "json", o = Xe(e);
635
+ if (o === null) throw new Je(e.id);
627
636
  let c = o;
628
- c === "none" && O({ scope: `webhook:${e.id}` }).warn("incoming webhook mounted WITHOUT verification — anyone who can reach this URL can run its handler", {
637
+ c === "none" && A({ scope: `webhook:${e.id}` }).warn("incoming webhook mounted WITHOUT verification — anyone who can reach this URL can run its handler", {
629
638
  webhookId: e.id,
630
639
  verification: "none"
631
640
  });
632
- let l = t.idempotencyCache ?? Ke(), u = qe(i?.ttl), d = t.log ?? ((e) => {
633
- O({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
641
+ let l = t.idempotencyCache ?? Ge(), u = Ke(i?.ttl), d = t.log ?? ((e) => {
642
+ A({ scope: `webhook:${e.webhookId}` }).debug("incoming webhook", {
634
643
  status: e.status,
635
644
  signatureOk: e.signatureOk,
636
645
  idempotency: e.idempotency,
@@ -641,7 +650,7 @@ var j = ["network:outbound:*"], M = [{
641
650
  return Object.assign(async (n) => {
642
651
  let o = Date.now();
643
652
  if (n.method !== "POST") {
644
- let t = J(405, {
653
+ let t = Y(405, {
645
654
  error: "method not allowed",
646
655
  expected: "POST"
647
656
  });
@@ -657,7 +666,7 @@ var j = ["network:outbound:*"], M = [{
657
666
  if (r !== null && c === "signature") {
658
667
  let i = await t.resolveSecret(e.id);
659
668
  if (i === null) {
660
- let t = `no signing secret configured — set ${Xe(e.id)}`, n = J(503, {
669
+ let t = `no signing secret configured — set ${Ye(e.id)}`, n = Y(503, {
661
670
  error: "webhook not configured",
662
671
  reason: t
663
672
  });
@@ -677,7 +686,7 @@ var j = ["network:outbound:*"], M = [{
677
686
  headers: n.headers
678
687
  });
679
688
  if (f = t.ok, !t.ok) {
680
- let n = J(401, {
689
+ let n = Y(401, {
681
690
  error: "invalid signature",
682
691
  reason: t.reason
683
692
  });
@@ -703,7 +712,7 @@ var j = ["network:outbound:*"], M = [{
703
712
  p = r;
704
713
  } else p = n.rawBody;
705
714
  } catch (t) {
706
- let n = J(400, {
715
+ let n = Y(400, {
707
716
  error: "malformed body",
708
717
  reason: t.message
709
718
  });
@@ -718,9 +727,9 @@ var j = ["network:outbound:*"], M = [{
718
727
  }
719
728
  let m;
720
729
  try {
721
- m = w.decodeUnknownSync(e.payload)(p);
730
+ m = T.decodeUnknownSync(e.payload)(p);
722
731
  } catch (t) {
723
- let n = J(422, {
732
+ let n = Y(422, {
724
733
  error: "schema validation failed",
725
734
  reason: t.message
726
735
  });
@@ -739,7 +748,7 @@ var j = ["network:outbound:*"], M = [{
739
748
  if (h = typeof t == "string" ? n.headers[t.toLowerCase()] : t(n.headers, n.rawBody), h !== void 0 && h.length > 0) {
740
749
  let t = l.claim(h, u);
741
750
  if (g = t, t === "duplicate") {
742
- let t = J(200, {
751
+ let t = Y(200, {
743
752
  received: !0,
744
753
  duplicate: !0
745
754
  });
@@ -752,7 +761,7 @@ var j = ["network:outbound:*"], M = [{
752
761
  }), t;
753
762
  }
754
763
  if (t === "inflight") {
755
- let t = J(409, {
764
+ let t = Y(409, {
756
765
  error: "request already in flight",
757
766
  idempotencyKey: h
758
767
  });
@@ -775,7 +784,7 @@ var j = ["network:outbound:*"], M = [{
775
784
  idempotencyKey: h ?? "",
776
785
  ...r ? { workflows: r } : {}
777
786
  }), h !== void 0 && l.commit(h);
778
- let i = J(200, { received: !0 });
787
+ let i = Y(200, { received: !0 });
779
788
  return d({
780
789
  webhookId: e.id,
781
790
  status: 200,
@@ -785,7 +794,7 @@ var j = ["network:outbound:*"], M = [{
785
794
  }), i;
786
795
  } catch (t) {
787
796
  h !== void 0 && l.release(h);
788
- let n = J(500, {
797
+ let n = Y(500, {
789
798
  error: "handler threw",
790
799
  reason: t.message
791
800
  });
@@ -796,28 +805,28 @@ var j = ["network:outbound:*"], M = [{
796
805
  idempotency: g,
797
806
  durationMs: Date.now() - o,
798
807
  errorMessage: t.message
799
- }), _e({
808
+ }), ge({
800
809
  error: t,
801
810
  source: "webhook",
802
811
  name: e.id,
803
812
  fields: { status: 500 }
804
813
  }), n;
805
814
  }
806
- }, { [Je]: c });
807
- }, $e = (e) => `/webhooks/${e}`, et = "_voltro_webhook_rate_windows", tt = 6e4, nt = (e, t) => `${e}@${t}`, rt = async (e, t, n) => (await e.query({
815
+ }, { [qe]: c });
816
+ }, Qe = (e) => `/webhooks/${e}`, $e = "_voltro_webhook_rate_windows", et = 6e4, tt = (e, t) => `${e}@${t}`, nt = async (e, t, n) => (await e.query({
808
817
  table: "_voltro_webhook_rate_windows",
809
- predicate: E(D("scope", t), D("bucket", n)),
818
+ predicate: D(O("scope", t), O("bucket", n)),
810
819
  order: [],
811
820
  take: 1,
812
821
  skip: void 0,
813
822
  projection: void 0
814
- }))[0] ?? null, Y = 32, X = async (e, t, n) => {
815
- for (let r = 0; r < Y; r++) {
823
+ }))[0] ?? null, X = 32, rt = async (e, t, n) => {
824
+ for (let r = 0; r < X; r++) {
816
825
  r > 0 && await new Promise((e) => setTimeout(e, r));
817
- let i = await rt(e, t.key, n);
826
+ let i = await nt(e, t.key, n);
818
827
  if (i === null) {
819
- await e.insertIgnore(et, {
820
- id: nt(t.key, n),
828
+ await e.insertIgnore($e, {
829
+ id: tt(t.key, n),
821
830
  scope: t.key,
822
831
  bucket: n,
823
832
  count: 0,
@@ -830,27 +839,27 @@ var j = ["network:outbound:*"], M = [{
830
839
  if (await e.updateMany("_voltro_webhook_rate_windows", {
831
840
  count: i.count + 1,
832
841
  updatedAt: /* @__PURE__ */ new Date()
833
- }, { where: E(D("id", i.id), D("count", i.count)) }) === 1) return !0;
842
+ }, { where: D(O("id", i.id), O("count", i.count)) }) === 1) return !0;
834
843
  }
835
- throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${Y} attempts`);
844
+ throw Error(`webhook rate window: contention on (${t.key}, ${n}) exceeded ${X} attempts`);
836
845
  }, it = async (e, t, n) => {
837
- for (let r = 0; r < Y; r++) {
846
+ for (let r = 0; r < X; r++) {
838
847
  r > 0 && await new Promise((e) => setTimeout(e, r));
839
- let i = await rt(e, t, n);
848
+ let i = await nt(e, t, n);
840
849
  if (i === null || i.count <= 0 || await e.updateMany("_voltro_webhook_rate_windows", {
841
850
  count: i.count - 1,
842
851
  updatedAt: /* @__PURE__ */ new Date()
843
- }, { where: E(D("id", i.id), D("count", i.count)) }) === 1) return;
852
+ }, { where: D(O("id", i.id), O("count", i.count)) }) === 1) return;
844
853
  }
845
- throw Error(`webhook rate window: release contention on (${t}) exceeded ${Y} attempts`);
846
- }, at = async (e, t, n, r = tt) => {
854
+ throw Error(`webhook rate window: release contention on (${t}) exceeded ${X} attempts`);
855
+ }, at = async (e, t, n, r = et) => {
847
856
  if (t.length === 0) return {
848
857
  acquired: !0,
849
858
  retryInMs: 0
850
859
  };
851
860
  let i = Math.floor(n / r), a = [];
852
861
  for (let o of t) {
853
- if (await X(e, o, i)) {
862
+ if (await rt(e, o, i)) {
854
863
  a.push(o);
855
864
  continue;
856
865
  }
@@ -923,7 +932,7 @@ var j = ["network:outbound:*"], M = [{
923
932
  }
924
933
  }), ft = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e, pt = "_voltro_webhook_targets", mt = 32, ht = async (e, t) => (await e.query({
925
934
  table: "_voltro_webhook_targets",
926
- predicate: D("id", t),
935
+ predicate: O("id", t),
927
936
  order: [],
928
937
  take: 1,
929
938
  skip: void 0,
@@ -941,7 +950,7 @@ var j = ["network:outbound:*"], M = [{
941
950
  if (c === 0 || await e.updateMany("_voltro_webhook_targets", {
942
951
  consecutiveFailures: 0,
943
952
  updatedAt: i
944
- }, { where: E(D("id", t), D("consecutiveFailures", c)) }) === 1) return {
953
+ }, { where: D(O("id", t), O("consecutiveFailures", c)) }) === 1) return {
945
954
  consecutiveFailures: 0,
946
955
  autoDisabled: !1
947
956
  };
@@ -951,41 +960,48 @@ var j = ["network:outbound:*"], M = [{
951
960
  consecutiveFailures: l,
952
961
  updatedAt: i
953
962
  };
954
- if (d && (f.active = !1, f.autoDisabledAt = i, f.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", f, { where: E(D("id", t), D("consecutiveFailures", c)) }) === 1) return {
963
+ if (d && (f.active = !1, f.autoDisabledAt = i, f.autoDisableReason = r.slice(0, 500)), await e.updateMany("_voltro_webhook_targets", f, { where: D(O("id", t), O("consecutiveFailures", c)) }) === 1) return {
955
964
  consecutiveFailures: l,
956
965
  autoDisabled: d
957
966
  };
958
967
  }
959
968
  throw Error(`webhook auto-disable: streak CAS contention on target ${t} exceeded ${mt} attempts`);
960
- }, _t = w.Struct({
961
- status: w.Number,
962
- body: w.String,
963
- latencyMs: w.Number,
964
- retryAfterSec: w.Union(w.Number, w.Undefined),
965
- transportError: w.Union(w.String, w.Undefined),
966
- encodeError: w.Union(w.String, w.Undefined)
967
- }), vt = w.Struct({
968
- outcome: w.Literal("succeeded", "failed", "retry"),
969
- delayMs: w.Union(w.Number, w.Undefined),
970
- reason: w.Union(w.String, w.Undefined),
971
- autoDisabled: w.Union(w.Boolean, w.Undefined),
972
- consecutiveFailures: w.Union(w.Number, w.Undefined)
973
- }), yt = w.Struct({
974
- acquired: w.Boolean,
975
- retryInMs: w.Number
969
+ }, _t = T.Struct({
970
+ status: T.Number,
971
+ body: T.String,
972
+ latencyMs: T.Number,
973
+ retryAfterSec: T.Union([T.Number, T.Undefined]),
974
+ transportError: T.Union([T.String, T.Undefined]),
975
+ encodeError: T.Union([T.String, T.Undefined])
976
+ }), vt = T.Struct({
977
+ outcome: T.Literals([
978
+ "succeeded",
979
+ "failed",
980
+ "retry"
981
+ ]),
982
+ delayMs: T.Union([T.Number, T.Undefined]),
983
+ reason: T.Union([T.String, T.Undefined]),
984
+ autoDisabled: T.Union([T.Boolean, T.Undefined]),
985
+ consecutiveFailures: T.Union([T.Number, T.Undefined])
986
+ }), yt = T.Struct({
987
+ acquired: T.Boolean,
988
+ retryInMs: T.Number
976
989
  }), bt = {
977
- deliveryId: w.String,
978
- targetId: w.String,
979
- event: w.String,
980
- eventId: w.String,
981
- payloadJson: w.String,
982
- attemptEpoch: w.optionalWith(w.Number, { default: () => 0 })
983
- }, xt = be.make({
984
- name: "voltro.deliverWebhook",
990
+ deliveryId: T.String,
991
+ targetId: T.String,
992
+ event: T.String,
993
+ eventId: T.String,
994
+ payloadJson: T.String,
995
+ attemptEpoch: T.optional(T.Number)
996
+ }, xt = ye.make("voltro.deliverWebhook", {
985
997
  payload: bt,
986
- success: w.Struct({
987
- finalStatus: w.Literal("succeeded", "failed", "deferred"),
988
- attempts: w.Number
998
+ success: T.Struct({
999
+ finalStatus: T.Literals([
1000
+ "succeeded",
1001
+ "failed",
1002
+ "deferred"
1003
+ ]),
1004
+ attempts: T.Number
989
1005
  }),
990
1006
  idempotencyKey: ({ deliveryId: e, attemptEpoch: t }) => `voltro.deliverWebhook:${e}:${t ?? 0}`
991
1007
  }), St = 3e4, Ct = (e, t) => {
@@ -993,30 +1009,31 @@ var j = ["network:outbound:*"], M = [{
993
1009
  let n = Number(t.VOLTRO_WEBHOOK_TIMEOUT_MS);
994
1010
  return Number.isFinite(n) && n > 0 ? n : St;
995
1011
  }, wt = (e, t = {}) => (n, r) => {
996
- let { deliveryId: i, targetId: a, event: o, eventId: s, payloadJson: c } = n, l = O({ scope: `webhook:${i}` });
997
- return C.gen(function* () {
998
- let n = yield* k.make({
1012
+ let { deliveryId: i, targetId: a, event: o, eventId: s, payloadJson: c } = n, l = A({ scope: `webhook:${i}` });
1013
+ return w.gen(function* () {
1014
+ let n = yield* j.make({
999
1015
  name: "fetch-target",
1000
- success: w.Union(w.Null, w.Struct({
1001
- id: w.String,
1002
- event: w.String,
1003
- url: w.String,
1004
- secret: w.String,
1005
- signing: w.Any,
1006
- retry: w.Any,
1007
- headers: w.Union(w.Record({
1008
- key: w.String,
1009
- value: w.String
1010
- }), w.Null),
1011
- rateLimitPerMinute: w.Union(w.Number, w.Null),
1012
- active: w.Boolean,
1013
- format: w.Literal("json", "form", "xml"),
1014
- tenantId: w.Union(w.String, w.Null)
1015
- })),
1016
- execute: C.tryPromise({
1016
+ success: T.Union([T.Null, T.Struct({
1017
+ id: T.String,
1018
+ event: T.String,
1019
+ url: T.String,
1020
+ secret: T.String,
1021
+ signing: T.Any,
1022
+ retry: T.Any,
1023
+ headers: T.Union([T.Record(T.String, T.String), T.Null]),
1024
+ rateLimitPerMinute: T.Union([T.Number, T.Null]),
1025
+ active: T.Boolean,
1026
+ format: T.Literals([
1027
+ "json",
1028
+ "form",
1029
+ "xml"
1030
+ ]),
1031
+ tenantId: T.Union([T.String, T.Null])
1032
+ })]),
1033
+ execute: w.tryPromise({
1017
1034
  try: async () => (await e.store.query({
1018
1035
  table: "_voltro_webhook_targets",
1019
- predicate: D("id", a),
1036
+ predicate: O("id", a),
1020
1037
  order: [{
1021
1038
  column: "createdAt",
1022
1039
  direction: "asc"
@@ -1030,7 +1047,7 @@ var j = ["network:outbound:*"], M = [{
1030
1047
  event: o,
1031
1048
  cause: String(e)
1032
1049
  }), /* @__PURE__ */ Error(`fetch-target failed: ${e.message}`))
1033
- }).pipe(C.orDie)
1050
+ }).pipe(w.orDie)
1034
1051
  });
1035
1052
  if (n === null) return {
1036
1053
  finalStatus: "failed",
@@ -1055,13 +1072,13 @@ var j = ["network:outbound:*"], M = [{
1055
1072
  ...l
1056
1073
  });
1057
1074
  };
1058
- if (n.active !== !0) return yield* k.make({
1075
+ if (n.active !== !0) return yield* j.make({
1059
1076
  name: "record-paused-pending",
1060
- success: w.Void,
1061
- execute: C.tryPromise({
1077
+ success: T.Void,
1078
+ execute: w.tryPromise({
1062
1079
  try: () => r(`${i}:1`, 1, { status: "pending" }),
1063
1080
  catch: (e) => /* @__PURE__ */ Error(`record-paused-pending failed: ${e.message}`)
1064
- }).pipe(C.orDie)
1081
+ }).pipe(w.orDie)
1065
1082
  }), {
1066
1083
  finalStatus: "deferred",
1067
1084
  attempts: 0
@@ -1076,10 +1093,10 @@ var j = ["network:outbound:*"], M = [{
1076
1093
  for (let t = 1; t <= d.maxAttempts; t++) {
1077
1094
  let u = `${i}:${t}`;
1078
1095
  if (v.length > 0) for (let n = 0;; n++) {
1079
- let i = yield* k.make({
1096
+ let i = yield* j.make({
1080
1097
  name: `rate-acquire-${t}-${n}`,
1081
1098
  success: yt,
1082
- execute: C.tryPromise({
1099
+ execute: w.tryPromise({
1083
1100
  try: () => at(e.store, v, Date.now(), h),
1084
1101
  catch: (e) => (l.debug("rate-acquire raw error", {
1085
1102
  targetId: a,
@@ -1087,40 +1104,40 @@ var j = ["network:outbound:*"], M = [{
1087
1104
  attempt: t,
1088
1105
  cause: String(e)
1089
1106
  }), /* @__PURE__ */ Error(`rate-acquire failed: ${e.message}`))
1090
- }).pipe(C.orDie)
1107
+ }).pipe(w.orDie)
1091
1108
  });
1092
1109
  if (i.acquired) break;
1093
- yield* k.make({
1110
+ yield* j.make({
1094
1111
  name: `record-rate-deferral-${t}-${n}`,
1095
- success: w.Void,
1096
- execute: C.tryPromise({
1112
+ success: T.Void,
1113
+ execute: w.tryPromise({
1097
1114
  try: () => r(u, t, {
1098
1115
  status: "pending",
1099
1116
  nextAttemptAt: new Date(Date.now() + i.retryInMs)
1100
1117
  }),
1101
1118
  catch: (e) => /* @__PURE__ */ Error(`record-rate-deferral failed: ${e.message}`)
1102
- }).pipe(C.orDie)
1103
- }), yield* A.sleep({
1119
+ }).pipe(w.orDie)
1120
+ }), yield* ve.sleep({
1104
1121
  name: `rate-window-sleep-${t}-${n}`,
1105
1122
  duration: `${i.retryInMs} millis`
1106
1123
  });
1107
1124
  }
1108
- yield* k.make({
1125
+ yield* j.make({
1109
1126
  name: `record-attempt-start-${t}`,
1110
- success: w.Void,
1111
- execute: C.tryPromise({
1127
+ success: T.Void,
1128
+ execute: w.tryPromise({
1112
1129
  try: () => r(u, t, {
1113
1130
  status: "inFlight",
1114
1131
  nextAttemptAt: null,
1115
1132
  scheduledAt: /* @__PURE__ */ new Date()
1116
1133
  }),
1117
1134
  catch: (e) => /* @__PURE__ */ Error(`record-attempt-start failed: ${e.message}`)
1118
- }).pipe(C.orDie)
1135
+ }).pipe(w.orDie)
1119
1136
  });
1120
- let _ = yield* k.make({
1137
+ let _ = yield* j.make({
1121
1138
  name: `sign-and-post-${t}`,
1122
1139
  success: _t,
1123
- execute: C.promise(async () => {
1140
+ execute: w.promise(async () => {
1124
1141
  let e = Date.now(), r;
1125
1142
  try {
1126
1143
  r = ot(n.format, c);
@@ -1140,7 +1157,7 @@ var j = ["network:outbound:*"], M = [{
1140
1157
  secret: n.secret,
1141
1158
  messageId: i
1142
1159
  });
1143
- process.env.NODE_ENV === "production" && ye(n.url);
1160
+ process.env.NODE_ENV === "production" && k(n.url);
1144
1161
  try {
1145
1162
  let c = await fetch(n.url, {
1146
1163
  method: "POST",
@@ -1177,10 +1194,10 @@ var j = ["network:outbound:*"], M = [{
1177
1194
  };
1178
1195
  }
1179
1196
  })
1180
- }), y = yield* k.make({
1197
+ }), y = yield* j.make({
1181
1198
  name: `classify-and-record-${t}`,
1182
1199
  success: vt,
1183
- execute: C.tryPromise({
1200
+ execute: w.tryPromise({
1184
1201
  try: async () => {
1185
1202
  let r = _.status >= 200 && _.status < 300, i = _.transportError !== void 0, o = _.encodeError !== void 0, s = _.status === 410, c = (t, n) => gt(e.store, a, t, n, /* @__PURE__ */ new Date(), !t && s);
1186
1203
  if (r) {
@@ -1200,7 +1217,7 @@ var j = ["network:outbound:*"], M = [{
1200
1217
  consecutiveFailures: t.consecutiveFailures
1201
1218
  };
1202
1219
  }
1203
- let l = o ? null : Ee(d, t, {
1220
+ let l = o ? null : Te(d, t, {
1204
1221
  ...i ? {} : { status: _.status },
1205
1222
  ..._.retryAfterSec === void 0 ? {} : { retryAfterSeconds: _.retryAfterSec }
1206
1223
  });
@@ -1245,7 +1262,7 @@ var j = ["network:outbound:*"], M = [{
1245
1262
  attempt: t,
1246
1263
  cause: String(e)
1247
1264
  }), /* @__PURE__ */ Error(`classify-and-record failed: ${e.message}`))
1248
- }).pipe(C.orDie)
1265
+ }).pipe(w.orDie)
1249
1266
  });
1250
1267
  if (y.autoDisabled === !0 && l.warn("target auto-disabled after consecutive failures", {
1251
1268
  targetId: a,
@@ -1260,7 +1277,7 @@ var j = ["network:outbound:*"], M = [{
1260
1277
  finalStatus: "failed",
1261
1278
  attempts: t
1262
1279
  };
1263
- y.delayMs !== void 0 && (yield* A.sleep({
1280
+ y.delayMs !== void 0 && (yield* ve.sleep({
1264
1281
  name: `retry-sleep-${t}`,
1265
1282
  duration: `${y.delayMs} millis`
1266
1283
  }));
@@ -1270,15 +1287,18 @@ var j = ["network:outbound:*"], M = [{
1270
1287
  attempts: d.maxAttempts
1271
1288
  };
1272
1289
  });
1273
- }, $ = "voltro.webhook.emit", Tt = (e) => typeof e.event == "string", Et = (e) => xe({
1290
+ }, $ = "voltro.webhook.emit", Tt = (e) => typeof e.event == "string", Et = (e) => be({
1274
1291
  effect: $,
1275
1292
  maxAttempts: 1,
1276
- handler: async ({ payload: t }) => {
1293
+ handler: async ({ payload: t, outboxId: n }) => {
1277
1294
  if (!Tt(t)) throw Error(`${$}: row payload has no \`event\` name — cannot resolve a descriptor. Got keys: ${Object.keys(t).join(", ") || "(none)"}`);
1278
- let n = e();
1279
- if (n === void 0) throw Error(`${$}: the outgoing-webhooks service is not available in this process. An emit was enqueued by a build that had the plugin registered; this one does not.`);
1280
- await n.emit(t.event, t.payload, { tenantId: t.tenantId });
1295
+ let r = e();
1296
+ if (r === void 0) throw Error(`${$}: the outgoing-webhooks service is not available in this process. An emit was enqueued by a build that had the plugin registered; this one does not.`);
1297
+ await r.emit(t.event, t.payload, {
1298
+ tenantId: t.tenantId,
1299
+ eventId: n
1300
+ });
1281
1301
  }
1282
1302
  });
1283
1303
  //#endregion
1284
- export { Ge as IdempotencyCache, tt as RATE_WINDOW_MS, et as RATE_WINDOW_TABLE, p as STANDARD_WEBHOOKS_DEFAULT_TOLERANCE_SECONDS, te as STANDARD_WEBHOOKS_ID_HEADER, c as STANDARD_WEBHOOKS_MAX_KEY_BYTES, l as STANDARD_WEBHOOKS_MIN_KEY_BYTES, _ as STANDARD_WEBHOOKS_SECRET_PREFIX, m as STANDARD_WEBHOOKS_SIGNATURE_HEADER, d as STANDARD_WEBHOOKS_TIMESTAMP_HEADER, u as STANDARD_WEBHOOKS_VERSION, pt as TARGETS_TABLE, Ye as UnverifiedIncomingWebhook, M as WEBHOOKS_EGRESS, j as WEBHOOKS_PLUGIN_PERMISSIONS, $ as WEBHOOK_EMIT_EFFECT, Je as WEBHOOK_VERIFICATION_PROPERTY, oe as WebhookDeliveryNotFound, se as WebhookPayloadInvalid, b as WebhookPayloadUnrepresentable, ce as WebhookPayloadVersionInvalid, x as WebhookSubscribeInvalid, S as WebhookTargetNotFound, ke as WebhooksService, le as _voltroWebhookDeliveriesTable, ue as _voltroWebhookEventStatsTable, de as _voltroWebhookRateWindowsTable, fe as _voltroWebhookTargetsTable, at as acquireRateSlots, we as asOutgoingEvent, wt as buildDeliverWebhookExecute, Ve as buildWebhooksService, Fe as compareVersions, X as consumeRateSlot, $e as defaultIncomingPath, ee as defaultOutgoingSignature, De as defaultRetryPolicy, re as defineIncomingWebhook, r as defineWebhookProvider, xt as deliverWebhookWorkflow, ot as encodePayload, F as eventsOf, Oe as fastRetryPolicy, Me as generateSecret, i as generateStandardWebhooksSecret, h as genericHmacSignature, Ke as getIdempotencyCache, v as githubSignature, Ce as hasWebhookAudience, Ze as incomingWebhookVerification, ne as isStandardWebhooksSecret, t as isWebhookDescriptor, Et as makeDeferredEmitHandler, V as matchesFilter, Qe as mountIncomingWebhook, Ee as nextRetry, N as parseDuration, qe as parseTtl, gt as recordDeliveryOutcome, it as releaseRateSlot, R as resolveSubscribe, f as signRequest, a as slackSignature, ae as standardWebhooksHeaders, o as standardWebhooksKey, g as standardWebhooksSignature, ie as standardWebhooksSignatureToken, n as standardWebhooksSignedContent, y as stripeSignature, Ue as useWebhooks, He as useWebhooksEffect, L as validateSubscribe, s as verifyRequest, e as verifyStandardWebhooks, pe as webhookTables, Se as webhooksPlugin };
1304
+ export { We as IdempotencyCache, et as RATE_WINDOW_MS, $e as RATE_WINDOW_TABLE, p as STANDARD_WEBHOOKS_DEFAULT_TOLERANCE_SECONDS, te as STANDARD_WEBHOOKS_ID_HEADER, c as STANDARD_WEBHOOKS_MAX_KEY_BYTES, l as STANDARD_WEBHOOKS_MIN_KEY_BYTES, _ as STANDARD_WEBHOOKS_SECRET_PREFIX, m as STANDARD_WEBHOOKS_SIGNATURE_HEADER, d as STANDARD_WEBHOOKS_TIMESTAMP_HEADER, u as STANDARD_WEBHOOKS_VERSION, pt as TARGETS_TABLE, Je as UnverifiedIncomingWebhook, M as WEBHOOKS_EGRESS, xe as WEBHOOKS_PLUGIN_PERMISSIONS, $ as WEBHOOK_EMIT_EFFECT, qe as WEBHOOK_VERIFICATION_PROPERTY, oe as WebhookDeliveryNotFound, se as WebhookPayloadInvalid, b as WebhookPayloadUnrepresentable, x as WebhookPayloadVersionInvalid, S as WebhookSubscribeInvalid, C as WebhookTargetNotFound, Oe as WebhooksService, ce as _voltroWebhookDeliveriesTable, le as _voltroWebhookEventStatsTable, ue as _voltroWebhookRateWindowsTable, de as _voltroWebhookTargetsTable, at as acquireRateSlots, N as asOutgoingEvent, wt as buildDeliverWebhookExecute, Be as buildWebhooksService, Pe as compareVersions, rt as consumeRateSlot, Qe as defaultIncomingPath, ee as defaultOutgoingSignature, Ee as defaultRetryPolicy, re as defineIncomingWebhook, r as defineWebhookProvider, xt as deliverWebhookWorkflow, ot as encodePayload, I as eventsOf, De as fastRetryPolicy, je as generateSecret, i as generateStandardWebhooksSecret, h as genericHmacSignature, Ge as getIdempotencyCache, v as githubSignature, Ce as hasWebhookAudience, Xe as incomingWebhookVerification, ne as isStandardWebhooksSecret, t as isWebhookDescriptor, Et as makeDeferredEmitHandler, H as matchesFilter, Ze as mountIncomingWebhook, Te as nextRetry, P as parseDuration, Ke as parseTtl, gt as recordDeliveryOutcome, it as releaseRateSlot, z as resolveSubscribe, f as signRequest, a as slackSignature, ae as standardWebhooksHeaders, o as standardWebhooksKey, g as standardWebhooksSignature, ie as standardWebhooksSignatureToken, n as standardWebhooksSignedContent, y as stripeSignature, He as useWebhooks, Ve as useWebhooksEffect, R as validateSubscribe, s as verifyRequest, e as verifyStandardWebhooks, fe as webhookTables, Se as webhooksPlugin };