@blokjs/trigger-webhook 0.2.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 ADDED
@@ -0,0 +1,22 @@
1
+ # @blokjs/trigger-webhook
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial public release of Blok packages.
8
+
9
+ This release includes:
10
+
11
+ - Core packages: @blokjs/shared, @blokjs/helper, @blokjs/runner
12
+ - Node packages: @blokjs/api-call, @blokjs/if-else, @blokjs/react
13
+ - Trigger packages: pubsub, queue, webhook, websocket, worker, cron, grpc
14
+ - CLI tool: blokctl
15
+ - Editor support: @blokjs/lsp-server, @blokjs/syntax
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+ - @blokjs/shared@0.2.0
21
+ - @blokjs/helper@0.2.0
22
+ - @blokjs/runner@0.2.0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * WebhookTrigger - Handle webhook events from external services
3
+ *
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
9
+ *
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
61
+ */
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;
72
+ };
73
+ }
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;
84
+ 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;
97
+ /**
98
+ * Initialize webhook trigger (call after loading workflows)
99
+ */
100
+ listen(): Promise<number>;
101
+ /**
102
+ * Stop the webhook trigger
103
+ */
104
+ 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;
127
+ }
128
+ export default WebhookTrigger;
129
+ export { sourceHandlers };
@@ -0,0 +1,355 @@
1
+ "use strict";
2
+ /**
3
+ * WebhookTrigger - Handle webhook events from external services
4
+ *
5
+ * Extends TriggerBase to process webhook events from:
6
+ * - GitHub (push, pull_request, issues, etc.)
7
+ * - Stripe (payment_intent, checkout.session, etc.)
8
+ * - Shopify (orders, products, customers)
9
+ * - Custom webhooks
10
+ *
11
+ * Features:
12
+ * - Signature verification for security
13
+ * - Event type filtering
14
+ * - Retry support
15
+ * - Dead letter handling
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.sourceHandlers = exports.WebhookTrigger = void 0;
22
+ const node_crypto_1 = __importDefault(require("node:crypto"));
23
+ const runner_1 = require("@blok/runner");
24
+ const api_1 = require("@opentelemetry/api");
25
+ const uuid_1 = require("uuid");
26
+ /**
27
+ * Built-in source handlers
28
+ */
29
+ const sourceHandlers = {
30
+ github: {
31
+ getEventType: (headers) => headers["x-github-event"] || "unknown",
32
+ getSignature: (headers) => headers["x-hub-signature-256"] || headers["x-hub-signature"],
33
+ verifySignature: (rawBody, signature, secret) => {
34
+ const hmac = node_crypto_1.default.createHmac("sha256", secret);
35
+ const digest = `sha256=${hmac.update(rawBody).digest("hex")}`;
36
+ const sigBuffer = Buffer.from(signature);
37
+ const digestBuffer = Buffer.from(digest);
38
+ // Length check first to avoid timing attack on length
39
+ if (sigBuffer.length !== digestBuffer.length) {
40
+ return { valid: false, error: "Invalid GitHub signature" };
41
+ }
42
+ const valid = node_crypto_1.default.timingSafeEqual(sigBuffer, digestBuffer);
43
+ return { valid, error: valid ? undefined : "Invalid GitHub signature" };
44
+ },
45
+ getEventId: (headers) => headers["x-github-delivery"] || (0, uuid_1.v4)(),
46
+ },
47
+ stripe: {
48
+ getEventType: (_, body) => body?.type || "unknown",
49
+ getSignature: (headers) => headers["stripe-signature"],
50
+ verifySignature: (rawBody, signature, secret) => {
51
+ // Stripe signature format: t=timestamp,v1=signature
52
+ const parts = signature.split(",").reduce((acc, part) => {
53
+ const [key, value] = part.split("=");
54
+ acc[key] = value;
55
+ return acc;
56
+ }, {});
57
+ const timestamp = parts.t;
58
+ const expectedSig = parts.v1;
59
+ if (!timestamp || !expectedSig) {
60
+ return { valid: false, error: "Invalid Stripe signature format" };
61
+ }
62
+ const payload = `${timestamp}.${rawBody}`;
63
+ const hmac = node_crypto_1.default.createHmac("sha256", secret);
64
+ const computedSig = hmac.update(payload).digest("hex");
65
+ const sigBuffer = Buffer.from(expectedSig);
66
+ const computedBuffer = Buffer.from(computedSig);
67
+ if (sigBuffer.length !== computedBuffer.length) {
68
+ return { valid: false, error: "Invalid Stripe signature" };
69
+ }
70
+ const valid = node_crypto_1.default.timingSafeEqual(sigBuffer, computedBuffer);
71
+ return { valid, error: valid ? undefined : "Invalid Stripe signature" };
72
+ },
73
+ getEventId: (_, body) => body?.id || (0, uuid_1.v4)(),
74
+ },
75
+ shopify: {
76
+ getEventType: (headers) => headers["x-shopify-topic"] || "unknown",
77
+ getSignature: (headers) => headers["x-shopify-hmac-sha256"],
78
+ verifySignature: (rawBody, signature, secret) => {
79
+ const hmac = node_crypto_1.default.createHmac("sha256", secret);
80
+ const digest = hmac.update(rawBody, "utf8").digest("base64");
81
+ const sigBuffer = Buffer.from(signature, "base64");
82
+ const digestBuffer = Buffer.from(digest, "base64");
83
+ if (sigBuffer.length !== digestBuffer.length) {
84
+ return { valid: false, error: "Invalid Shopify signature" };
85
+ }
86
+ const valid = node_crypto_1.default.timingSafeEqual(sigBuffer, digestBuffer);
87
+ return { valid, error: valid ? undefined : "Invalid Shopify signature" };
88
+ },
89
+ getEventId: (headers) => headers["x-shopify-webhook-id"] || (0, uuid_1.v4)(),
90
+ },
91
+ custom: {
92
+ getEventType: (headers, body) => headers["x-event-type"] || body?.event || "custom",
93
+ getSignature: (headers) => headers["x-signature"] || headers["x-webhook-signature"],
94
+ verifySignature: (rawBody, signature, secret) => {
95
+ // Default: HMAC-SHA256
96
+ const hmac = node_crypto_1.default.createHmac("sha256", secret);
97
+ const digest = hmac.update(rawBody).digest("hex");
98
+ const valid = signature === digest || signature === `sha256=${digest}`;
99
+ return { valid, error: valid ? undefined : "Invalid signature" };
100
+ },
101
+ getEventId: (headers, body) => headers["x-event-id"] || body?.id || (0, uuid_1.v4)(),
102
+ },
103
+ };
104
+ exports.sourceHandlers = sourceHandlers;
105
+ /**
106
+ * WebhookTrigger - Handle webhook events
107
+ */
108
+ class WebhookTrigger extends runner_1.TriggerBase {
109
+ nodeMap = {};
110
+ tracer = api_1.trace.getTracer(process.env.PROJECT_NAME || "trigger-webhook-workflow", process.env.PROJECT_VERSION || "0.0.1");
111
+ logger = new runner_1.DefaultLogger();
112
+ webhookWorkflows = [];
113
+ constructor() {
114
+ super();
115
+ this.loadNodes();
116
+ this.loadWorkflows();
117
+ }
118
+ /**
119
+ * Load nodes into the node map
120
+ */
121
+ loadNodes() {
122
+ this.nodeMap.nodes = new runner_1.NodeMap();
123
+ const nodeKeys = Object.keys(this.nodes);
124
+ for (const key of nodeKeys) {
125
+ this.nodeMap.nodes.addNode(key, this.nodes[key]);
126
+ }
127
+ }
128
+ /**
129
+ * Load workflows into the workflow map
130
+ */
131
+ loadWorkflows() {
132
+ this.nodeMap.workflows = this.workflows;
133
+ }
134
+ /**
135
+ * Initialize webhook trigger (call after loading workflows)
136
+ */
137
+ async listen() {
138
+ const startTime = this.startCounter();
139
+ // Find all workflows with webhook triggers
140
+ this.webhookWorkflows = this.getWebhookWorkflows();
141
+ if (this.webhookWorkflows.length === 0) {
142
+ this.logger.log("No workflows with webhook triggers found");
143
+ }
144
+ else {
145
+ this.logger.log(`Webhook trigger initialized. ${this.webhookWorkflows.length} workflow(s) registered`);
146
+ }
147
+ // Enable HMR in development mode
148
+ if (process.env.BLOK_HMR === "true" || process.env.NODE_ENV === "development") {
149
+ await this.enableHotReload();
150
+ }
151
+ return this.endCounter(startTime);
152
+ }
153
+ /**
154
+ * Stop the webhook trigger
155
+ */
156
+ async stop() {
157
+ this.webhookWorkflows = [];
158
+ this.logger.log("Webhook trigger stopped");
159
+ }
160
+ async onHmrWorkflowChange() {
161
+ this.loadWorkflows();
162
+ this.webhookWorkflows = this.getWebhookWorkflows();
163
+ this.logger.log(`[HMR] Webhook workflows reloaded. ${this.webhookWorkflows.length} workflow(s) registered`);
164
+ }
165
+ /**
166
+ * Process an incoming webhook request
167
+ * Call this from your HTTP endpoint handler
168
+ */
169
+ async handleWebhook(source, rawBody, headers) {
170
+ const handler = sourceHandlers[source] || sourceHandlers.custom;
171
+ // Parse body
172
+ let body;
173
+ try {
174
+ body = JSON.parse(rawBody);
175
+ }
176
+ catch {
177
+ body = rawBody;
178
+ }
179
+ // Create webhook event
180
+ const event = {
181
+ id: handler.getEventId(headers, body),
182
+ source,
183
+ eventType: handler.getEventType(headers, body),
184
+ payload: body,
185
+ headers,
186
+ signature: handler.getSignature(headers),
187
+ timestamp: new Date(),
188
+ rawBody,
189
+ };
190
+ // Find matching workflow
191
+ const workflow = this.findMatchingWorkflow(event);
192
+ if (!workflow) {
193
+ this.logger.log(`No matching workflow for webhook: ${source}/${event.eventType}`);
194
+ return null;
195
+ }
196
+ const config = workflow.config.trigger?.webhook;
197
+ // Verify signature if secret is configured
198
+ if (config.secret && event.signature) {
199
+ const verification = handler.verifySignature(rawBody, event.signature, config.secret);
200
+ if (!verification.valid) {
201
+ this.logger.error(`Webhook signature verification failed: ${verification.error}`);
202
+ throw new Error(`Signature verification failed: ${verification.error}`);
203
+ }
204
+ }
205
+ else if (config.secret && !event.signature) {
206
+ this.logger.error("Webhook signature missing but secret is configured");
207
+ throw new Error("Signature missing");
208
+ }
209
+ return this.executeWorkflow(event, workflow, config);
210
+ }
211
+ /**
212
+ * Get all workflows that have webhook triggers
213
+ */
214
+ getWebhookWorkflows() {
215
+ const workflows = [];
216
+ for (const [path, workflow] of Object.entries(this.nodeMap.workflows || {})) {
217
+ const workflowConfig = workflow._config;
218
+ if (workflowConfig?.trigger) {
219
+ const triggerType = Object.keys(workflowConfig.trigger)[0];
220
+ if (triggerType === "webhook" && workflowConfig.trigger.webhook) {
221
+ workflows.push({
222
+ path,
223
+ config: workflowConfig,
224
+ });
225
+ }
226
+ }
227
+ }
228
+ return workflows;
229
+ }
230
+ /**
231
+ * Find workflow matching the webhook event
232
+ */
233
+ findMatchingWorkflow(event) {
234
+ for (const workflow of this.webhookWorkflows) {
235
+ const config = workflow.config.trigger?.webhook;
236
+ if (!config)
237
+ continue;
238
+ // Check source match
239
+ if (config.source !== event.source)
240
+ continue;
241
+ // Check event type match
242
+ if (config.events && config.events.length > 0) {
243
+ const matches = config.events.some((pattern) => {
244
+ // Support wildcards (e.g., "push", "pull_request.*")
245
+ if (pattern === "*")
246
+ return true;
247
+ if (pattern.endsWith(".*")) {
248
+ const prefix = pattern.slice(0, -2);
249
+ return event.eventType.startsWith(prefix);
250
+ }
251
+ return pattern === event.eventType;
252
+ });
253
+ if (!matches)
254
+ continue;
255
+ }
256
+ return workflow;
257
+ }
258
+ return null;
259
+ }
260
+ /**
261
+ * Execute a workflow for a webhook event
262
+ */
263
+ async executeWorkflow(event, workflow, _config) {
264
+ const executionId = (0, uuid_1.v4)();
265
+ const defaultMeter = api_1.metrics.getMeter("default");
266
+ const webhookExecutions = defaultMeter.createCounter("webhook_executions", {
267
+ description: "Webhook executions",
268
+ });
269
+ const webhookErrors = defaultMeter.createCounter("webhook_errors", {
270
+ description: "Webhook execution errors",
271
+ });
272
+ return new Promise((resolve) => {
273
+ this.tracer.startActiveSpan(`webhook:${event.source}/${event.eventType}`, async (span) => {
274
+ try {
275
+ const start = performance.now();
276
+ // Initialize configuration for this workflow
277
+ await this.configuration.init(workflow.path, this.nodeMap);
278
+ // Create context
279
+ const ctx = this.createContext(undefined, workflow.path, executionId);
280
+ // Populate request with webhook event
281
+ ctx.request = {
282
+ body: event.payload,
283
+ headers: event.headers,
284
+ query: {},
285
+ params: {
286
+ source: event.source,
287
+ eventType: event.eventType,
288
+ eventId: event.id,
289
+ },
290
+ };
291
+ // Store webhook context in vars
292
+ if (!ctx.vars)
293
+ ctx.vars = {};
294
+ ctx.vars._webhook_event = {
295
+ id: event.id,
296
+ source: event.source,
297
+ eventType: event.eventType,
298
+ timestamp: event.timestamp.toISOString(),
299
+ hasSignature: String(!!event.signature),
300
+ };
301
+ ctx.logger.log(`Processing webhook: ${event.source}/${event.eventType} (${event.id})`);
302
+ // Execute workflow
303
+ const response = await this.run(ctx);
304
+ const end = performance.now();
305
+ // Set span attributes
306
+ span.setAttribute("success", true);
307
+ span.setAttribute("event_id", event.id);
308
+ span.setAttribute("source", event.source);
309
+ span.setAttribute("event_type", event.eventType);
310
+ span.setAttribute("workflow_path", workflow.path);
311
+ span.setAttribute("elapsed_ms", end - start);
312
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
313
+ // Record metrics
314
+ webhookExecutions.add(1, {
315
+ env: process.env.NODE_ENV,
316
+ source: event.source,
317
+ event_type: event.eventType,
318
+ workflow_name: this.configuration.name,
319
+ success: "true",
320
+ });
321
+ ctx.logger.log(`Webhook processed in ${(end - start).toFixed(2)}ms: ${event.id}`);
322
+ resolve(response);
323
+ }
324
+ catch (error) {
325
+ const errorMessage = error.message;
326
+ // Set span error
327
+ span.setAttribute("success", false);
328
+ span.recordException(error);
329
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: errorMessage });
330
+ // Record error metrics
331
+ webhookErrors.add(1, {
332
+ env: process.env.NODE_ENV,
333
+ source: event.source,
334
+ event_type: event.eventType,
335
+ workflow_name: this.configuration?.name || "unknown",
336
+ });
337
+ this.logger.error(`Webhook failed ${event.id}: ${errorMessage}`, error.stack);
338
+ throw error;
339
+ }
340
+ finally {
341
+ span.end();
342
+ }
343
+ });
344
+ });
345
+ }
346
+ /**
347
+ * Register a custom source handler
348
+ */
349
+ static registerSourceHandler(source, handler) {
350
+ sourceHandlers[source] = handler;
351
+ }
352
+ }
353
+ exports.WebhookTrigger = WebhookTrigger;
354
+ exports.default = WebhookTrigger;
355
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ViaG9va1RyaWdnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvV2ViaG9va1RyaWdnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHOzs7Ozs7QUFFSCw4REFBaUM7QUFFakMseUNBT3NCO0FBRXRCLDRDQUErRTtBQUMvRSwrQkFBa0M7QUE4RGxDOztHQUVHO0FBQ0gsTUFBTSxjQUFjLEdBQXlDO0lBQzVELE1BQU0sRUFBRTtRQUNQLFlBQVksRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLElBQUksU0FBUztRQUNqRSxZQUFZLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztRQUN2RixlQUFlLEVBQUUsQ0FBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQy9DLE1BQU0sSUFBSSxHQUFHLHFCQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNqRCxNQUFNLE1BQU0sR0FBRyxVQUFVLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDOUQsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUN6QyxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3pDLHNEQUFzRDtZQUN0RCxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUM5QyxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsMEJBQTBCLEVBQUUsQ0FBQztZQUM1RCxDQUFDO1lBQ0QsTUFBTSxLQUFLLEdBQUcs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b0JBRXpGLE1BQU0sS0FBSyxDQUFDO2dCQUNiLENBQUM7d0JBQVMsQ0FBQztvQkFDVixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ1osQ0FBQztZQUNGLENBQUMsQ0FBQyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMscUJBQXFCLENBQUMsTUFBYyxFQUFFLE9BQTZCO1FBQ3pFLGNBQWMsQ0FBQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUM7SUFDbEMsQ0FBQztDQUNEO0FBdFNELHdDQXNTQztBQUVELGtCQUFlLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogV2ViaG9va1RyaWdnZXIgLSBIYW5kbGUgd2ViaG9vayBldmVudHMgZnJvbSBleHRlcm5hbCBzZXJ2aWNlc1xuICpcbiAqIEV4dGVuZHMgVHJpZ2dlckJhc2UgdG8gcHJvY2VzcyB3ZWJob29rIGV2ZW50cyBmcm9tOlxuICogLSBHaXRIdWIgKHB1c2gsIHB1bGxfcmVxdWVzdCwgaXNzdWVzLCBldGMuKVxuICogLSBTdHJpcGUgKHBheW1lbnRfaW50ZW50LCBjaGVja291dC5zZXNzaW9uLCBldGMuKVxuICogLSBTaG9waWZ5IChvcmRlcnMsIHByb2R1Y3RzLCBjdXN0b21lcnMpXG4gKiAtIEN1c3RvbSB3ZWJob29rc1xuICpcbiAqIEZlYXR1cmVzOlxuICogLSBTaWduYXR1cmUgdmVyaWZpY2F0aW9uIGZvciBzZWN1cml0eVxuICogLSBFdmVudCB0eXBlIGZpbHRlcmluZ1xuICogLSBSZXRyeSBzdXBwb3J0XG4gKiAtIERlYWQgbGV0dGVyIGhhbmRsaW5nXG4gKi9cblxuaW1wb3J0IGNyeXB0byBmcm9tIFwibm9kZTpjcnlwdG9cIjtcbmltcG9ydCB0eXBlIHsgSGVscGVyUmVzcG9uc2UsIFdlYmhvb2tUcmlnZ2VyT3B0cyB9IGZyb20gXCJAYmxvay9oZWxwZXJcIjtcbmltcG9ydCB7XG5cdERlZmF1bHRMb2dnZXIsXG5cdHR5cGUgR2xvYmFsT3B0aW9ucyxcblx0dHlwZSBCbG9rU2VydmljZSxcblx0Tm9kZU1hcCxcblx0VHJpZ2dlckJhc2UsXG5cdHR5cGUgVHJpZ2dlclJlc3BvbnNlLFxufSBmcm9tIFwiQGJsb2svcnVubmVyXCI7XG5pbXBvcnQgdHlwZSB7IENvbnRleHQsIFJlcXVlc3RDb250ZXh0IH0gZnJvbSBcIkBibG9rL3NoYXJlZFwiO1xuaW1wb3J0IHsgdHlwZSBTcGFuLCBTcGFuU3RhdHVzQ29kZSwgbWV0cmljcywgdHJhY2UgfSBmcm9tIFwiQG9wZW50ZWxlbWV0cnkvYXBpXCI7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSBcInV1aWRcIjtcblxuLyoqXG4gKiBXZWJob29rIGV2ZW50IHN0cnVjdHVyZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdlYmhvb2tFdmVudCB7XG5cdC8qKiBVbmlxdWUgZXZlbnQgSUQgKi9cblx0aWQ6IHN0cmluZztcblx0LyoqIFNvdXJjZSBzZXJ2aWNlIChnaXRodWIsIHN0cmlwZSwgc2hvcGlmeSwgY3VzdG9tKSAqL1xuXHRzb3VyY2U6IHN0cmluZztcblx0LyoqIEV2ZW50IHR5cGUgKGUuZy4sIHB1c2gsIHBheW1lbnRfaW50ZW50LnN1Y2NlZWRlZCkgKi9cblx0ZXZlbnRUeXBlOiBzdHJpbmc7XG5cdC8qKiBFdmVudCBwYXlsb2FkICovXG5cdHBheWxvYWQ6IHVua25vd247XG5cdC8qKiBSZXF1ZXN0IGhlYWRlcnMgKi9cblx0aGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcblx0LyoqIFNpZ25hdHVyZSAoaWYgcHJvdmlkZWQpICovXG5cdHNpZ25hdHVyZT86IHN0cmluZztcblx0LyoqIFRpbWVzdGFtcCAqL1xuXHR0aW1lc3RhbXA6IERhdGU7XG5cdC8qKiBSYXcgcmVxdWVzdCBib2R5ICovXG5cdHJhd0JvZHk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBTaWduYXR1cmUgdmVyaWZpY2F0aW9uIHJlc3VsdFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFZlcmlmaWNhdGlvblJlc3VsdCB7XG5cdHZhbGlkOiBib29sZWFuO1xuXHRlcnJvcj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBXZWJob29rIHNvdXJjZSBoYW5kbGVyc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIFdlYmhvb2tTb3VyY2VIYW5kbGVyIHtcblx0LyoqIEV4dHJhY3QgZXZlbnQgdHlwZSBmcm9tIHJlcXVlc3QgKi9cblx0Z2V0RXZlbnRUeXBlKGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4sIGJvZHk6IHVua25vd24pOiBzdHJpbmc7XG5cdC8qKiBHZXQgc2lnbmF0dXJlIGZyb20gcmVxdWVzdCAqL1xuXHRnZXRTaWduYXR1cmUoaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPik6IHN0cmluZyB8IHVuZGVmaW5lZDtcblx0LyoqIFZlcmlmeSBzaWduYXR1cmUgKi9cblx0dmVyaWZ5U2lnbmF0dXJlKHJhd0JvZHk6IHN0cmluZywgc2lnbmF0dXJlOiBzdHJpbmcsIHNlY3JldDogc3RyaW5nKTogVmVyaWZpY2F0aW9uUmVzdWx0O1xuXHQvKiogR2V0IGV2ZW50IElEICovXG5cdGdldEV2ZW50SWQoaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiwgYm9keTogdW5rbm93bik6IHN0cmluZztcbn1cblxuLyoqXG4gKiBXb3JrZmxvdyBtb2RlbCB3aXRoIHdlYmhvb2sgdHJpZ2dlciBjb25maWd1cmF0aW9uXG4gKi9cbmludGVyZmFjZSBXZWJob29rV29ya2Zsb3dNb2RlbCB7XG5cdHBhdGg6IHN0cmluZztcblx0Y29uZmlnOiB7XG5cdFx0bmFtZTogc3RyaW5nO1xuXHRcdHZlcnNpb246IHN0cmluZztcblx0XHR0cmlnZ2VyPzoge1xuXHRcdFx0d2ViaG9vaz86IFdlYmhvb2tUcmlnZ2VyT3B0cztcblx0XHRcdFtrZXk6IHN0cmluZ106IHVua25vd247XG5cdFx0fTtcblx0XHRba2V5OiBzdHJpbmddOiB1bmtub3duO1xuXHR9O1xufVxuXG4vKipcbiAqIEJ1aWx0LWluIHNvdXJjZSBoYW5kbGVyc1xuICovXG5jb25zdCBzb3VyY2VIYW5kbGVyczogUmVjb3JkPHN0cmluZywgV2ViaG9va1NvdXJjZUhhbmRsZXI+ID0ge1xuXHRnaXRodWI6IHtcblx0XHRnZXRFdmVudFR5cGU6IChoZWFkZXJzKSA9PiBoZWFkZXJzW1wieC1naXRodWItZXZlbnRcIl0gfHwgXCJ1bmtub3duXCIsXG5cdFx0Z2V0U2lnbmF0dXJlOiAoaGVhZGVycykgPT4gaGVhZGVyc1tcIngtaHViLXNpZ25hdHVyZS0yNTZcIl0gfHwgaGVhZGVyc1tcIngtaHViLXNpZ25hdHVyZVwiXSxcblx0XHR2ZXJpZnlTaWduYXR1cmU6IChyYXdCb2R5LCBzaWduYXR1cmUsIHNlY3JldCkgPT4ge1xuXHRcdFx0Y29uc3QgaG1hYyA9IGNyeXB0by5jcmVhdGVIbWFjKFwic2hhMjU2XCIsIHNlY3JldCk7XG5cdFx0XHRjb25zdCBkaWdlc3QgPSBgc2hhMjU2PSR7aG1hYy51cGRhdGUocmF3Qm9keSkuZGlnZXN0KFwiaGV4XCIpfWA7XG5cdFx0XHRjb25zdCBzaWdCdWZmZXIgPSBCdWZmZXIuZnJvbShzaWduYXR1cmUpO1xuXHRcdFx0Y29uc3QgZGlnZXN0QnVmZmVyID0gQnVmZmVyLmZyb20oZGlnZXN0KTtcblx0XHRcdC8vIExlbmd0aCBjaGVjayBmaXJzdCB0byBhdm9pZCB0aW1pbmcgYXR0YWNrIG9uIGxlbmd0aFxuXHRcdFx0aWYgKHNpZ0J1ZmZlci5sZW5ndGggIT09IGRpZ2VzdEJ1ZmZlci5sZW5ndGgpIHtcblx0XHRcdFx0cmV0dXJuIHsgdmFsaWQ6IGZhbHNlLCBlcnJvcjogXCJJbnZhbGlkIEdpdEh1YiBzaWduYXR1cmVcIiB9O1xuXHRcdFx0fVxuXHRcdFx0Y29uc3QgdmFsaWQgPSBjcnlwdG8udGltaW5nU2FmZUVxdWFsKHNpZ0J1ZmZlciwgZGlnZXN0QnVmZmVyKTtcblx0XHRcdHJldHVybiB7IHZhbGlkLCBlcnJvcjogdmFsaWQgPyB1bmRlZmluZWQgOiBcIkludmFsaWQgR2l0SHViIHNpZ25hdHVyZVwiIH07XG5cdFx0fSxcblx0XHRnZXRFdmVudElkOiAoaGVhZGVycykgPT4gaGVhZGVyc1tcIngtZ2l0aHViLWRlbGl2ZXJ5XCJdIHx8IHV1aWQoKSxcblx0fSxcblxuXHRzdHJpcGU6IHtcblx0XHRnZXRFdmVudFR5cGU6IChfLCBib2R5KSA9PiAoYm9keSBhcyB7IHR5cGU/OiBzdHJpbmcgfSk/LnR5cGUgfHwgXCJ1bmtub3duXCIsXG5cdFx0Z2V0U2lnbmF0dXJlOiAoaGVhZGVycykgPT4gaGVhZGVyc1tcInN0cmlwZS1zaWduYXR1cmVcIl0sXG5cdFx0dmVyaWZ5U2lnbmF0dXJlOiAocmF3Qm9keSwgc2lnbmF0dXJlLCBzZWNyZXQpID0+IHtcblx0XHRcdC8vIFN0cmlwZSBzaWduYXR1cmUgZm9ybWF0OiB0PXRpbWVzdGFtcCx2MT1zaWduYXR1cmVcblx0XHRcdGNvbnN0IHBhcnRzID0gc2lnbmF0dXJlLnNwbGl0KFwiLFwiKS5yZWR1Y2UoXG5cdFx0XHRcdChhY2MsIHBhcnQpID0+IHtcblx0XHRcdFx0XHRjb25zdCBba2V5LCB2YWx1ZV0gPSBwYXJ0LnNwbGl0KFwiPVwiKTtcblx0XHRcdFx0XHRhY2Nba2V5XSA9IHZhbHVlO1xuXHRcdFx0XHRcdHJldHVybiBhY2M7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHt9IGFzIFJlY29yZDxzdHJpbmcsIHN0cmluZz4sXG5cdFx0XHQpO1xuXG5cdFx0XHRjb25zdCB0aW1lc3RhbXAgPSBwYXJ0cy50O1xuXHRcdFx0Y29uc3QgZXhwZWN0ZWRTaWcgPSBwYXJ0cy52MTtcblxuXHRcdFx0aWYgKCF0aW1lc3RhbXAgfHwgIWV4cGVjdGVkU2lnKSB7XG5cdFx0XHRcdHJldHVybiB7IHZhbGlkOiBmYWxzZSwgZXJyb3I6IFwiSW52YWxpZCBTdHJpcGUgc2lnbmF0dXJlIGZvcm1hdFwiIH07XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHBheWxvYWQgPSBgJHt0aW1lc3RhbXB9LiR7cmF3Qm9keX1gO1xuXHRcdFx0Y29uc3QgaG1hYyA9IGNyeXB0by5jcmVhdGVIbWFjKFwic2hhMjU2XCIsIHNlY3JldCk7XG5cdFx0XHRjb25zdCBjb21wdXRlZFNpZyA9IGhtYWMudXBkYXRlKHBheWxvYWQpLmRpZ2VzdChcImhleFwiKTtcblxuXHRcdFx0Y29uc3Qgc2lnQnVmZmVyID0gQnVmZmVyLmZyb20oZXhwZWN0ZWRTaWcpO1xuXHRcdFx0Y29uc3QgY29tcHV0ZWRCdWZmZXIgPSBCdWZmZXIuZnJvbShjb21wdXRlZFNpZyk7XG5cdFx0XHRpZiAoc2lnQnVmZmVyLmxlbmd0aCAhPT0gY29tcHV0ZWRCdWZmZXIubGVuZ3RoKSB7XG5cdFx0XHRcdHJldHVybiB7IHZhbGlkOiBmYWxzZSwgZXJyb3I6IFwiSW52YWxpZCBTdHJpcGUgc2lnbmF0dXJlXCIgfTtcblx0XHRcdH1cblx0XHRcdGNvbnN0IHZhbGlkID0gY3J5cHRvLnRpbWluZ1NhZmVFcXVhbChzaWdCdWZmZXIsIGNvbXB1dGVkQnVmZmVyKTtcblx0XHRcdHJldHVybiB7IHZhbGlkLCBlcnJvcjogdmFsaWQgPyB1bmRlZmluZWQgOiBcIkludmFsaWQgU3RyaXBlIHNpZ25hdHVyZVwiIH07XG5cdFx0fSxcblx0XHRnZXRFdmVudElkOiAoXywgYm9keSkgPT4gKGJvZHkgYXMgeyBpZD86IHN0cmluZyB9KT8uaWQgfHwgdXVpZCgpLFxuXHR9LFxuXG5cdHNob3BpZnk6IHtcblx0XHRnZXRFdmVudFR5cGU6IChoZWFkZXJzKSA9PiBoZWFkZXJzW1wieC1zaG9waWZ5LXRvcGljXCJdIHx8IFwidW5rbm93blwiLFxuXHRcdGdldFNpZ25hdHVyZTogKGhlYWRlcnMpID0+IGhlYWRlcnNbXCJ4LXNob3BpZnktaG1hYy1zaGEyNTZcIl0sXG5cdFx0dmVyaWZ5U2lnbmF0dXJlOiAocmF3Qm9keSwgc2lnbmF0dXJlLCBzZWNyZXQpID0+IHtcblx0XHRcdGNvbnN0IGhtYWMgPSBjcnlwdG8uY3JlYXRlSG1hYyhcInNoYTI1NlwiLCBzZWNyZXQpO1xuXHRcdFx0Y29uc3QgZGlnZXN0ID0gaG1hYy51cGRhdGUocmF3Qm9keSwgXCJ1dGY4XCIpLmRpZ2VzdChcImJhc2U2NFwiKTtcblx0XHRcdGNvbnN0IHNpZ0J1ZmZlciA9IEJ1ZmZlci5mcm9tKHNpZ25hdHVyZSwgXCJiYXNlNjRcIik7XG5cdFx0XHRjb25zdCBkaWdlc3RCdWZmZXIgPSBCdWZmZXIuZnJvbShkaWdlc3QsIFwiYmFzZTY0XCIpO1xuXHRcdFx0aWYgKHNpZ0J1ZmZlci5sZW5ndGggIT09IGRpZ2VzdEJ1ZmZlci5sZW5ndGgpIHtcblx0XHRcdFx0cmV0dXJuIHsgdmFsaWQ6IGZhbHNlLCBlcnJvcjogXCJJbnZhbGlkIFNob3BpZnkgc2lnbmF0dXJlXCIgfTtcblx0XHRcdH1cblx0XHRcdGNvbnN0IHZhbGlkID0gY3J5cHRvLnRpbWluZ1NhZmVFcXVhbChzaWdCdWZmZXIsIGRpZ2VzdEJ1ZmZlcik7XG5cdFx0XHRyZXR1cm4geyB2YWxpZCwgZXJyb3I6IHZhbGlkID8gdW5kZWZpbmVkIDogXCJJbnZhbGlkIFNob3BpZnkgc2lnbmF0dXJlXCIgfTtcblx0XHR9LFxuXHRcdGdldEV2ZW50SWQ6IChoZWFkZXJzKSA9PiBoZWFkZXJzW1wieC1zaG9waWZ5LXdlYmhvb2staWRcIl0gfHwgdXVpZCgpLFxuXHR9LFxuXG5cdGN1c3RvbToge1xuXHRcdGdldEV2ZW50VHlwZTogKGhlYWRlcnMsIGJvZHkpID0+IGhlYWRlcnNbXCJ4LWV2ZW50LXR5cGVcIl0gfHwgKGJvZHkgYXMgeyBldmVudD86IHN0cmluZyB9KT8uZXZlbnQgfHwgXCJjdXN0b21cIixcblx0XHRnZXRTaWduYXR1cmU6IChoZWFkZXJzKSA9PiBoZWFkZXJzW1wieC1zaWduYXR1cmVcIl0gfHwgaGVhZGVyc1tcIngtd2ViaG9vay1zaWduYXR1cmVcIl0sXG5cdFx0dmVyaWZ5U2lnbmF0dXJlOiAocmF3Qm9keSwgc2lnbmF0dXJlLCBzZWNyZXQpID0+IHtcblx0XHRcdC8vIERlZmF1bHQ6IEhNQUMtU0hBMjU2XG5cdFx0XHRjb25zdCBobWFjID0gY3J5cHRvLmNyZWF0ZUhtYWMoXCJzaGEyNTZcIiwgc2VjcmV0KTtcblx0XHRcdGNvbnN0IGRpZ2VzdCA9IGhtYWMudXBkYXRlKHJhd0JvZHkpLmRpZ2VzdChcImhleFwiKTtcblx0XHRcdGNvbnN0IHZhbGlkID0gc2lnbmF0dXJlID09PSBkaWdlc3QgfHwgc2lnbmF0dXJlID09PSBgc2hhMjU2PSR7ZGlnZXN0fWA7XG5cdFx0XHRyZXR1cm4geyB2YWxpZCwgZXJyb3I6IHZhbGlkID8gdW5kZWZpbmVkIDogXCJJbnZhbGlkIHNpZ25hdHVyZVwiIH07XG5cdFx0fSxcblx0XHRnZXRFdmVudElkOiAoaGVhZGVycywgYm9keSkgPT4gaGVhZGVyc1tcIngtZXZlbnQtaWRcIl0gfHwgKGJvZHkgYXMgeyBpZD86IHN0cmluZyB9KT8uaWQgfHwgdXVpZCgpLFxuXHR9LFxufTtcblxuLyoqXG4gKiBXZWJob29rVHJpZ2dlciAtIEhhbmRsZSB3ZWJob29rIGV2ZW50c1xuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgV2ViaG9va1RyaWdnZXIgZXh0ZW5kcyBUcmlnZ2VyQmFzZSB7XG5cdHByb3RlY3RlZCBub2RlTWFwOiBHbG9iYWxPcHRpb25zID0ge30gYXMgR2xvYmFsT3B0aW9ucztcblx0cHJvdGVjdGVkIHJlYWRvbmx5IHRyYWNlciA9IHRyYWNlLmdldFRyYWNlcihcblx0XHRwcm9jZXNzLmVudi5QUk9KRUNUX05BTUUgfHwgXCJ0cmlnZ2VyLXdlYmhvb2std29ya2Zsb3dcIixcblx0XHRwcm9jZXNzLmVudi5QUk9KRUNUX1ZFUlNJT04gfHwgXCIwLjAuMVwiLFxuXHQpO1xuXHRwcm90ZWN0ZWQgcmVhZG9ubHkgbG9nZ2VyID0gbmV3IERlZmF1bHRMb2dnZXIoKTtcblx0cHJvdGVjdGVkIHdlYmhvb2tXb3JrZmxvd3M6IFdlYmhvb2tXb3JrZmxvd01vZGVsW10gPSBbXTtcblxuXHQvLyBTdWJjbGFzc2VzIHByb3ZpZGUgdGhlc2Vcblx0cHJvdGVjdGVkIGFic3RyYWN0IG5vZGVzOiBSZWNvcmQ8c3RyaW5nLCBCbG9rU2VydmljZTx1bmtub3duPj47XG5cdHByb3RlY3RlZCBhYnN0cmFjdCB3b3JrZmxvd3M6IFJlY29yZDxzdHJpbmcsIEhlbHBlclJlc3BvbnNlPjtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHRzdXBlcigpO1xuXHRcdHRoaXMubG9hZE5vZGVzKCk7XG5cdFx0dGhpcy5sb2FkV29ya2Zsb3dzKCk7XG5cdH1cblxuXHQvKipcblx0ICogTG9hZCBub2RlcyBpbnRvIHRoZSBub2RlIG1hcFxuXHQgKi9cblx0bG9hZE5vZGVzKCk6IHZvaWQge1xuXHRcdHRoaXMubm9kZU1hcC5ub2RlcyA9IG5ldyBOb2RlTWFwKCk7XG5cdFx0Y29uc3Qgbm9kZUtleXMgPSBPYmplY3Qua2V5cyh0aGlzLm5vZGVzKTtcblx0XHRmb3IgKGNvbnN0IGtleSBvZiBub2RlS2V5cykge1xuXHRcdFx0dGhpcy5ub2RlTWFwLm5vZGVzLmFkZE5vZGUoa2V5LCB0aGlzLm5vZGVzW2tleV0pO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBMb2FkIHdvcmtmbG93cyBpbnRvIHRoZSB3b3JrZmxvdyBtYXBcblx0ICovXG5cdGxvYWRXb3JrZmxvd3MoKTogdm9pZCB7XG5cdFx0dGhpcy5ub2RlTWFwLndvcmtmbG93cyA9IHRoaXMud29ya2Zsb3dzO1xuXHR9XG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgd2ViaG9vayB0cmlnZ2VyIChjYWxsIGFmdGVyIGxvYWRpbmcgd29ya2Zsb3dzKVxuXHQgKi9cblx0YXN5bmMgbGlzdGVuKCk6IFByb21pc2U8bnVtYmVyPiB7XG5cdFx0Y29uc3Qgc3RhcnRUaW1lID0gdGhpcy5zdGFydENvdW50ZXIoKTtcblxuXHRcdC8vIEZpbmQgYWxsIHdvcmtmbG93cyB3aXRoIHdlYmhvb2sgdHJpZ2dlcnNcblx0XHR0aGlzLndlYmhvb2tXb3JrZmxvd3MgPSB0aGlzLmdldFdlYmhvb2tXb3JrZmxvd3MoKTtcblxuXHRcdGlmICh0aGlzLndlYmhvb2tXb3JrZmxvd3MubGVuZ3RoID09PSAwKSB7XG5cdFx0XHR0aGlzLmxvZ2dlci5sb2coXCJObyB3b3JrZmxvd3Mgd2l0aCB3ZWJob29rIHRyaWdnZXJzIGZvdW5kXCIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmxvZ2dlci5sb2coYFdlYmhvb2sgdHJpZ2dlciBpbml0aWFsaXplZC4gJHt0aGlzLndlYmhvb2tXb3JrZmxvd3MubGVuZ3RofSB3b3JrZmxvdyhzKSByZWdpc3RlcmVkYCk7XG5cdFx0fVxuXG5cdFx0Ly8gRW5hYmxlIEhNUiBpbiBkZXZlbG9wbWVudCBtb2RlXG5cdFx0aWYgKHByb2Nlc3MuZW52LkJMT0tfSE1SID09PSBcInRydWVcIiB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gXCJkZXZlbG9wbWVudFwiKSB7XG5cdFx0XHRhd2FpdCB0aGlzLmVuYWJsZUhvdFJlbG9hZCgpO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmVuZENvdW50ZXIoc3RhcnRUaW1lKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTdG9wIHRoZSB3ZWJob29rIHRyaWdnZXJcblx0ICovXG5cdGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0dGhpcy53ZWJob29rV29ya2Zsb3dzID0gW107XG5cdFx0dGhpcy5sb2dnZXIubG9nKFwiV2ViaG9vayB0cmlnZ2VyIHN0b3BwZWRcIik7XG5cdH1cblxuXHRwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgb25IbXJXb3JrZmxvd0NoYW5nZSgpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHR0aGlzLmxvYWRXb3JrZmxvd3MoKTtcblx0XHR0aGlzLndlYmhvb2tXb3JrZmxvd3MgPSB0aGlzLmdldFdlYmhvb2tXb3JrZmxvd3MoKTtcblx0XHR0aGlzLmxvZ2dlci5sb2coYFtITVJdIFdlYmhvb2sgd29ya2Zsb3dzIHJlbG9hZGVkLiAke3RoaXMud2ViaG9va1dvcmtmbG93cy5sZW5ndGh9IHdvcmtmbG93KHMpIHJlZ2lzdGVyZWRgKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBQcm9jZXNzIGFuIGluY29taW5nIHdlYmhvb2sgcmVxdWVzdFxuXHQgKiBDYWxsIHRoaXMgZnJvbSB5b3VyIEhUVFAgZW5kcG9pbnQgaGFuZGxlclxuXHQgKi9cblx0YXN5bmMgaGFuZGxlV2ViaG9vayhcblx0XHRzb3VyY2U6IHN0cmluZyxcblx0XHRyYXdCb2R5OiBzdHJpbmcsXG5cdFx0aGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcblx0KTogUHJvbWlzZTxUcmlnZ2VyUmVzcG9uc2UgfCBudWxsPiB7XG5cdFx0Y29uc3QgaGFuZGxlciA9IHNvdXJjZUhhbmRsZXJzW3NvdXJjZV0gfHwgc291cmNlSGFuZGxlcnMuY3VzdG9tO1xuXG5cdFx0Ly8gUGFyc2UgYm9keVxuXHRcdGxldCBib2R5OiB1bmtub3duO1xuXHRcdHRyeSB7XG5cdFx0XHRib2R5ID0gSlNPTi5wYXJzZShyYXdCb2R5KTtcblx0XHR9IGNhdGNoIHtcblx0XHRcdGJvZHkgPSByYXdCb2R5O1xuXHRcdH1cblxuXHRcdC8vIENyZWF0ZSB3ZWJob29rIGV2ZW50XG5cdFx0Y29uc3QgZXZlbnQ6IFdlYmhvb2tFdmVudCA9IHtcblx0XHRcdGlkOiBoYW5kbGVyLmdldEV2ZW50SWQoaGVhZGVycywgYm9keSksXG5cdFx0XHRzb3VyY2UsXG5cdFx0XHRldmVudFR5cGU6IGhhbmRsZXIuZ2V0RXZlbnRUeXBlKGhlYWRlcnMsIGJvZHkpLFxuXHRcdFx0cGF5bG9hZDogYm9keSxcblx0XHRcdGhlYWRlcnMsXG5cdFx0XHRzaWduYXR1cmU6IGhhbmRsZXIuZ2V0U2lnbmF0dXJlKGhlYWRlcnMpLFxuXHRcdFx0dGltZXN0YW1wOiBuZXcgRGF0ZSgpLFxuXHRcdFx0cmF3Qm9keSxcblx0XHR9O1xuXG5cdFx0Ly8gRmluZCBtYXRjaGluZyB3b3JrZmxvd1xuXHRcdGNvbnN0IHdvcmtmbG93ID0gdGhpcy5maW5kTWF0Y2hpbmdXb3JrZmxvdyhldmVudCk7XG5cdFx0aWYgKCF3b3JrZmxvdykge1xuXHRcdFx0dGhpcy5sb2dnZXIubG9nKGBObyBtYXRjaGluZyB3b3JrZmxvdyBmb3Igd2ViaG9vazogJHtzb3VyY2V9LyR7ZXZlbnQuZXZlbnRUeXBlfWApO1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXG5cdFx0Y29uc3QgY29uZmlnID0gd29ya2Zsb3cuY29uZmlnLnRyaWdnZXI/LndlYmhvb2sgYXMgV2ViaG9va1RyaWdnZXJPcHRzO1xuXG5cdFx0Ly8gVmVyaWZ5IHNpZ25hdHVyZSBpZiBzZWNyZXQgaXMgY29uZmlndXJlZFxuXHRcdGlmIChjb25maWcuc2VjcmV0ICYmIGV2ZW50LnNpZ25hdHVyZSkge1xuXHRcdFx0Y29uc3QgdmVyaWZpY2F0aW9uID0gaGFuZGxlci52ZXJpZnlTaWduYXR1cmUocmF3Qm9keSwgZXZlbnQuc2lnbmF0dXJlLCBjb25maWcuc2VjcmV0KTtcblx0XHRcdGlmICghdmVyaWZpY2F0aW9uLnZhbGlkKSB7XG5cdFx0XHRcdHRoaXMubG9nZ2VyLmVycm9yKGBXZWJob29rIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24gZmFpbGVkOiAke3ZlcmlmaWNhdGlvbi5lcnJvcn1gKTtcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKGBTaWduYXR1cmUgdmVyaWZpY2F0aW9uIGZhaWxlZDogJHt2ZXJpZmljYXRpb24uZXJyb3J9YCk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIGlmIChjb25maWcuc2VjcmV0ICYmICFldmVudC5zaWduYXR1cmUpIHtcblx0XHRcdHRoaXMubG9nZ2VyLmVycm9yKFwiV2ViaG9vayBzaWduYXR1cmUgbWlzc2luZyBidXQgc2VjcmV0IGlzIGNvbmZpZ3VyZWRcIik7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJTaWduYXR1cmUgbWlzc2luZ1wiKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5leGVjdXRlV29ya2Zsb3coZXZlbnQsIHdvcmtmbG93LCBjb25maWcpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldCBhbGwgd29ya2Zsb3dzIHRoYXQgaGF2ZSB3ZWJob29rIHRyaWdnZXJzXG5cdCAqL1xuXHRwcm90ZWN0ZWQgZ2V0V2ViaG9va1dvcmtmbG93cygpOiBXZWJob29rV29ya2Zsb3dNb2RlbFtdIHtcblx0XHRjb25zdCB3b3JrZmxvd3M6IFdlYmhvb2tXb3JrZmxvd01vZGVsW10gPSBbXTtcblxuXHRcdGZvciAoY29uc3QgW3BhdGgsIHdvcmtmbG93XSBvZiBPYmplY3QuZW50cmllcyh0aGlzLm5vZGVNYXAud29ya2Zsb3dzIHx8IHt9KSkge1xuXHRcdFx0Y29uc3Qgd29ya2Zsb3dDb25maWcgPSAod29ya2Zsb3cgYXMgdW5rbm93biBhcyB7IF9jb25maWc6IFdlYmhvb2tXb3JrZmxvd01vZGVsW1wiY29uZmlnXCJdIH0pLl9jb25maWc7XG5cblx0XHRcdGlmICh3b3JrZmxvd0NvbmZpZz8udHJpZ2dlcikge1xuXHRcdFx0XHRjb25zdCB0cmlnZ2VyVHlwZSA9IE9iamVjdC5rZXlzKHdvcmtmbG93Q29uZmlnLnRyaWdnZXIpWzBdO1xuXG5cdFx0XHRcdGlmICh0cmlnZ2VyVHlwZSA9PT0gXCJ3ZWJob29rXCIgJiYgd29ya2Zsb3dDb25maWcudHJpZ2dlci53ZWJob29rKSB7XG5cdFx0XHRcdFx0d29ya2Zsb3dzLnB1c2goe1xuXHRcdFx0XHRcdFx0cGF0aCxcblx0XHRcdFx0XHRcdGNvbmZpZzogd29ya2Zsb3dDb25maWcsXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gd29ya2Zsb3dzO1xuXHR9XG5cblx0LyoqXG5cdCAqIEZpbmQgd29ya2Zsb3cgbWF0Y2hpbmcgdGhlIHdlYmhvb2sgZXZlbnRcblx0ICovXG5cdHByb3RlY3RlZCBmaW5kTWF0Y2hpbmdXb3JrZmxvdyhldmVudDogV2ViaG9va0V2ZW50KTogV2ViaG9va1dvcmtmbG93TW9kZWwgfCBudWxsIHtcblx0XHRmb3IgKGNvbnN0IHdvcmtmbG93IG9mIHRoaXMud2ViaG9va1dvcmtmbG93cykge1xuXHRcdFx0Y29uc3QgY29uZmlnID0gd29ya2Zsb3cuY29uZmlnLnRyaWdnZXI/LndlYmhvb2s7XG5cdFx0XHRpZiAoIWNvbmZpZykgY29udGludWU7XG5cblx0XHRcdC8vIENoZWNrIHNvdXJjZSBtYXRjaFxuXHRcdFx0aWYgKGNvbmZpZy5zb3VyY2UgIT09IGV2ZW50LnNvdXJjZSkgY29udGludWU7XG5cblx0XHRcdC8vIENoZWNrIGV2ZW50IHR5cGUgbWF0Y2hcblx0XHRcdGlmIChjb25maWcuZXZlbnRzICYmIGNvbmZpZy5ldmVudHMubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRjb25zdCBtYXRjaGVzID0gY29uZmlnLmV2ZW50cy5zb21lKChwYXR0ZXJuKSA9PiB7XG5cdFx0XHRcdFx0Ly8gU3VwcG9ydCB3aWxkY2FyZHMgKGUuZy4sIFwicHVzaFwiLCBcInB1bGxfcmVxdWVzdC4qXCIpXG5cdFx0XHRcdFx0aWYgKHBhdHRlcm4gPT09IFwiKlwiKSByZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRpZiAocGF0dGVybi5lbmRzV2l0aChcIi4qXCIpKSB7XG5cdFx0XHRcdFx0XHRjb25zdCBwcmVmaXggPSBwYXR0ZXJuLnNsaWNlKDAsIC0yKTtcblx0XHRcdFx0XHRcdHJldHVybiBldmVudC5ldmVudFR5cGUuc3RhcnRzV2l0aChwcmVmaXgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm4gcGF0dGVybiA9PT0gZXZlbnQuZXZlbnRUeXBlO1xuXHRcdFx0XHR9KTtcblx0XHRcdFx0aWYgKCFtYXRjaGVzKSBjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHdvcmtmbG93O1xuXHRcdH1cblxuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0LyoqXG5cdCAqIEV4ZWN1dGUgYSB3b3JrZmxvdyBmb3IgYSB3ZWJob29rIGV2ZW50XG5cdCAqL1xuXHRwcm90ZWN0ZWQgYXN5bmMgZXhlY3V0ZVdvcmtmbG93KFxuXHRcdGV2ZW50OiBXZWJob29rRXZlbnQsXG5cdFx0d29ya2Zsb3c6IFdlYmhvb2tXb3JrZmxvd01vZGVsLFxuXHRcdF9jb25maWc6IFdlYmhvb2tUcmlnZ2VyT3B0cyxcblx0KTogUHJvbWlzZTxUcmlnZ2VyUmVzcG9uc2U+IHtcblx0XHRjb25zdCBleGVjdXRpb25JZCA9IHV1aWQoKTtcblxuXHRcdGNvbnN0IGRlZmF1bHRNZXRlciA9IG1ldHJpY3MuZ2V0TWV0ZXIoXCJkZWZhdWx0XCIpO1xuXHRcdGNvbnN0IHdlYmhvb2tFeGVjdXRpb25zID0gZGVmYXVsdE1ldGVyLmNyZWF0ZUNvdW50ZXIoXCJ3ZWJob29rX2V4ZWN1dGlvbnNcIiwge1xuXHRcdFx0ZGVzY3JpcHRpb246IFwiV2ViaG9vayBleGVjdXRpb25zXCIsXG5cdFx0fSk7XG5cdFx0Y29uc3Qgd2ViaG9va0Vycm9ycyA9IGRlZmF1bHRNZXRlci5jcmVhdGVDb3VudGVyKFwid2ViaG9va19lcnJvcnNcIiwge1xuXHRcdFx0ZGVzY3JpcHRpb246IFwiV2ViaG9vayBleGVjdXRpb24gZXJyb3JzXCIsXG5cdFx0fSk7XG5cblx0XHRyZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcblx0XHRcdHRoaXMudHJhY2VyLnN0YXJ0QWN0aXZlU3Bhbihgd2ViaG9vazoke2V2ZW50LnNvdXJjZX0vJHtldmVudC5ldmVudFR5cGV9YCwgYXN5bmMgKHNwYW46IFNwYW4pID0+IHtcblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRjb25zdCBzdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuXG5cdFx0XHRcdFx0Ly8gSW5pdGlhbGl6ZSBjb25maWd1cmF0aW9uIGZvciB0aGlzIHdvcmtmbG93XG5cdFx0XHRcdFx0YXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXQod29ya2Zsb3cucGF0aCwgdGhpcy5ub2RlTWFwKTtcblxuXHRcdFx0XHRcdC8vIENyZWF0ZSBjb250ZXh0XG5cdFx0XHRcdFx0Y29uc3QgY3R4OiBDb250ZXh0ID0gdGhpcy5jcmVhdGVDb250ZXh0KHVuZGVmaW5lZCwgd29ya2Zsb3cucGF0aCwgZXhlY3V0aW9uSWQpO1xuXG5cdFx0XHRcdFx0Ly8gUG9wdWxhdGUgcmVxdWVzdCB3aXRoIHdlYmhvb2sgZXZlbnRcblx0XHRcdFx0XHRjdHgucmVxdWVzdCA9IHtcblx0XHRcdFx0XHRcdGJvZHk6IGV2ZW50LnBheWxvYWQsXG5cdFx0XHRcdFx0XHRoZWFkZXJzOiBldmVudC5oZWFkZXJzLFxuXHRcdFx0XHRcdFx0cXVlcnk6IHt9LFxuXHRcdFx0XHRcdFx0cGFyYW1zOiB7XG5cdFx0XHRcdFx0XHRcdHNvdXJjZTogZXZlbnQuc291cmNlLFxuXHRcdFx0XHRcdFx0XHRldmVudFR5cGU6IGV2ZW50LmV2ZW50VHlwZSxcblx0XHRcdFx0XHRcdFx0ZXZlbnRJZDogZXZlbnQuaWQsXG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0Q29udGV4dDtcblxuXHRcdFx0XHRcdC8vIFN0b3JlIHdlYmhvb2sgY29udGV4dCBpbiB2YXJzXG5cdFx0XHRcdFx0aWYgKCFjdHgudmFycykgY3R4LnZhcnMgPSB7fTtcblx0XHRcdFx0XHRjdHgudmFycy5fd2ViaG9va19ldmVudCA9IHtcblx0XHRcdFx0XHRcdGlkOiBldmVudC5pZCxcblx0XHRcdFx0XHRcdHNvdXJjZTogZXZlbnQuc291cmNlLFxuXHRcdFx0XHRcdFx0ZXZlbnRUeXBlOiBldmVudC5ldmVudFR5cGUsXG5cdFx0XHRcdFx0XHR0aW1lc3RhbXA6IGV2ZW50LnRpbWVzdGFtcC50b0lTT1N0cmluZygpLFxuXHRcdFx0XHRcdFx0aGFzU2lnbmF0dXJlOiBTdHJpbmcoISFldmVudC5zaWduYXR1cmUpLFxuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHRjdHgubG9nZ2VyLmxvZyhgUHJvY2Vzc2luZyB3ZWJob29rOiAke2V2ZW50LnNvdXJjZX0vJHtldmVudC5ldmVudFR5cGV9ICgke2V2ZW50LmlkfSlgKTtcblxuXHRcdFx0XHRcdC8vIEV4ZWN1dGUgd29ya2Zsb3dcblx0XHRcdFx0XHRjb25zdCByZXNwb25zZTogVHJpZ2dlclJlc3BvbnNlID0gYXdhaXQgdGhpcy5ydW4oY3R4KTtcblx0XHRcdFx0XHRjb25zdCBlbmQgPSBwZXJmb3JtYW5jZS5ub3coKTtcblxuXHRcdFx0XHRcdC8vIFNldCBzcGFuIGF0dHJpYnV0ZXNcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcInN1Y2Nlc3NcIiwgdHJ1ZSk7XG5cdFx0XHRcdFx0c3Bhbi5zZXRBdHRyaWJ1dGUoXCJldmVudF9pZFwiLCBldmVudC5pZCk7XG5cdFx0XHRcdFx0c3Bhbi5zZXRBdHRyaWJ1dGUoXCJzb3VyY2VcIiwgZXZlbnQuc291cmNlKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcImV2ZW50X3R5cGVcIiwgZXZlbnQuZXZlbnRUeXBlKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcIndvcmtmbG93X3BhdGhcIiwgd29ya2Zsb3cucGF0aCk7XG5cdFx0XHRcdFx0c3Bhbi5zZXRBdHRyaWJ1dGUoXCJlbGFwc2VkX21zXCIsIGVuZCAtIHN0YXJ0KTtcblx0XHRcdFx0XHRzcGFuLnNldFN0YXR1cyh7IGNvZGU6IFNwYW5TdGF0dXNDb2RlLk9LIH0pO1xuXG5cdFx0XHRcdFx0Ly8gUmVjb3JkIG1ldHJpY3Ncblx0XHRcdFx0XHR3ZWJob29rRXhlY3V0aW9ucy5hZGQoMSwge1xuXHRcdFx0XHRcdFx0ZW52OiBwcm9jZXNzLmVudi5OT0RFX0VOVixcblx0XHRcdFx0XHRcdHNvdXJjZTogZXZlbnQuc291cmNlLFxuXHRcdFx0XHRcdFx0ZXZlbnRfdHlwZTogZXZlbnQuZXZlbnRUeXBlLFxuXHRcdFx0XHRcdFx0d29ya2Zsb3dfbmFtZTogdGhpcy5jb25maWd1cmF0aW9uLm5hbWUsXG5cdFx0XHRcdFx0XHRzdWNjZXNzOiBcInRydWVcIixcblx0XHRcdFx0XHR9KTtcblxuXHRcdFx0XHRcdGN0eC5sb2dnZXIubG9nKGBXZWJob29rIHByb2Nlc3NlZCBpbiAkeyhlbmQgLSBzdGFydCkudG9GaXhlZCgyKX1tczogJHtldmVudC5pZH1gKTtcblxuXHRcdFx0XHRcdHJlc29sdmUocmVzcG9uc2UpO1xuXHRcdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRcdGNvbnN0IGVycm9yTWVzc2FnZSA9IChlcnJvciBhcyBFcnJvcikubWVzc2FnZTtcblxuXHRcdFx0XHRcdC8vIFNldCBzcGFuIGVycm9yXG5cdFx0XHRcdFx0c3Bhbi5zZXRBdHRyaWJ1dGUoXCJzdWNjZXNzXCIsIGZhbHNlKTtcblx0XHRcdFx0XHRzcGFuLnJlY29yZEV4Y2VwdGlvbihlcnJvciBhcyBFcnJvcik7XG5cdFx0XHRcdFx0c3Bhbi5zZXRTdGF0dXMoeyBjb2RlOiBTcGFuU3RhdHVzQ29kZS5FUlJPUiwgbWVzc2FnZTogZXJyb3JNZXNzYWdlIH0pO1xuXG5cdFx0XHRcdFx0Ly8gUmVjb3JkIGVycm9yIG1ldHJpY3Ncblx0XHRcdFx0XHR3ZWJob29rRXJyb3JzLmFkZCgxLCB7XG5cdFx0XHRcdFx0XHRlbnY6IHByb2Nlc3MuZW52Lk5PREVfRU5WLFxuXHRcdFx0XHRcdFx0c291cmNlOiBldmVudC5zb3VyY2UsXG5cdFx0XHRcdFx0XHRldmVudF90eXBlOiBldmVudC5ldmVudFR5cGUsXG5cdFx0XHRcdFx0XHR3b3JrZmxvd19uYW1lOiB0aGlzLmNvbmZpZ3VyYXRpb24/Lm5hbWUgfHwgXCJ1bmtub3duXCIsXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHR0aGlzLmxvZ2dlci5lcnJvcihgV2ViaG9vayBmYWlsZWQgJHtldmVudC5pZH06ICR7ZXJyb3JNZXNzYWdlfWAsIChlcnJvciBhcyBFcnJvcikuc3RhY2spO1xuXG5cdFx0XHRcdFx0dGhyb3cgZXJyb3I7XG5cdFx0XHRcdH0gZmluYWxseSB7XG5cdFx0XHRcdFx0c3Bhbi5lbmQoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fSk7XG5cdH1cblxuXHQvKipcblx0ICogUmVnaXN0ZXIgYSBjdXN0b20gc291cmNlIGhhbmRsZXJcblx0ICovXG5cdHN0YXRpYyByZWdpc3RlclNvdXJjZUhhbmRsZXIoc291cmNlOiBzdHJpbmcsIGhhbmRsZXI6IFdlYmhvb2tTb3VyY2VIYW5kbGVyKTogdm9pZCB7XG5cdFx0c291cmNlSGFuZGxlcnNbc291cmNlXSA9IGhhbmRsZXI7XG5cdH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgV2ViaG9va1RyaWdnZXI7XG5leHBvcnQgeyBzb3VyY2VIYW5kbGVycyB9O1xuIl19
@@ -0,0 +1,70 @@
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;
26
+ * }
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
+ * ```
53
+ *
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
+ * ```
68
+ */
69
+ export { WebhookTrigger, sourceHandlers, type WebhookEvent, type VerificationResult, type WebhookSourceHandler, } from "./WebhookTrigger";
70
+ export type { WebhookTriggerOpts } from "@blok/helper";