@voltro/plugin-webhooks 0.86.0 → 0.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5484 -0
- package/THIRD-PARTY-NOTICES.md +1511 -276
- package/dist/autoDisable.js +1 -2
- package/dist/deferredEmit.js +1 -2
- package/dist/deliverWorkflow.js +28 -15
- package/dist/dsl.js +1 -2
- package/dist/encode.js +1 -2
- package/dist/errors.js +1 -2
- package/dist/eventAudience.js +1 -2
- package/dist/idempotency.js +1 -2
- package/dist/incoming.js +1 -2
- package/dist/index.d.ts +46 -4
- package/dist/index.js +10 -10
- package/dist/mixin.d.ts +16 -2
- package/dist/mixin.js +3 -2
- package/dist/plugin.js +1 -2
- package/dist/providers/generic.js +1 -2
- package/dist/providers/github.js +1 -2
- package/dist/providers/slack.js +1 -2
- package/dist/providers/stripe.js +1 -2
- package/dist/rateLimit.js +1 -2
- package/dist/retry.js +1 -2
- package/dist/service.js +88 -53
- package/dist/signing.js +1 -2
- package/dist/standardWebhooks.js +1 -2
- package/package.json +8 -8
package/dist/autoDisable.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { and as e, eq as t } from "@voltro/database";
|
|
2
|
-
|
|
2
|
+
// src/autoDisable.ts
|
|
3
3
|
var n = "_voltro_webhook_targets", r = 32, i = async (e, n) => (await e.query({
|
|
4
4
|
table: "_voltro_webhook_targets",
|
|
5
5
|
predicate: t("id", n),
|
|
@@ -37,5 +37,4 @@ var n = "_voltro_webhook_targets", r = 32, i = async (e, n) => (await e.query({
|
|
|
37
37
|
}
|
|
38
38
|
throw Error(`webhook auto-disable: streak CAS contention on target ${a} exceeded ${r} attempts`);
|
|
39
39
|
};
|
|
40
|
-
//#endregion
|
|
41
40
|
export { n as TARGETS_TABLE, a as recordDeliveryOutcome };
|
package/dist/deferredEmit.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineOutboxHandler as e } from "@voltro/runtime";
|
|
2
|
-
|
|
2
|
+
// src/deferredEmit.ts
|
|
3
3
|
var t = "voltro.webhook.emit", n = (e) => typeof e.event == "string", r = (r) => e({
|
|
4
4
|
effect: t,
|
|
5
5
|
maxAttempts: 1,
|
|
@@ -13,5 +13,4 @@ var t = "voltro.webhook.emit", n = (e) => typeof e.event == "string", r = (r) =>
|
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
|
-
//#endregion
|
|
17
16
|
export { t as WEBHOOK_EMIT_EFFECT, r as makeDeferredEmitHandler };
|
package/dist/deliverWorkflow.js
CHANGED
|
@@ -9,7 +9,7 @@ import { eq as c } from "@voltro/database";
|
|
|
9
9
|
import { assertPublicUrl as l } from "@voltro/integration-http";
|
|
10
10
|
import { createLogger as u } from "@voltro/logger";
|
|
11
11
|
import { Activity as d, DurableClock as f, Workflow as p } from "effect/workflow";
|
|
12
|
-
|
|
12
|
+
// src/deliverWorkflow.ts
|
|
13
13
|
var m = s.Struct({
|
|
14
14
|
status: s.Number,
|
|
15
15
|
body: s.String,
|
|
@@ -62,6 +62,8 @@ var m = s.Struct({
|
|
|
62
62
|
event: s.String,
|
|
63
63
|
url: s.String,
|
|
64
64
|
secret: s.String,
|
|
65
|
+
previousSecret: s.optional(s.Union([s.String, s.Null])),
|
|
66
|
+
previousSecretUntil: s.optional(s.Union([s.String, s.Null])),
|
|
65
67
|
signing: s.Any,
|
|
66
68
|
retry: s.Any,
|
|
67
69
|
headers: s.Union([s.Record(s.String, s.String), s.Null]),
|
|
@@ -75,17 +77,26 @@ var m = s.Struct({
|
|
|
75
77
|
tenantId: s.Union([s.String, s.Null])
|
|
76
78
|
})]),
|
|
77
79
|
execute: o.tryPromise({
|
|
78
|
-
try: async () =>
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
try: async () => {
|
|
81
|
+
let e = (await p.store.query({
|
|
82
|
+
table: "_voltro_webhook_targets",
|
|
83
|
+
predicate: c("id", S),
|
|
84
|
+
order: [{
|
|
85
|
+
column: "createdAt",
|
|
86
|
+
direction: "asc"
|
|
87
|
+
}],
|
|
88
|
+
take: 1,
|
|
89
|
+
skip: void 0,
|
|
90
|
+
projection: void 0
|
|
91
|
+
}))[0];
|
|
92
|
+
if (e === void 0) return null;
|
|
93
|
+
let t = e.previousSecretUntil;
|
|
94
|
+
return {
|
|
95
|
+
...e,
|
|
96
|
+
previousSecret: e.previousSecret ?? null,
|
|
97
|
+
previousSecretUntil: t instanceof Date ? t.toISOString() : t ?? null
|
|
98
|
+
};
|
|
99
|
+
},
|
|
89
100
|
catch: (e) => (E.debug("fetch-target raw error", {
|
|
90
101
|
targetId: S,
|
|
91
102
|
event: C,
|
|
@@ -196,7 +207,10 @@ var m = s.Struct({
|
|
|
196
207
|
};
|
|
197
208
|
throw e;
|
|
198
209
|
}
|
|
199
|
-
let a = Buffer.from(r.bytes),
|
|
210
|
+
let a = Buffer.from(r.bytes), o = u.previousSecret != null && u.previousSecretUntil != null && Date.parse(u.previousSecretUntil) > Date.now() && O._tag === "standardWebhooks" && O.previousSecret === void 0 ? {
|
|
211
|
+
...O,
|
|
212
|
+
previousSecret: u.previousSecret
|
|
213
|
+
} : O, { headers: s } = e(o, {
|
|
200
214
|
rawBody: a,
|
|
201
215
|
secret: u.secret,
|
|
202
216
|
messageId: x
|
|
@@ -207,7 +221,7 @@ var m = s.Struct({
|
|
|
207
221
|
method: "POST",
|
|
208
222
|
headers: {
|
|
209
223
|
"content-type": r.contentType,
|
|
210
|
-
...
|
|
224
|
+
...s,
|
|
211
225
|
"x-voltro-event": C,
|
|
212
226
|
"x-voltro-event-id": w,
|
|
213
227
|
"x-voltro-delivery-id": x,
|
|
@@ -332,5 +346,4 @@ var m = s.Struct({
|
|
|
332
346
|
};
|
|
333
347
|
});
|
|
334
348
|
};
|
|
335
|
-
//#endregion
|
|
336
349
|
export { y as DEFAULT_WEBHOOK_TIMEOUT_MS, x as buildDeliverWebhookExecute, v as deliverWebhookWorkflow };
|
package/dist/dsl.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/dsl.ts
|
|
2
2
|
var e = (e) => ({
|
|
3
3
|
_tag: "incomingWebhook",
|
|
4
4
|
...e
|
|
@@ -10,5 +10,4 @@ var e = (e) => ({
|
|
|
10
10
|
let t = e._tag;
|
|
11
11
|
return t === "outgoingEvent" || t === "incomingWebhook" || t === "webhookProvider";
|
|
12
12
|
};
|
|
13
|
-
//#endregion
|
|
14
13
|
export { e as defineIncomingWebhook, t as defineWebhookProvider, n as isWebhookDescriptor };
|
package/dist/encode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WebhookPayloadUnrepresentable as e } from "./errors.js";
|
|
2
|
-
|
|
2
|
+
// src/encode.ts
|
|
3
3
|
var t = (t, r) => {
|
|
4
4
|
if (t === "json") return {
|
|
5
5
|
contentType: "application/json",
|
|
@@ -49,5 +49,4 @@ var t = (t, r) => {
|
|
|
49
49
|
default: return "'";
|
|
50
50
|
}
|
|
51
51
|
}), l = (e) => e === null ? "null" : Array.isArray(e) ? "array" : typeof e;
|
|
52
|
-
//#endregion
|
|
53
52
|
export { t as encodePayload };
|
package/dist/errors.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Schema as e } from "effect";
|
|
2
|
-
|
|
2
|
+
// src/errors.ts
|
|
3
3
|
var t = class extends e.TaggedError()("WebhookSubscribeInvalid", {
|
|
4
4
|
field: e.String,
|
|
5
5
|
reason: e.String
|
|
@@ -18,5 +18,4 @@ var t = class extends e.TaggedError()("WebhookSubscribeInvalid", {
|
|
|
18
18
|
]),
|
|
19
19
|
reason: e.String
|
|
20
20
|
}) {};
|
|
21
|
-
//#endregion
|
|
22
21
|
export { n as WebhookDeliveryNotFound, a as WebhookPayloadInvalid, o as WebhookPayloadUnrepresentable, i as WebhookPayloadVersionInvalid, t as WebhookSubscribeInvalid, r as WebhookTargetNotFound };
|
package/dist/eventAudience.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/eventAudience.ts
|
|
2
2
|
var e = (e) => e.webhook !== void 0, t = (e) => {
|
|
3
3
|
let t = e.webhook;
|
|
4
4
|
if (t !== void 0) return {
|
|
@@ -10,5 +10,4 @@ var e = (e) => e.webhook !== void 0, t = (e) => {
|
|
|
10
10
|
...t.rateLimit === void 0 ? {} : { globalRateLimit: t.rateLimit }
|
|
11
11
|
};
|
|
12
12
|
};
|
|
13
|
-
//#endregion
|
|
14
13
|
export { t as asOutgoingEvent, e as hasWebhookAudience };
|
package/dist/idempotency.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/idempotency.ts
|
|
2
2
|
var e = class {
|
|
3
3
|
capacity;
|
|
4
4
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -45,5 +45,4 @@ var e = class {
|
|
|
45
45
|
"7d": 6048e5,
|
|
46
46
|
"30d": 2592e6
|
|
47
47
|
}, i = (e) => e === void 0 ? r["7d"] : r[e] ?? r["7d"];
|
|
48
|
-
//#endregion
|
|
49
48
|
export { e as IdempotencyCache, n as getIdempotencyCache, i as parseTtl };
|
package/dist/incoming.js
CHANGED
|
@@ -3,7 +3,7 @@ import { getIdempotencyCache as t, parseTtl as n } from "./idempotency.js";
|
|
|
3
3
|
import { Schema as r } from "effect";
|
|
4
4
|
import { publishServerError as i } from "@voltro/protocol";
|
|
5
5
|
import { createLogger as a } from "@voltro/logger";
|
|
6
|
-
|
|
6
|
+
// src/incoming.ts
|
|
7
7
|
var o = (e, t) => ({
|
|
8
8
|
status: e,
|
|
9
9
|
contentType: "application/json; charset=utf-8",
|
|
@@ -201,5 +201,4 @@ var o = (e, t) => ({
|
|
|
201
201
|
}
|
|
202
202
|
}, { [s]: v });
|
|
203
203
|
}, f = (e) => `/webhooks/${e}`;
|
|
204
|
-
//#endregion
|
|
205
204
|
export { c as UnverifiedIncomingWebhook, s as WEBHOOK_VERIFICATION_PROPERTY, f as defaultIncomingPath, u as incomingWebhookVerification, d as mountIncomingWebhook };
|
package/dist/index.d.ts
CHANGED
|
@@ -617,6 +617,9 @@ emitter: () => Pick<WebhooksServiceShape, "emit"> | undefined) => OutboxHandlerD
|
|
|
617
617
|
*/
|
|
618
618
|
export declare const matchesFilter: (filter: WebhookFilter | Readonly<Record<string, unknown>> | null, payload: unknown) => boolean;
|
|
619
619
|
|
|
620
|
+
/** The longest overlap `rotateSecret` accepts, and its default: 30 days, unless ended earlier. */
|
|
621
|
+
export declare const MAX_SECRET_OVERLAP_SECONDS: number;
|
|
622
|
+
|
|
620
623
|
/** A mounted handler, carrying its verification declaration. */
|
|
621
624
|
export declare type MountedIncomingWebhook = ((request: IncomingRequest) => Promise<IncomingResponse>) & {
|
|
622
625
|
readonly [WEBHOOK_VERIFICATION_PROPERTY]: IncomingWebhookVerification;
|
|
@@ -822,6 +825,28 @@ export declare interface RetryPolicy {
|
|
|
822
825
|
|
|
823
826
|
export declare type RetryStrategy = 'fixed' | 'linear' | 'exponential';
|
|
824
827
|
|
|
828
|
+
/** What `rotateSecret` returns. */
|
|
829
|
+
export declare interface RotatedSecret {
|
|
830
|
+
/** The new secret — returned once; hand it to the receiver. */
|
|
831
|
+
readonly secret: string;
|
|
832
|
+
/** Until when deliveries are signed under the previous secret too. `null`:
|
|
833
|
+
* no overlap — asked for none, or a scheme with one signature per message. */
|
|
834
|
+
readonly previousSignedUntil: Date | null;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/** How long a rotated webhook secret keeps signing beside the new one. */
|
|
838
|
+
export declare interface RotateSecretOptions {
|
|
839
|
+
/**
|
|
840
|
+
* Seconds every delivery still carries a signature under the previous
|
|
841
|
+
* secret, so the receiver can switch when it is ready. The length is the
|
|
842
|
+
* RECEIVER's switch-over time — nothing on the sending side can measure it —
|
|
843
|
+
* so by default the overlap lasts until {@link WebhooksServiceShape.endSecretOverlap}
|
|
844
|
+
* ends it (once the receiver has switched), and at most 30 days. Pass a
|
|
845
|
+
* number to bound it yourself; `0` switches at once (after a leak).
|
|
846
|
+
*/
|
|
847
|
+
readonly overlapSeconds?: number;
|
|
848
|
+
}
|
|
849
|
+
|
|
825
850
|
export declare type SignatureScheme = HmacSignatureScheme | CustomSignatureScheme | StandardWebhooksSignatureScheme;
|
|
826
851
|
|
|
827
852
|
export declare interface SignedRequest {
|
|
@@ -1250,7 +1275,7 @@ export declare const _voltroWebhookDeliveriesTable: Table<"_voltro_webhook_deliv
|
|
|
1250
1275
|
readonly eventId: ColumnBuilder<string | null, "text", boolean>;
|
|
1251
1276
|
/** Attempt counter (1-indexed). */
|
|
1252
1277
|
readonly attempt: ColumnBuilder<number, "integer", boolean>;
|
|
1253
|
-
readonly status: ColumnBuilder<"failed" | "
|
|
1278
|
+
readonly status: ColumnBuilder<"failed" | "succeeded" | "pending" | "inFlight" | "retryScheduled", "text", boolean>;
|
|
1254
1279
|
/** Payload as sent over the wire. Stored verbatim — re-rendering
|
|
1255
1280
|
* from a referenced event row would lose the snapshot if the
|
|
1256
1281
|
* source event was deleted. */
|
|
@@ -1389,6 +1414,13 @@ export declare const _voltroWebhookTargetsTable: Table<"_voltro_webhook_targets"
|
|
|
1389
1414
|
* (a non-ciphertext value passes through); `voltro db encrypt-column
|
|
1390
1415
|
* _voltro_webhook_targets.secret` converts them in place. */
|
|
1391
1416
|
readonly secret: ColumnBuilder<string, "text", boolean>;
|
|
1417
|
+
/** During a rotation (`rotateSecret`): the secret the receiver may still
|
|
1418
|
+
* verify with. Every delivery until {@link previousSecretUntil} carries a
|
|
1419
|
+
* signature under it beside the new one (Standard Webhooks' signature list),
|
|
1420
|
+
* so the receiver switches when it is ready. Encrypted like `secret`. */
|
|
1421
|
+
readonly previousSecret: ColumnBuilder<string | null, "text", boolean>;
|
|
1422
|
+
/** When deliveries stop signing under `previousSecret`. */
|
|
1423
|
+
readonly previousSecretUntil: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
1392
1424
|
/** Serialised `SignatureScheme` discriminated union — see `signing.ts`.
|
|
1393
1425
|
* Stored as JSON so future schemes don't require a schema migration. */
|
|
1394
1426
|
readonly signing: ColumnBuilder<unknown, "json", boolean>;
|
|
@@ -1702,8 +1734,11 @@ export declare interface WebhooksServiceShape {
|
|
|
1702
1734
|
* must sign identically, and the previous way to achieve it was delete +
|
|
1703
1735
|
* re-subscribe, minting new ids and orphaning the delivery history.
|
|
1704
1736
|
*/
|
|
1705
|
-
readonly rotateSecret: (target: TargetSelector) => Promise<
|
|
1706
|
-
|
|
1737
|
+
readonly rotateSecret: (target: TargetSelector, options?: RotateSecretOptions) => Promise<RotatedSecret>;
|
|
1738
|
+
/** End a rotation's overlap once the receiver verifies with the new secret: the
|
|
1739
|
+
* previous secret stops signing at once. Returns how many targets were overlapping. */
|
|
1740
|
+
readonly endSecretOverlap: (target: TargetSelector) => Promise<{
|
|
1741
|
+
readonly ended: number;
|
|
1707
1742
|
}>;
|
|
1708
1743
|
/** Re-pin a target's `payloadVersion` to the event's current
|
|
1709
1744
|
* version. Called from the dashboard's "Re-pin" action after
|
|
@@ -1805,6 +1840,13 @@ export declare const webhookTables: () => readonly [ Table<"_voltro_webhook_targ
|
|
|
1805
1840
|
* (a non-ciphertext value passes through); `voltro db encrypt-column
|
|
1806
1841
|
* _voltro_webhook_targets.secret` converts them in place. */
|
|
1807
1842
|
readonly secret: ColumnBuilder<string, "text", boolean>;
|
|
1843
|
+
/** During a rotation (`rotateSecret`): the secret the receiver may still
|
|
1844
|
+
* verify with. Every delivery until {@link previousSecretUntil} carries a
|
|
1845
|
+
* signature under it beside the new one (Standard Webhooks' signature list),
|
|
1846
|
+
* so the receiver switches when it is ready. Encrypted like `secret`. */
|
|
1847
|
+
readonly previousSecret: ColumnBuilder<string | null, "text", boolean>;
|
|
1848
|
+
/** When deliveries stop signing under `previousSecret`. */
|
|
1849
|
+
readonly previousSecretUntil: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
1808
1850
|
/** Serialised `SignatureScheme` discriminated union — see `signing.ts`.
|
|
1809
1851
|
* Stored as JSON so future schemes don't require a schema migration. */
|
|
1810
1852
|
readonly signing: ColumnBuilder<unknown, "json", boolean>;
|
|
@@ -1910,7 +1952,7 @@ export declare const webhookTables: () => readonly [ Table<"_voltro_webhook_targ
|
|
|
1910
1952
|
readonly eventId: ColumnBuilder<string | null, "text", boolean>;
|
|
1911
1953
|
/** Attempt counter (1-indexed). */
|
|
1912
1954
|
readonly attempt: ColumnBuilder<number, "integer", boolean>;
|
|
1913
|
-
readonly status: ColumnBuilder<"failed" | "
|
|
1955
|
+
readonly status: ColumnBuilder<"failed" | "succeeded" | "pending" | "inFlight" | "retryScheduled", "text", boolean>;
|
|
1914
1956
|
/** Payload as sent over the wire. Stored verbatim — re-rendering
|
|
1915
1957
|
* from a referenced event row would lose the snapshot if the
|
|
1916
1958
|
* source event was deleted. */
|
package/dist/index.js
CHANGED
|
@@ -5,13 +5,13 @@ import { STANDARD_WEBHOOKS_DEFAULT_TOLERANCE_SECONDS as c, STANDARD_WEBHOOKS_ID_
|
|
|
5
5
|
import { defaultOutgoingSignature as C, genericHmacSignature as w, githubSignature as T, signRequest as E, slackSignature as D, standardWebhooksSignature as O, stripeSignature as k, verifyRequest as A } from "./signing.js";
|
|
6
6
|
import { defaultRetryPolicy as j, fastRetryPolicy as M, nextRetry as N, parseDuration as P } from "./retry.js";
|
|
7
7
|
import { WebhookDeliveryNotFound as F, WebhookPayloadInvalid as I, WebhookPayloadUnrepresentable as L, WebhookPayloadVersionInvalid as R, WebhookSubscribeInvalid as z, WebhookTargetNotFound as B } from "./errors.js";
|
|
8
|
-
import {
|
|
9
|
-
import { IdempotencyCache as
|
|
10
|
-
import { UnverifiedIncomingWebhook as
|
|
11
|
-
import { RATE_WINDOW_MS as
|
|
12
|
-
import { encodePayload as
|
|
13
|
-
import { TARGETS_TABLE as
|
|
14
|
-
import { buildDeliverWebhookExecute as
|
|
15
|
-
import { _voltroWebhookDeliveriesTable as
|
|
16
|
-
import { WEBHOOK_EMIT_EFFECT as
|
|
17
|
-
export {
|
|
8
|
+
import { MAX_SECRET_OVERLAP_SECONDS as V, WebhooksService as H, buildWebhooksService as U, compareVersions as W, eventsOf as G, generateSecret as K, matchesFilter as q, resolveSubscribe as J, useWebhooks as Y, useWebhooksEffect as X, validateSubscribe as Z } from "./service.js";
|
|
9
|
+
import { IdempotencyCache as Q, getIdempotencyCache as $, parseTtl as ee } from "./idempotency.js";
|
|
10
|
+
import { UnverifiedIncomingWebhook as te, WEBHOOK_VERIFICATION_PROPERTY as ne, defaultIncomingPath as re, incomingWebhookVerification as ie, mountIncomingWebhook as ae } from "./incoming.js";
|
|
11
|
+
import { RATE_WINDOW_MS as oe, RATE_WINDOW_TABLE as se, acquireRateSlots as ce, consumeRateSlot as le, releaseRateSlot as ue } from "./rateLimit.js";
|
|
12
|
+
import { encodePayload as de } from "./encode.js";
|
|
13
|
+
import { TARGETS_TABLE as fe, recordDeliveryOutcome as pe } from "./autoDisable.js";
|
|
14
|
+
import { buildDeliverWebhookExecute as me, deliverWebhookWorkflow as he } from "./deliverWorkflow.js";
|
|
15
|
+
import { _voltroWebhookDeliveriesTable as ge, _voltroWebhookEventStatsTable as _e, _voltroWebhookRateWindowsTable as ve, _voltroWebhookTargetsTable as ye, webhookTables as be } from "./mixin.js";
|
|
16
|
+
import { WEBHOOK_EMIT_EFFECT as xe, makeDeferredEmitHandler as Se } from "./deferredEmit.js";
|
|
17
|
+
export { Q as IdempotencyCache, V as MAX_SECRET_OVERLAP_SECONDS, oe as RATE_WINDOW_MS, se as RATE_WINDOW_TABLE, c as STANDARD_WEBHOOKS_DEFAULT_TOLERANCE_SECONDS, l as STANDARD_WEBHOOKS_ID_HEADER, u as STANDARD_WEBHOOKS_MAX_KEY_BYTES, d as STANDARD_WEBHOOKS_MIN_KEY_BYTES, f as STANDARD_WEBHOOKS_SECRET_PREFIX, p as STANDARD_WEBHOOKS_SIGNATURE_HEADER, m as STANDARD_WEBHOOKS_TIMESTAMP_HEADER, h as STANDARD_WEBHOOKS_VERSION, fe as TARGETS_TABLE, te as UnverifiedIncomingWebhook, e as WEBHOOKS_EGRESS, t as WEBHOOKS_PLUGIN_PERMISSIONS, xe as WEBHOOK_EMIT_EFFECT, ne as WEBHOOK_VERIFICATION_PROPERTY, F as WebhookDeliveryNotFound, I as WebhookPayloadInvalid, L as WebhookPayloadUnrepresentable, R as WebhookPayloadVersionInvalid, z as WebhookSubscribeInvalid, B as WebhookTargetNotFound, H as WebhooksService, ge as _voltroWebhookDeliveriesTable, _e as _voltroWebhookEventStatsTable, ve as _voltroWebhookRateWindowsTable, ye as _voltroWebhookTargetsTable, ce as acquireRateSlots, o as asOutgoingEvent, me as buildDeliverWebhookExecute, U as buildWebhooksService, W as compareVersions, le as consumeRateSlot, re as defaultIncomingPath, C as defaultOutgoingSignature, j as defaultRetryPolicy, r as defineIncomingWebhook, i as defineWebhookProvider, he as deliverWebhookWorkflow, de as encodePayload, G as eventsOf, M as fastRetryPolicy, K as generateSecret, g as generateStandardWebhooksSecret, w as genericHmacSignature, $ as getIdempotencyCache, T as githubSignature, s as hasWebhookAudience, ie as incomingWebhookVerification, _ as isStandardWebhooksSecret, a as isWebhookDescriptor, Se as makeDeferredEmitHandler, q as matchesFilter, ae as mountIncomingWebhook, N as nextRetry, P as parseDuration, ee as parseTtl, pe as recordDeliveryOutcome, ue as releaseRateSlot, J as resolveSubscribe, E as signRequest, D as slackSignature, v as standardWebhooksHeaders, y as standardWebhooksKey, O as standardWebhooksSignature, b as standardWebhooksSignatureToken, x as standardWebhooksSignedContent, k as stripeSignature, Y as useWebhooks, X as useWebhooksEffect, Z as validateSubscribe, A as verifyRequest, S as verifyStandardWebhooks, be as webhookTables, n as webhooksPlugin };
|
package/dist/mixin.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export declare const _voltroWebhookDeliveriesTable: Table<"_voltro_webhook_deliv
|
|
|
32
32
|
readonly eventId: ColumnBuilder<string | null, "text", boolean>;
|
|
33
33
|
/** Attempt counter (1-indexed). */
|
|
34
34
|
readonly attempt: ColumnBuilder<number, "integer", boolean>;
|
|
35
|
-
readonly status: ColumnBuilder<"failed" | "
|
|
35
|
+
readonly status: ColumnBuilder<"failed" | "succeeded" | "pending" | "inFlight" | "retryScheduled", "text", boolean>;
|
|
36
36
|
/** Payload as sent over the wire. Stored verbatim — re-rendering
|
|
37
37
|
* from a referenced event row would lose the snapshot if the
|
|
38
38
|
* source event was deleted. */
|
|
@@ -171,6 +171,13 @@ export declare const _voltroWebhookTargetsTable: Table<"_voltro_webhook_targets"
|
|
|
171
171
|
* (a non-ciphertext value passes through); `voltro db encrypt-column
|
|
172
172
|
* _voltro_webhook_targets.secret` converts them in place. */
|
|
173
173
|
readonly secret: ColumnBuilder<string, "text", boolean>;
|
|
174
|
+
/** During a rotation (`rotateSecret`): the secret the receiver may still
|
|
175
|
+
* verify with. Every delivery until {@link previousSecretUntil} carries a
|
|
176
|
+
* signature under it beside the new one (Standard Webhooks' signature list),
|
|
177
|
+
* so the receiver switches when it is ready. Encrypted like `secret`. */
|
|
178
|
+
readonly previousSecret: ColumnBuilder<string | null, "text", boolean>;
|
|
179
|
+
/** When deliveries stop signing under `previousSecret`. */
|
|
180
|
+
readonly previousSecretUntil: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
174
181
|
/** Serialised `SignatureScheme` discriminated union — see `signing.ts`.
|
|
175
182
|
* Stored as JSON so future schemes don't require a schema migration. */
|
|
176
183
|
readonly signing: ColumnBuilder<unknown, "json", boolean>;
|
|
@@ -287,6 +294,13 @@ export declare const webhookTables: () => readonly [ Table<"_voltro_webhook_targ
|
|
|
287
294
|
* (a non-ciphertext value passes through); `voltro db encrypt-column
|
|
288
295
|
* _voltro_webhook_targets.secret` converts them in place. */
|
|
289
296
|
readonly secret: ColumnBuilder<string, "text", boolean>;
|
|
297
|
+
/** During a rotation (`rotateSecret`): the secret the receiver may still
|
|
298
|
+
* verify with. Every delivery until {@link previousSecretUntil} carries a
|
|
299
|
+
* signature under it beside the new one (Standard Webhooks' signature list),
|
|
300
|
+
* so the receiver switches when it is ready. Encrypted like `secret`. */
|
|
301
|
+
readonly previousSecret: ColumnBuilder<string | null, "text", boolean>;
|
|
302
|
+
/** When deliveries stop signing under `previousSecret`. */
|
|
303
|
+
readonly previousSecretUntil: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
290
304
|
/** Serialised `SignatureScheme` discriminated union — see `signing.ts`.
|
|
291
305
|
* Stored as JSON so future schemes don't require a schema migration. */
|
|
292
306
|
readonly signing: ColumnBuilder<unknown, "json", boolean>;
|
|
@@ -392,7 +406,7 @@ export declare const webhookTables: () => readonly [ Table<"_voltro_webhook_targ
|
|
|
392
406
|
readonly eventId: ColumnBuilder<string | null, "text", boolean>;
|
|
393
407
|
/** Attempt counter (1-indexed). */
|
|
394
408
|
readonly attempt: ColumnBuilder<number, "integer", boolean>;
|
|
395
|
-
readonly status: ColumnBuilder<"failed" | "
|
|
409
|
+
readonly status: ColumnBuilder<"failed" | "succeeded" | "pending" | "inFlight" | "retryScheduled", "text", boolean>;
|
|
396
410
|
/** Payload as sent over the wire. Stored verbatim — re-rendering
|
|
397
411
|
* from a referenced event row would lose the snapshot if the
|
|
398
412
|
* source event was deleted. */
|
package/dist/mixin.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { boolean as e, id as t, integer as n, json as r, registerRetention as i, retentionTtlMsFromEnv as a, table as o, text as s, timestamp as c } from "@voltro/database";
|
|
2
2
|
import { tenant as l } from "@voltro/plugin-multitenancy/mixin";
|
|
3
|
-
|
|
3
|
+
// src/mixin.ts
|
|
4
4
|
var u = o("_voltro_webhook_targets", {
|
|
5
5
|
id: t({ prefix: "whtarget" }),
|
|
6
6
|
event: s(),
|
|
7
7
|
url: s(),
|
|
8
8
|
secret: s().encrypted().serverOnly(),
|
|
9
|
+
previousSecret: s().encrypted().serverOnly().nullable(),
|
|
10
|
+
previousSecretUntil: c().nullable(),
|
|
9
11
|
signing: r(),
|
|
10
12
|
retry: r(),
|
|
11
13
|
scope: r().nullable(),
|
|
@@ -75,5 +77,4 @@ var u = o("_voltro_webhook_targets", {
|
|
|
75
77
|
f,
|
|
76
78
|
p
|
|
77
79
|
]);
|
|
78
|
-
//#endregion
|
|
79
80
|
export { d as _voltroWebhookDeliveriesTable, p as _voltroWebhookEventStatsTable, f as _voltroWebhookRateWindowsTable, u as _voltroWebhookTargetsTable, m as webhookTables };
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect as e } from "effect";
|
|
2
2
|
import { definePlugin as t } from "@voltro/protocol";
|
|
3
|
-
|
|
3
|
+
// src/plugin.ts
|
|
4
4
|
var n = ["network:outbound:*"], r = [{
|
|
5
5
|
destination: "runtime:registered webhook targets (_voltro_webhook_targets)",
|
|
6
6
|
purpose: "event deliveries, HMAC-signed",
|
|
@@ -15,5 +15,4 @@ var n = ["network:outbound:*"], r = [{
|
|
|
15
15
|
t.logger.info("webhooks active", { outbound: "network:outbound:* (subscriber-configured target URLs — audit visibility, not a restriction)" });
|
|
16
16
|
})
|
|
17
17
|
});
|
|
18
|
-
//#endregion
|
|
19
18
|
export { r as WEBHOOKS_EGRESS, n as WEBHOOKS_PLUGIN_PERMISSIONS, i as webhooksPlugin };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineWebhookProvider as e } from "../dsl.js";
|
|
2
2
|
import { genericHmacSignature as t } from "../signing.js";
|
|
3
|
-
|
|
3
|
+
// src/providers/generic.ts
|
|
4
4
|
var n = (n) => e({
|
|
5
5
|
id: "generic",
|
|
6
6
|
name: "Generic",
|
|
@@ -15,5 +15,4 @@ var n = (n) => e({
|
|
|
15
15
|
},
|
|
16
16
|
bodyType: "json"
|
|
17
17
|
});
|
|
18
|
-
//#endregion
|
|
19
18
|
export { n as genericProvider };
|
package/dist/providers/github.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineWebhookProvider as e } from "../dsl.js";
|
|
2
2
|
import { githubSignature as t } from "../signing.js";
|
|
3
|
-
|
|
3
|
+
// src/providers/github.ts
|
|
4
4
|
var n = () => e({
|
|
5
5
|
id: "github",
|
|
6
6
|
name: "GitHub",
|
|
@@ -12,5 +12,4 @@ var n = () => e({
|
|
|
12
12
|
bodyType: "json",
|
|
13
13
|
eventTypeFrom: (e) => {}
|
|
14
14
|
});
|
|
15
|
-
//#endregion
|
|
16
15
|
export { n as githubProvider };
|
package/dist/providers/slack.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineWebhookProvider as e } from "../dsl.js";
|
|
2
2
|
import { createHmac as t, timingSafeEqual as n } from "node:crypto";
|
|
3
|
-
|
|
3
|
+
// src/providers/slack.ts
|
|
4
4
|
var r = () => ({
|
|
5
5
|
_tag: "custom",
|
|
6
6
|
header: "X-Slack-Signature",
|
|
@@ -35,5 +35,4 @@ var r = () => ({
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
|
-
//#endregion
|
|
39
38
|
export { i as slackProvider };
|
package/dist/providers/stripe.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineWebhookProvider as e } from "../dsl.js";
|
|
2
2
|
import { stripeSignature as t } from "../signing.js";
|
|
3
|
-
|
|
3
|
+
// src/providers/stripe.ts
|
|
4
4
|
var n = (n) => e({
|
|
5
5
|
id: "stripe",
|
|
6
6
|
name: "Stripe",
|
|
@@ -26,5 +26,4 @@ var n = (n) => e({
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
-
//#endregion
|
|
30
29
|
export { n as stripeProvider };
|
package/dist/rateLimit.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { and as e, eq as t } from "@voltro/database";
|
|
2
|
-
|
|
2
|
+
// src/rateLimit.ts
|
|
3
3
|
var n = "_voltro_webhook_rate_windows", r = 6e4, i = (e, t) => `${e}@${t}`, a = async (n, r, i) => (await n.query({
|
|
4
4
|
table: "_voltro_webhook_rate_windows",
|
|
5
5
|
predicate: e(t("scope", r), t("bucket", i)),
|
|
@@ -57,5 +57,4 @@ var n = "_voltro_webhook_rate_windows", r = 6e4, i = (e, t) => `${e}@${t}`, a =
|
|
|
57
57
|
retryInMs: 0
|
|
58
58
|
};
|
|
59
59
|
};
|
|
60
|
-
//#endregion
|
|
61
60
|
export { r as RATE_WINDOW_MS, n as RATE_WINDOW_TABLE, l as acquireRateSlots, s as consumeRateSlot, c as releaseRateSlot };
|
package/dist/retry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/retry.ts
|
|
2
2
|
var e = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, t = (t) => {
|
|
3
3
|
let n = e.exec(t);
|
|
4
4
|
if (!n) throw Error(`invalid duration literal: ${t}`);
|
|
@@ -61,5 +61,4 @@ var e = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)?$/, t = (t) => {
|
|
|
61
61
|
honourRetryAfter: !0,
|
|
62
62
|
jitter: "full"
|
|
63
63
|
});
|
|
64
|
-
//#endregion
|
|
65
64
|
export { i as defaultRetryPolicy, a as fastRetryPolicy, r as nextRetry, t as parseDuration };
|