@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.
@@ -1,129 +1,112 @@
1
1
  /**
2
- * WebhookTrigger - Handle webhook events from external services
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
- * Extends TriggerBase to process webhook events from:
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
- * Features:
11
- * - Signature verification for security
12
- * - Event type filtering
13
- * - Retry support
14
- * - Dead letter handling
15
- */
16
- import type { HelperResponse, WebhookTriggerOpts } from "@blok/helper";
17
- import { DefaultLogger, type GlobalOptions, type BlokService, TriggerBase, type TriggerResponse } from "@blok/runner";
18
- /**
19
- * Webhook event structure
20
- */
21
- export interface WebhookEvent {
22
- /** Unique event ID */
23
- id: string;
24
- /** Source service (github, stripe, shopify, custom) */
25
- source: string;
26
- /** Event type (e.g., push, payment_intent.succeeded) */
27
- eventType: string;
28
- /** Event payload */
29
- payload: unknown;
30
- /** Request headers */
31
- headers: Record<string, string>;
32
- /** Signature (if provided) */
33
- signature?: string;
34
- /** Timestamp */
35
- timestamp: Date;
36
- /** Raw request body */
37
- rawBody: string;
38
- }
39
- /**
40
- * Signature verification result
41
- */
42
- export interface VerificationResult {
43
- valid: boolean;
44
- error?: string;
45
- }
46
- /**
47
- * Webhook source handlers
48
- */
49
- export interface WebhookSourceHandler {
50
- /** Extract event type from request */
51
- getEventType(headers: Record<string, string>, body: unknown): string;
52
- /** Get signature from request */
53
- getSignature(headers: Record<string, string>): string | undefined;
54
- /** Verify signature */
55
- verifySignature(rawBody: string, signature: string, secret: string): VerificationResult;
56
- /** Get event ID */
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
- interface WebhookWorkflowModel {
63
- path: string;
64
- config: {
65
- name: string;
66
- version: string;
67
- trigger?: {
68
- webhook?: WebhookTriggerOpts;
69
- [key: string]: unknown;
70
- };
71
- [key: string]: unknown;
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
- * Built-in source handlers
76
- */
77
- declare const sourceHandlers: Record<string, WebhookSourceHandler>;
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 webhookWorkflows: WebhookWorkflowModel[];
86
- protected abstract nodes: Record<string, BlokService<unknown>>;
87
- protected abstract workflows: Record<string, HelperResponse>;
88
- constructor();
89
- /**
90
- * Load nodes into the node map
91
- */
92
- loadNodes(): void;
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
- * Initialize webhook trigger (call after loading workflows)
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
- protected onHmrWorkflowChange(): Promise<void>;
106
- /**
107
- * Process an incoming webhook request
108
- * Call this from your HTTP endpoint handler
109
- */
110
- handleWebhook(source: string, rawBody: string, headers: Record<string, string>): Promise<TriggerResponse | null>;
111
- /**
112
- * Get all workflows that have webhook triggers
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 default WebhookTrigger;
129
- export { sourceHandlers };
110
+ export declare function _setActiveWebhookTrigger(trigger: WebhookTrigger | null): void;
111
+ export declare function _getActiveWebhookTrigger(): WebhookTrigger | null;
112
+ export type { WebhookTriggerConfig };