@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/WebhookTrigger.d.ts +100 -117
- package/dist/WebhookTrigger.js +315 -316
- package/dist/index.d.ts +36 -65
- package/dist/index.js +34 -71
- package/dist/verifiers.d.ts +80 -0
- package/dist/verifiers.js +294 -0
- package/package.json +6 -4
- package/src/WebhookTrigger.integration.test.ts +162 -0
- package/src/WebhookTrigger.test.ts +232 -143
- package/src/WebhookTrigger.ts +386 -407
- package/src/index.ts +41 -70
- package/src/verifiers.test.ts +316 -0
- package/src/verifiers.ts +357 -0
package/dist/WebhookTrigger.d.ts
CHANGED
|
@@ -1,129 +1,112 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WebhookTrigger
|
|
2
|
+
* WebhookTrigger — v0.7 PR 4 — Inbound webhook trigger that mounts
|
|
3
|
+
* verified POST routes on the shared Hono app. One route per workflow
|
|
4
|
+
* whose `trigger.webhook` config is registered.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
* - GitHub (push, pull_request, issues, etc.)
|
|
6
|
-
* - Stripe (payment_intent, checkout.session, etc.)
|
|
7
|
-
* - Shopify (orders, products, customers)
|
|
8
|
-
* - Custom webhooks
|
|
6
|
+
* **Authoring surface (built-in provider):**
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
getEventId(headers: Record<string, string>, body: unknown): string;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Workflow model with webhook trigger configuration
|
|
8
|
+
* ```json
|
|
9
|
+
* {
|
|
10
|
+
* "name": "stripe-events",
|
|
11
|
+
* "trigger": {
|
|
12
|
+
* "webhook": {
|
|
13
|
+
* "provider": "stripe",
|
|
14
|
+
* "path": "/webhooks/stripe",
|
|
15
|
+
* "secretEnv": "STRIPE_WEBHOOK_SECRET",
|
|
16
|
+
* "namespace": "stripe",
|
|
17
|
+
* "idempotencyKey": "js/ctx.request.body.id"
|
|
18
|
+
* }
|
|
19
|
+
* },
|
|
20
|
+
* "steps": [
|
|
21
|
+
* { "id": "dispatch", "subworkflow": "js/ctx.request.body.type", "inputs": { "stripeEvent": "js/ctx.request.body" } }
|
|
22
|
+
* ]
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* **Pipeline (per inbound request):**
|
|
27
|
+
*
|
|
28
|
+
* 1. Read raw body — verifiers MUST sign the bytes that crossed
|
|
29
|
+
* the wire, not the JSON-re-stringified body (Stripe / GitHub /
|
|
30
|
+
* Slack all sign raw bytes).
|
|
31
|
+
* 2. Verify the signature via the per-provider strategy
|
|
32
|
+
* (`verifiers.ts`). On failure, return 401 with structured
|
|
33
|
+
* `{ error, reason, message }`.
|
|
34
|
+
* 3. Replay check: if `idempotencyKey` is configured, look up
|
|
35
|
+
* `(workflowName, eventId)` in the idempotency cache (same store
|
|
36
|
+
* as Tier 1 step caching). On hit, return 200 with
|
|
37
|
+
* `{ status: "duplicate", eventId }` and DON'T run the workflow.
|
|
38
|
+
* 4. Events allowlist: if `events: [...]` is configured, skip
|
|
39
|
+
* workflow runs whose event type isn't in the list — return
|
|
40
|
+
* 200 with `{ status: "ignored", eventType }` so the sender
|
|
41
|
+
* doesn't retry.
|
|
42
|
+
* 5. Run the workflow through `TriggerBase.run` so middleware,
|
|
43
|
+
* tracing, retries, concurrency, etc. apply uniformly.
|
|
44
|
+
* 6. Cache the eventId so a retry within the TTL window returns
|
|
45
|
+
* the duplicate response.
|
|
46
|
+
*
|
|
47
|
+
* **Hono integration:** identical to WebSocket and SSE — accepts the
|
|
48
|
+
* shared `Hono<any, any, any>` app and an optional `HttpTriggerLike`
|
|
49
|
+
* exposing `addPreCatchAllHook` so webhook routes mount BEFORE the
|
|
50
|
+
* legacy `/:workflow{.+}` catch-all and win Hono's first-match
|
|
51
|
+
* dispatch.
|
|
52
|
+
*
|
|
53
|
+
* See [additional-triggers-plan.mdx](../../../docs/c/devtools/additional-triggers-plan.mdx#webhook-trigger)
|
|
54
|
+
* for the full v0.7 design.
|
|
61
55
|
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
56
|
+
import { DefaultLogger, type GlobalOptions as RunnerGlobalOptions, TriggerBase } from "@blokjs/runner";
|
|
57
|
+
import type { Hono } from "hono";
|
|
58
|
+
interface WebhookTriggerConfig {
|
|
59
|
+
provider?: "github" | "stripe" | "slack" | "shopify" | "svix";
|
|
60
|
+
path?: string;
|
|
61
|
+
events?: string[];
|
|
62
|
+
secretEnv?: string;
|
|
63
|
+
signature?: {
|
|
64
|
+
scheme?: "hmac-sha256" | "hmac-sha1" | "hmac-sha512";
|
|
65
|
+
header: string;
|
|
66
|
+
format?: string;
|
|
67
|
+
secretEnv: string;
|
|
68
|
+
tolerance?: number;
|
|
69
|
+
timestampHeader?: string;
|
|
72
70
|
};
|
|
71
|
+
tolerance?: number;
|
|
72
|
+
idempotencyKey?: string;
|
|
73
|
+
namespace?: string;
|
|
74
|
+
middleware?: string[];
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
* WebhookTrigger - Handle webhook events
|
|
80
|
-
*/
|
|
81
|
-
export declare abstract class WebhookTrigger extends TriggerBase {
|
|
82
|
-
protected nodeMap: GlobalOptions;
|
|
83
|
-
protected readonly tracer: import("@opentelemetry/api").Tracer;
|
|
76
|
+
interface HttpTriggerLike {
|
|
77
|
+
addPreCatchAllHook(cb: () => void | Promise<void>): void;
|
|
78
|
+
}
|
|
79
|
+
export default class WebhookTrigger extends TriggerBase {
|
|
80
|
+
protected nodeMap: RunnerGlobalOptions;
|
|
84
81
|
protected readonly logger: DefaultLogger;
|
|
85
|
-
protected
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
* Load workflows into the workflow map
|
|
95
|
-
*/
|
|
96
|
-
loadWorkflows(): void;
|
|
82
|
+
protected readonly tracer: import("@opentelemetry/api").Tracer;
|
|
83
|
+
private readonly meter;
|
|
84
|
+
private readonly counterReceived;
|
|
85
|
+
private readonly counterRejected;
|
|
86
|
+
private readonly counterAccepted;
|
|
87
|
+
private readonly app;
|
|
88
|
+
private readonly httpTrigger;
|
|
89
|
+
private wired;
|
|
90
|
+
constructor(app: Hono<any, any, any>, httpTrigger?: HttpTriggerLike);
|
|
97
91
|
/**
|
|
98
|
-
*
|
|
92
|
+
* Inject the runner's GlobalOptions (nodes + workflows). Called by
|
|
93
|
+
* the orchestrator AFTER constructing the trigger but BEFORE
|
|
94
|
+
* `listen()`. Shares HttpTrigger's nodeMap so per-request workflow
|
|
95
|
+
* runs resolve helpers + sub-workflows through the same registry.
|
|
99
96
|
*/
|
|
97
|
+
setNodeMap(nodeMap: RunnerGlobalOptions): void;
|
|
100
98
|
listen(): Promise<number>;
|
|
101
|
-
/**
|
|
102
|
-
* Stop the webhook trigger
|
|
103
|
-
*/
|
|
104
99
|
stop(): Promise<void>;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
protected getWebhookWorkflows(): WebhookWorkflowModel[];
|
|
115
|
-
/**
|
|
116
|
-
* Find workflow matching the webhook event
|
|
117
|
-
*/
|
|
118
|
-
protected findMatchingWorkflow(event: WebhookEvent): WebhookWorkflowModel | null;
|
|
119
|
-
/**
|
|
120
|
-
* Execute a workflow for a webhook event
|
|
121
|
-
*/
|
|
122
|
-
protected executeWorkflow(event: WebhookEvent, workflow: WebhookWorkflowModel, _config: WebhookTriggerOpts): Promise<TriggerResponse>;
|
|
123
|
-
/**
|
|
124
|
-
* Register a custom source handler
|
|
125
|
-
*/
|
|
126
|
-
static registerSourceHandler(source: string, handler: WebhookSourceHandler): void;
|
|
100
|
+
private registerRoutesFromRegistry;
|
|
101
|
+
private registerWebhookRoute;
|
|
102
|
+
private handleRequest;
|
|
103
|
+
private resolveVerifier;
|
|
104
|
+
private dispatchWorkflow;
|
|
105
|
+
getStats(): {
|
|
106
|
+
workflowsRegistered: number;
|
|
107
|
+
};
|
|
108
|
+
private getWebhookWorkflows;
|
|
127
109
|
}
|
|
128
|
-
export
|
|
129
|
-
export
|
|
110
|
+
export declare function _setActiveWebhookTrigger(trigger: WebhookTrigger | null): void;
|
|
111
|
+
export declare function _getActiveWebhookTrigger(): WebhookTrigger | null;
|
|
112
|
+
export type { WebhookTriggerConfig };
|