@blokjs/trigger-webhook 0.2.1 → 0.6.2

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.d.ts CHANGED
@@ -1,70 +1,41 @@
1
1
  /**
2
- * @blok/trigger-webhook
3
- *
4
- * Webhook trigger for Blok workflows.
5
- * Handle webhook events from external services.
6
- *
7
- * Supported Services:
8
- * - GitHub (push, pull_request, issues, releases, etc.)
9
- * - Stripe (payment_intent, checkout.session, customer, etc.)
10
- * - Shopify (orders, products, customers, etc.)
11
- * - Custom webhooks (any service with signature verification)
12
- *
13
- * Features:
14
- * - Signature verification (HMAC-SHA256)
15
- * - Event type filtering
16
- * - Source-specific handlers
17
- * - Custom source registration
18
- *
19
- * @example
20
- * ```typescript
21
- * import { WebhookTrigger } from "@blok/trigger-webhook";
22
- *
23
- * class MyWebhookTrigger extends WebhookTrigger {
24
- * protected nodes = myNodes;
25
- * protected workflows = myWorkflows;
2
+ * @blokjs/trigger-webhook
3
+ *
4
+ * Inbound webhook trigger for Blok workflows. Mounts verified POST
5
+ * routes on the shared Hono server alongside HTTP, WebSocket, and
6
+ * SSE routes — same port, same middleware chain, same Studio
7
+ * tracing. Verifies provider signatures (GitHub, Stripe, Slack,
8
+ * Shopify, Svix/Standard Webhooks) or a custom HMAC scheme, applies
9
+ * replay protection via the idempotency cache, and dispatches the
10
+ * workflow.
11
+ *
12
+ * v0.7+ usage (just add the trigger to your workflow):
13
+ *
14
+ * ```json
15
+ * {
16
+ * "name": "stripe-events",
17
+ * "trigger": {
18
+ * "webhook": {
19
+ * "provider": "stripe",
20
+ * "path": "/webhooks/stripe",
21
+ * "secretEnv": "STRIPE_WEBHOOK_SECRET",
22
+ * "namespace": "stripe",
23
+ * "idempotencyKey": "js/ctx.request.body.id"
24
+ * }
25
+ * },
26
+ * "steps": [
27
+ * { "id": "dispatch", "subworkflow": "js/ctx.request.body.type", "inputs": { "stripeEvent": "js/ctx.request.body" } }
28
+ * ]
26
29
  * }
27
- *
28
- * const trigger = new MyWebhookTrigger();
29
- * await trigger.listen();
30
- *
31
- * // In your HTTP endpoint handler:
32
- * app.post("/webhooks/:source", async (req, res) => {
33
- * const rawBody = JSON.stringify(req.body);
34
- * const result = await trigger.handleWebhook(
35
- * req.params.source,
36
- * rawBody,
37
- * req.headers as Record<string, string>
38
- * );
39
- * res.status(200).json({ received: true });
40
- * });
41
- * ```
42
- *
43
- * Workflow Definition:
44
- * ```typescript
45
- * Workflow({ name: "github-push", version: "1.0.0" })
46
- * .addTrigger("webhook", {
47
- * source: "github",
48
- * events: ["push", "pull_request.*"],
49
- * secret: process.env.GITHUB_WEBHOOK_SECRET,
50
- * })
51
- * .addStep({ ... });
52
30
  * ```
53
31
  *
54
- * Custom Source Handler:
55
- * ```typescript
56
- * import { WebhookTrigger } from "@blok/trigger-webhook";
57
- *
58
- * WebhookTrigger.registerSourceHandler("my-service", {
59
- * getEventType: (headers, body) => body.event_type,
60
- * getSignature: (headers) => headers["x-my-signature"],
61
- * verifySignature: (rawBody, signature, secret) => {
62
- * // Your verification logic
63
- * return { valid: true };
64
- * },
65
- * getEventId: (headers, body) => body.id,
66
- * });
67
- * ```
32
+ * See [additional-triggers-plan.mdx](../../../docs/c/devtools/additional-triggers-plan.mdx#webhook-trigger)
33
+ * for the full design.
68
34
  */
69
- export { WebhookTrigger, sourceHandlers, type WebhookEvent, type VerificationResult, type WebhookSourceHandler, } from "./WebhookTrigger";
70
- export type { WebhookTriggerOpts } from "@blok/helper";
35
+ import WebhookTrigger, { _getActiveWebhookTrigger, _setActiveWebhookTrigger } from "./WebhookTrigger";
36
+ export default WebhookTrigger;
37
+ export { WebhookTrigger, _getActiveWebhookTrigger, _setActiveWebhookTrigger };
38
+ export type { WebhookTriggerConfig } from "./WebhookTrigger";
39
+ export type { WebhookTriggerOpts } from "@blokjs/helper";
40
+ export { BUILTIN_VERIFIERS, buildCustomVerifier, githubVerifier, shopifyVerifier, slackVerifier, stripeVerifier, svixVerifier, } from "./verifiers";
41
+ export type { CustomSignatureConfig, VerifyError, VerifyInput, VerifyOk, VerifyResult, Verifier } from "./verifiers";
package/dist/index.js CHANGED
@@ -1,76 +1,39 @@
1
- "use strict";
2
1
  /**
3
- * @blok/trigger-webhook
4
- *
5
- * Webhook trigger for Blok workflows.
6
- * Handle webhook events from external services.
7
- *
8
- * Supported Services:
9
- * - GitHub (push, pull_request, issues, releases, etc.)
10
- * - Stripe (payment_intent, checkout.session, customer, etc.)
11
- * - Shopify (orders, products, customers, etc.)
12
- * - Custom webhooks (any service with signature verification)
13
- *
14
- * Features:
15
- * - Signature verification (HMAC-SHA256)
16
- * - Event type filtering
17
- * - Source-specific handlers
18
- * - Custom source registration
19
- *
20
- * @example
21
- * ```typescript
22
- * import { WebhookTrigger } from "@blok/trigger-webhook";
23
- *
24
- * class MyWebhookTrigger extends WebhookTrigger {
25
- * protected nodes = myNodes;
26
- * protected workflows = myWorkflows;
2
+ * @blokjs/trigger-webhook
3
+ *
4
+ * Inbound webhook trigger for Blok workflows. Mounts verified POST
5
+ * routes on the shared Hono server alongside HTTP, WebSocket, and
6
+ * SSE routes — same port, same middleware chain, same Studio
7
+ * tracing. Verifies provider signatures (GitHub, Stripe, Slack,
8
+ * Shopify, Svix/Standard Webhooks) or a custom HMAC scheme, applies
9
+ * replay protection via the idempotency cache, and dispatches the
10
+ * workflow.
11
+ *
12
+ * v0.7+ usage (just add the trigger to your workflow):
13
+ *
14
+ * ```json
15
+ * {
16
+ * "name": "stripe-events",
17
+ * "trigger": {
18
+ * "webhook": {
19
+ * "provider": "stripe",
20
+ * "path": "/webhooks/stripe",
21
+ * "secretEnv": "STRIPE_WEBHOOK_SECRET",
22
+ * "namespace": "stripe",
23
+ * "idempotencyKey": "js/ctx.request.body.id"
24
+ * }
25
+ * },
26
+ * "steps": [
27
+ * { "id": "dispatch", "subworkflow": "js/ctx.request.body.type", "inputs": { "stripeEvent": "js/ctx.request.body" } }
28
+ * ]
27
29
  * }
28
- *
29
- * const trigger = new MyWebhookTrigger();
30
- * await trigger.listen();
31
- *
32
- * // In your HTTP endpoint handler:
33
- * app.post("/webhooks/:source", async (req, res) => {
34
- * const rawBody = JSON.stringify(req.body);
35
- * const result = await trigger.handleWebhook(
36
- * req.params.source,
37
- * rawBody,
38
- * req.headers as Record<string, string>
39
- * );
40
- * res.status(200).json({ received: true });
41
- * });
42
- * ```
43
- *
44
- * Workflow Definition:
45
- * ```typescript
46
- * Workflow({ name: "github-push", version: "1.0.0" })
47
- * .addTrigger("webhook", {
48
- * source: "github",
49
- * events: ["push", "pull_request.*"],
50
- * secret: process.env.GITHUB_WEBHOOK_SECRET,
51
- * })
52
- * .addStep({ ... });
53
30
  * ```
54
31
  *
55
- * Custom Source Handler:
56
- * ```typescript
57
- * import { WebhookTrigger } from "@blok/trigger-webhook";
58
- *
59
- * WebhookTrigger.registerSourceHandler("my-service", {
60
- * getEventType: (headers, body) => body.event_type,
61
- * getSignature: (headers) => headers["x-my-signature"],
62
- * verifySignature: (rawBody, signature, secret) => {
63
- * // Your verification logic
64
- * return { valid: true };
65
- * },
66
- * getEventId: (headers, body) => body.id,
67
- * });
68
- * ```
32
+ * See [additional-triggers-plan.mdx](../../../docs/c/devtools/additional-triggers-plan.mdx#webhook-trigger)
33
+ * for the full design.
69
34
  */
