@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 +22 -0
- package/dist/WebhookTrigger.d.ts +129 -0
- package/dist/WebhookTrigger.js +355 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +76 -0
- package/package.json +33 -0
- package/src/WebhookTrigger.test.ts +163 -0
- package/src/WebhookTrigger.ts +480 -0
- package/src/index.ts +80 -0
- package/tsconfig.json +32 -0
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
|
package/dist/index.d.ts
ADDED
|
@@ -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";
|