diff --git a/components/heroku/common/constants.mjs b/components/heroku/common/constants.mjs new file mode 100644 index 0000000000000..c446d21da03ca --- /dev/null +++ b/components/heroku/common/constants.mjs @@ -0,0 +1,46 @@ +const ENTITIES = [ + { + value: "api:addon-attachment", + label: "addon-attachment - An add-on has been attached or removed from the app", + }, + { + value: "api:addon", + label: "addon - An add-on for the app has been newly provisioned or deleted, or its details have been modified", + }, + { + value: "api:app", + label: "app - The app itself has been provisioned or deleted, or its details have been modified", + }, + { + value: "api:build", + label: "build - A new build for the app has been initiated or the build’s status has changed since the last notification", + }, + { + value: "api:collaborator", + label: "collaborator - A collaborator has been added or removed from the app, or an existing collaborator’s details have been modified", + }, + { + value: "api:domain", + label: "domain - Custom domain details have been added or removed from the app", + }, + { + value: "api:dyno", + label: "dyno - A new dyno has begun running for the app", + }, + { + value: "api:formation", + label: "formation - The dyno formation for a particular process type has been modified", + }, + { + value: "api:release", + label: "release - A new release for the app has been initiated or the release’s status has changed since the last notification", + }, + { + value: "api:sni-endpoint", + label: "sni-endpoint - An SNI endpoint has been specified or removed for the app, or the existing SNI endpoint’s details have been modified", + }, +]; + +export default { + ENTITIES, +}; diff --git a/components/heroku/heroku.app.mjs b/components/heroku/heroku.app.mjs index f6921cc192a59..c994c684b3f58 100644 --- a/components/heroku/heroku.app.mjs +++ b/components/heroku/heroku.app.mjs @@ -1,11 +1,71 @@ +import { axios } from "@pipedream/platform"; +import constants from "./common/constants.mjs"; + export default { type: "app", app: "heroku", - propDefinitions: {}, + propDefinitions: { + appId: { + type: "string", + label: "App ID", + description: "The ID of the app", + async options() { + const apps = await this.listApps(); + return apps?.map((app) => ({ + label: app.name, + value: app.id, + })) || []; + }, + }, + entities: { + type: "string[]", + label: "Entities", + description: "The entity or entities to subscribe to", + options: constants.ENTITIES, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.heroku.com"; + }, + _makeRequest(opts = {}) { + const { + $ = this, + path, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + url: `${this._baseUrl()}${path}`, + headers: { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + Accept: "application/vnd.heroku+json; version=3", + }, + }); + }, + listApps(opts = {}) { + return this._makeRequest({ + path: "/apps", + ...opts, + }); + }, + createWebhookSubscription({ + appId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/apps/${appId}/webhooks`, + ...opts, + }); + }, + deleteWebhookSubscription({ + appId, hookId, ...opts + }) { + return this._makeRequest({ + method: "DELETE", + path: `/apps/${appId}/webhooks/${hookId}`, + ...opts, + }); }, }, }; diff --git a/components/heroku/package.json b/components/heroku/package.json new file mode 100644 index 0000000000000..ad831ce609311 --- /dev/null +++ b/components/heroku/package.json @@ -0,0 +1,18 @@ +{ + "name": "@pipedream/heroku", + "version": "0.0.1", + "description": "Pipedream Heroku Components", + "main": "heroku.app.mjs", + "keywords": [ + "pipedream", + "heroku" + ], + "homepage": "https://pipedream.com/apps/heroku", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" + } +} diff --git a/components/heroku/sources/new-webhook-event-instant/new-webhook-event-instant.mjs b/components/heroku/sources/new-webhook-event-instant/new-webhook-event-instant.mjs new file mode 100644 index 0000000000000..89f2dc4f9b745 --- /dev/null +++ b/components/heroku/sources/new-webhook-event-instant/new-webhook-event-instant.mjs @@ -0,0 +1,74 @@ +import heroku from "../../heroku.app.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + key: "heroku-new-webhook-event-instant", + name: "New Webhook Event (Instant)", + description: "Emit new event on each webhook event. [See the documentation](https://devcenter.heroku.com/articles/app-webhooks-schema#webhook-create)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + heroku, + http: "$.interface.http", + db: "$.service.db", + appId: { + propDefinition: [ + heroku, + "appId", + ], + }, + entities: { + propDefinition: [ + heroku, + "entities", + ], + }, + }, + hooks: { + async activate() { + const { id } = await this.heroku.createWebhookSubscription({ + appId: this.appId, + data: { + include: this.entities, + level: "notify", + url: this.http.endpoint, + }, + }); + this._setHookId(id); + }, + async deactivate() { + const hookId = this._getHookId(); + if (hookId) { + await this.heroku.deleteWebhookSubscription({ + appId: this.appId, + hookId, + }); + } + }, + }, + methods: { + _getHookId() { + return this.db.get("hookId"); + }, + _setHookId(hookId) { + this.db.set("hookId", hookId); + }, + generateMeta(event) { + return { + id: event.id, + summary: `New ${event.webhook_metadata.event.include} - ${event.action} Event`, + ts: Date.now(), + }; + }, + }, + async run(event) { + const { body } = event; + if (!body) { + return; + } + const meta = this.generateMeta(body); + this.$emit(body, meta); + }, + sampleEmit, +}; diff --git a/components/heroku/sources/new-webhook-event-instant/test-event.mjs b/components/heroku/sources/new-webhook-event-instant/test-event.mjs new file mode 100644 index 0000000000000..fa44155a44ad1 --- /dev/null +++ b/components/heroku/sources/new-webhook-event-instant/test-event.mjs @@ -0,0 +1,69 @@ +export default { + "id": "a5b27512-1f14-4f45-bc26-fe6bf03686fe", + "data": { + "id": "9a4eaeed-24cc-4b23-a8ca-7867b251eaf3", + "acm": false, + "name": "", + "team": null, + "owner": { + "id": "7b25912d-b147-48d6-b03d-f0fc72be381b", + "email": "" + }, + "space": null, + "stack": { + "id": "74cfe988-7527-4ca9-9667-77bb9f3029cf", + "name": "heroku-24" + }, + "region": { + "id": "59accabd-516d-4f0e-83e6-6e3757701145", + "name": "us" + }, + "git_url": "", + "web_url": "", + "repo_size": null, + "slug_size": null, + "created_at": "2024-11-07T16:38:38Z", + "updated_at": "2024-11-07T17:14:52Z", + "archived_at": null, + "build_stack": { + "id": "74cfe988-7527-4ca9-9667-77bb9f3029cf", + "name": "heroku-24" + }, + "maintenance": false, + "released_at": "2024-11-07T16:38:39Z", + "organization": null, + "internal_routing": null, + "buildpack_provided_description": null + }, + "actor": { + "id": "7b25912d-b147-48d6-b03d-f0fc72be381b", + "email": "" + }, + "action": "update", + "version": "application/vnd.heroku+json; version=3", + "resource": "app", + "sequence": null, + "created_at": "2024-11-07T17:14:52.475272Z", + "updated_at": "2024-11-07T17:14:52.475276Z", + "published_at": "2024-11-07T17:14:52Z", + "previous_data": { + "name": "", + "git_url": "", + "updated_at": "2024-11-07T17:13:42Z" + }, + "webhook_metadata": { + "attempt": { + "id": "16e90948-01d8-4ba0-97de-5868a4aed0bf" + }, + "delivery": { + "id": "bbf72057-15f2-40b0-87c7-99ccf95e1666" + }, + "event": { + "id": "a5b27512-1f14-4f45-bc26-fe6bf03686fe", + "include": "api:app" + }, + "webhook": { + "id": "c385bb39-42ab-49c6-9255-108ff4cabdbd" + } + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5cc3b372e7b90..a9e691b417e49 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4640,6 +4640,12 @@ importers: dependencies: '@pipedream/platform': 1.6.0 + components/heroku: + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 + components/heygen: specifiers: '@pipedream/platform': ^1.5.1 @@ -13347,6 +13353,55 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sso-oidc/3.600.0_tdq3komn4zwyd65w7klbptsu34: + resolution: {integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.2.1 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.2 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.6 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.2 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + dev: false + /@aws-sdk/client-sso/3.423.0: resolution: {integrity: sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==} engines: {node: '>=14.0.0'} @@ -13582,7 +13637,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 + '@aws-sdk/client-sso-oidc': 3.600.0_tdq3komn4zwyd65w7klbptsu34 '@aws-sdk/core': 3.598.0 '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 '@aws-sdk/middleware-host-header': 3.598.0 @@ -13624,55 +13679,6 @@ packages: - aws-crt dev: false - /@aws-sdk/client-sts/3.600.0_dseaa2p5u2yk67qiepewcq3hkq: - resolution: {integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 - '@aws-sdk/core': 3.598.0 - '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 - '@aws-sdk/middleware-host-header': 3.598.0 - '@aws-sdk/middleware-logger': 3.598.0 - '@aws-sdk/middleware-recursion-detection': 3.598.0 - '@aws-sdk/middleware-user-agent': 3.598.0 - '@aws-sdk/region-config-resolver': 3.598.0 - '@aws-sdk/types': 3.598.0 - '@aws-sdk/util-endpoints': 3.598.0 - '@aws-sdk/util-user-agent-browser': 3.598.0 - '@aws-sdk/util-user-agent-node': 3.598.0 - '@smithy/config-resolver': 3.0.3 - '@smithy/core': 2.2.3 - '@smithy/fetch-http-handler': 3.2.1 - '@smithy/hash-node': 3.0.2 - '@smithy/invalid-dependency': 3.0.2 - '@smithy/middleware-content-length': 3.0.2 - '@smithy/middleware-endpoint': 3.0.4 - '@smithy/middleware-retry': 3.0.6 - '@smithy/middleware-serde': 3.0.3 - '@smithy/middleware-stack': 3.0.3 - '@smithy/node-config-provider': 3.1.3 - '@smithy/node-http-handler': 3.1.2 - '@smithy/protocol-http': 4.0.3 - '@smithy/smithy-client': 3.1.6 - '@smithy/types': 3.3.0 - '@smithy/url-parser': 3.0.3 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.6 - '@smithy/util-defaults-mode-node': 3.0.6 - '@smithy/util-endpoints': 2.0.3 - '@smithy/util-middleware': 3.0.3 - '@smithy/util-retry': 3.0.2 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - dev: false - /@aws-sdk/core/3.556.0: resolution: {integrity: sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==} engines: {node: '>=14.0.0'} @@ -18016,7 +18022,7 @@ packages: '@aws-sdk/client-sns': 3.423.0 '@aws-sdk/client-sqs': 3.423.0 '@aws-sdk/client-ssm': 3.423.0 - '@aws-sdk/client-sts': 3.600.0_dseaa2p5u2yk67qiepewcq3hkq + '@aws-sdk/client-sts': 3.600.0 '@aws-sdk/s3-request-presigner': 3.609.0 '@pipedream/helper_functions': 0.3.12 '@pipedream/platform': 1.6.6