diff --git a/components/zerobounce/.gitignore b/components/zerobounce/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/zerobounce/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/zerobounce/actions/ai-scoring/ai-scoring.mjs b/components/zerobounce/actions/ai-scoring/ai-scoring.mjs new file mode 100644 index 0000000000000..d191cea4053af --- /dev/null +++ b/components/zerobounce/actions/ai-scoring/ai-scoring.mjs @@ -0,0 +1,27 @@ +import zerobounce from "../../zerobounce.app.mjs"; + +export default { + key: "zerobounce-ai-scoring", + name: "AI Scoring", + description: "Estimates a reliability score based on ZeroBounce's AI for the provided email. [See the documentation](https://www.zerobounce.net/docs/ai-scoring-api/#single_email_scoring)", + version: "0.0.1", + type: "action", + props: { + zerobounce, + email: { + type: "string", + label: "Email", + description: "The email address that you want to retrieve Scoring data for", + }, + }, + async run({ $ }) { + const response = await this.zerobounce.getReliabilityScore({ + $, + params: { + email: this.email, + }, + }); + $.export("$summary", `Successfully estimated reliability score for email: ${this.email}`); + return response; + }, +}; diff --git a/components/zerobounce/actions/file-validation/file-validation.mjs b/components/zerobounce/actions/file-validation/file-validation.mjs new file mode 100644 index 0000000000000..92384e9928ff1 --- /dev/null +++ b/components/zerobounce/actions/file-validation/file-validation.mjs @@ -0,0 +1,128 @@ +import zerobounce from "../../zerobounce.app.mjs"; +import fs from "fs"; +import FormData from "form-data"; +import path from "path"; + +export default { + key: "zerobounce-file-validation", + name: "Validate Emails in File", + description: "Performs email validation on all the addresses contained in a provided file. [See the documentation](https://www.zerobounce.net/docs/email-validation-api-quickstart/)", + version: "0.0.1", + type: "action", + props: { + zerobounce, + filePath: { + type: "string", + label: "File Path", + description: "The path to a csv or txt file in the `/tmp` directory. [See the documentation on working with files](https://pipedream.com/docs/code/nodejs/working-with-files/#writing-a-file-to-tmp)", + }, + emailAddressColumn: { + type: "integer", + label: "Email Address Column", + description: "The column index of the email address in the file. Index starts from 1.", + }, + firstNameColumn: { + type: "integer", + label: "First Name Column", + description: "The column index of the first name column. Index starts from 1.", + optional: true, + }, + lastNameColumn: { + type: "integer", + label: "Last Name Column", + description: "The column index of the last name column. Index starts from 1.", + optional: true, + }, + ipAddressColumn: { + type: "integer", + label: "IP Address Column", + description: "The IP Address the email signed up from. Index starts from 1", + optional: true, + }, + hasHeaderRow: { + type: "boolean", + label: "Has Header Row", + description: "If the first row from the submitted file is a header row", + optional: true, + }, + removeDuplicates: { + type: "boolean", + label: "Remove Duplicates", + description: "If you want the system to remove duplicate emails. Default is `true`. Please note that if we remove more than 50% of the lines because of duplicates (parameter is true), system will return a 400 bad request error as a safety net to let you know that more than 50% of the file has been modified.", + optional: true, + }, + returnUrl: { + type: "string", + label: "Return URL", + description: "The URL will be used to call back when the validation is completed", + optional: true, + }, + callbackWithRerun: { + type: "boolean", + label: "Callback With Rerun", + description: "Use the `$.flow.rerun` Node.js helper to rerun the step when the validation is completed. Overrides the `rerunUrl` prop. This will increase execution time and credit usage as a result. [See the documentation](https://pipedream.com/docs/code/nodejs/rerun/#flow-rerun)", + optional: true, + }, + }, + async run({ $ }) { + let response, summary; + const { run } = $.context; + + if (run.runs === 1) { + let returnUrl = this.returnUrl; + if (this.callbackWithRerun) { + ({ resume_url: returnUrl } = $.flow.rerun(600000, null, 1)); + } + + const filePath = this.filePath.includes("tmp/") + ? this.filePath + : `/tmp/${this.filePath}`; + const fileName = path.basename(filePath); + const fileContent = fs.readFileSync(filePath); + + const formData = new FormData(); + formData.append("file", fileContent, fileName); + formData.append("email_address_column", this.emailAddressColumn); + formData.append("api_key", this.zerobounce.$auth.api_key); + if (this.firstNameColumn) { + formData.append("first_name_column", this.firstNameColumn); + } + if (this.lastNameColumn) { + formData.append("last_name_column", this.lastNameColumn); + } + if (this.ipAddressColumn) { + formData.append("ip_address_column", this.ipAddressColumn); + } + if (this.hasHeaderRow) { + formData.append("has_header_row", this.hasHeaderRow + ? "true" + : "false"); + } + if (this.removeDuplicates) { + formData.append("remove_duplicate", this.removeDuplicates + ? "true" + : "false"); + } + if (returnUrl) { + formData.append("return_url", returnUrl); + } + + response = await this.zerobounce.validateEmailsInFile({ + $, + data: formData, + headers: { + ...formData.getHeaders(), + }, + }); + summary = "Successfully sent file for validation"; + } + + if (run.callback_request) { + response = run.callback_request.body; + summary = "Successfully validated emails in file"; + } + + $.export("$summary", summary); + return response; + }, +}; diff --git a/components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs b/components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs new file mode 100644 index 0000000000000..a4fb5146ee7db --- /dev/null +++ b/components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs @@ -0,0 +1,64 @@ +import zerobounce from "../../zerobounce.app.mjs"; +import fs from "fs"; +import { ConfigurationError } from "@pipedream/platform"; + +export default { + key: "zerobounce-get-validation-results-file", + name: "Get Validation Results File", + description: "Downloads the validation results for a file submitted using sendfile API. [See the documentation](https://www.zerobounce.net/docs/email-validation-api-quickstart/#get_file__v2__)", + version: "0.0.1", + type: "action", + props: { + zerobounce, + fileId: { + type: "string", + label: "File ID", + description: "The file_id returned when sending the file for validation. Can be found on your Zerobounce \"Validate\" tab under Results next to each filename. Click on the ID circle.", + }, + fileName: { + type: "string", + label: "File Name", + description: "The filename to save the file as in the \"/tmp\" directory", + }, + }, + methods: { + getResultsFile({ + $, ...opts + }) { + return this.zerobounce.getResultsFile({ + $, + params: { + file_id: this.fileId, + }, + ...opts, + }); + }, + async validateFileId({ $ }) { + try { + return await this.getResultsFile({ + $, + }); + } catch { + throw new ConfigurationError("File not found. Make sure the File ID is correct"); + } + }, + }, + async run({ $ }) { + if (!(await this.validateFileId({ + $, + }))) { + return; + } + const response = await this.getResultsFile({ + $, + responseType: "arraybuffer", + }); + + const filePath = `/tmp/${this.fileName}`; + fs.writeFileSync(filePath, response); + + $.export("$summary", `File saved to ${filePath}`); + + return filePath; + }, +}; diff --git a/components/zerobounce/actions/validate-email/validate-email.mjs b/components/zerobounce/actions/validate-email/validate-email.mjs new file mode 100644 index 0000000000000..45399108a0c80 --- /dev/null +++ b/components/zerobounce/actions/validate-email/validate-email.mjs @@ -0,0 +1,41 @@ +import zerobounce from "../../zerobounce.app.mjs"; + +export default { + key: "zerobounce-validate-email", + name: "Validate Email", + description: "Validates a specific email. [See the documentation](https://www.zerobounce.net/docs/email-validation-api-quickstart/#validate_emails__v2__)", + version: "0.0.1", + type: "action", + props: { + zerobounce, + email: { + type: "string", + label: "Email", + description: "The email address to be validated", + }, + ipAddress: { + type: "string", + label: "IP Address", + description: "The IP Address the email signed up from", + optional: true, + }, + activityData: { + type: "boolean", + label: "Activity Data", + description: "If set to `true`, Activity Data information will be appended to the validation result", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.zerobounce.validateEmail({ + $, + params: { + email: this.email, + ip_address: this.ipAddress || "", + activity_data: this.activityData, + }, + }); + $.export("$summary", `Successfully validated email: ${this.email}`); + return response; + }, +}; diff --git a/components/zerobounce/app/zerobounce.app.ts b/components/zerobounce/app/zerobounce.app.ts deleted file mode 100644 index 56554ac30099a..0000000000000 --- a/components/zerobounce/app/zerobounce.app.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ - type: "app", - app: "zerobounce", - propDefinitions: {}, - methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); - }, - }, -}); \ No newline at end of file diff --git a/components/zerobounce/package.json b/components/zerobounce/package.json index b94be62eec373..cbe8e85ba7dc8 100644 --- a/components/zerobounce/package.json +++ b/components/zerobounce/package.json @@ -1,16 +1,20 @@ { "name": "@pipedream/zerobounce", - "version": "0.0.2", + "version": "0.1.0", "description": "Pipedream ZeroBounce Components", - "main": "dist/app/zerobounce.app.mjs", + "main": "zerobounce.app.mjs", "keywords": [ "pipedream", "zerobounce" ], - "files": ["dist"], "homepage": "https://pipedream.com/apps/zerobounce", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3", + "form-data": "^4.0.1", + "path": "^0.12.7" } } diff --git a/components/zerobounce/zerobounce.app.mjs b/components/zerobounce/zerobounce.app.mjs new file mode 100644 index 0000000000000..88ecf05bc55dd --- /dev/null +++ b/components/zerobounce/zerobounce.app.mjs @@ -0,0 +1,53 @@ +import { axios } from "@pipedream/platform"; + +export default { + type: "app", + app: "zerobounce", + methods: { + _baseUrl() { + return "https://api.zerobounce.net/v2"; + }, + _makeRequest(opts = {}) { + const { + $ = this, + path, + url, + params, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + url: url || `${this._baseUrl()}${path}`, + params: { + ...params, + api_key: this.$auth.api_key, + }, + }); + }, + validateEmail(opts = {}) { + return this._makeRequest({ + path: "/validate", + ...opts, + }); + }, + getReliabilityScore(opts = {}) { + return this._makeRequest({ + path: "/scoring", + ...opts, + }); + }, + validateEmailsInFile(opts = {}) { + return this._makeRequest({ + method: "POST", + url: "https://bulkapi.zerobounce.net/v2/sendfile", + ...opts, + }); + }, + getResultsFile(opts = {}) { + return this._makeRequest({ + url: "https://bulkapi.zerobounce.net/v2/getfile", + ...opts, + }); + }, + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1961b265a9372..470f1c341983b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11842,7 +11842,14 @@ importers: '@pipedream/platform': 3.0.3 components/zerobounce: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + form-data: ^4.0.1 + path: ^0.12.7 + dependencies: + '@pipedream/platform': 3.0.3 + form-data: 4.0.1 + path: 0.12.7 components/zerotier: specifiers: