diff --git a/components/kustomer/actions/create-conversation/create-conversation.mjs b/components/kustomer/actions/create-conversation/create-conversation.mjs new file mode 100644 index 0000000000000..68c3416e212fe --- /dev/null +++ b/components/kustomer/actions/create-conversation/create-conversation.mjs @@ -0,0 +1,119 @@ +import { + parseObject, throwError, +} from "../../common/utils.mjs"; +import kustomer from "../../kustomer.app.mjs"; + +export default { + key: "kustomer-create-conversation", + name: "Create Conversation", + description: "Creates a new conversation in Kustomer. [See the documentation](https://developer.kustomer.com/kustomer-api-docs/reference/createaconversation)", + version: "0.0.1", + type: "action", + props: { + kustomer, + customer: { + propDefinition: [ + kustomer, + "customerId", + ], + }, + externalId: { + propDefinition: [ + kustomer, + "externalId", + ], + optional: true, + }, + name: { + propDefinition: [ + kustomer, + "name", + ], + description: "Name of the conversation", + optional: true, + }, + status: { + propDefinition: [ + kustomer, + "status", + ], + optional: true, + }, + priority: { + propDefinition: [ + kustomer, + "priority", + ], + optional: true, + }, + direction: { + propDefinition: [ + kustomer, + "direction", + ], + optional: true, + }, + tags: { + propDefinition: [ + kustomer, + "tags", + ], + optional: true, + }, + assignedUsers: { + propDefinition: [ + kustomer, + "assignedUsers", + ], + optional: true, + }, + assignedTeams: { + propDefinition: [ + kustomer, + "assignedTeams", + ], + optional: true, + }, + defaultLang: { + propDefinition: [ + kustomer, + "defaultLang", + ], + description: "Default language for the conversation", + optional: true, + }, + queueId: { + propDefinition: [ + kustomer, + "queueId", + ], + }, + }, + async run({ $ }) { + try { + const response = await this.kustomer.createConversation({ + $, + data: { + customer: this.customer, + externalId: this.externalId, + name: this.name, + status: this.status, + priority: this.priority, + direction: this.direction, + tags: parseObject(this.tags), + assignedUsers: parseObject(this.assignedUsers), + assignedTeams: parseObject(this.assignedTeams), + defaultLang: this.defaultLang, + queue: { + id: this.queueId, + }, + }, + }); + + $.export("$summary", `Created conversation with ID ${response.data.id}`); + return response; + } catch ({ message }) { + throwError(message); + } + }, +}; diff --git a/components/kustomer/actions/create-customer/create-customer.mjs b/components/kustomer/actions/create-customer/create-customer.mjs new file mode 100644 index 0000000000000..a2987830f4e81 --- /dev/null +++ b/components/kustomer/actions/create-customer/create-customer.mjs @@ -0,0 +1,203 @@ +import { + parseObject, throwError, +} from "../../common/utils.mjs"; +import kustomer from "../../kustomer.app.mjs"; + +export default { + key: "kustomer-create-customer", + name: "Create Customer", + description: "Creates a new customer in Kustomer. [See the documentation](https://developer.kustomer.com/kustomer-api-docs/reference/createacustomer)", + version: "0.0.1", + type: "action", + props: { + kustomer, + name: { + propDefinition: [ + kustomer, + "name", + ], + optional: true, + }, + company: { + propDefinition: [ + kustomer, + "company", + ], + optional: true, + }, + externalId: { + propDefinition: [ + kustomer, + "externalId", + ], + optional: true, + }, + username: { + propDefinition: [ + kustomer, + "username", + ], + optional: true, + }, + avatarUrl: { + propDefinition: [ + kustomer, + "avatarUrl", + ], + optional: true, + }, + externalIds: { + propDefinition: [ + kustomer, + "externalIds", + ], + optional: true, + }, + sharedExternalIds: { + propDefinition: [ + kustomer, + "sharedExternalIds", + ], + optional: true, + }, + emails: { + propDefinition: [ + kustomer, + "emails", + ], + optional: true, + }, + sharedEmails: { + propDefinition: [ + kustomer, + "sharedEmails", + ], + optional: true, + }, + phones: { + propDefinition: [ + kustomer, + "phones", + ], + optional: true, + }, + sharedPhones: { + propDefinition: [ + kustomer, + "sharedPhones", + ], + optional: true, + }, + whatsApps: { + propDefinition: [ + kustomer, + "whatsApps", + ], + optional: true, + }, + urls: { + propDefinition: [ + kustomer, + "urls", + ], + optional: true, + }, + tags: { + propDefinition: [ + kustomer, + "tags", + ], + optional: true, + }, + sentimentPolarity: { + propDefinition: [ + kustomer, + "sentimentPolarity", + ], + optional: true, + }, + sentimentConfidence: { + propDefinition: [ + kustomer, + "sentimentConfidence", + ], + optional: true, + }, + birthdayAt: { + propDefinition: [ + kustomer, + "birthdayAt", + ], + optional: true, + }, + gender: { + propDefinition: [ + kustomer, + "gender", + ], + optional: true, + }, + defaultLang: { + propDefinition: [ + kustomer, + "defaultLang", + ], + optional: true, + }, + }, + async run({ $ }) { + try { + const sentiment = {}; + if (this.sentimentConfidence) sentiment.confidence = parseInt(this.sentimentConfidence); + if (this.sentimentPolarity) sentiment.polarity = parseInt(this.sentimentPolarity); + + const response = await this.kustomer.createCustomer({ + $, + data: { + name: this.name, + company: this.company, + externalId: this.externalId, + username: this.username, + avatarUrl: this.avatarUrl, + externalIds: parseObject(this.externalIds)?.map((id) => ({ + externalId: id, + })), + sharedExternalIds: parseObject(this.sharedExternalIds)?.map((id) => ({ + externalId: id, + })), + emails: parseObject(this.emails)?.map((email) => ({ + email, + })), + sharedEmails: parseObject(this.sharedEmails)?.map((email) => ({ + email, + })), + phones: parseObject(this.phones)?.map((phone) => ({ + phone: `${phone}`, + })), + sharedPhones: parseObject(this.sharedPhones)?.map((phone) => ({ + phone: `${phone}`, + })), + whatsapps: parseObject(this.whatsApps)?.map((phone) => ({ + phone: `${phone}`, + })), + urls: parseObject(this.urls)?.map((url) => ({ + url, + })), + tags: parseObject(this.tags), + sentiment: Object.entries(sentiment).length + ? sentiment + : undefined, + birthdayAt: this.birthdayAt, + gender: this.gender, + createdAt: this.createdAt, + importedAt: this.importedAt, + defaultLang: this.defaultLang, + }, + }); + $.export("$summary", `Created customer with ID ${response.data.id}`); + return response; + } catch ({ message }) { + throwError(message); + } + }, +}; diff --git a/components/kustomer/actions/update-conversation/update-conversation.mjs b/components/kustomer/actions/update-conversation/update-conversation.mjs new file mode 100644 index 0000000000000..2e2a1c486dfd6 --- /dev/null +++ b/components/kustomer/actions/update-conversation/update-conversation.mjs @@ -0,0 +1,121 @@ +import { + parseObject, throwError, +} from "../../common/utils.mjs"; +import kustomer from "../../kustomer.app.mjs"; + +export default { + key: "kustomer-update-conversation", + name: "Update Conversation", + description: "Updates an existing conversation in Kustomer. [See the documentation](https://developer.kustomer.com/kustomer-api-docs/reference/updateconversation).", + version: "0.0.1", + type: "action", + props: { + kustomer, + conversationId: { + propDefinition: [ + kustomer, + "conversationId", + ], + }, + externalId: { + propDefinition: [ + kustomer, + "externalId", + ], + optional: true, + }, + name: { + propDefinition: [ + kustomer, + "name", + ], + description: "Name of the conversation", + optional: true, + }, + status: { + propDefinition: [ + kustomer, + "status", + ], + optional: true, + }, + priority: { + propDefinition: [ + kustomer, + "priority", + ], + optional: true, + }, + direction: { + propDefinition: [ + kustomer, + "direction", + ], + optional: true, + }, + tags: { + propDefinition: [ + kustomer, + "tags", + ], + optional: true, + }, + assignedUsers: { + propDefinition: [ + kustomer, + "assignedUsers", + ], + optional: true, + }, + assignedTeams: { + propDefinition: [ + kustomer, + "assignedTeams", + ], + optional: true, + }, + defaultLang: { + propDefinition: [ + kustomer, + "defaultLang", + ], + description: "Default language for the conversation", + optional: true, + }, + queueId: { + propDefinition: [ + kustomer, + "queueId", + ], + optional: true, + }, + }, + async run({ $ }) { + try { + const data = { + externalId: this.externalId, + name: this.name, + status: this.status, + priority: this.priority, + direction: this.direction, + tags: parseObject(this.tags), + assignedUsers: parseObject(this.assignedUsers), + assignedTeams: parseObject(this.assignedTeams), + defaultLang: this.defaultLang, + }; + + if (this.queue) data.queue = this.queue; + + const response = await this.kustomer.updateConversation({ + $, + conversationId: this.conversationId, + data, + }); + + $.export("$summary", `Conversation ${this.conversationId} updated successfully`); + return response; + } catch ({ message }) { + throwError(message); + } + }, +}; diff --git a/components/kustomer/actions/update-customer/update-customer.mjs b/components/kustomer/actions/update-customer/update-customer.mjs new file mode 100644 index 0000000000000..22227af9e6843 --- /dev/null +++ b/components/kustomer/actions/update-customer/update-customer.mjs @@ -0,0 +1,210 @@ +import { + parseObject, throwError, +} from "../../common/utils.mjs"; +import kustomer from "../../kustomer.app.mjs"; + +export default { + key: "kustomer-update-customer", + name: "Update Customer", + description: "Updates an existing customer in Kustomer. [See the documentation](https://developer.kustomer.com/kustomer-api-docs/reference/updatecustomer)", + version: "0.0.1", + type: "action", + props: { + kustomer, + customerId: { + propDefinition: [ + kustomer, + "customerId", + ], + }, + name: { + propDefinition: [ + kustomer, + "name", + ], + optional: true, + }, + company: { + propDefinition: [ + kustomer, + "company", + ], + optional: true, + }, + externalId: { + propDefinition: [ + kustomer, + "externalId", + ], + optional: true, + }, + username: { + propDefinition: [ + kustomer, + "username", + ], + optional: true, + }, + avatarUrl: { + propDefinition: [ + kustomer, + "avatarUrl", + ], + optional: true, + }, + externalIds: { + propDefinition: [ + kustomer, + "externalIds", + ], + optional: true, + }, + sharedExternalIds: { + propDefinition: [ + kustomer, + "sharedExternalIds", + ], + optional: true, + }, + emails: { + propDefinition: [ + kustomer, + "emails", + ], + optional: true, + }, + sharedEmails: { + propDefinition: [ + kustomer, + "sharedEmails", + ], + optional: true, + }, + phones: { + propDefinition: [ + kustomer, + "phones", + ], + optional: true, + }, + sharedPhones: { + propDefinition: [ + kustomer, + "sharedPhones", + ], + optional: true, + }, + whatsApps: { + propDefinition: [ + kustomer, + "whatsApps", + ], + optional: true, + }, + urls: { + propDefinition: [ + kustomer, + "urls", + ], + optional: true, + }, + tags: { + propDefinition: [ + kustomer, + "tags", + ], + optional: true, + }, + sentimentPolarity: { + propDefinition: [ + kustomer, + "sentimentPolarity", + ], + optional: true, + }, + sentimentConfidence: { + propDefinition: [ + kustomer, + "sentimentConfidence", + ], + optional: true, + }, + birthdayAt: { + propDefinition: [ + kustomer, + "birthdayAt", + ], + optional: true, + }, + gender: { + propDefinition: [ + kustomer, + "gender", + ], + optional: true, + }, + defaultLang: { + propDefinition: [ + kustomer, + "defaultLang", + ], + optional: true, + }, + }, + async run({ $ }) { + try { + const sentiment = {}; + if (this.sentimentConfidence) sentiment.confidence = parseInt(this.sentimentConfidence); + if (this.sentimentPolarity) sentiment.polarity = parseInt(this.sentimentPolarity); + + const response = await this.kustomer.updateCustomer({ + $, + customerId: this.customerId, + data: { + name: this.name, + company: this.company, + externalId: this.externalId, + username: this.username, + avatarUrl: this.avatarUrl, + externalIds: parseObject(this.externalIds)?.map((id) => ({ + externalId: id, + })), + sharedExternalIds: parseObject(this.sharedExternalIds)?.map((id) => ({ + externalId: id, + })), + emails: parseObject(this.emails)?.map((email) => ({ + email, + })), + sharedEmails: parseObject(this.sharedEmails)?.map((email) => ({ + email, + })), + phones: parseObject(this.phones)?.map((phone) => ({ + phone: `${phone}`, + })), + sharedPhones: parseObject(this.sharedPhones)?.map((phone) => ({ + phone: `${phone}`, + })), + whatsapps: parseObject(this.whatsApps)?.map((phone) => ({ + phone: `${phone}`, + })), + urls: parseObject(this.urls)?.map((url) => ({ + url, + })), + tags: parseObject(this.tags), + sentiment: Object.entries(sentiment).length + ? sentiment + : undefined, + birthdayAt: this.birthdayAt, + gender: this.gender, + createdAt: this.createdAt, + importedAt: this.importedAt, + defaultLang: this.defaultLang, + }, + }); + $.export("$summary", `Successfully updated customer with ID ${this.customerId}`); + return response; + } catch ({ message }) { + throwError(message); + } + }, +}; diff --git a/components/kustomer/common/constants.mjs b/components/kustomer/common/constants.mjs new file mode 100644 index 0000000000000..5d0189acecfc0 --- /dev/null +++ b/components/kustomer/common/constants.mjs @@ -0,0 +1,337 @@ +export const LIMIT = 100; + +export const STATUS_OPTIONS = [ + "open", + "done", +]; + +export const DIRECTION_OPTIONS = [ + "in", + "out", +]; + +export const GENDER_OPTIONS = [ + "m", + "f", +]; + +export const SENTIMENT_OPTIONS = [ + "-1", + "0", + "1", +]; + +export const DEFAULT_LANG_OPTIONS = [ + { + label: "Afrikaans", + value: "af", + }, + { + label: "Arabic", + value: "ar", + }, + { + label: "Arabic (EG)", + value: "ar_eg", + }, + { + label: "Arabic (MA)", + value: "ar_ma", + }, + { + label: "Arabic (TN)", + value: "ar_tn", + }, + { + label: "Azerbaijani", + value: "az", + }, + { + label: "Belarusian", + value: "be", + }, + { + label: "Bulgarian", + value: "bg", + }, + { + label: "Bosnian", + value: "bs", + }, + { + label: "Catalan", + value: "ca", + }, + { + label: "Montenegrin", + value: "cnr", + }, + { + label: "Czech", + value: "cs", + }, + { + label: "Danish", + value: "da", + }, + { + label: "German", + value: "de", + }, + { + label: "Dutch", + value: "nl", + }, + { + label: "Dutch (BE)", + value: "nl_be", + }, + { + label: "Greek", + value: "el", + }, + { + label: "English (US)", + value: "en_us", + }, + { + label: "English (CA)", + value: "en_ca", + }, + { + label: "English (UK)", + value: "en_gb", + }, + { + label: "Spanish", + value: "es", + }, + { + label: "Spanish (AR)", + value: "es_ar", + }, + { + label: "Spanish (Spain)", + value: "es_es", + }, + { + label: "Spanish (PA)", + value: "es_pa", + }, + { + label: "Spanish (PE)", + value: "es_pe", + }, + { + label: "Estonian", + value: "et", + }, + { + label: "Persian", + value: "fa", + }, + { + label: "Finnish", + value: "fi", + }, + { + label: "Filipino", + value: "fil", + }, + { + label: "French", + value: "fr", + }, + { + label: "French (BE)", + value: "fr_be", + }, + { + label: "French (CA)", + value: "fr_ca", + }, + { + label: "French (MA)", + value: "fr_ma", + }, + { + label: "Hebrew", + value: "he", + }, + { + label: "Hindi", + value: "hi", + }, + { + label: "Croatian", + value: "hr", + }, + { + label: "Hungarian", + value: "hu", + }, + { + label: "Armenian", + value: "hy", + }, + { + label: "Indonesian", + value: "id", + }, + { + label: "Icelandic", + value: "is", + }, + { + label: "Italian", + value: "it", + }, + { + label: "Japanese", + value: "ja", + }, + { + label: "Georgian", + value: "ka", + }, + { + label: "Kazakh", + value: "kk", + }, + { + label: "Kannada", + value: "kn", + }, + { + label: "Korean", + value: "ko", + }, + { + label: "Kyrgyz", + value: "ky", + }, + { + label: "Luxembourgish", + value: "lb", + }, + { + label: "Lithuanian", + value: "lt", + }, + { + label: "Latvian", + value: "lv", + }, + { + label: "Mongolian", + value: "mn", + }, + { + label: "Norwegian", + value: "no", + }, + { + label: "Norwegian (NB)", + value: "nb", + }, + { + label: "Punjabi", + value: "pa", + }, + { + label: "Polish", + value: "pl", + }, + { + label: "Portuguese (PT)", + value: "pt", + }, + { + label: "Portuguese (BR)", + value: "pt_br", + }, + { + label: "Romanian", + value: "ro", + }, + { + label: "Russian", + value: "ru", + }, + { + label: "Sinhala", + value: "si", + }, + { + label: "Slovakian", + value: "sk", + }, + { + label: "Slovenian", + value: "sl", + }, + { + label: "Albanian", + value: "sq", + }, + { + label: "Serbian", + value: "sr", + }, + { + label: "Serbian (Montenegro)", + value: "sr_me", + }, + { + label: "Swedish", + value: "sv", + }, + { + label: "Swahili", + value: "sw", + }, + { + label: "Tamil", + value: "ta", + }, + { + label: "Telugu", + value: "te", + }, + { + label: "Thai", + value: "th", + }, + { + label: "Turkish", + value: "tr", + }, + { + label: "Twi", + value: "tw", + }, + { + label: "Ukrainian", + value: "uk", + }, + { + label: "Urdu", + value: "ur", + }, + { + label: "Uzbek", + value: "uz", + }, + { + label: "Vietnamese", + value: "vi", + }, + { + label: "Simplified Chinese", + value: "zh_cn", + }, + { + label: "Traditional Chinese", + value: "zh_tw", + }, +]; diff --git a/components/kustomer/common/utils.mjs b/components/kustomer/common/utils.mjs new file mode 100644 index 0000000000000..39432d01960a7 --- /dev/null +++ b/components/kustomer/common/utils.mjs @@ -0,0 +1,37 @@ +import { ConfigurationError } from "@pipedream/platform"; + +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; + +export const throwError = (message) => { + const parsedMessage = JSON.parse(message); + const error = parsedMessage.errors[0]; + const errorParameter = + error.source.parameter || + error.source.pointer || + error.meta?.subErrors[0]?.source?.pointer; + const errorMessage = error.detail || error.title || error.meta?.subErrors[0]?.title; + throw new ConfigurationError(`${errorParameter} - ${errorMessage}`); +}; diff --git a/components/kustomer/kustomer.app.mjs b/components/kustomer/kustomer.app.mjs index 80387a512a261..02350afd565d9 100644 --- a/components/kustomer/kustomer.app.mjs +++ b/components/kustomer/kustomer.app.mjs @@ -1,11 +1,344 @@ +import { axios } from "@pipedream/platform"; +import { + DEFAULT_LANG_OPTIONS, + DIRECTION_OPTIONS, + GENDER_OPTIONS, + LIMIT, + SENTIMENT_OPTIONS, + STATUS_OPTIONS, +} from "./common/constants.mjs"; + export default { type: "app", app: "kustomer", - propDefinitions: {}, + propDefinitions: { + customerId: { + type: "string", + label: "Customer ID", + description: "Unique identifier for the customer", + async options({ page }) { + const { data } = await this.listCustomers({ + params: { + page: page + 1, + pageSize: LIMIT * page, + }, + }); + + return data.map(({ + id: value, attributes: { displayName: label }, + }) => ({ + label, + value, + })); + }, + }, + tags: { + type: "string[]", + label: "Tags", + description: "Tags associated with the conversation", + async options({ page }) { + const { data } = await this.listTags({ + params: { + page: page + 1, + pageSize: LIMIT * page, + }, + }); + return data.map(({ + id: value, attributes: { name: label }, + }) => ({ + label, + value, + })); + }, + }, + assignedUsers: { + type: "string[]", + label: "Assigned Users", + description: "Users assigned to the conversation", + async options({ page }) { + const { data } = await this.listUsers({ + params: { + page: page + 1, + pageSize: LIMIT * page, + }, + }); + return data.map(({ + id: value, attributes: { displayName: label }, + }) => ({ + label, + value, + })); + }, + }, + assignedTeams: { + type: "string[]", + label: "Assigned Teams", + description: "Teams assigned to the resource", + async options({ page }) { + const { data } = await this.listTeams({ + params: { + page: page + 1, + pageSize: LIMIT * page, + }, + }); + return data.map(({ + id: value, attributes: { name: label }, + }) => ({ + label, + value, + })); + }, + }, + queueId: { + type: "string", + label: "Queue Id", + description: "Queue ID assigned to the conversation", + async options({ page }) { + const { data } = await this.listQueues({ + params: { + page: page + 1, + pageSize: LIMIT * page, + }, + }); + return data.map(({ + id: value, attributes: { displayName: label }, + }) => ({ + label, + value, + })); + }, + }, + conversationId: { + type: "string", + label: "Conversation ID", + description: "Unique identifier for the conversation", + async options({ page }) { + const { data } = await this.listConversations({ + params: { + page: page + 1, + pageSize: LIMIT * page, + }, + }); + return data.map(({ + id: value, attributes: { name: label }, + }) => ({ + label, + value, + })); + }, + }, + externalId: { + type: "string", + label: "External ID", + description: "External identifier", + }, + name: { + type: "string", + label: "Name", + description: "Name of the customer", + }, + status: { + type: "string", + label: "Status", + description: "Status of the conversation", + options: STATUS_OPTIONS, + }, + priority: { + type: "integer", + label: "Priority", + description: "Priority level (1-5)", + min: 1, + max: 5, + }, + direction: { + type: "string", + label: "Direction", + description: "Direction of the conversation", + options: DIRECTION_OPTIONS, + }, + sentimentPolarity: { + type: "string", + label: "Sentiment Polarity", + description: "Sentiment polarity associated with the conversation", + options: SENTIMENT_OPTIONS, + }, + sentimentConfidence: { + type: "string", + label: "Sentiment Confidence", + description: "Sentiment confidence associated with the conversation", + options: SENTIMENT_OPTIONS, + }, + defaultLang: { + type: "string", + label: "Default Language", + description: "Default language for the customer", + options: DEFAULT_LANG_OPTIONS, + }, + company: { + type: "string", + label: "Company", + description: "Company of the customer", + }, + username: { + type: "string", + label: "Username", + description: "Username of the customer", + }, + avatarUrl: { + type: "string", + label: "Avatar URL", + description: "URL to the avatar", + }, + externalIds: { + type: "string[]", + label: "External IDs", + description: "External identifiers", + }, + sharedExternalIds: { + type: "string[]", + label: "Shared External IDs", + description: "Shared external identifiers", + }, + emails: { + type: "string[]", + label: "Emails", + description: "Emails of the customer", + }, + sharedEmails: { + type: "string[]", + label: "Shared Emails", + description: "Shared emails", + }, + phones: { + type: "string[]", + label: "Phones", + description: "Phone numbers of the customer", + }, + sharedPhones: { + type: "string[]", + label: "Shared Phones", + description: "Shared phone numbers", + }, + whatsApps: { + type: "string[]", + label: "WhatsApps", + description: "WhatsApp numbers of the customer", + }, + urls: { + type: "string[]", + label: "URLs", + description: "Associated URLs", + }, + birthdayAt: { + type: "string", + label: "Birthday At", + description: "A valid [ISO 8601](https://pt.wikipedia.org/wiki/ISO_8601) date/time", + }, + gender: { + type: "string", + label: "Gender", + description: "Gender of the customer", + options: GENDER_OPTIONS, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return `https://${this.$auth.subdomain}.api.kustomerapp.com/v1`; + }, + _headers() { + return { + Authorization: `Bearer ${this.$auth.api_key}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: this._baseUrl() + path, + headers: this._headers(), + ...opts, + }); + }, + createConversation(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/conversations", + ...opts, + }); + }, + updateConversation({ + conversationId, ...opts + }) { + return this._makeRequest({ + method: "PATCH", + path: `/conversations/${conversationId}`, + ...opts, + }); + }, + createCustomer(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/customers", + ...opts, + }); + }, + updateCustomer({ + customerId, ...opts + }) { + return this._makeRequest({ + method: "PUT", + path: `/customers/${customerId}`, + ...opts, + }); + }, + listConversations(opts = {}) { + return this._makeRequest({ + path: "/conversations", + ...opts, + }); + }, + listCustomers(opts = {}) { + return this._makeRequest({ + path: "/customers", + ...opts, + }); + }, + listQueues(opts = {}) { + return this._makeRequest({ + path: "/routing/queues", + ...opts, + }); + }, + listTags(opts = {}) { + return this._makeRequest({ + path: "/tags", + ...opts, + }); + }, + listUsers(opts = {}) { + return this._makeRequest({ + path: "/users", + ...opts, + }); + }, + listTeams(opts = {}) { + return this._makeRequest({ + path: "/teams", + ...opts, + }); + }, + createWebhook(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/outbound-webhooks", + ...opts, + }); + }, + deleteWebhook(webhookId) { + return this._makeRequest({ + method: "DELETE", + path: `/outbound-webhooks/${webhookId}`, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/kustomer/package.json b/components/kustomer/package.json index c6b02118b4303..461537a2f3dad 100644 --- a/components/kustomer/package.json +++ b/components/kustomer/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/kustomer", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Kustomer Components", "main": "kustomer.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } -} \ No newline at end of file +} diff --git a/components/kustomer/sources/common/base.mjs b/components/kustomer/sources/common/base.mjs new file mode 100644 index 0000000000000..c0cf615ed9654 --- /dev/null +++ b/components/kustomer/sources/common/base.mjs @@ -0,0 +1,49 @@ +import kustomer from "../../kustomer.app.mjs"; + +export default { + props: { + kustomer, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + name: { + type: "string", + label: "Webhook Name", + description: "The name of the webhook to be identified in the UI", + }, + }, + methods: { + _getHookId() { + return this.db.get("hookId"); + }, + _setHookId(hookId) { + this.db.set("hookId", hookId); + }, + }, + hooks: { + async activate() { + const response = await this.kustomer.createWebhook({ + data: { + name: this.name, + url: this.http.endpoint, + events: this.getEventType(), + }, + }); + this._setHookId(response.data.id); + }, + async deactivate() { + const webhookId = this._getHookId(); + await this.kustomer.deleteWebhook(webhookId); + }, + }, + async run({ body }) { + const ts = Date.parse(body.createdAt); + this.$emit(body, { + id: body.id, + summary: this.getSummary(body), + ts: ts, + }); + }, +}; diff --git a/components/kustomer/sources/new-conversation-instant/new-conversation-instant.mjs b/components/kustomer/sources/new-conversation-instant/new-conversation-instant.mjs new file mode 100644 index 0000000000000..3e43317b7df50 --- /dev/null +++ b/components/kustomer/sources/new-conversation-instant/new-conversation-instant.mjs @@ -0,0 +1,24 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "kustomer-new-conversation-instant", + name: "New Conversation Created (Instant)", + description: "Emit new event when a conversation is created in Kustomer.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return [ + "kustomer.conversation.create", + ]; + }, + getSummary(body) { + return `New Conversation: ${body.data.attributes.name}`; + }, + }, + sampleEmit, +}; diff --git a/components/kustomer/sources/new-conversation-instant/test-event.mjs b/components/kustomer/sources/new-conversation-instant/test-event.mjs new file mode 100644 index 0000000000000..00d007cf663d2 --- /dev/null +++ b/components/kustomer/sources/new-conversation-instant/test-event.mjs @@ -0,0 +1,192 @@ +export default { + "data": { + "id": "67dd47dfbc632c1804db1bf1", + "name": "kustomer.conversation.create", + "org": "67dd47dfbc632c1804db1bf1", + "partition": "67dd47dfbc632c1804db1bf1", + "data": { + "type": "conversation", + "id": "67dd47dfbc632c1804db1bf1", + "attributes": { + "externalId": "", + "name": "Conversation Name", + "channels": [], + "status": "open", + "open": { + "statusAt": "2025-03-21T20:04:04.375Z" + }, + "messageCount": 0, + "noteCount": 0, + "satisfaction": 0, + "satisfactionLevel": { + "sentByTeams": [], + "answers": [] + }, + "createdAt": "2025-03-21T20:04:04.375Z", + "updatedAt": "2025-03-21T20:04:04.375Z", + "modifiedAt": "2025-03-21T20:04:04.375Z", + "lastActivityAt": "2025-03-21T20:04:04.377Z", + "spam": false, + "ended": false, + "tags": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "suggestedTags": [], + "predictions": [], + "suggestedShortcuts": [], + "firstMessageIn": {}, + "firstMessageOut": { + "createdByTeams": [] + }, + "lastMessageIn": {}, + "lastMessageOut": {}, + "lastMessageUnrespondedTo": {}, + "lastMessageUnrespondedToSinceLastDone": {}, + "assignedUsers": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "assignedTeams": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "firstResponse": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "firstResponseSinceLastDone": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "lastResponse": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "firstDone": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "lastDone": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "direction": "in", + "outboundMessageCount": 0, + "inboundMessageCount": 0, + "rev": 1, + "priority": 5, + "defaultLang": "en_us", + "locale": "US", + "roleGroupVersions": [], + "accessOverride": [], + "modificationHistory": { + "nameAt": "2025-03-21T20:04:04.375Z", + "priorityAt": "2025-03-21T20:04:04.375Z", + "channelAt": "2025-03-21T20:04:04.375Z", + "assignedTeamsAt": "2025-03-21T20:04:04.375Z", + "assignedUsersAt": "2025-03-21T20:04:04.375Z", + "brandAt": null, + "defaultLangAt": null, + "statusAt": "2025-03-21T20:04:04.375Z", + "tagsAt": "2025-03-21T20:04:04.375Z", + "customAt": null + }, + "billingStatus": "no_messages", + "assistant": { + "fac": { + "reasons": [], + "exclusions": [], + "source": {} + }, + "assistantId": [] + }, + "aiAgent": { + "automationId": [] + }, + "phase": "initial", + "matchedTimeBasedRules": [] + }, + "relationships": { + "messages": { + "links": { + "self": "/v1/conversations/67dd47dfbc632c1804db1bf1/messages" + } + }, + "createdBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "modifiedBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "org": { + "links": { + "self": "/v1/orgs/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "org", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "customer": { + "data": { + "type": "customer", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/customers/67dd47dfbc632c1804db1bf1" + } + }, + "queue": { + "data": { + "type": "queue", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/routing/queues/67dd47dfbc632c1804db1bf1" + } + }, + "brand": { + "data": { + "type": "brand", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/brands/67dd47dfbc632c1804db1bf1" + } + } + }, + "links": { + "self": "/v1/conversations/67dd47dfbc632c1804db1bf1" + } + }, + "createdAt": "2025-03-21T20:04:04.399Z", + "persist": true, + "dataId": "67dd47dfbc632c1804db1bf1", + "meta": { + "customChanged": false + }, + "snsFilters": [ + "csat" + ] + } +} \ No newline at end of file diff --git a/components/kustomer/sources/new-customer-instant/new-customer-instant.mjs b/components/kustomer/sources/new-customer-instant/new-customer-instant.mjs new file mode 100644 index 0000000000000..f95c61d64135b --- /dev/null +++ b/components/kustomer/sources/new-customer-instant/new-customer-instant.mjs @@ -0,0 +1,24 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "kustomer-new-customer-instant", + name: "New Customer Created (Instant)", + description: "Emit new event when a new customer is added to Kustomer.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return [ + "kustomer.customer.create", + ]; + }, + getSummary(body) { + return `New Customer: ${body.data.attributes.name}`; + }, + }, + sampleEmit, +}; diff --git a/components/kustomer/sources/new-customer-instant/test-event.mjs b/components/kustomer/sources/new-customer-instant/test-event.mjs new file mode 100644 index 0000000000000..b6e875cb95e13 --- /dev/null +++ b/components/kustomer/sources/new-customer-instant/test-event.mjs @@ -0,0 +1,111 @@ +export default { + "id": "67dd47dfbc632c1804db1bf1", + "name": "kustomer.customer.create", + "org": "67dd47dfbc632c1804db1bf1", + "partition": "67dd47dfbc632c1804db1bf1", + "orgName": "par-pipedream-berta", + "data": { + "type": "customer", + "id": "67dd47dfbc632c1804db1bf1", + "attributes": { + "displayName": "Silver Scissors", + "displayColor": "silver", + "displayIcon": "scissors", + "externalIds": [], + "sharedExternalIds": [], + "emails": [], + "sharedEmails": [], + "phones": [], + "sharedPhones": [], + "whatsapps": [], + "sharedWhatsapps": [], + "facebookIds": [], + "instagramIds": [], + "socials": [], + "sharedSocials": [], + "urls": [], + "locations": [], + "activeUsers": [], + "watchers": [], + "recentLocation": { + "updatedAt": "2025-03-21T20:10:26.482Z" + }, + "createdAt": "2025-03-21T20:10:26.481Z", + "updatedAt": "2025-03-21T20:10:26.481Z", + "modifiedAt": "2025-03-21T20:10:26.481Z", + "lastActivityAt": "2025-03-21T20:10:26.481Z", + "deleted": false, + "lastConversation": { + "channels": [], + "tags": [] + }, + "conversationCounts": { + "done": 0, + "open": 0, + "snoozed": 0, + "all": 0 + }, + "preview": {}, + "tags": [], + "progressiveStatus": null, + "verified": false, + "rev": 1, + "recentItems": [], + "satisfactionLevel": { + "firstSatisfaction": { + "sentByTeams": [] + }, + "lastSatisfaction": { + "sentByTeams": [] + } + }, + "roleGroupVersions": [], + "accessOverride": [] + }, + "relationships": { + "messages": { + "links": { + "self": "/v1/customers/67dd47dfbc632c1804db1bf1/messages" + } + }, + "createdBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "modifiedBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "org": { + "data": { + "type": "org", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/orgs/67dd47dfbc632c1804db1bf1" + } + } + }, + "links": { + "self": "/v1/customers/67dd47dfbc632c1804db1bf1" + } + }, + "createdAt": "2025-03-21T20:10:26.494Z", + "persist": true, + "client": "api-gw", + "dataId": "67dd47dfbc632c1804db1bf1", + "meta": { + "customChanged": false + }, + "snsFilters": [] +} \ No newline at end of file diff --git a/components/kustomer/sources/new-message-instant/new-message-instant.mjs b/components/kustomer/sources/new-message-instant/new-message-instant.mjs new file mode 100644 index 0000000000000..6a1dc899c41fb --- /dev/null +++ b/components/kustomer/sources/new-message-instant/new-message-instant.mjs @@ -0,0 +1,24 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "kustomer-new-message-instant", + name: "New Message Created in Conversation (Instant)", + description: "Emit new event when a new message is created in a conversation.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return [ + "kustomer.message.create", + ]; + }, + getSummary(body) { + return `New message created: ${body.dataId}`; + }, + }, + sampleEmit, +}; diff --git a/components/kustomer/sources/new-message-instant/test-event.mjs b/components/kustomer/sources/new-message-instant/test-event.mjs new file mode 100644 index 0000000000000..d233e4eededcb --- /dev/null +++ b/components/kustomer/sources/new-message-instant/test-event.mjs @@ -0,0 +1,115 @@ +export default { + "id": "67dd47dfbc632c1804db1bf1", + "name": "kustomer.message.create", + "org": "67dd47dfbc632c1804db1bf1", + "partition": "67dd47dfbc632c1804db1bf1", + "data": { + "type": "message", + "id": "67dd47dfbc632c1804db1bf1", + "attributes": { + "channel": "email", + "app": "postmark", + "size": 0, + "direction": "out", + "directionType": "initial-out", + "preview": "message...", + "meta": { + "from": "support@subdomain.mail.kustomerapp.com", + "to": [ + { + "email": "moishe@example.com" + } + ] + }, + "status": "error", + "assignedTeams": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "assignedUsers": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "error": { + "status": 400, + "code": "invalid-recipient", + "title": "You tried to send to recipient(s) that have been marked as inactive. Found inactive addresses: . Inactive recipients are ones that have generated a hard bounce, a spam complaint, or a manual suppression.", + "meta": { + "appErrorCode": 406 + } + }, + "errorAt": "2025-03-21T20:13:07.702Z", + "auto": false, + "sentAt": "2025-03-21T20:13:07.702Z", + "createdAt": "2025-03-21T20:13:07.798Z", + "updatedAt": "2025-03-21T20:13:07.798Z", + "modifiedAt": "2025-03-21T20:13:07.798Z", + "redacted": false, + "createdByTeams": [], + "rev": 1, + "reactions": [], + "intentDetections": [] + }, + "relationships": { + "org": { + "links": { + "self": "/v1/orgs/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "org", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "createdBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "modifiedBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "customer": { + "links": { + "self": "/v1/customers/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "customers", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "conversation": { + "links": { + "self": "/v1/conversations/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "conversation", + "id": "67dd47dfbc632c1804db1bf1" + } + } + }, + "links": { + "self": "/v1/messages/67dd47dfbc632c1804db1bf1" + } + }, + "createdAt": "2025-03-21T20:13:07.814Z", + "persist": true, + "client": "postmark-drafts-sender", + "dataId": "67dd47dfbc632c1804db1bf1", + "meta": { + "customChanged": false + }, + "snsFilters": [ + "assistant" + ] +} \ No newline at end of file diff --git a/components/kustomer/sources/updated-conversation-instant/test-event.mjs b/components/kustomer/sources/updated-conversation-instant/test-event.mjs new file mode 100644 index 0000000000000..16002e915f18a --- /dev/null +++ b/components/kustomer/sources/updated-conversation-instant/test-event.mjs @@ -0,0 +1,250 @@ +export default { + "id": "67dd47dfbc632c1804db1bf1", + "name": "kustomer.conversation.update", + "org": "67dd47dfbc632c1804db1bf1", + "partition": "67dd47dfbc632c1804db1bf1", + "orgName": "par-pipedream-berta", + "data": { + "type": "conversation", + "id": "67dd47dfbc632c1804db1bf1", + "attributes": { + "externalId": "123", + "name": "Updated Name", + "channels": [], + "status": "open", + "open": { + "statusAt": "2025-03-20T18:50:55.976Z" + }, + "messageCount": 0, + "noteCount": 0, + "satisfaction": 0, + "satisfactionLevel": { + "sentByTeams": [], + "answers": [] + }, + "createdAt": "2025-03-20T18:50:55.976Z", + "updatedAt": "2025-03-21T20:20:11.424Z", + "modifiedAt": "2025-03-21T20:20:11.424Z", + "lastActivityAt": "2025-03-20T18:50:55.981Z", + "spam": false, + "ended": false, + "tags": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "suggestedTags": [], + "predictions": [], + "suggestedShortcuts": [], + "firstMessageIn": {}, + "firstMessageOut": { + "createdByTeams": [] + }, + "lastMessageIn": {}, + "lastMessageOut": {}, + "lastMessageUnrespondedTo": {}, + "lastMessageUnrespondedToSinceLastDone": {}, + "assignedUsers": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "assignedTeams": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "firstResponse": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "firstResponseSinceLastDone": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "lastResponse": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "firstDone": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "lastDone": { + "createdByTeams": [], + "assignedTeams": [], + "assignedUsers": [] + }, + "direction": "in", + "outboundMessageCount": 0, + "inboundMessageCount": 0, + "rev": 3, + "priority": 5, + "defaultLang": "en_us", + "locale": "US", + "roleGroupVersions": [], + "accessOverride": [], + "modificationHistory": { + "nameAt": "2025-03-21T20:20:11.426Z", + "priorityAt": "2025-03-20T18:50:55.976Z", + "channelAt": "2025-03-20T18:50:55.976Z", + "assignedTeamsAt": "2025-03-20T18:50:55.976Z", + "assignedUsersAt": "2025-03-20T18:50:55.976Z", + "brandAt": null, + "defaultLangAt": null, + "statusAt": "2025-03-20T18:50:55.976Z", + "tagsAt": "2025-03-20T18:50:55.976Z", + "customAt": null + }, + "billingStatus": "no_messages", + "assistant": { + "fac": { + "reasons": [], + "exclusions": [], + "source": {} + }, + "assistantId": [] + }, + "aiAgent": { + "automationId": [] + }, + "phase": "initial", + "matchedTimeBasedRules": [] + }, + "relationships": { + "messages": { + "links": { + "self": "/v1/conversations/67dd47dfbc632c1804db1bf1/messages" + } + }, + "createdBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "modifiedBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "org": { + "links": { + "self": "/v1/orgs/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "org", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "customer": { + "data": { + "type": "customer", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/customers/67dd47dfbc632c1804db1bf1" + } + }, + "queue": { + "data": { + "type": "queue", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/routing/queues/67dd47dfbc632c1804db1bf1" + } + }, + "brand": { + "data": { + "type": "brand", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/brands/67dd47dfbc632c1804db1bf1" + } + } + }, + "links": { + "self": "/v1/conversations/67dd47dfbc632c1804db1bf1" + } + }, + "createdAt": "2025-03-21T20:20:11.435Z", + "changes": { + "attributes": { + "externalId": { + "op": "replace", + "before": "123", + "after": "321" + }, + "name": { + "op": "replace", + "before": "Name", + "after": "Update Name" + }, + "updatedAt": { + "op": "replace", + "before": "2025-03-21T19:54:02.663Z", + "after": "2025-03-21T20:20:11.424Z" + }, + "modifiedAt": { + "op": "replace", + "before": "2025-03-21T19:54:02.663Z", + "after": "2025-03-21T20:20:11.424Z" + }, + "rev": { + "op": "replace", + "before": 2, + "after": 3 + }, + "modificationHistory": { + "op": "replace", + "before": { + "nameAt": "2025-03-21T19:54:02.664Z", + "priorityAt": "2025-03-20T18:50:55.976Z", + "channelAt": "2025-03-20T18:50:55.976Z", + "assignedTeamsAt": "2025-03-20T18:50:55.976Z", + "assignedUsersAt": "2025-03-20T18:50:55.976Z", + "brandAt": null, + "defaultLangAt": null, + "statusAt": "2025-03-20T18:50:55.976Z", + "tagsAt": "2025-03-20T18:50:55.976Z", + "customAt": null + }, + "after": { + "nameAt": "2025-03-21T20:20:11.426Z", + "priorityAt": "2025-03-20T18:50:55.976Z", + "channelAt": "2025-03-20T18:50:55.976Z", + "assignedTeamsAt": "2025-03-20T18:50:55.976Z", + "assignedUsersAt": "2025-03-20T18:50:55.976Z", + "brandAt": null, + "defaultLangAt": null, + "statusAt": "2025-03-20T18:50:55.976Z", + "tagsAt": "2025-03-20T18:50:55.976Z", + "customAt": null + } + } + }, + "relationships": {} + }, + "persist": true, + "client": "api-gw", + "dataId": "67dd47dfbc632c1804db1bf1", + "meta": { + "customChanged": false + }, + "snsFilters": [ + "assistant", + "csat" + ] +} \ No newline at end of file diff --git a/components/kustomer/sources/updated-conversation-instant/updated-conversation-instant.mjs b/components/kustomer/sources/updated-conversation-instant/updated-conversation-instant.mjs new file mode 100644 index 0000000000000..eea7b13895ee1 --- /dev/null +++ b/components/kustomer/sources/updated-conversation-instant/updated-conversation-instant.mjs @@ -0,0 +1,24 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "kustomer-updated-conversation-instant", + name: "Updated Conversation (Instant)", + description: "Emit new event when an existing conversation is updated in Kustomer.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return [ + "kustomer.conversation.update", + ]; + }, + getSummary(body) { + return `Conversation Updated: ${body.data.attributes.name}`; + }, + }, + sampleEmit, +}; diff --git a/components/kustomer/sources/updated-customer-instant/test-event.mjs b/components/kustomer/sources/updated-customer-instant/test-event.mjs new file mode 100644 index 0000000000000..3aee78beffd11 --- /dev/null +++ b/components/kustomer/sources/updated-customer-instant/test-event.mjs @@ -0,0 +1,222 @@ +export default { + "id": "67dd47dfbc632c1804db1bf1", + "name": "kustomer.customer.update", + "org": "67dd47dfbc632c1804db1bf1", + "partition": "67dd47dfbc632c1804db1bf1", + "data": { + "type": "customer", + "id": "67dd47dfbc632c1804db1bf1", + "attributes": { + "name": "Updated Name", + "displayName": "Updated Name", + "displayColor": "pink", + "displayIcon": "stereo", + "externalId": "123", + "externalIds": [ + { + "externalId": "123", + "verified": true, + "externalVerified": false + } + ], + "sharedExternalIds": [ + { + "externalId": "123", + "verified": false, + "externalVerified": false + } + ], + "avatarUrl": "https://avatarUrl.com", + "username": "username", + "emails": [ + { + "type": "home", + "email": "email@email.com", + "verified": false, + "externalVerified": false + } + ], + "sharedEmails": [ + { + "type": "home", + "email": "email@email.com", + "verified": false, + "externalVerified": false + } + ], + "phones": [ + { + "type": "mobile", + "phone": "+1234567890", + "verified": false + } + ], + "sharedPhones": [ + { + "type": "mobile", + "phone": "+1234567890", + "verified": false + } + ], + "whatsapps": [ + { + "type": "mobile", + "phone": "whatsapp:+1234567890", + "verified": false + } + ], + "sharedWhatsapps": [], + "facebookIds": [], + "instagramIds": [], + "socials": [], + "sharedSocials": [], + "urls": [ + { + "type": "website", + "url": "https://url.com" + } + ], + "locations": [], + "activeUsers": [], + "watchers": [], + "recentLocation": { + "updatedAt": "2025-03-21T19:25:27.886Z" + }, + "locale": null, + "birthdayAt": "2001-12-12T12:12:12.000Z", + "gender": "f", + "createdAt": "2025-03-21T19:25:27.882Z", + "updatedAt": "2025-03-21T20:23:52.827Z", + "modifiedAt": "2025-03-21T20:23:52.827Z", + "lastActivityAt": "2025-03-21T20:23:52.826Z", + "deleted": false, + "lastConversation": { + "channels": [], + "tags": [] + }, + "conversationCounts": { + "done": 0, + "open": 0, + "snoozed": 0, + "all": 0 + }, + "preview": {}, + "tags": [ + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1", + "67dd47dfbc632c1804db1bf1" + ], + "sentiment": { + "polarity": -1, + "confidence": -1 + }, + "progressiveStatus": null, + "verified": true, + "rev": 7, + "recentItems": [], + "defaultLang": "af", + "satisfactionLevel": { + "firstSatisfaction": { + "sentByTeams": [] + }, + "lastSatisfaction": { + "sentByTeams": [] + } + }, + "roleGroupVersions": [], + "accessOverride": [], + "companyName": "company name", + "firstName": "company", + "lastName": "name" + }, + "relationships": { + "messages": { + "links": { + "self": "/v1/customers/67dd47dfbc632c1804db1bf1/messages" + } + }, + "createdBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "modifiedBy": { + "links": { + "self": "/v1/users/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "user", + "id": "67dd47dfbc632c1804db1bf1" + } + }, + "org": { + "data": { + "type": "org", + "id": "67dd47dfbc632c1804db1bf1" + }, + "links": { + "self": "/v1/orgs/67dd47dfbc632c1804db1bf1" + } + }, + "company": { + "links": { + "self": "/v1/companies/67dd47dfbc632c1804db1bf1" + }, + "data": { + "type": "company", + "id": "67dd47dfbc632c1804db1bf1" + } + } + }, + "links": { + "self": "/v1/customers/67dd47dfbc632c1804db1bf1" + } + }, + "createdAt": "2025-03-21T20:23:52.847Z", + "changes": { + "attributes": { + "name": { + "op": "replace", + "before": "Name", + "after": "Updated Name" + }, + "displayName": { + "op": "replace", + "before": "Name", + "after": "Updated Name" + }, + "updatedAt": { + "op": "replace", + "before": "2025-03-21T19:32:42.243Z", + "after": "2025-03-21T20:23:52.827Z" + }, + "modifiedAt": { + "op": "replace", + "before": "2025-03-21T19:32:42.243Z", + "after": "2025-03-21T20:23:52.827Z" + }, + "lastActivityAt": { + "op": "replace", + "before": "2025-03-21T19:32:42.242Z", + "after": "2025-03-21T20:23:52.826Z" + }, + "rev": { + "op": "replace", + "before": 6, + "after": 7 + }, + }, + "relationships": {} + }, + "persist": true, + "client": "api-gw", + "dataId": "67dd47dfbc632c1804db1bf1", + "meta": { + "customChanged": false + }, + "snsFilters": [] +} \ No newline at end of file diff --git a/components/kustomer/sources/updated-customer-instant/updated-customer-instant.mjs b/components/kustomer/sources/updated-customer-instant/updated-customer-instant.mjs new file mode 100644 index 0000000000000..bfc23bd58c609 --- /dev/null +++ b/components/kustomer/sources/updated-customer-instant/updated-customer-instant.mjs @@ -0,0 +1,24 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "kustomer-updated-customer-instant", + name: "Updated Customer (Instant)", + description: "Emit new event when an existing customer's details are updated in Kustomer.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return [ + "kustomer.customer.update", + ]; + }, + getSummary(body) { + return `Customer Updated: ${body.data.attributes.name}`; + }, + }, + sampleEmit, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58e08a1481b83..f0a04fd82b6cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4658,9 +4658,6 @@ importers: specifier: ^3.0.3 version: 3.0.3 - components/formatting: - specifiers: {} - components/formbricks: dependencies: '@pipedream/platform': @@ -6898,7 +6895,11 @@ importers: components/kucoin_futures: {} - components/kustomer: {} + components/kustomer: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 components/kvdb: dependencies: @@ -8040,8 +8041,7 @@ importers: specifier: ^3.0.0 version: 3.0.3 - components/miyn: - specifiers: {} + components/miyn: {} components/moaform: dependencies: @@ -9325,8 +9325,7 @@ importers: components/perry_github_test: {} - components/persanaai: - specifiers: {} + components/persanaai: {} components/persistiq: dependencies: