diff --git a/components/apiframe/apiframe.app.mjs b/components/apiframe/apiframe.app.mjs index e9ea57725f454..c6027ec3a22ed 100644 --- a/components/apiframe/apiframe.app.mjs +++ b/components/apiframe/apiframe.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/brand_dev/brand_dev.app.mjs b/components/brand_dev/brand_dev.app.mjs index 0dfee237e97da..d7046bafc7019 100644 --- a/components/brand_dev/brand_dev.app.mjs +++ b/components/brand_dev/brand_dev.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/contentdrips/contentdrips.app.mjs b/components/contentdrips/contentdrips.app.mjs index 3176c60f15372..d6aa0d3ef06c4 100644 --- a/components/contentdrips/contentdrips.app.mjs +++ b/components/contentdrips/contentdrips.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/cursor/cursor.app.mjs b/components/cursor/cursor.app.mjs index e201371cbc766..d6f25215fa77c 100644 --- a/components/cursor/cursor.app.mjs +++ b/components/cursor/cursor.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/emailchef/emailchef.app.mjs b/components/emailchef/emailchef.app.mjs index ea43e0f26fea1..7345b5ad7c4e7 100644 --- a/components/emailchef/emailchef.app.mjs +++ b/components/emailchef/emailchef.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/encharge/actions/add-or-update-person/add-or-update-person.mjs b/components/encharge/actions/add-or-update-person/add-or-update-person.mjs new file mode 100644 index 0000000000000..feb9e425fcc85 --- /dev/null +++ b/components/encharge/actions/add-or-update-person/add-or-update-person.mjs @@ -0,0 +1,73 @@ +import { parseObject } from "../../common/utils.mjs"; +import app from "../../encharge.app.mjs"; + +export default { + key: "encharge-add-or-update-person", + name: "Add or Update Person", + description: "Add or update a person in Encharge. [See the documentation](https://app-encharge-resources.s3.amazonaws.com/redoc.html#/people/createupdatepeople)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + app, + userId: { + propDefinition: [ + app, + "userId", + ], + optional: true, + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the person.", + optional: true, + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the person.", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The email of the person.", + optional: true, + }, + additionalFields: { + type: "object", + label: "Additional Fields", + description: "Additional fields to include in the request body.", + optional: true, + }, + }, + async run({ $ }) { + const parsedAdditionalFields = parseObject(this.additionalFields) || {}; + const data = [ + { + firstName: this.firstName, + lastName: this.lastName, + email: this.email, + id: this.userId, + ...parsedAdditionalFields, + }, + ]; + + const response = await this.app.addOrUpdatePerson({ + $, + data, + }); + + $.export("$summary", `Successfully ${this.userId + ? "updated" + : "added"} person${this.email + ? ` with email ${this.email}` + : ""}`); + return response; + }, +}; diff --git a/components/encharge/actions/archive-person/archive-person.mjs b/components/encharge/actions/archive-person/archive-person.mjs new file mode 100644 index 0000000000000..dfd2bfb9369e1 --- /dev/null +++ b/components/encharge/actions/archive-person/archive-person.mjs @@ -0,0 +1,62 @@ +import app from "../../encharge.app.mjs"; + +export default { + key: "encharge-archive-person", + name: "Archive Person", + description: "Archive a person in Encharge. [See the documentation](https://app-encharge-resources.s3.amazonaws.com/redoc.html#/people/archivepeople)", + version: "0.0.1", + annotations: { + destructiveHint: true, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + app, + userId: { + propDefinition: [ + app, + "userId", + ], + description: "The user ID of the person to archive.", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The email of the person to archive.", + optional: true, + }, + force: { + type: "boolean", + label: "Force", + description: "If set to `true`, will delete the person's data. This is useful for GDPR-compliant removal of user data.", + default: false, + }, + }, + async run({ $ }) { + if (!this.userId && !this.email) { + throw new Error("You must provide either a user ID or an email."); + } + if (this.userId && this.email) { + throw new Error("You must provide either a user ID or an email, not both."); + } + + const response = await this.app.archivePerson({ + $, + params: { + people: [ + { + id: this.userId, + email: this.email, + }, + ], + force: this.force, + }, + }); + $.export("$summary", `Successfully archived person with ${this.userId + ? `ID ${this.userId}` + : `email ${this.email}`}`); + return response; + }, +}; diff --git a/components/encharge/actions/remove-tags/remove-tags.mjs b/components/encharge/actions/remove-tags/remove-tags.mjs new file mode 100644 index 0000000000000..d47f102dbd83a --- /dev/null +++ b/components/encharge/actions/remove-tags/remove-tags.mjs @@ -0,0 +1,53 @@ +import { parseObject } from "../../common/utils.mjs"; +import app from "../../encharge.app.mjs"; + +export default { + key: "encharge-remove-tags", + name: "Remove Tags", + description: "Remove tag(s) from existing user. [See the documentation](https://app-encharge-resources.s3.amazonaws.com/#/tags/removetag)", + version: "0.0.1", + annotations: { + destructiveHint: true, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + app, + userId: { + propDefinition: [ + app, + "userId", + ], + description: "UserID of the person.", + }, + tags: { + propDefinition: [ + app, + "tags", + ({ userId }) => ({ + userId, + }), + ], + }, + }, + async run({ $ }) { + const tags = parseObject(this.tags); + const tagsArray = Array.isArray(tags) + ? tags + : [ + tags, + ]; + const response = await this.app.removeTag({ + $, + data: { + tag: tagsArray.join(","), + id: this.userId, + }, + }); + $.export("$summary", `Successfully removed ${tagsArray.length} tag${tagsArray.length > 1 + ? "s" + : ""} from person with ID ${this.userId}`); + return response; + }, +}; diff --git a/components/encharge/common/constants.mjs b/components/encharge/common/constants.mjs new file mode 100644 index 0000000000000..ea830c15a04cb --- /dev/null +++ b/components/encharge/common/constants.mjs @@ -0,0 +1 @@ +export const LIMIT = 100; diff --git a/components/encharge/common/utils.mjs b/components/encharge/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/encharge/common/utils.mjs @@ -0,0 +1,24 @@ +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; +}; diff --git a/components/encharge/encharge.app.mjs b/components/encharge/encharge.app.mjs index 32eb5dceb5a53..e24b353e8a0a0 100644 --- a/components/encharge/encharge.app.mjs +++ b/components/encharge/encharge.app.mjs @@ -1,11 +1,119 @@ +import { axios } from "@pipedream/platform"; +import { LIMIT } from "./common/constants.mjs"; + export default { type: "app", app: "encharge", - propDefinitions: {}, + propDefinitions: { + userId: { + type: "string", + label: "User ID", + description: "The user ID of the person to update.", + async options({ page }) { + const { people } = await this.listPeople({ + params: { + limit: LIMIT, + offset: LIMIT * page, + }, + }); + + return people.map(({ + id: value, name, email, + }) => ({ + label: `${name}${email + ? ` (${email})` + : ""}`, + value, + })); + }, + }, + tags: { + type: "string[]", + label: "Tags", + description: "Tags to remove from the person.", + async options({ userId }) { + const { + users: [ + { tags }, + ], + } = await this.getPerson({ + params: { + people: [ + { + id: userId, + }, + ], + }, + }); + return tags + ? tags.split(",") + : []; + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _apiUrl() { + return "https://api.encharge.io/v1"; + }, + _getHeaders() { + return { + "Authorization": `Bearer ${this.$auth.oauth_access_token}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: `${this._apiUrl()}/${path}`, + headers: this._getHeaders(), + ...opts, + }); + }, + getPerson(args = {}) { + return this._makeRequest({ + path: "people", + ...args, + }); + }, + listPeople(args = {}) { + return this._makeRequest({ + path: "people/all", + ...args, + }); + }, + addOrUpdatePerson(args = {}) { + return this._makeRequest({ + method: "POST", + path: "people", + ...args, + }); + }, + archivePerson(args = {}) { + return this._makeRequest({ + method: "DELETE", + path: "people", + ...args, + }); + }, + removeTag(args = {}) { + return this._makeRequest({ + method: "DELETE", + path: "tags", + ...args, + }); + }, + createHook(args = {}) { + return this._makeRequest({ + method: "POST", + path: "event-subscriptions", + ...args, + }); + }, + deleteHook(hookId) { + return this._makeRequest({ + method: "DELETE", + path: `event-subscriptions/${hookId}`, + }); }, }, }; diff --git a/components/encharge/package.json b/components/encharge/package.json index d5f4ed7920251..2bcf07317ccba 100644 --- a/components/encharge/package.json +++ b/components/encharge/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/encharge", - "version": "0.0.2", + "version": "0.1.0", "description": "Pipedream Encharge Components", "main": "encharge.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.1" } } diff --git a/components/encharge/sources/common/base.mjs b/components/encharge/sources/common/base.mjs new file mode 100644 index 0000000000000..d16377435d1e1 --- /dev/null +++ b/components/encharge/sources/common/base.mjs @@ -0,0 +1,35 @@ +import encharge from "../../encharge.app.mjs"; + +export default { + props: { + encharge, + db: "$.service.db", + http: "$.interface.http", + }, + methods: { + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + _getWebhookId() { + return this.db.get("webhookId"); + }, + }, + hooks: { + async activate() { + const { subscription } = await this.encharge.createHook({ + data: { + url: this.http.endpoint, + eventType: this.getEvent(), + }, + }); + this._setWebhookId(subscription.id); + }, + async deactivate() { + const webhookId = this._getWebhookId(); + await this.encharge.deleteHook(webhookId); + }, + }, + async run({ body }) { + this.$emit(body, this.generateMeta(body)); + }, +}; diff --git a/components/encharge/sources/new-person-instant/new-person-instant.mjs b/components/encharge/sources/new-person-instant/new-person-instant.mjs new file mode 100644 index 0000000000000..813167a9d5f9e --- /dev/null +++ b/components/encharge/sources/new-person-instant/new-person-instant.mjs @@ -0,0 +1,30 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "encharge-new-person-instant", + name: "New Person (Instant)", + description: "Emit new event when a person is created.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEvent() { + return "newUser"; + }, + generateMeta({ + endUserData: [ + data, + ], + }) { + return { + id: data.id, + summary: `New person with ID ${data.id} created`, + ts: data.createdAt, + }; + }, + }, + sampleEmit, +}; diff --git a/components/encharge/sources/new-person-instant/test-event.mjs b/components/encharge/sources/new-person-instant/test-event.mjs new file mode 100644 index 0000000000000..70463d3f16bea --- /dev/null +++ b/components/encharge/sources/new-person-instant/test-event.mjs @@ -0,0 +1,23 @@ +export default { + "eventType": "newUser", + "eventPayload": {}, + "endUserData": [ + { + "email": "email@test.com", + "firstName": "John", + "lastName": "Doe", + "name": "John Doe", + "lastActivity": "2025-11-20T19:05:09.385Z", + "createdAt": "2025-11-20T19:05:09.375Z", + "leadScore": 0, + "updatedAt": "2025-11-20T19:05:09.387Z", + "id": "934d4608-dce3-423e-815a-e6a4cc64b930", + "data": { + "additionalFields": { + "field01": "value 01", + "field02": "value 02" + } + } + } + ] +} \ No newline at end of file diff --git a/components/encharge/sources/tag-removed-from-person-instant/tag-removed-from-person-instant.mjs b/components/encharge/sources/tag-removed-from-person-instant/tag-removed-from-person-instant.mjs new file mode 100644 index 0000000000000..59620d3f059e8 --- /dev/null +++ b/components/encharge/sources/tag-removed-from-person-instant/tag-removed-from-person-instant.mjs @@ -0,0 +1,38 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "encharge-tag-removed-from-person-instant", + name: "Tag Removed from Person (Instant)", + description: "Emit new event when a tag is removed from a person.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + tagId: { + type: "string", + label: "Tag ID", + description: "Tag ID to remove from person.", + }, + }, + methods: { + ...common.methods, + getEvent() { + return `removed-tag-${this.tagId}`; + }, + generateMeta({ + endUserData: [ + { id }, + ], + }) { + return { + id: `${id}-${this.tagId}`, + summary: `Tag ${this.tagId} removed from person with ID ${id}`, + ts: Date.now(), + }; + }, + }, + sampleEmit, +}; diff --git a/components/encharge/sources/tag-removed-from-person-instant/test-event.mjs b/components/encharge/sources/tag-removed-from-person-instant/test-event.mjs new file mode 100644 index 0000000000000..87acda15c1441 --- /dev/null +++ b/components/encharge/sources/tag-removed-from-person-instant/test-event.mjs @@ -0,0 +1,11 @@ +export default { + "eventType": "removed-tag-tagName", + "eventPayload": { + "tag": "tagName" + }, + "endUserData": [ + { + "id": "12345678-1234-1234-1234-1234567890" + } + ] +} \ No newline at end of file diff --git a/components/encharge/sources/updated-person-instant/test-event.mjs b/components/encharge/sources/updated-person-instant/test-event.mjs new file mode 100644 index 0000000000000..e1afebcf45d6c --- /dev/null +++ b/components/encharge/sources/updated-person-instant/test-event.mjs @@ -0,0 +1,45 @@ +export default { + "eventType": "updatedUser", + "eventPayload": { + "changedFields": { + "firstName": { + "newValue": "John", + "oldValue": "Martin" + }, + "lastName": { + "newValue": "Doe", + "oldValue": "Smith" + }, + "name": { + "newValue": "John Doe", + "oldValue": "Martin Smith" + } + }, + "source": "api" + }, + "endUserData": [ + { + "email": "email@test.com", + "firstName": "Martin", + "lastName": "Smith", + "name": "Martin Smith", + "lastActivity": "2025-11-20T19:08:19.373Z", + "createdAt": "2025-11-20T19:08:19.366Z", + "leadScore": 0, + "updatedAt": "2025-11-20T19:21:59.973Z", + "id": "12345678-1234-1234-1234-1234567890", + "validationResult": "invalid", + "validationConfidence": 75, + "isEmailDisposable": false, + "isEmailRole": false, + "data": { + "field01": "value 01", + "field02": "value 02", + "additionalFields": { + "field01": "value 01", + "field02": "value 02" + } + } + } + ] +} \ No newline at end of file diff --git a/components/encharge/sources/updated-person-instant/updated-person-instant.mjs b/components/encharge/sources/updated-person-instant/updated-person-instant.mjs new file mode 100644 index 0000000000000..4a30e884f7a39 --- /dev/null +++ b/components/encharge/sources/updated-person-instant/updated-person-instant.mjs @@ -0,0 +1,30 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "encharge-updated-person-instant", + name: "Updated Person (Instant)", + description: "Emit new event when a person is updated.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEvent() { + return "updatedUser"; + }, + generateMeta({ + endUserData: [ + data, + ], + }) { + return { + id: data.id, + summary: `Person with ID ${data.id} updated`, + ts: data.createdAt, + }; + }, + }, + sampleEmit, +}; diff --git a/components/fynk/fynk.app.mjs b/components/fynk/fynk.app.mjs index 80e7e676b82ff..5b4c2ef06ccbf 100644 --- a/components/fynk/fynk.app.mjs +++ b/components/fynk/fynk.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/helicone/helicone.app.mjs b/components/helicone/helicone.app.mjs index 340f2162482ab..83f2f5a753e80 100644 --- a/components/helicone/helicone.app.mjs +++ b/components/helicone/helicone.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/iplocate/iplocate.app.mjs b/components/iplocate/iplocate.app.mjs index be8e8d529181a..84ec0bcbfe123 100644 --- a/components/iplocate/iplocate.app.mjs +++ b/components/iplocate/iplocate.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/magicalapi/magicalapi.app.mjs b/components/magicalapi/magicalapi.app.mjs index 9e769076d848e..2fca94fe7e06c 100644 --- a/components/magicalapi/magicalapi.app.mjs +++ b/components/magicalapi/magicalapi.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/relationcity/relationcity.app.mjs b/components/relationcity/relationcity.app.mjs index c55efdbd4f6b6..e36017576fc89 100644 --- a/components/relationcity/relationcity.app.mjs +++ b/components/relationcity/relationcity.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/shortpen/shortpen.app.mjs b/components/shortpen/shortpen.app.mjs index 2b574c2cd7638..5a8b4b4e5a5ba 100644 --- a/components/shortpen/shortpen.app.mjs +++ b/components/shortpen/shortpen.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/socket/socket.app.mjs b/components/socket/socket.app.mjs index 4b4392bc2996b..ed8ca54fe27c0 100644 --- a/components/socket/socket.app.mjs +++ b/components/socket/socket.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/turbosmtp/turbosmtp.app.mjs b/components/turbosmtp/turbosmtp.app.mjs index a3456395a7e60..5db64c72679c5 100644 --- a/components/turbosmtp/turbosmtp.app.mjs +++ b/components/turbosmtp/turbosmtp.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/validemail/validemail.app.mjs b/components/validemail/validemail.app.mjs index 16e67e492a93f..21f3df6cc61c2 100644 --- a/components/validemail/validemail.app.mjs +++ b/components/validemail/validemail.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/veryfi/veryfi.app.mjs b/components/veryfi/veryfi.app.mjs index d14f4f654d692..8550c22b23fd4 100644 --- a/components/veryfi/veryfi.app.mjs +++ b/components/veryfi/veryfi.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a89f72da8aa97..96e4ae0a472ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4722,7 +4722,11 @@ importers: components/emelia: {} - components/encharge: {} + components/encharge: + dependencies: + '@pipedream/platform': + specifier: ^3.1.1 + version: 3.1.1 components/encodian: dependencies: