diff --git a/components/salesforge/actions/create-contact/create-contact.mjs b/components/salesforge/actions/create-contact/create-contact.mjs new file mode 100644 index 0000000000000..0b8611f5f4199 --- /dev/null +++ b/components/salesforge/actions/create-contact/create-contact.mjs @@ -0,0 +1,65 @@ +import app from "../../salesforge.app.mjs"; + +export default { + key: "salesforge-create-contact", + name: "Create Contact", + description: "Create a new contact in Salesforge. [See the documentation](https://api.salesforge.ai/public/v2/swagger/index.html)", + version: "0.0.1", + type: "action", + props: { + app, + workspaceId: { + propDefinition: [ + app, + "workspaceId", + ], + }, + email: { + type: "string", + label: "Email", + description: "The email address of the contact", + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the contact", + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the contact", + }, + company: { + type: "string", + label: "Company", + description: "The company name of the contact", + optional: true, + }, + linkedinUrl: { + type: "string", + label: "LinkedIn URL", + description: "The LinkedIn profile URL of the contact", + optional: true, + }, + tags: { + type: "string[]", + label: "Tags", + description: "One or more tags to assign to the contact", + optional: true, + }, + }, + async run({ $ }) { + const { + app, workspaceId, ...data + } = this; + + const response = await app.createContact({ + $, + workspaceId, + data, + }); + + $.export("$summary", `Successfully created contact (ID: ${response.id})`); + return response; + }, +}; diff --git a/components/salesforge/package.json b/components/salesforge/package.json index b6f067c9bdf29..ceefb7a33f4ed 100644 --- a/components/salesforge/package.json +++ b/components/salesforge/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/salesforge", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Salesforge Components", "main": "salesforge.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } -} \ No newline at end of file +} diff --git a/components/salesforge/salesforge.app.mjs b/components/salesforge/salesforge.app.mjs index 0efa5793bc144..93758fdb216a8 100644 --- a/components/salesforge/salesforge.app.mjs +++ b/components/salesforge/salesforge.app.mjs @@ -1,11 +1,75 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "salesforge", - propDefinitions: {}, + propDefinitions: { + workspaceId: { + type: "string", + label: "Workspace ID", + description: "Select a workspace or provide a workspace ID", + async options({ page }) { + const response = await this.listWorkspaces({ + params: { + offset: page, + }, + }); + return response.data?.map((workspace) => ({ + label: workspace.name, + value: workspace.id, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _apiUrl() { + return "https://api.salesforge.ai/public/v2"; + }, + async _makeRequest({ + $ = this, + path, + ...args + }) { + return axios($, { + url: `${this._apiUrl()}${path}`, + headers: { + "Authorization": `${this.$auth.api_key}`, + }, + ...args, + }); + }, + async listWorkspaces(args = {}) { + return this._makeRequest({ + path: "/workspaces", + ...args, + }); + }, + async createWebhook({ + workspaceId, ...args + }) { + return this._makeRequest({ + path: `/workspaces/${workspaceId}/integrations/webhooks`, + method: "POST", + ...args, + }); + }, + async deleteWebhook({ + workspaceId, webhookId, ...args + }) { + return this._makeRequest({ + path: `/workspaces/${workspaceId}/integrations/webhooks/${webhookId}`, + method: "DELETE", + ...args, + }); + }, + async createContact({ + workspaceId, ...args + }) { + return this._makeRequest({ + path: `/workspaces/${workspaceId}/contacts`, + method: "POST", + ...args, + }); }, }, }; diff --git a/components/salesforge/sources/common/webhook.mjs b/components/salesforge/sources/common/webhook.mjs new file mode 100644 index 0000000000000..9773f45eec412 --- /dev/null +++ b/components/salesforge/sources/common/webhook.mjs @@ -0,0 +1,56 @@ +import salesforge from "../../salesforge.app.mjs"; + +export default { + props: { + salesforge, + db: "$.service.db", + http: "$.interface.http", + workspaceId: { + propDefinition: [ + salesforge, + "workspaceId", + ], + }, + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(webhookId) { + this.db.set("webhookId", webhookId); + }, + generateMeta(data) { + const { webhookInfo } = data; + const ts = webhookInfo?.eventTime + ? new Date(webhookInfo.eventTime).valueOf() + : Date.now(); + const id = `${this.getEventType()}-${ts}`; + return { + id, + summary: this.getSummary(data), + ts, + }; + }, + }, + hooks: { + async activate() { + const response = await this.salesforge.createWebhook({ + workspaceId: this.workspaceId, + data: { + name: `Pipedream ${this.getEventType()} webhook`, + type: this.getEventType(), + url: this.http.endpoint, + }, + }); + this._setWebhookId(response.id); + }, + // Salesforge does not seem to support deactivating/deleting webhooks via the API + }, + async run(event) { + const { body } = event; + if (body) { + const meta = this.generateMeta(body); + this.$emit(body, meta); + } + }, +}; diff --git a/components/salesforge/sources/contact-unsubscribed-instant/contact-unsubscribed-instant.mjs b/components/salesforge/sources/contact-unsubscribed-instant/contact-unsubscribed-instant.mjs new file mode 100644 index 0000000000000..296e60262a155 --- /dev/null +++ b/components/salesforge/sources/contact-unsubscribed-instant/contact-unsubscribed-instant.mjs @@ -0,0 +1,20 @@ +import common from "../common/webhook.mjs"; + +export default { + ...common, + key: "salesforge-contact-unsubscribed-instant", + name: "Contact Unsubscribed (Instant)", + description: "Emit new event when a contact unsubscribes in Salesforge. [See the documentation](https://help.salesforge.ai/en/articles/8680365-how-to-use-webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "contact_unsubscribed"; + }, + getSummary({ contact }) { + return `Contact unsubscribed: ${contact?.email || "unknown contact"}`; + }, + }, +}; diff --git a/components/salesforge/sources/email-bounced-instant/email-bounced-instant.mjs b/components/salesforge/sources/email-bounced-instant/email-bounced-instant.mjs new file mode 100644 index 0000000000000..270a29cadb43a --- /dev/null +++ b/components/salesforge/sources/email-bounced-instant/email-bounced-instant.mjs @@ -0,0 +1,20 @@ +import common from "../common/webhook.mjs"; + +export default { + ...common, + key: "salesforge-email-bounced-instant", + name: "Email Bounced (Instant)", + description: "Emit new event when an email bounces in Salesforge. [See the documentation](https://help.salesforge.ai/en/articles/8680365-how-to-use-webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "email_bounced"; + }, + getSummary({ contact }) { + return `Email bounced to ${contact?.email || "unknown recipient"}`; + }, + }, +}; diff --git a/components/salesforge/sources/email-opened-instant/email-opened-instant.mjs b/components/salesforge/sources/email-opened-instant/email-opened-instant.mjs new file mode 100644 index 0000000000000..cbd05d6fa42dc --- /dev/null +++ b/components/salesforge/sources/email-opened-instant/email-opened-instant.mjs @@ -0,0 +1,20 @@ +import common from "../common/webhook.mjs"; + +export default { + ...common, + key: "salesforge-email-opened-instant", + name: "Email Opened (Instant)", + description: "Emit new event when an email is opened in Salesforge. [See the documentation](https://help.salesforge.ai/en/articles/8680365-how-to-use-webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "email_opened"; + }, + getSummary({ sequenceEmail }) { + return `Email opened: "${sequenceEmail?.subject}"`; + }, + }, +}; diff --git a/components/salesforge/sources/email-replied-instant/email-replied-instant.mjs b/components/salesforge/sources/email-replied-instant/email-replied-instant.mjs new file mode 100644 index 0000000000000..1192be30e897b --- /dev/null +++ b/components/salesforge/sources/email-replied-instant/email-replied-instant.mjs @@ -0,0 +1,20 @@ +import common from "../common/webhook.mjs"; + +export default { + ...common, + key: "salesforge-email-replied-instant", + name: "Email Reply Received (Instant)", + description: "Emit new event when an email reply is received in Salesforge. [See the documentation](https://help.salesforge.ai/en/articles/8680365-how-to-use-webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "email_replied"; + }, + getSummary({ sequenceEmail }) { + return `Email reply received: "${sequenceEmail?.subject}"`; + }, + }, +}; diff --git a/components/salesforge/sources/email-sent-instant/email-sent-instant.mjs b/components/salesforge/sources/email-sent-instant/email-sent-instant.mjs new file mode 100644 index 0000000000000..639aedbab8250 --- /dev/null +++ b/components/salesforge/sources/email-sent-instant/email-sent-instant.mjs @@ -0,0 +1,20 @@ +import common from "../common/webhook.mjs"; + +export default { + ...common, + key: "salesforge-email-sent-instant", + name: "Email Sent (Instant)", + description: "Emit new event when an email is sent in Salesforge. [See the documentation](https://help.salesforge.ai/en/articles/8680365-how-to-use-webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "email_sent"; + }, + getSummary({ sequenceEmail }) { + return `Email sent: "${sequenceEmail?.subject}"`; + }, + }, +}; diff --git a/components/salesforge/sources/link-clicked-instant/link-clicked-instant.mjs b/components/salesforge/sources/link-clicked-instant/link-clicked-instant.mjs new file mode 100644 index 0000000000000..fddd49f33e142 --- /dev/null +++ b/components/salesforge/sources/link-clicked-instant/link-clicked-instant.mjs @@ -0,0 +1,22 @@ +import common from "../common/webhook.mjs"; + +export default { + ...common, + key: "salesforge-link-clicked-instant", + name: "Link Clicked (Instant)", + description: "Emit new event when a link is clicked in Salesforge. [See the documentation](https://help.salesforge.ai/en/articles/8680365-how-to-use-webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "link_clicked"; + }, + getSummary({ + sequenceEmail, linkUrl, + }) { + return `Link clicked: ${linkUrl} in "${sequenceEmail?.subject}"`; + }, + }, +}; diff --git a/components/salesforge/sources/negative-reply-instant/negative-reply-instant.mjs b/components/salesforge/sources/negative-reply-instant/negative-reply-instant.mjs new file mode 100644 index 0000000000000..d7d9f2514c89b --- /dev/null +++ b/components/salesforge/sources/negative-reply-instant/negative-reply-instant.mjs @@ -0,0 +1,20 @@ +import common from "../common/webhook.mjs"; + +export default { + ...common, + key: "salesforge-negative-reply-instant", + name: "Negative Reply Received (Instant)", + description: "Emit new event when a negative reply is received in Salesforge. [See the documentation](https://help.salesforge.ai/en/articles/8680365-how-to-use-webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "negative_reply"; + }, + getSummary({ contact }) { + return `Negative reply received from ${contact?.email || "unknown contact"}`; + }, + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e1b833f216ee4..82b7de1387b9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11656,7 +11656,11 @@ importers: specifier: ^9.0.1 version: 9.0.1 - components/salesforge: {} + components/salesforge: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/saleslens: dependencies: @@ -15832,14 +15836,6 @@ importers: specifier: ^6.0.0 version: 6.2.0 - modelcontextprotocol/node_modules2/@modelcontextprotocol/sdk/dist/cjs: {} - - modelcontextprotocol/node_modules2/@modelcontextprotocol/sdk/dist/esm: {} - - modelcontextprotocol/node_modules2/zod-to-json-schema/dist/cjs: {} - - modelcontextprotocol/node_modules2/zod-to-json-schema/dist/esm: {} - packages/ai: dependencies: '@pipedream/sdk': @@ -36200,7 +36196,7 @@ snapshots: '@pipedream/shopify@0.7.0': dependencies: - '@pipedream/platform': 3.0.3 + '@pipedream/platform': 3.1.0 async-retry: 1.3.3 bottleneck: 2.19.5 form-data: 4.0.2