70
- Object.defineProperty(exports, "__esModule", { value: true });
71
- exports.sourceHandlers = exports.WebhookTrigger = void 0;
72
- // Core exports
73
- var WebhookTrigger_1 = require("./WebhookTrigger");
74
- Object.defineProperty(exports, "WebhookTrigger", { enumerable: true, get: function () { return WebhookTrigger_1.WebhookTrigger; } });
75
- Object.defineProperty(exports, "sourceHandlers", { enumerable: true, get: function () { return WebhookTrigger_1.sourceHandlers; } });
76
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUVHOzs7QUFFSCxlQUFlO0FBQ2YsbURBTTBCO0FBTHpCLGdIQUFBLGNBQWMsT0FBQTtBQUNkLGdIQUFBLGNBQWMsT0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGJsb2svdHJpZ2dlci13ZWJob29rXG4gKlxuICogV2ViaG9vayB0cmlnZ2VyIGZvciBCbG9rIHdvcmtmbG93cy5cbiAqIEhhbmRsZSB3ZWJob29rIGV2ZW50cyBmcm9tIGV4dGVybmFsIHNlcnZpY2VzLlxuICpcbiAqIFN1cHBvcnRlZCBTZXJ2aWNlczpcbiAqIC0gR2l0SHViIChwdXNoLCBwdWxsX3JlcXVlc3QsIGlzc3VlcywgcmVsZWFzZXMsIGV0Yy4pXG4gKiAtIFN0cmlwZSAocGF5bWVudF9pbnRlbnQsIGNoZWNrb3V0LnNlc3Npb24sIGN1c3RvbWVyLCBldGMuKVxuICogLSBTaG9waWZ5IChvcmRlcnMsIHByb2R1Y3RzLCBjdXN0b21lcnMsIGV0Yy4pXG4gKiAtIEN1c3RvbSB3ZWJob29rcyAoYW55IHNlcnZpY2Ugd2l0aCBzaWduYXR1cmUgdmVyaWZpY2F0aW9uKVxuICpcbiAqIEZlYXR1cmVzOlxuICogLSBTaWduYXR1cmUgdmVyaWZpY2F0aW9uIChITUFDLVNIQTI1NilcbiAqIC0gRXZlbnQgdHlwZSBmaWx0ZXJpbmdcbiAqIC0gU291cmNlLXNwZWNpZmljIGhhbmRsZXJzXG4gKiAtIEN1c3RvbSBzb3VyY2UgcmVnaXN0cmF0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IFdlYmhvb2tUcmlnZ2VyIH0gZnJvbSBcIkBibG9rL3RyaWdnZXItd2ViaG9va1wiO1xuICpcbiAqIGNsYXNzIE15V2ViaG9va1RyaWdnZXIgZXh0ZW5kcyBXZWJob29rVHJpZ2dlciB7XG4gKiAgIHByb3RlY3RlZCBub2RlcyA9IG15Tm9kZXM7XG4gKiAgIHByb3RlY3RlZCB3b3JrZmxvd3MgPSBteVdvcmtmbG93cztcbiAqIH1cbiAqXG4gKiBjb25zdCB0cmlnZ2VyID0gbmV3IE15V2ViaG9va1RyaWdnZXIoKTtcbiAqIGF3YWl0IHRyaWdnZXIubGlzdGVuKCk7XG4gKlxuICogLy8gSW4geW91ciBIVFRQIGVuZHBvaW50IGhhbmRsZXI6XG4gKiBhcHAucG9zdChcIi93ZWJob29rcy86c291cmNlXCIsIGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICogICBjb25zdCByYXdCb2R5ID0gSlNPTi5zdHJpbmdpZnkocmVxLmJvZHkpO1xuICogICBjb25zdCByZXN1bHQgPSBhd2FpdCB0cmlnZ2VyLmhhbmRsZVdlYmhvb2soXG4gKiAgICAgcmVxLnBhcmFtcy5zb3VyY2UsXG4gKiAgICAgcmF3Qm9keSxcbiAqICAgICByZXEuaGVhZGVycyBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+XG4gKiAgICk7XG4gKiAgIHJlcy5zdGF0dXMoMjAwKS5qc29uKHsgcmVjZWl2ZWQ6IHRydWUgfSk7XG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIFdvcmtmbG93IERlZmluaXRpb246XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBXb3JrZmxvdyh7IG5hbWU6IFwiZ2l0aHViLXB1c2hcIiwgdmVyc2lvbjogXCIxLjAuMFwiIH0pXG4gKiAgIC5hZGRUcmlnZ2VyKFwid2ViaG9va1wiLCB7XG4gKiAgICAgc291cmNlOiBcImdpdGh1YlwiLFxuICogICAgIGV2ZW50czogW1wicHVzaFwiLCBcInB1bGxfcmVxdWVzdC4qXCJdLFxuICogICAgIHNlY3JldDogcHJvY2Vzcy5lbnYuR0lUSFVCX1dFQkhPT0tfU0VDUkVULFxuICogICB9KVxuICogICAuYWRkU3RlcCh7IC4uLiB9KTtcbiAqIGBgYFxuICpcbiAqIEN1c3RvbSBTb3VyY2UgSGFuZGxlcjpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IFdlYmhvb2tUcmlnZ2VyIH0gZnJvbSBcIkBibG9rL3RyaWdnZXItd2ViaG9va1wiO1xuICpcbiAqIFdlYmhvb2tUcmlnZ2VyLnJlZ2lzdGVyU291cmNlSGFuZGxlcihcIm15LXNlcnZpY2VcIiwge1xuICogICBnZXRFdmVudFR5cGU6IChoZWFkZXJzLCBib2R5KSA9PiBib2R5LmV2ZW50X3R5cGUsXG4gKiAgIGdldFNpZ25hdHVyZTogKGhlYWRlcnMpID0+IGhlYWRlcnNbXCJ4LW15LXNpZ25hdHVyZVwiXSxcbiAqICAgdmVyaWZ5U2lnbmF0dXJlOiAocmF3Qm9keSwgc2lnbmF0dXJlLCBzZWNyZXQpID0+IHtcbiAqICAgICAvLyBZb3VyIHZlcmlmaWNhdGlvbiBsb2dpY1xuICogICAgIHJldHVybiB7IHZhbGlkOiB0cnVlIH07XG4gKiAgIH0sXG4gKiAgIGdldEV2ZW50SWQ6IChoZWFkZXJzLCBib2R5KSA9PiBib2R5LmlkLFxuICogfSk7XG4gKiBgYGBcbiAqL1xuXG4vLyBDb3JlIGV4cG9ydHNcbmV4cG9ydCB7XG5cdFdlYmhvb2tUcmlnZ2VyLFxuXHRzb3VyY2VIYW5kbGVycyxcblx0dHlwZSBXZWJob29rRXZlbnQsXG5cdHR5cGUgVmVyaWZpY2F0aW9uUmVzdWx0LFxuXHR0eXBlIFdlYmhvb2tTb3VyY2VIYW5kbGVyLFxufSBmcm9tIFwiLi9XZWJob29rVHJpZ2dlclwiO1xuXG4vLyBSZS1leHBvcnQgdHlwZXMgZnJvbSBoZWxwZXIgZm9yIGNvbnZlbmllbmNlXG5leHBvcnQgdHlwZSB7IFdlYmhvb2tUcmlnZ2VyT3B0cyB9IGZyb20gXCJAYmxvay9oZWxwZXJcIjtcbiJdfQ==
35
+ import WebhookTrigger, { _getActiveWebhookTrigger, _setActiveWebhookTrigger } from "./WebhookTrigger";
36
+ export default WebhookTrigger;
37
+ export { WebhookTrigger, _getActiveWebhookTrigger, _setActiveWebhookTrigger };
38
+ export { BUILTIN_VERIFIERS, buildCustomVerifier, githubVerifier, shopifyVerifier, slackVerifier, stripeVerifier, svixVerifier, } from "./verifiers";
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWlDRztBQUVILE9BQU8sY0FBYyxFQUFFLEVBQUUsd0JBQXdCLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUV0RyxlQUFlLGNBQWMsQ0FBQztBQUM5QixPQUFPLEVBQUUsY0FBYyxFQUFFLHdCQUF3QixFQUFFLHdCQUF3QixFQUFFLENBQUM7QUFHOUUsT0FBTyxFQUNOLGlCQUFpQixFQUNqQixtQkFBbUIsRUFDbkIsY0FBYyxFQUNkLGVBQWUsRUFDZixhQUFhLEVBQ2IsY0FBYyxFQUNkLFlBQVksR0FDWixNQUFNLGFBQWEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGJsb2tqcy90cmlnZ2VyLXdlYmhvb2tcbiAqXG4gKiBJbmJvdW5kIHdlYmhvb2sgdHJpZ2dlciBmb3IgQmxvayB3b3JrZmxvd3MuIE1vdW50cyB2ZXJpZmllZCBQT1NUXG4gKiByb3V0ZXMgb24gdGhlIHNoYXJlZCBIb25vIHNlcnZlciBhbG9uZ3NpZGUgSFRUUCwgV2ViU29ja2V0LCBhbmRcbiAqIFNTRSByb3V0ZXMg4oCUIHNhbWUgcG9ydCwgc2FtZSBtaWRkbGV3YXJlIGNoYWluLCBzYW1lIFN0dWRpb1xuICogdHJhY2luZy4gVmVyaWZpZXMgcHJvdmlkZXIgc2lnbmF0dXJlcyAoR2l0SHViLCBTdHJpcGUsIFNsYWNrLFxuICogU2hvcGlmeSwgU3ZpeC9TdGFuZGFyZCBXZWJob29rcykgb3IgYSBjdXN0b20gSE1BQyBzY2hlbWUsIGFwcGxpZXNcbiAqIHJlcGxheSBwcm90ZWN0aW9uIHZpYSB0aGUgaWRlbXBvdGVuY3kgY2FjaGUsIGFuZCBkaXNwYXRjaGVzIHRoZVxuICogd29ya2Zsb3cuXG4gKlxuICogdjAuNysgdXNhZ2UgKGp1c3QgYWRkIHRoZSB0cmlnZ2VyIHRvIHlvdXIgd29ya2Zsb3cpOlxuICpcbiAqIGBgYGpzb25cbiAqIHtcbiAqICAgXCJuYW1lXCI6IFwic3RyaXBlLWV2ZW50c1wiLFxuICogICBcInRyaWdnZXJcIjoge1xuICogICAgIFwid2ViaG9va1wiOiB7XG4gKiAgICAgICBcInByb3ZpZGVyXCI6IFwic3RyaXBlXCIsXG4gKiAgICAgICBcInBhdGhcIjogXCIvd2ViaG9va3Mvc3RyaXBlXCIsXG4gKiAgICAgICBcInNlY3JldEVudlwiOiBcIlNUUklQRV9XRUJIT09LX1NFQ1JFVFwiLFxuICogICAgICAgXCJuYW1lc3BhY2VcIjogXCJzdHJpcGVcIixcbiAqICAgICAgIFwiaWRlbXBvdGVuY3lLZXlcIjogXCJqcy9jdHgucmVxdWVzdC5ib2R5LmlkXCJcbiAqICAgICB9XG4gKiAgIH0sXG4gKiAgIFwic3RlcHNcIjogW1xuICogICAgIHsgXCJpZFwiOiBcImRpc3BhdGNoXCIsIFwic3Vid29ya2Zsb3dcIjogXCJqcy9jdHgucmVxdWVzdC5ib2R5LnR5cGVcIiwgXCJpbnB1dHNcIjogeyBcInN0cmlwZUV2ZW50XCI6IFwianMvY3R4LnJlcXVlc3QuYm9keVwiIH0gfVxuICogICBdXG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBTZWUgW2FkZGl0aW9uYWwtdHJpZ2dlcnMtcGxhbi5tZHhdKC4uLy4uLy4uL2RvY3MvYy9kZXZ0b29scy9hZGRpdGlvbmFsLXRyaWdnZXJzLXBsYW4ubWR4I3dlYmhvb2stdHJpZ2dlcilcbiAqIGZvciB0aGUgZnVsbCBkZXNpZ24uXG4gKi9cblxuaW1wb3J0IFdlYmhvb2tUcmlnZ2VyLCB7IF9nZXRBY3RpdmVXZWJob29rVHJpZ2dlciwgX3NldEFjdGl2ZVdlYmhvb2tUcmlnZ2VyIH0gZnJvbSBcIi4vV2ViaG9va1RyaWdnZXJcIjtcblxuZXhwb3J0IGRlZmF1bHQgV2ViaG9va1RyaWdnZXI7XG5leHBvcnQgeyBXZWJob29rVHJpZ2dlciwgX2dldEFjdGl2ZVdlYmhvb2tUcmlnZ2VyLCBfc2V0QWN0aXZlV2ViaG9va1RyaWdnZXIgfTtcbmV4cG9ydCB0eXBlIHsgV2ViaG9va1RyaWdnZXJDb25maWcgfSBmcm9tIFwiLi9XZWJob29rVHJpZ2dlclwiO1xuZXhwb3J0IHR5cGUgeyBXZWJob29rVHJpZ2dlck9wdHMgfSBmcm9tIFwiQGJsb2tqcy9oZWxwZXJcIjtcbmV4cG9ydCB7XG5cdEJVSUxUSU5fVkVSSUZJRVJTLFxuXHRidWlsZEN1c3RvbVZlcmlmaWVyLFxuXHRnaXRodWJWZXJpZmllcixcblx0c2hvcGlmeVZlcmlmaWVyLFxuXHRzbGFja1ZlcmlmaWVyLFxuXHRzdHJpcGVWZXJpZmllcixcblx0c3ZpeFZlcmlmaWVyLFxufSBmcm9tIFwiLi92ZXJpZmllcnNcIjtcbmV4cG9ydCB0eXBlIHsgQ3VzdG9tU2lnbmF0dXJlQ29uZmlnLCBWZXJpZnlFcnJvciwgVmVyaWZ5SW5wdXQsIFZlcmlmeU9rLCBWZXJpZnlSZXN1bHQsIFZlcmlmaWVyIH0gZnJvbSBcIi4vdmVyaWZpZXJzXCI7XG4iXX0=
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Webhook signature verifiers — one strategy per supported provider.
3
+ *
4
+ * Each verifier reads the raw request bytes (NOT the JSON-parsed body)
5
+ * and the provider-specific signature header, computes the expected
6
+ * HMAC against a shared secret, and constant-time compares. On match,
7
+ * returns `{ ok: true, eventId, eventType }`. On mismatch / missing
8
+ * header / drift, returns `{ ok: false, reason, message }`.
9
+ *
10
+ * Constant-time comparison via `crypto.timingSafeEqual` is mandatory —
11
+ * a naive `===` compare leaks the expected HMAC byte by byte through
12
+ * timing variance and a network-adjacent attacker can recover the
13
+ * secret in ~256 requests per byte.
14
+ *
15
+ * Built-in providers + their signature shapes:
16
+ *
17
+ * - **github**: `X-Hub-Signature-256: sha256=<hex>` over rawBody.
18
+ * Event id from `X-GitHub-Delivery`; event type
19
+ * from `X-GitHub-Event` header.
20
+ * - **stripe**: `Stripe-Signature: t=<ts>,v1=<hex>` over
21
+ * `<ts>.<rawBody>` with a 5-minute drift window.
22
+ * Event id + type from body.id / body.type.
23
+ * - **slack**: `X-Slack-Signature: v0=<hex>` over
24
+ * `v0:<X-Slack-Request-Timestamp>:<rawBody>` with a
25
+ * 5-minute drift window. Event type from
26
+ * body.event.type; event id from body.event_id.
27
+ * - **shopify**: `X-Shopify-Hmac-Sha256: <base64>` over rawBody.
28
+ * Event type from `X-Shopify-Topic`; event id from
29
+ * `X-Shopify-Webhook-Id`.
30
+ * - **svix**: Standard Webhooks. `webhook-signature:
31
+ * v1,<base64>` over `<webhook-id>.<webhook-timestamp>.<rawBody>`
32
+ * with a 5-minute drift window. Event id from
33
+ * `webhook-id`; event type from body.type.
34
+ *
35
+ * Custom (unknown provider) verifier is built dynamically by
36
+ * `buildCustomVerifier()` from the workflow's `signature` config.
37
+ */
38
+ /** Successful verification result — workflow may proceed. */
39
+ export interface VerifyOk {
40
+ ok: true;
41
+ /** Provider-specific event id (used for replay-protection cache key). */
42
+ eventId: string;
43
+ /** Provider-specific event type (used for the allowlist check). */
44
+ eventType: string;
45
+ }
46
+ /** Verification failure — trigger returns 401 with structured reason. */
47
+ export interface VerifyError {
48
+ ok: false;
49
+ /** Stable discriminator — log/alert dashboards branch on this. */
50
+ reason: "missing_signature" | "missing_timestamp" | "missing_secret" | "bad_format" | "timestamp_drift" | "signature_mismatch";
51
+ /** Human-readable error message. Safe to surface to the sender. */
52
+ message: string;
53
+ }
54
+ export type VerifyResult = VerifyOk | VerifyError;
55
+ /** Inputs every verifier receives. */
56
+ export interface VerifyInput {
57
+ headers: Record<string, string>;
58
+ rawBody: string;
59
+ parsedBody: unknown;
60
+ secret: string;
61
+ toleranceSec: number;
62
+ }
63
+ export interface Verifier {
64
+ verify(input: VerifyInput): VerifyResult;
65
+ }
66
+ export declare const githubVerifier: Verifier;
67
+ export declare const stripeVerifier: Verifier;
68
+ export declare const slackVerifier: Verifier;
69
+ export declare const shopifyVerifier: Verifier;
70
+ export declare const svixVerifier: Verifier;
71
+ export interface CustomSignatureConfig {
72
+ scheme: "hmac-sha256" | "hmac-sha1" | "hmac-sha512";
73
+ header: string;
74
+ format: string;
75
+ secretEnv: string;
76
+ tolerance: number;
77
+ timestampHeader?: string;
78
+ }
79
+ export declare function buildCustomVerifier(config: CustomSignatureConfig): Verifier;
80
+ export declare const BUILTIN_VERIFIERS: Record<string, Verifier>;