From 591409393d79548cc44172a92530cddbc14bbeb0 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 28 May 2025 16:52:02 -0300 Subject: [PATCH 1/7] icontact init --- .../actions/create-contact/create-contact.mjs | 51 ++++++ .../actions/create-message/create-message.mjs | 49 +++++ .../subscribe-contact-list.mjs | 34 ++++ components/icontact/app/icontact.app.ts | 2 +- components/icontact/icontact.app.mjs | 167 ++++++++++++++++++ .../contact-subscribed-instant.mjs | 113 ++++++++++++ .../new-contact-instant.mjs | 81 +++++++++ .../updated-contact-instant.mjs | 104 +++++++++++ 8 files changed, 600 insertions(+), 1 deletion(-) create mode 100644 components/icontact/actions/create-contact/create-contact.mjs create mode 100644 components/icontact/actions/create-message/create-message.mjs create mode 100644 components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs create mode 100644 components/icontact/icontact.app.mjs create mode 100644 components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs create mode 100644 components/icontact/sources/new-contact-instant/new-contact-instant.mjs create mode 100644 components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs diff --git a/components/icontact/actions/create-contact/create-contact.mjs b/components/icontact/actions/create-contact/create-contact.mjs new file mode 100644 index 0000000000000..c60a13d9ae11e --- /dev/null +++ b/components/icontact/actions/create-contact/create-contact.mjs @@ -0,0 +1,51 @@ +import icontact from "../../icontact.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "icontact-create-contact", + name: "Create Contact", + description: "Creates a new contact within the iContact account. [See the documentation](https://help.icontact.com/customers/s/article/contacts-icontact-api)", + version: "0.0.1", + type: "action", + props: { + icontact, + contactEmail: { + propDefinition: [ + icontact, + "contactEmail", + ], + }, + contactInfo: { + propDefinition: [ + icontact, + "contactInfo", + ], + optional: true, + }, + firstName: { + propDefinition: [ + icontact, + "firstName", + ], + optional: true, + }, + lastName: { + propDefinition: [ + icontact, + "lastName", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.icontact.createContact({ + contactEmail: this.contactEmail, + contactInfo: this.contactInfo || {}, + firstName: this.firstName, + lastName: this.lastName, + }); + + $.export("$summary", `Successfully created contact with email ${this.contactEmail}`); + return response; + }, +}; diff --git a/components/icontact/actions/create-message/create-message.mjs b/components/icontact/actions/create-message/create-message.mjs new file mode 100644 index 0000000000000..a81a41ad4a904 --- /dev/null +++ b/components/icontact/actions/create-message/create-message.mjs @@ -0,0 +1,49 @@ +import icontact from "../../icontact.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "icontact-create-message", + name: "Create and Dispatch Message", + description: "Creates and dispatches a new message using custom HTML. [See the documentation](https://help.icontact.com/customers/s/article/messages-icontact-api)", + version: "0.0.{{ts}}", + type: "action", + props: { + icontact, + recipientEmail: { + propDefinition: [ + icontact, + "recipientEmail", + ], + }, + senderEmail: { + propDefinition: [ + icontact, + "senderEmail", + ], + }, + htmlContent: { + propDefinition: [ + icontact, + "htmlContent", + ], + }, + subject: { + propDefinition: [ + icontact, + "subject", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.icontact.createAndSendMessage({ + recipientEmail: this.recipientEmail, + senderEmail: this.senderEmail, + htmlContent: this.htmlContent, + subject: this.subject, + }); + + $.export("$summary", `Message sent successfully to ${this.recipientEmail}`); + return response; + }, +}; diff --git a/components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs b/components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs new file mode 100644 index 0000000000000..be911fe282fed --- /dev/null +++ b/components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs @@ -0,0 +1,34 @@ +import icontact from "../../icontact.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "icontact-subscribe-contact-list", + name: "Subscribe Contact to List", + description: "Adds a contact to a specific list within iContact. [See the documentation](https://help.icontact.com/customers/s/article/subscriptions-icontact-api)", + version: "0.0.{{ts}}", + type: "action", + props: { + icontact, + contactEmail: { + propDefinition: [ + icontact, + "contactEmail", + ], + }, + listId: { + propDefinition: [ + icontact, + "listId", + ], + }, + }, + async run({ $ }) { + const response = await this.icontact.subscribeContactToList({ + contactEmail: this.contactEmail, + listId: this.listId, + }); + + $.export("$summary", `Successfully subscribed ${this.contactEmail} to list with ID ${this.listId}`); + return response; + }, +}; diff --git a/components/icontact/app/icontact.app.ts b/components/icontact/app/icontact.app.ts index 09268f74246d3..c5260310ecbdf 100644 --- a/components/icontact/app/icontact.app.ts +++ b/components/icontact/app/icontact.app.ts @@ -10,4 +10,4 @@ export default defineApp({ console.log(Object.keys(this.$auth)); }, }, -}); \ No newline at end of file +}); diff --git a/components/icontact/icontact.app.mjs b/components/icontact/icontact.app.mjs new file mode 100644 index 0000000000000..854a9a04eb9d4 --- /dev/null +++ b/components/icontact/icontact.app.mjs @@ -0,0 +1,167 @@ +import { axios } from "@pipedream/platform"; + +export default { + type: "app", + app: "icontact", + propDefinitions: { + contactEmail: { + type: "string", + label: "Contact Email", + description: "The email of the contact", + }, + contactInfo: { + type: "object", + label: "Contact Information", + description: "Additional information for the contact", + }, + contactId: { + type: "string", + label: "Contact ID", + description: "The ID of the contact", + }, + listId: { + type: "string", + label: "List ID", + description: "The ID of the list", + async options() { + const lists = await this.getLists(); + return lists.map((list) => ({ + label: list.name, + value: list.id, + })); + }, + }, + senderEmail: { + type: "string", + label: "Sender Email", + description: "The email of the sender", + }, + recipientEmail: { + type: "string", + label: "Recipient Email", + description: "The email of the recipient", + }, + htmlContent: { + type: "string", + label: "HTML Content", + description: "The HTML content for the message", + }, + subject: { + type: "string", + label: "Subject", + description: "The subject of the message", + optional: true, + }, + firstName: { + type: "string", + label: "First Name", + description: "The contact's first name", + optional: true, + }, + lastName: { + type: "string", + label: "Last Name", + description: "The contact's last name", + optional: true, + }, + }, + methods: { + _baseUrl() { + return "https://api.icontact.com/v2.0"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, + method = "GET", + path = "/", + headers = {}, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + "Content-Type": "application/json", + "Authorization": `Bearer ${this.$auth.api_key}`, + }, + }); + }, + async getLists(opts = {}) { + return this._makeRequest({ + path: "/lists", + ...opts, + }); + }, + async createContact({ + contactEmail, contactInfo, firstName, lastName, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: "/contacts", + data: { + email: contactEmail, + firstName, + lastName, + ...contactInfo, + }, + ...opts, + }); + }, + async updateContact({ + contactId, contactInfo, ...opts + }) { + return this._makeRequest({ + method: "PUT", + path: `/contacts/${contactId}`, + data: contactInfo, + ...opts, + }); + }, + async subscribeContactToList({ + contactEmail, listId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/lists/${listId}/contacts`, + data: { + email: contactEmail, + }, + ...opts, + }); + }, + async createAndSendMessage({ + recipientEmail, + senderEmail, + htmlContent, + subject, + ...opts + }) { + return this._makeRequest({ + method: "POST", + path: "/messages", + data: { + recipient: recipientEmail, + sender: senderEmail, + message: { + body: htmlContent, + subject, + }, + }, + ...opts, + }); + }, + }, + hooks: { + async contactCreated() { + // Emit a new event when a contact is created. + }, + async contactUpdated() { + // Emit a new event when a contact is updated. + }, + async contactSubscribed() { + // Emit a new event when a contact is subscribed to a list. + }, + }, +}; diff --git a/components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs b/components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs new file mode 100644 index 0000000000000..1c4de0a5ab609 --- /dev/null +++ b/components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs @@ -0,0 +1,113 @@ +import icontact from "../../icontact.app.mjs"; +import crypto from "crypto"; +import { axios } from "@pipedream/platform"; + +export default { + key: "icontact-contact-subscribed-instant", + name: "New Contact Subscribed", + description: "Emit new event when a contact is subscribed to a list. [See the documentation](https://help.icontact.com/customers/s/article/web-hooks-icontact-api)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + icontact: { + type: "app", + app: "icontact", + }, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + listId: { + propDefinition: [ + icontact, + "listId", + ], + }, + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + _computeSignature(secretKey, rawBody) { + return crypto.createHmac("sha256", secretKey).update(rawBody) + .digest("base64"); + }, + }, + hooks: { + async deploy() { + const contacts = await this.icontact._makeRequest({ + path: `/lists/${this.listId}/contacts`, + }); + let count = 0; + for (const contact of contacts.reverse()) { + if (count < 50) { + this.$emit(contact, { + id: contact.contactId, + summary: `New subscription: ${contact.email}`, + ts: Date.parse(contact.subscribedAt), + }); + count++; + } else { + break; + } + } + }, + async activate() { + const webhook = await this.icontact._makeRequest({ + method: "POST", + path: "/webhooks", + data: { + eventType: "contact_subscribed", + targetUrl: this.http.endpoint, + triggerEvent: this.listId, + }, + }); + this._setWebhookId(webhook.id); + }, + async deactivate() { + const webhookId = this._getWebhookId(); + if (webhookId) { + await this.icontact._makeRequest({ + method: "DELETE", + path: `/webhooks/${webhookId}`, + }); + this._setWebhookId(null); + } + }, + }, + async run(event) { + const signature = event.headers["x-icontact-signature"]; + const secretKey = this.icontact.$auth.api_key; + const rawBody = event.body_raw; + const computedSignature = this._computeSignature(secretKey, rawBody); + + if (signature !== computedSignature) { + this.http.respond({ + status: 401, + body: "Unauthorized", + }); + return; + } + + const contact = event.body.contact; + const listId = this.listId; + + if (event.body.type === "contact_subscribed" && event.body.listId === listId) { + this.$emit(contact, { + id: contact.contactId, + summary: `Contact subscribed: ${contact.email}`, + ts: Date.parse(event.body.timestamp), + }); + } + + this.http.respond({ + status: 200, + body: "OK", + }); + }, +}; diff --git a/components/icontact/sources/new-contact-instant/new-contact-instant.mjs b/components/icontact/sources/new-contact-instant/new-contact-instant.mjs new file mode 100644 index 0000000000000..8e5bc78f351e5 --- /dev/null +++ b/components/icontact/sources/new-contact-instant/new-contact-instant.mjs @@ -0,0 +1,81 @@ +import icontact from "../../icontact.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "icontact-new-contact-instant", + name: "New Contact Created", + description: "Emit new event when a contact is created. [See the documentation](https://help.icontact.com/customers/s/article/web-hooks-icontact-api)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + icontact: { + type: "app", + app: "icontact", + }, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + async _verifySignature(event) { + const computedSignature = require("crypto") + .createHmac("sha256", this.icontact.$auth.api_key) + .update(event.rawBody) + .digest("base64"); + + const webhookSignature = event.headers["x-icontact-signature"]; + return computedSignature === webhookSignature; + }, + }, + hooks: { + async deploy() { + // Implement fetching and emitting historical events if the API supports this + }, + async activate() { + const response = await this.icontact._makeRequest({ + method: "POST", + path: "/webhooks", + data: { + event: "contact.created", + target_url: this.http.endpoint, + }, + }); + this._setWebhookId(response.id); + }, + async deactivate() { + const webhookId = this._getWebhookId(); + if (webhookId) { + await this.icontact._makeRequest({ + method: "DELETE", + path: `/webhooks/${webhookId}`, + }); + this._setWebhookId(null); + } + }, + }, + async run(event) { + if (!await this._verifySignature(event)) { + this.http.respond({ + status: 401, + body: "Unauthorized", + }); + return; + } + + const { data: contact } = event; + this.$emit(contact, { + id: contact.contactId, + summary: `New contact created: ${contact.firstName} ${contact.lastName} (${contact.contactEmail})`, + ts: Date.parse(contact.createdAt), + }); + }, +}; diff --git a/components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs b/components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs new file mode 100644 index 0000000000000..783eb38aebe4d --- /dev/null +++ b/components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs @@ -0,0 +1,104 @@ +import icontact from "../../icontact.app.mjs"; +import crypto from "crypto"; +import { axios } from "@pipedream/platform"; + +export default { + key: "icontact-updated-contact-instant", + name: "Updated Contact Instant", + description: "Emit new event when a contact is updated. [See the documentation](https://help.icontact.com/customers/s/article/web-hooks-icontact-api)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + icontact, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + }, + hooks: { + async deploy() { + // Fetch historical data and emit past events + console.log("Deploying hook to fetch historical contact update data"); + const contacts = await this.icontact.getContacts({ + max: 50, + }); + contacts.forEach((contact) => { + this.$emit(contact, { + id: contact.contactId, + summary: `Contact Updated: ${contact.email}`, + ts: Date.parse(contact.updatedAt), + }); + }); + }, + async activate() { + const opts = { + method: "POST", + path: "/webhooks", + data: { + events: [ + "contact.updated", + ], + target_url: this.http.endpoint, + }, + }; + const response = await this.icontact._makeRequest(opts); + this._setWebhookId(response.id); + }, + async deactivate() { + const webhookId = this._getWebhookId(); + if (webhookId) { + const opts = { + method: "DELETE", + path: `/webhooks/${webhookId}`, + }; + await this.icontact._makeRequest(opts); + } + }, + }, + async run(event) { + const secretKey = this.icontact.$auth.secret; + const rawBody = event.body; + const webhookSignature = event.headers["x-icontact-signature"]; + + const computedSignature = crypto + .createHmac("sha256", secretKey) + .update(rawBody) + .digest("base64"); + + if (computedSignature !== webhookSignature) { + this.http.respond({ + status: 401, + body: "Unauthorized", + }); + return; + } + + this.http.respond({ + status: 200, + body: "OK", + }); + + const data = JSON.parse(rawBody); + const { + contactId, email, updatedAt, + } = data; + + this.$emit(data, { + id: contactId, + summary: `Updated contact: ${email}`, + ts: updatedAt + ? Date.parse(updatedAt) + : Date.now(), + }); + }, +}; From a21a58ce4983a821a56608aee4de21ee220b29c1 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 29 May 2025 14:06:42 -0300 Subject: [PATCH 2/7] [Components] icontact #13263 Sources - New Contact (Instant) - Updated Contact (Instant) - Contact Subscribed (Instant) Actions - Create Contact - Create Message - Subscribe Contact List --- components/icontact/.gitignore | 3 - .../actions/create-contact/create-contact.mjs | 127 +++++++++--- .../actions/create-message/create-message.mjs | 81 +++++--- .../subscribe-contact-list.mjs | 25 ++- components/icontact/app/icontact.app.ts | 13 -- components/icontact/common/constants.mjs | 37 ++++ components/icontact/common/utils.mjs | 10 + components/icontact/icontact.app.mjs | 189 +++++++----------- components/icontact/package.json | 8 +- components/icontact/sources/common/base.mjs | 41 ++++ .../contact-subscribed-instant.mjs | 123 ++---------- .../contact-subscribed-instant/test-event.mjs | 30 +++ .../new-contact-instant.mjs | 87 ++------ .../new-contact-instant/test-event.mjs | 21 ++ .../updated-contact-instant/test-event.mjs | 21 ++ .../updated-contact-instant.mjs | 108 ++-------- 16 files changed, 463 insertions(+), 461 deletions(-) delete mode 100644 components/icontact/.gitignore delete mode 100644 components/icontact/app/icontact.app.ts create mode 100644 components/icontact/common/constants.mjs create mode 100644 components/icontact/common/utils.mjs create mode 100644 components/icontact/sources/common/base.mjs create mode 100644 components/icontact/sources/contact-subscribed-instant/test-event.mjs create mode 100644 components/icontact/sources/new-contact-instant/test-event.mjs create mode 100644 components/icontact/sources/updated-contact-instant/test-event.mjs diff --git a/components/icontact/.gitignore b/components/icontact/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/icontact/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/icontact/actions/create-contact/create-contact.mjs b/components/icontact/actions/create-contact/create-contact.mjs index c60a13d9ae11e..aa4b2da909d61 100644 --- a/components/icontact/actions/create-contact/create-contact.mjs +++ b/components/icontact/actions/create-contact/create-contact.mjs @@ -1,51 +1,124 @@ +import { STATUS_OPTIONS } from "../../common/constants.mjs"; +import { checkWarnings } from "../../common/utils.mjs"; import icontact from "../../icontact.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "icontact-create-contact", name: "Create Contact", - description: "Creates a new contact within the iContact account. [See the documentation](https://help.icontact.com/customers/s/article/contacts-icontact-api)", + description: "Creates a new contact within the iContact account. [See the documentation](https://help.icontact.com/customers/s/article/Contacts-iContact-API?r=153&ui-knowledge-components-aura-actions.KnowledgeArticleVersionCreateDraftFromOnlineAction.createDraftFromOnlineArticle=1)", version: "0.0.1", type: "action", props: { icontact, - contactEmail: { - propDefinition: [ - icontact, - "contactEmail", - ], + email: { + type: "string", + label: "Email", + description: "The contact's email address. **Note: The email address must be unique**.", }, - contactInfo: { - propDefinition: [ - icontact, - "contactInfo", - ], + prefix: { + type: "string", + label: "Prefix", + description: "The contact's salutation. **E.g. Miss**", optional: true, }, firstName: { - propDefinition: [ - icontact, - "firstName", - ], + type: "string", + label: "First Name", + description: "The contact's first name.", optional: true, }, lastName: { - propDefinition: [ - icontact, - "lastName", - ], + type: "string", + label: "Last Name", + description: "The contact's last name.", + optional: true, + }, + suffix: { + type: "string", + label: "Suffix", + description: "The contact's name qualifications **E.g. III**.", + optional: true, + }, + street: { + type: "string", + label: "Street", + description: "The contact's street address information.", + optional: true, + }, + street2: { + type: "string", + label: "Street 2", + description: "The contact's line 2 information.", + optional: true, + }, + city: { + type: "string", + label: "City", + description: "The contact's city information.", + optional: true, + }, + state: { + type: "string", + label: "State", + description: "The contact's state information.", + optional: true, + }, + postalCode: { + type: "string", + label: "Postal Code", + description: "The contact's postal code information.", + optional: true, + }, + phone: { + type: "string", + label: "Phone", + description: "The contact's phone number.", + optional: true, + }, + fax: { + type: "string", + label: "Fax", + description: "The contact's fax number.", + optional: true, + }, + business: { + type: "string", + label: "Business", + description: "The contact's business phone number.", + optional: true, + }, + status: { + type: "string", + label: "Status", + description: "The subscription status of the contact.", + options: STATUS_OPTIONS, optional: true, }, }, async run({ $ }) { - const response = await this.icontact.createContact({ - contactEmail: this.contactEmail, - contactInfo: this.contactInfo || {}, - firstName: this.firstName, - lastName: this.lastName, + const { + icontact, + ...campaign + } = this; + + const { contacts } = await icontact.searchContact({ + params: { + email: campaign.email, + }, + }); + + if (contacts.length) throw new Error("A contact with the provided email already exists."); + + const response = await icontact.createContact({ + $, + data: { + campaign, + }, }); - $.export("$summary", `Successfully created contact with email ${this.contactEmail}`); - return response; + checkWarnings(response); + + $.export("$summary", `Successfully created contact with ID: ${response.contacts[0].contactId}`); + return response.contacts[0]; }, }; diff --git a/components/icontact/actions/create-message/create-message.mjs b/components/icontact/actions/create-message/create-message.mjs index a81a41ad4a904..4cf87efd2077b 100644 --- a/components/icontact/actions/create-message/create-message.mjs +++ b/components/icontact/actions/create-message/create-message.mjs @@ -1,49 +1,82 @@ +import { MESSAGE_TYPE_OPTIONS } from "../../common/constants.mjs"; +import { checkWarnings } from "../../common/utils.mjs"; import icontact from "../../icontact.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "icontact-create-message", name: "Create and Dispatch Message", - description: "Creates and dispatches a new message using custom HTML. [See the documentation](https://help.icontact.com/customers/s/article/messages-icontact-api)", - version: "0.0.{{ts}}", + description: "Creates and dispatches a new message using custom HTML. [See the documentation](https://help.icontact.com/customers/s/article/Messages-iContact-API?r=153&ui-knowledge-components-aura-actions.KnowledgeArticleVersionCreateDraftFromOnlineAction.createDraftFromOnlineArticle=1)", + version: "0.0.1", type: "action", props: { icontact, - recipientEmail: { + campaignId: { propDefinition: [ icontact, - "recipientEmail", + "campaignId", ], }, - senderEmail: { - propDefinition: [ - icontact, - "senderEmail", - ], - }, - htmlContent: { - propDefinition: [ - icontact, - "htmlContent", - ], + messageType: { + type: "string", + label: "Message Type", + description: "The kind of message being added.", + options: MESSAGE_TYPE_OPTIONS, }, subject: { + type: "string", + label: "Subject", + description: "The subject line of the email.", + }, + htmlBody: { + type: "string", + label: "HTML Body", + description: "Contains the HTML version of the email message body.", + optional: true, + }, + textBody: { + type: "string", + label: "Text Body", + description: "Contains the text version of the email message body.", + optional: true, + }, + messageName: { + type: "string", + label: "Message Name", + description: "The reference name of the message. This is used for organizational purposes and will not be seen by your contacts.", + optional: true, + }, + previewText: { + type: "string", + label: "Preview Text", + description: "Indicates the preview text that some email systems display before opening the email.", + optional: true, + }, + replyToCampaignId: { propDefinition: [ icontact, - "subject", + "campaignId", ], + label: "Reply To Campaign Id", + description: "Indicates the sender property where you want reply emails to be sent to.", optional: true, }, }, async run({ $ }) { - const response = await this.icontact.createAndSendMessage({ - recipientEmail: this.recipientEmail, - senderEmail: this.senderEmail, - htmlContent: this.htmlContent, - subject: this.subject, + const { + icontact, + ...message + } = this; + + const response = await icontact.createMessage({ + $, + data: { + message, + }, }); - $.export("$summary", `Message sent successfully to ${this.recipientEmail}`); - return response; + checkWarnings(response); + + $.export("$summary", `Successfully created contact with ID: ${response.messages[0].messageId}`); + return response.messages[0]; }, }; diff --git a/components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs b/components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs index be911fe282fed..b95415988f361 100644 --- a/components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs +++ b/components/icontact/actions/subscribe-contact-list/subscribe-contact-list.mjs @@ -1,18 +1,18 @@ +import { checkWarnings } from "../../common/utils.mjs"; import icontact from "../../icontact.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "icontact-subscribe-contact-list", name: "Subscribe Contact to List", - description: "Adds a contact to a specific list within iContact. [See the documentation](https://help.icontact.com/customers/s/article/subscriptions-icontact-api)", - version: "0.0.{{ts}}", + description: "Adds a contact to a specific list within iContact. [See the documentation](https://help.icontact.com/customers/s/article/Subscriptions-iContact-API?r=153&ui-knowledge-components-aura-actions.KnowledgeArticleVersionCreateDraftFromOnlineAction.createDraftFromOnlineArticle=1)", + version: "0.0.1", type: "action", props: { icontact, - contactEmail: { + contactId: { propDefinition: [ icontact, - "contactEmail", + "contactId", ], }, listId: { @@ -24,11 +24,18 @@ export default { }, async run({ $ }) { const response = await this.icontact.subscribeContactToList({ - contactEmail: this.contactEmail, - listId: this.listId, + data: { + subscription: { + contactId: this.contactId, + listId: this.listId, + status: "normal", + }, + }, }); - $.export("$summary", `Successfully subscribed ${this.contactEmail} to list with ID ${this.listId}`); - return response; + checkWarnings(response); + + $.export("$summary", `Successfully created subscription with ID: ${response.subscriptions[0].subscriptionId}`); + return response.subscriptions[0]; }, }; diff --git a/components/icontact/app/icontact.app.ts b/components/icontact/app/icontact.app.ts deleted file mode 100644 index c5260310ecbdf..0000000000000 --- a/components/icontact/app/icontact.app.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ - type: "app", - app: "icontact", - propDefinitions: {}, - methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); - }, - }, -}); diff --git a/components/icontact/common/constants.mjs b/components/icontact/common/constants.mjs new file mode 100644 index 0000000000000..f8fe8fae2d370 --- /dev/null +++ b/components/icontact/common/constants.mjs @@ -0,0 +1,37 @@ +export const STATUS_OPTIONS = [ + { + label: "Normal - Contact can receive emails sent to them.", + value: "normal", + }, + { + label: "Bounced - Contact is unreachable via email.", + value: "bounced", + }, + { + label: "Do Not Contact - Contact is blocked from receiving emails.", + value: "donotcontact", + }, + { + label: "Pending - Contact must confirm a subscription before receiving emails.", + value: "pending", + }, + { + label: "Invitable - Contact must be sent an invitation message before receiving emails.", + value: "invitable", + }, + { + label: "Deleted - Contact was deleted from your records", + value: "deleted", + }, +]; + +export const MESSAGE_TYPE_OPTIONS = [ + { + label: "Normal - An email message.", + value: "normal", + }, + { + label: "Confirmation - An email that requests a contact to confirm their subscription", + value: "confirmation", + }, +]; diff --git a/components/icontact/common/utils.mjs b/components/icontact/common/utils.mjs new file mode 100644 index 0000000000000..429936ef55a4e --- /dev/null +++ b/components/icontact/common/utils.mjs @@ -0,0 +1,10 @@ +import { ConfigurationError } from "@pipedream/platform"; + +export const checkWarnings = (response) => { + if (response.warnings) { + throw new ConfigurationError(response.warnings[0]); + } + if (response.notices) { + throw new ConfigurationError(response.notices[0]); + } +}; diff --git a/components/icontact/icontact.app.mjs b/components/icontact/icontact.app.mjs index 854a9a04eb9d4..5367a5f4e82f5 100644 --- a/components/icontact/icontact.app.mjs +++ b/components/icontact/icontact.app.mjs @@ -4,164 +4,125 @@ export default { type: "app", app: "icontact", propDefinitions: { - contactEmail: { + campaignId: { type: "string", - label: "Contact Email", - description: "The email of the contact", - }, - contactInfo: { - type: "object", - label: "Contact Information", - description: "Additional information for the contact", + label: "Campaign ID", + description: "The sender property from which the message will pull its sending information.", + async options() { + const { campaigns } = await this.listCampaigns(); + + return campaigns.map(({ + campaignId: value, name: label, + }) => ({ + label, + value, + })); + }, }, contactId: { type: "string", label: "Contact ID", - description: "The ID of the contact", + description: "The contact that will be subscribed to the list.", + async options() { + const { contacts } = await this.listContacts(); + + return contacts.map(({ + contactId: value, email: label, + }) => ({ + label, + value, + })); + }, }, listId: { type: "string", label: "List ID", description: "The ID of the list", async options() { - const lists = await this.getLists(); - return lists.map((list) => ({ - label: list.name, - value: list.id, + const { lists } = await this.listLists(); + + return lists.map(({ + listId: value, name: label, + }) => ({ + label, + value, })); }, }, - senderEmail: { - type: "string", - label: "Sender Email", - description: "The email of the sender", - }, - recipientEmail: { - type: "string", - label: "Recipient Email", - description: "The email of the recipient", - }, - htmlContent: { - type: "string", - label: "HTML Content", - description: "The HTML content for the message", - }, - subject: { - type: "string", - label: "Subject", - description: "The subject of the message", - optional: true, - }, - firstName: { - type: "string", - label: "First Name", - description: "The contact's first name", - optional: true, - }, - lastName: { - type: "string", - label: "Last Name", - description: "The contact's last name", - optional: true, - }, }, methods: { _baseUrl() { - return "https://api.icontact.com/v2.0"; - }, - async _makeRequest(opts = {}) { - const { - $ = this, - method = "GET", - path = "/", - headers = {}, - ...otherOpts - } = opts; + return `https://app.icontact.com/icp/a/${this.$auth.account_id}/c/${this.$auth.client_folder_id}`; + }, + _headers() { + return { + "Accept": "application/json", + "Content-Type": "application/json", + "API-Version": "2.2", + "API-AppId": `${this.$auth.api_app_id}`, + "API-Username": `${this.$auth.api_username}`, + "API-Password": `${this.$auth.api_password}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { return axios($, { - ...otherOpts, - method, url: this._baseUrl() + path, - headers: { - ...headers, - "Content-Type": "application/json", - "Authorization": `Bearer ${this.$auth.api_key}`, - }, + headers: this._headers(), + ...opts, }); }, - async getLists(opts = {}) { + createContact(opts = {}) { return this._makeRequest({ - path: "/lists", + method: "POST", + path: "/contacts", ...opts, }); }, - async createContact({ - contactEmail, contactInfo, firstName, lastName, ...opts - }) { + createMessage(opts = {}) { return this._makeRequest({ method: "POST", - path: "/contacts", - data: { - email: contactEmail, - firstName, - lastName, - ...contactInfo, - }, + path: "/messages", ...opts, }); }, - async updateContact({ - contactId, contactInfo, ...opts - }) { + searchContact(opts = {}) { return this._makeRequest({ - method: "PUT", - path: `/contacts/${contactId}`, - data: contactInfo, + path: "/contacts", ...opts, }); }, - async subscribeContactToList({ - contactEmail, listId, ...opts - }) { + listCampaigns(opts = {}) { return this._makeRequest({ - method: "POST", - path: `/lists/${listId}/contacts`, - data: { - email: contactEmail, - }, + path: "/campaigns", ...opts, }); }, - async createAndSendMessage({ - recipientEmail, - senderEmail, - htmlContent, - subject, - ...opts - }) { + listContacts(opts = {}) { return this._makeRequest({ - method: "POST", - path: "/messages", - data: { - recipient: recipientEmail, - sender: senderEmail, - message: { - body: htmlContent, - subject, - }, - }, + path: "/contacts", ...opts, }); }, - }, - hooks: { - async contactCreated() { - // Emit a new event when a contact is created. + listLists(opts = {}) { + return this._makeRequest({ + path: "/lists", + ...opts, + }); }, - async contactUpdated() { - // Emit a new event when a contact is updated. + createWebhook(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/webhooks", + ...opts, + }); }, - async contactSubscribed() { - // Emit a new event when a contact is subscribed to a list. + deleteWebhook(webhookId) { + return this._makeRequest({ + method: "DELETE", + path: `/webhooks/${webhookId}`, + }); }, }, }; diff --git a/components/icontact/package.json b/components/icontact/package.json index 71c16d5269151..1c73c55088f90 100644 --- a/components/icontact/package.json +++ b/components/icontact/package.json @@ -1,16 +1,18 @@ { "name": "@pipedream/icontact", - "version": "0.0.2", + "version": "0.1.0", "description": "Pipedream iContact Components", - "main": "dist/app/icontact.app.mjs", + "main": "icontact.app.mjs", "keywords": [ "pipedream", "icontact" ], - "files": ["dist"], "homepage": "https://pipedream.com/apps/icontact", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/icontact/sources/common/base.mjs b/components/icontact/sources/common/base.mjs new file mode 100644 index 0000000000000..9d1c654d89a92 --- /dev/null +++ b/components/icontact/sources/common/base.mjs @@ -0,0 +1,41 @@ +import icontact from "../../icontact.app.mjs"; + +export default { + props: { + icontact, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + }, + methods: { + _getHookId() { + return this.db.get("hookId"); + }, + _setHookId(hookId) { + this.db.set("hookId", hookId); + }, + }, + hooks: { + async activate() { + const response = await this.icontact.createWebhook({ + data: [ + { + url: this.http.endpoint, + eventId: this.getEventType(), + }, + ], + }); + this._setHookId(response.webhooks[0].webhookId); + }, + async deactivate() { + const webhookId = this._getHookId(); + await this.icontact.deleteWebhook(webhookId); + }, + }, + async run({ body }) { + const data = body[0]; + this.$emit(data, this.generateMeta(data)); + }, +}; diff --git a/components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs b/components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs index 1c4de0a5ab609..36b9d16be3e79 100644 --- a/components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs +++ b/components/icontact/sources/contact-subscribed-instant/contact-subscribed-instant.mjs @@ -1,113 +1,28 @@ -import icontact from "../../icontact.app.mjs"; -import crypto from "crypto"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "icontact-contact-subscribed-instant", - name: "New Contact Subscribed", - description: "Emit new event when a contact is subscribed to a list. [See the documentation](https://help.icontact.com/customers/s/article/web-hooks-icontact-api)", - version: "0.0.{{ts}}", + name: "New Contact Subscribed (Instant)", + description: "Emit new event when a contact is subscribed to a list.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - icontact: { - type: "app", - app: "icontact", - }, - http: { - type: "$.interface.http", - customResponse: true, - }, - db: "$.service.db", - listId: { - propDefinition: [ - icontact, - "listId", - ], - }, - }, methods: { - _getWebhookId() { - return this.db.get("webhookId"); - }, - _setWebhookId(id) { - this.db.set("webhookId", id); - }, - _computeSignature(secretKey, rawBody) { - return crypto.createHmac("sha256", secretKey).update(rawBody) - .digest("base64"); - }, - }, - hooks: { - async deploy() { - const contacts = await this.icontact._makeRequest({ - path: `/lists/${this.listId}/contacts`, - }); - let count = 0; - for (const contact of contacts.reverse()) { - if (count < 50) { - this.$emit(contact, { - id: contact.contactId, - summary: `New subscription: ${contact.email}`, - ts: Date.parse(contact.subscribedAt), - }); - count++; - } else { - break; - } - } + ...common.methods, + getEventType() { + return "contact_subscribed"; + }, + generateMeta({ + contact, list, + }) { + return { + id: `${contact.contactId}-${list.listId}`, + summary: `Contact "${contact.email}" subscribed to list "${list.name}"`, + ts: Date.now(), + }; }, - async activate() { - const webhook = await this.icontact._makeRequest({ - method: "POST", - path: "/webhooks", - data: { - eventType: "contact_subscribed", - targetUrl: this.http.endpoint, - triggerEvent: this.listId, - }, - }); - this._setWebhookId(webhook.id); - }, - async deactivate() { - const webhookId = this._getWebhookId(); - if (webhookId) { - await this.icontact._makeRequest({ - method: "DELETE", - path: `/webhooks/${webhookId}`, - }); - this._setWebhookId(null); - } - }, - }, - async run(event) { - const signature = event.headers["x-icontact-signature"]; - const secretKey = this.icontact.$auth.api_key; - const rawBody = event.body_raw; - const computedSignature = this._computeSignature(secretKey, rawBody); - - if (signature !== computedSignature) { - this.http.respond({ - status: 401, - body: "Unauthorized", - }); - return; - } - - const contact = event.body.contact; - const listId = this.listId; - - if (event.body.type === "contact_subscribed" && event.body.listId === listId) { - this.$emit(contact, { - id: contact.contactId, - summary: `Contact subscribed: ${contact.email}`, - ts: Date.parse(event.body.timestamp), - }); - } - - this.http.respond({ - status: 200, - body: "OK", - }); }, + sampleEmit, }; diff --git a/components/icontact/sources/contact-subscribed-instant/test-event.mjs b/components/icontact/sources/contact-subscribed-instant/test-event.mjs new file mode 100644 index 0000000000000..7ae7fb3dd5d20 --- /dev/null +++ b/components/icontact/sources/contact-subscribed-instant/test-event.mjs @@ -0,0 +1,30 @@ +export default { + "contact": { + "contactId":123, + "prefix":"Miss", + "firstName":"Mary", + "lastName":"Smith", + "suffix":"III", + "street":"2635 Meridian Parkway", + "street2":"Suite 100", + "city":"Durham", + "state":"NC", + "postalCode":"27713", + "phone":"8668039462", + "fax":"8668039462", + "business":"8668039462", + "email":"smith@icontact.com", + "createDate":"2009-06-18 22:39:54", + "bounceCount":3, + "status":"normal" + }, + "list": { + "listId": 375628, + "name": "My contacts", + "publicname": "Bakery Newsletter", + "description": "A list of every contact who subscribed on my main web site", + "emailOwnerOnChange": 1, + "welcomeOnManualAdd": 0, + "welcomeOnSignupAdd": 1 + } +} \ No newline at end of file diff --git a/components/icontact/sources/new-contact-instant/new-contact-instant.mjs b/components/icontact/sources/new-contact-instant/new-contact-instant.mjs index 8e5bc78f351e5..42d6cae0d30cc 100644 --- a/components/icontact/sources/new-contact-instant/new-contact-instant.mjs +++ b/components/icontact/sources/new-contact-instant/new-contact-instant.mjs @@ -1,81 +1,26 @@ -import icontact from "../../icontact.app.mjs"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "icontact-new-contact-instant", - name: "New Contact Created", - description: "Emit new event when a contact is created. [See the documentation](https://help.icontact.com/customers/s/article/web-hooks-icontact-api)", - version: "0.0.{{ts}}", + name: "New Contact Created (Instant)", + description: "Emit new event when a contact is created.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - icontact: { - type: "app", - app: "icontact", - }, - http: { - type: "$.interface.http", - customResponse: true, - }, - db: "$.service.db", - }, methods: { - _getWebhookId() { - return this.db.get("webhookId"); + ...common.methods, + getEventType() { + return "contact_created"; }, - _setWebhookId(id) { - this.db.set("webhookId", id); + generateMeta({ contact }) { + return { + id: contact.contactId, + summary: `New contact created: ${contact.email}`, + ts: contact.createDate, + }; }, - async _verifySignature(event) { - const computedSignature = require("crypto") - .createHmac("sha256", this.icontact.$auth.api_key) - .update(event.rawBody) - .digest("base64"); - - const webhookSignature = event.headers["x-icontact-signature"]; - return computedSignature === webhookSignature; - }, - }, - hooks: { - async deploy() { - // Implement fetching and emitting historical events if the API supports this - }, - async activate() { - const response = await this.icontact._makeRequest({ - method: "POST", - path: "/webhooks", - data: { - event: "contact.created", - target_url: this.http.endpoint, - }, - }); - this._setWebhookId(response.id); - }, - async deactivate() { - const webhookId = this._getWebhookId(); - if (webhookId) { - await this.icontact._makeRequest({ - method: "DELETE", - path: `/webhooks/${webhookId}`, - }); - this._setWebhookId(null); - } - }, - }, - async run(event) { - if (!await this._verifySignature(event)) { - this.http.respond({ - status: 401, - body: "Unauthorized", - }); - return; - } - - const { data: contact } = event; - this.$emit(contact, { - id: contact.contactId, - summary: `New contact created: ${contact.firstName} ${contact.lastName} (${contact.contactEmail})`, - ts: Date.parse(contact.createdAt), - }); }, + sampleEmit, }; diff --git a/components/icontact/sources/new-contact-instant/test-event.mjs b/components/icontact/sources/new-contact-instant/test-event.mjs new file mode 100644 index 0000000000000..b28417cf8f801 --- /dev/null +++ b/components/icontact/sources/new-contact-instant/test-event.mjs @@ -0,0 +1,21 @@ +export default { + "contact": { + "contactId":123, + "prefix":"Miss", + "firstName":"Mary", + "lastName":"Smith", + "suffix":"III", + "street":"2635 Meridian Parkway", + "street2":"Suite 100", + "city":"Durham", + "state":"NC", + "postalCode":"27713", + "phone":"8668039462", + "fax":"8668039462", + "business":"8668039462", + "email":"smith@icontact.com", + "createDate":"2009-06-18 22:39:54", + "bounceCount":3, + "status":"normal" + } +} \ No newline at end of file diff --git a/components/icontact/sources/updated-contact-instant/test-event.mjs b/components/icontact/sources/updated-contact-instant/test-event.mjs new file mode 100644 index 0000000000000..b28417cf8f801 --- /dev/null +++ b/components/icontact/sources/updated-contact-instant/test-event.mjs @@ -0,0 +1,21 @@ +export default { + "contact": { + "contactId":123, + "prefix":"Miss", + "firstName":"Mary", + "lastName":"Smith", + "suffix":"III", + "street":"2635 Meridian Parkway", + "street2":"Suite 100", + "city":"Durham", + "state":"NC", + "postalCode":"27713", + "phone":"8668039462", + "fax":"8668039462", + "business":"8668039462", + "email":"smith@icontact.com", + "createDate":"2009-06-18 22:39:54", + "bounceCount":3, + "status":"normal" + } +} \ No newline at end of file diff --git a/components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs b/components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs index 783eb38aebe4d..0afde6a107cff 100644 --- a/components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs +++ b/components/icontact/sources/updated-contact-instant/updated-contact-instant.mjs @@ -1,104 +1,26 @@ -import icontact from "../../icontact.app.mjs"; -import crypto from "crypto"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "icontact-updated-contact-instant", - name: "Updated Contact Instant", - description: "Emit new event when a contact is updated. [See the documentation](https://help.icontact.com/customers/s/article/web-hooks-icontact-api)", - version: "0.0.{{ts}}", + name: "Contact Updated (Instant)", + description: "Emit new event when a contact is updated.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - icontact, - http: { - type: "$.interface.http", - customResponse: true, - }, - db: "$.service.db", - }, methods: { - _getWebhookId() { - return this.db.get("webhookId"); - }, - _setWebhookId(id) { - this.db.set("webhookId", id); + ...common.methods, + getEventType() { + return "contact_updated"; }, - }, - hooks: { - async deploy() { - // Fetch historical data and emit past events - console.log("Deploying hook to fetch historical contact update data"); - const contacts = await this.icontact.getContacts({ - max: 50, - }); - contacts.forEach((contact) => { - this.$emit(contact, { - id: contact.contactId, - summary: `Contact Updated: ${contact.email}`, - ts: Date.parse(contact.updatedAt), - }); - }); - }, - async activate() { - const opts = { - method: "POST", - path: "/webhooks", - data: { - events: [ - "contact.updated", - ], - target_url: this.http.endpoint, - }, + generateMeta({ contact }) { + return { + id: contact.contactId, + summary: `New contact updated: ${contact.email}`, + ts: Date.now(), }; - const response = await this.icontact._makeRequest(opts); - this._setWebhookId(response.id); - }, - async deactivate() { - const webhookId = this._getWebhookId(); - if (webhookId) { - const opts = { - method: "DELETE", - path: `/webhooks/${webhookId}`, - }; - await this.icontact._makeRequest(opts); - } }, }, - async run(event) { - const secretKey = this.icontact.$auth.secret; - const rawBody = event.body; - const webhookSignature = event.headers["x-icontact-signature"]; - - const computedSignature = crypto - .createHmac("sha256", secretKey) - .update(rawBody) - .digest("base64"); - - if (computedSignature !== webhookSignature) { - this.http.respond({ - status: 401, - body: "Unauthorized", - }); - return; - } - - this.http.respond({ - status: 200, - body: "OK", - }); - - const data = JSON.parse(rawBody); - const { - contactId, email, updatedAt, - } = data; - - this.$emit(data, { - id: contactId, - summary: `Updated contact: ${email}`, - ts: updatedAt - ? Date.parse(updatedAt) - : Date.now(), - }); - }, + sampleEmit, }; From f05935530a0320515e3910c2e4427f4df6f14796 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 29 May 2025 14:12:02 -0300 Subject: [PATCH 3/7] pnpm update --- pnpm-lock.yaml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 291bdbd744ffc..74a6da320cf6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6350,7 +6350,11 @@ importers: components/ical: {} - components/icontact: {} + components/icontact: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 components/icypeas: dependencies: @@ -15521,14 +15525,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': @@ -35915,6 +35911,8 @@ snapshots: '@putout/operator-filesystem': 5.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3)) '@putout/operator-json': 2.2.0 putout: 36.13.1(eslint@8.57.1)(typescript@5.6.3) + transitivePeerDependencies: + - supports-color '@putout/operator-regexp@1.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3))': dependencies: From 10e2033ad4ac43d9e719c4ea43062c534bfe5c76 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 29 May 2025 14:58:57 -0300 Subject: [PATCH 4/7] Update components/icontact/actions/create-message/create-message.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- components/icontact/actions/create-message/create-message.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/icontact/actions/create-message/create-message.mjs b/components/icontact/actions/create-message/create-message.mjs index 4cf87efd2077b..97652ac94b0a4 100644 --- a/components/icontact/actions/create-message/create-message.mjs +++ b/components/icontact/actions/create-message/create-message.mjs @@ -76,7 +76,7 @@ export default { checkWarnings(response); - $.export("$summary", `Successfully created contact with ID: ${response.messages[0].messageId}`); + $.export("$summary", `Successfully created message with ID: ${response.messages[0].messageId}`); return response.messages[0]; }, }; From 65f764a4d33ce15fdb4fe2ca8bceca61fc434769 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 29 May 2025 15:00:26 -0300 Subject: [PATCH 5/7] Update components/icontact/actions/create-contact/create-contact.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../icontact/actions/create-contact/create-contact.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/icontact/actions/create-contact/create-contact.mjs b/components/icontact/actions/create-contact/create-contact.mjs index aa4b2da909d61..6cbb3348f1df1 100644 --- a/components/icontact/actions/create-contact/create-contact.mjs +++ b/components/icontact/actions/create-contact/create-contact.mjs @@ -98,12 +98,12 @@ export default { async run({ $ }) { const { icontact, - ...campaign + ...contact } = this; const { contacts } = await icontact.searchContact({ params: { - email: campaign.email, + email: contact.email, }, }); @@ -112,9 +112,10 @@ export default { const response = await icontact.createContact({ $, data: { - campaign, + contact, }, }); + }); checkWarnings(response); From 3ff05498ffb5dfb1a1f257ed745b8c6c35720140 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Thu, 29 May 2025 15:01:56 -0400 Subject: [PATCH 6/7] Update components/icontact/actions/create-contact/create-contact.mjs --- components/icontact/actions/create-contact/create-contact.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/icontact/actions/create-contact/create-contact.mjs b/components/icontact/actions/create-contact/create-contact.mjs index 6cbb3348f1df1..9e12781492ccc 100644 --- a/components/icontact/actions/create-contact/create-contact.mjs +++ b/components/icontact/actions/create-contact/create-contact.mjs @@ -115,7 +115,6 @@ export default { contact, }, }); - }); checkWarnings(response); From d7258b877c76c8962b5d755be125c4dba9176f62 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Fri, 30 May 2025 11:01:24 -0300 Subject: [PATCH 7/7] some adjusts --- components/icontact/icontact.app.mjs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/icontact/icontact.app.mjs b/components/icontact/icontact.app.mjs index 5367a5f4e82f5..52a15385fe926 100644 --- a/components/icontact/icontact.app.mjs +++ b/components/icontact/icontact.app.mjs @@ -87,6 +87,13 @@ export default { ...opts, }); }, + subscribeContactToList(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/subscriptions", + ...opts, + }); + }, searchContact(opts = {}) { return this._makeRequest({ path: "/contacts",