Skip to content

Commit 93f2094

Browse files
authored
[TRIGGER] Use Webhooks for Vercel Sources (#16570)
1 parent db6a41c commit 93f2094

File tree

14 files changed

+325
-13
lines changed

14 files changed

+325
-13
lines changed

components/vercel_token_auth/actions/cancel-deployment/cancel-deployment.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default {
44
key: "vercel_token_auth-cancel-deployment",
55
name: "Cancel Deployment",
66
description: "Cancel a deployment which is currently building. [See the documentation](https://vercel.com/docs/rest-api/endpoints/deployments#cancel-a-deployment)",
7-
version: "0.0.4",
7+
version: "0.0.5",
88
type: "action",
99
props: {
1010
vercelTokenAuth,

components/vercel_token_auth/actions/create-deployment/create-deployment.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default {
55
key: "vercel_token_auth-create-deployment",
66
name: "Create Deployment",
77
description: "Create a new deployment from a GitHub repository. [See the documentation](https://vercel.com/docs/rest-api/endpoints/deployments#create-a-new-deployment)",
8-
version: "0.0.4",
8+
version: "0.0.5",
99
type: "action",
1010
props: {
1111
vercelTokenAuth,

components/vercel_token_auth/actions/list-deployments/list-deployments.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default {
44
key: "vercel_token_auth-list-deployments",
55
name: "List Deployments",
66
description: "List deployments under the account corresponding to the API token. [See the documentation](https://vercel.com/docs/rest-api/endpoints/deployments#list-deployments)",
7-
version: "0.0.4",
7+
version: "0.0.5",
88
type: "action",
99
props: {
1010
vercelTokenAuth,

components/vercel_token_auth/common/constants.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ export default {
99
"READY",
1010
"CANCELED",
1111
],
12+
WEBHOOK_ID: "webhookId",
13+
WEBHOOK_SECRET: "webhookSecret",
1214
};

components/vercel_token_auth/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pipedream/vercel_token_auth",
3-
"version": "0.0.5",
3+
"version": "0.1.0",
44
"description": "Pipedream Vercel (token-based auth) Components",
55
"main": "vercel_token_auth.app.mjs",
66
"keywords": [
@@ -13,6 +13,7 @@
1313
"access": "public"
1414
},
1515
"dependencies": {
16-
"@pipedream/platform": "^3.0.3"
16+
"@pipedream/platform": "^3.0.3",
17+
"crypto": "^1.0.1"
1718
}
1819
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
export default {
2+
BUDGET_REACHED: "budget.reached",
3+
BUDGET_RESET: "budget.reset",
4+
DOMAIN_CREATED: "domain.created",
5+
DEPLOYMENT_CREATED: "deployment.created",
6+
DEPLOYMENT_ERROR: "deployment.error",
7+
DEPLOYMENT_CANCELED: "deployment.canceled",
8+
DEPLOYMENT_SUCCEEDED: "deployment.succeeded",
9+
DEPLOYMENT_READY: "deployment.ready",
10+
DEPLOYMENT_CHECK_REREQUESTED: "deployment.check-rerequested",
11+
DEPLOYMENT_PROMOTED: "deployment.promoted",
12+
DEPLOYMENT_INTEGRATION_ACTION_START: "deployment.integration.action.start",
13+
DEPLOYMENT_INTEGRATION_ACTION_CANCEL: "deployment.integration.action.cancel",
14+
DEPLOYMENT_INTEGRATION_ACTION_CLEANUP: "deployment.integration.action.cleanup",
15+
EDGE_CONFIG_CREATED: "edge-config.created",
16+
EDGE_CONFIG_DELETED: "edge-config.deleted",
17+
EDGE_CONFIG_ITEMS_UPDATED: "edge-config.items.updated",
18+
FIREWALL_ATTACK: "firewall.attack",
19+
INTEGRATION_CONFIGURATION_PERMISSION_UPGRADED: "integration-configuration.permission-upgraded",
20+
INTEGRATION_CONFIGURATION_REMOVED: "integration-configuration.removed",
21+
INTEGRATION_CONFIGURATION_SCOPE_CHANGE_CONFIRMED: "integration-configuration.scope-change-confirmed",
22+
INTEGRATION_RESOURCE_PROJECT_CONNECTED: "integration-resource.project-connected",
23+
INTEGRATION_RESOURCE_PROJECT_DISCONNECTED: "integration-resource.project-disconnected",
24+
PROJECT_CREATED: "project.created",
25+
PROJECT_REMOVED: "project.removed",
26+
DEPLOYMENT_CHECKS_COMPLETED: "deployment-checks-completed",
27+
DEPLOYMENT_READY_: "deployment-ready",
28+
DEPLOYMENT_PREPARED: "deployment-prepared",
29+
DEPLOYMENT_ERROR_: "deployment-error",
30+
DEPLOYMENT_CHECK_REREQUESTED_: "deployment-check-rerequested",
31+
DEPLOYMENT_CANCELED_: "deployment-canceled",
32+
PROJECT_CREATED_: "project-created",
33+
PROJECT_REMOVED_: "project-removed",
34+
DOMAIN_CREATED_: "domain-created",
35+
DEPLOYMENT_: "deployment",
36+
INTEGRATION_CONFIGURATION_PERMISSION_UPDATED: "integration-configuration-permission-updated",
37+
INTEGRATION_CONFIGURATION_REMOVED_: "integration-configuration-removed",
38+
INTEGRATION_CONFIGURATION_SCOPE_CHANGE_CONFIRMED_: "integration-configuration-scope-change-confirmed",
39+
MARKETPLACE_INVOICE_CREATED: "marketplace.invoice.created",
40+
MARKETPLACE_INVOICE_PAID: "marketplace.invoice.paid",
41+
MARKETPLACE_INVOICE_NOTPAID: "marketplace.invoice.notpaid",
42+
MARKETPLACE_INVOICE_REFUNDED: "marketplace.invoice.refunded",
43+
OBSERVABILITY_ANOMALY: "observability.anomaly",
44+
TEST_WEBHOOK: "test-webhook",
45+
};
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import { createHmac } from "crypto";
2+
import { ConfigurationError } from "@pipedream/platform";
3+
import app from "../../vercel_token_auth.app.mjs";
4+
import constants from "../../common/constants.mjs";
5+
6+
export default {
7+
props: {
8+
app,
9+
db: "$.service.db",
10+
http: "$.interface.http",
11+
teamId: {
12+
label: "Team ID",
13+
description: "The Team identifier to perform the request on behalf of. Eg. `team_1a2b3c4d5e6f7g8h9i0j1k2l`",
14+
optional: true,
15+
propDefinition: [
16+
app,
17+
"team",
18+
],
19+
},
20+
slug: {
21+
label: "Slug",
22+
description: "The Team slug to perform the request on behalf of. Eg. `my-team-url-slug`",
23+
optional: true,
24+
propDefinition: [
25+
app,
26+
"team",
27+
() => ({
28+
mapper: ({ slug }) => slug,
29+
}),
30+
],
31+
},
32+
projectIds: {
33+
type: "string[]",
34+
label: "Project IDs",
35+
description: "The Project identifiers to perform the request on behalf of",
36+
optional: true,
37+
propDefinition: [
38+
app,
39+
"project",
40+
],
41+
},
42+
},
43+
hooks: {
44+
async activate() {
45+
const {
46+
createWebhook,
47+
getEvents,
48+
http: { endpoint: url },
49+
setWebhookId,
50+
setWebhookSecret,
51+
teamId,
52+
slug,
53+
projectIds,
54+
} = this;
55+
56+
const response =
57+
await createWebhook({
58+
params: {
59+
teamId,
60+
slug,
61+
},
62+
data: {
63+
url,
64+
events: getEvents(),
65+
projectIds,
66+
},
67+
});
68+
69+
setWebhookId(response.id);
70+
setWebhookSecret(response.secret);
71+
},
72+
async deactivate() {
73+
const {
74+
deleteWebhook,
75+
getWebhookId,
76+
} = this;
77+
78+
const webhookId = getWebhookId();
79+
if (webhookId) {
80+
await deleteWebhook({
81+
webhookId,
82+
});
83+
}
84+
},
85+
},
86+
methods: {
87+
generateMeta() {
88+
throw new ConfigurationError("generateMeta is not implemented");
89+
},
90+
setWebhookId(value) {
91+
this.db.set(constants.WEBHOOK_ID, value);
92+
},
93+
getWebhookId() {
94+
return this.db.get(constants.WEBHOOK_ID);
95+
},
96+
setWebhookSecret(value) {
97+
this.db.set(constants.WEBHOOK_SECRET, value);
98+
},
99+
getWebhookSecret() {
100+
return this.db.get(constants.WEBHOOK_SECRET);
101+
},
102+
getEvents() {
103+
throw new ConfigurationError("getEvents is not implemented");
104+
},
105+
isSignatureValid(incommingSignature, bodyRaw) {
106+
const secret = this.getWebhookSecret();
107+
const rawBodyBuffer = Buffer.from(bodyRaw, "utf-8");
108+
const expectedSignature =
109+
createHmac("sha1", secret)
110+
.update(rawBodyBuffer)
111+
.digest("hex");
112+
return expectedSignature === incommingSignature;
113+
},
114+
processResource(resource) {
115+
this.$emit(resource, this.generateMeta(resource));
116+
},
117+
createWebhook(args = {}) {
118+
return this.app.makeRequest({
119+
method: "POST",
120+
endpoint: "v1/webhooks",
121+
...args,
122+
});
123+
},
124+
deleteWebhook({
125+
webhookId, ...args
126+
} = {}) {
127+
return this.app.makeRequest({
128+
method: "DELETE",
129+
endpoint: `v1/webhooks/${webhookId}`,
130+
...args,
131+
});
132+
},
133+
},
134+
async run({
135+
body, bodyRaw, headers,
136+
}) {
137+
const incommingSignature = headers["x-vercel-signature"];
138+
139+
if (!incommingSignature) {
140+
throw new ConfigurationError("Missing x-vercel-signature header");
141+
}
142+
143+
const isValid = this.isSignatureValid(incommingSignature, bodyRaw);
144+
145+
if (!isValid) {
146+
throw new ConfigurationError("Invalid x-vercel-signature header");
147+
}
148+
149+
this.processResource(body);
150+
},
151+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import common from "../common/webhook.mjs";
2+
import events from "../common/events.mjs";
3+
4+
export default {
5+
...common,
6+
key: "vercel_token_auth-deployment-canceled-instant",
7+
name: "Deployment Canceled (Instant)",
8+
description: "Emit new event when a deployment is canceled [See the documentation](https://vercel.com/docs/rest-api/reference/endpoints/webhooks/creates-a-webhook).",
9+
type: "source",
10+
version: "0.0.1",
11+
dedupe: "unique",
12+
methods: {
13+
...common.methods,
14+
getEvents() {
15+
return [
16+
events.DEPLOYMENT_CANCELED,
17+
];
18+
},
19+
generateMeta(resource) {
20+
return {
21+
id: resource.id,
22+
summary: `Deployment Canceled: ${resource.id}`,
23+
ts: resource.createdAt,
24+
};
25+
},
26+
},
27+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import common from "../common/webhook.mjs";
2+
import events from "../common/events.mjs";
3+
4+
export default {
5+
...common,
6+
key: "vercel_token_auth-deployment-error-instant",
7+
name: "Deployment Error (Instant)",
8+
description: "Emit new event when a deployment encounters an error [See the documentation](https://vercel.com/docs/rest-api/reference/endpoints/webhooks/creates-a-webhook).",
9+
type: "source",
10+
version: "0.0.1",
11+
dedupe: "unique",
12+
methods: {
13+
...common.methods,
14+
getEvents() {
15+
return [
16+
events.DEPLOYMENT_ERROR,
17+
];
18+
},
19+
generateMeta(resource) {
20+
return {
21+
id: resource.id,
22+
summary: `Deployment Error: ${resource.id}`,
23+
ts: resource.createdAt,
24+
};
25+
},
26+
},
27+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import common from "../common/webhook.mjs";
2+
import events from "../common/events.mjs";
3+
4+
export default {
5+
...common,
6+
key: "vercel_token_auth-deployment-succeeded-instant",
7+
name: "Deployment Succeeded (Instant)",
8+
description: "Emit new event when a deployment successfully completes [See the documentation](https://vercel.com/docs/rest-api/reference/endpoints/webhooks/creates-a-webhook).",
9+
type: "source",
10+
version: "0.0.1",
11+
dedupe: "unique",
12+
methods: {
13+
...common.methods,
14+
getEvents() {
15+
return [
16+
events.DEPLOYMENT_SUCCEEDED,
17+
];
18+
},
19+
generateMeta(resource) {
20+
return {
21+
id: resource.id,
22+
summary: `Deployment Succeeded: ${resource.id}`,
23+
ts: resource.createdAt,
24+
};
25+
},
26+
},
27+
};

0 commit comments

Comments
 (0)