first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.clearbit",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Sales"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/clearbit/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.clearbit/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { companyFields, companyOperations } from './CompanyDescription';
|
||||
import { clearbitApiRequest } from './GenericFunctions';
|
||||
import { personFields, personOperations } from './PersonDescription';
|
||||
|
||||
export class Clearbit implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Clearbit',
|
||||
name: 'clearbit',
|
||||
icon: 'file:clearbit.svg',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ":" + $parameter["resource"]}}',
|
||||
description: 'Consume Clearbit API',
|
||||
defaults: {
|
||||
name: 'Clearbit',
|
||||
},
|
||||
usableAsTool: true,
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'clearbitApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Company',
|
||||
value: 'company',
|
||||
description: 'The Company API allows you to look up a company by their domain',
|
||||
},
|
||||
{
|
||||
name: 'Person',
|
||||
value: 'person',
|
||||
description:
|
||||
'The Person API lets you retrieve social information associated with an email address, such as a person’s name, location and Twitter handle',
|
||||
},
|
||||
],
|
||||
default: 'company',
|
||||
},
|
||||
...companyOperations,
|
||||
...companyFields,
|
||||
...personOperations,
|
||||
...personFields,
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const length = items.length;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
for (let i = 0; i < length; i++) {
|
||||
try {
|
||||
if (resource === 'person') {
|
||||
if (operation === 'enrich') {
|
||||
const email = this.getNodeParameter('email', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
qs.email = email;
|
||||
if (additionalFields.givenName) {
|
||||
qs.given_name = additionalFields.givenName as string;
|
||||
}
|
||||
if (additionalFields.familyName) {
|
||||
qs.family_name = additionalFields.familyName as string;
|
||||
}
|
||||
if (additionalFields.ipAddress) {
|
||||
qs.ip_address = additionalFields.ipAddress as string;
|
||||
}
|
||||
if (additionalFields.location) {
|
||||
qs.location = additionalFields.location as string;
|
||||
}
|
||||
if (additionalFields.company) {
|
||||
qs.company = additionalFields.company as string;
|
||||
}
|
||||
if (additionalFields.companyDomain) {
|
||||
qs.company_domain = additionalFields.companyDomain as string;
|
||||
}
|
||||
if (additionalFields.linkedIn) {
|
||||
qs.linkedin = additionalFields.linkedIn as string;
|
||||
}
|
||||
if (additionalFields.twitter) {
|
||||
qs.twitter = additionalFields.twitter as string;
|
||||
}
|
||||
if (additionalFields.facebook) {
|
||||
qs.facebook = additionalFields.facebook as string;
|
||||
}
|
||||
responseData = await clearbitApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`${resource}-stream`,
|
||||
'/v2/people/find',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (resource === 'company') {
|
||||
if (operation === 'enrich') {
|
||||
const domain = this.getNodeParameter('domain', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
qs.domain = domain;
|
||||
if (additionalFields.companyName) {
|
||||
qs.company_name = additionalFields.companyName as string;
|
||||
}
|
||||
if (additionalFields.linkedin) {
|
||||
qs.linkedin = additionalFields.linkedin as string;
|
||||
}
|
||||
if (additionalFields.twitter) {
|
||||
qs.twitter = additionalFields.twitter as string;
|
||||
}
|
||||
if (additionalFields.facebook) {
|
||||
qs.facebook = additionalFields.facebook as string;
|
||||
}
|
||||
responseData = await clearbitApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`${resource}-stream`,
|
||||
'/v2/companies/find',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
if (operation === 'autocomplete') {
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
qs.query = name;
|
||||
responseData = await clearbitApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'autocomplete',
|
||||
'/v1/companies/suggest',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
}
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ error: error.message, json: {} });
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return [returnData];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const companyOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['company'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Autocomplete',
|
||||
value: 'autocomplete',
|
||||
description: 'Auto-complete company names and retrieve logo and domain',
|
||||
action: 'Autocomplete a company',
|
||||
},
|
||||
{
|
||||
name: 'Enrich',
|
||||
value: 'enrich',
|
||||
description: 'Look up person and company data based on an email or domain',
|
||||
action: 'Enrich a company',
|
||||
},
|
||||
],
|
||||
default: 'enrich',
|
||||
},
|
||||
];
|
||||
|
||||
export const companyFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* company:enrich */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Domain',
|
||||
name: 'domain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['company'],
|
||||
operation: ['enrich'],
|
||||
},
|
||||
},
|
||||
description: 'The domain to look up',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['company'],
|
||||
operation: ['enrich'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Company Name',
|
||||
name: 'companyName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The name of the company',
|
||||
},
|
||||
{
|
||||
displayName: 'Facebook',
|
||||
name: 'facebook',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The Facebook URL for the company',
|
||||
},
|
||||
{
|
||||
displayName: 'Linkedin',
|
||||
name: 'linkedin',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The LinkedIn URL for the company',
|
||||
},
|
||||
{
|
||||
displayName: 'Twitter',
|
||||
name: 'twitter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The Twitter handle for the company',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* company:autocomplete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['company'],
|
||||
operation: ['autocomplete'],
|
||||
},
|
||||
},
|
||||
description: 'Name is the partial name of the company',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
JsonObject,
|
||||
IRequestOptions,
|
||||
IHttpRequestMethods,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
|
||||
export async function clearbitApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
api: string,
|
||||
resource: string,
|
||||
|
||||
body: any = {},
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
option: IDataObject = {},
|
||||
): Promise<any> {
|
||||
const credentials = await this.getCredentials('clearbitApi');
|
||||
let options: IRequestOptions = {
|
||||
headers: { Authorization: `Bearer ${credentials.apiKey}` },
|
||||
method,
|
||||
qs,
|
||||
body,
|
||||
uri: uri || `https://${api}.clearbit.com${resource}`,
|
||||
json: true,
|
||||
};
|
||||
options = Object.assign({}, options, option);
|
||||
if (Object.keys(options.body as IDataObject).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
try {
|
||||
return await this.helpers.request(options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const personOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['person'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Enrich',
|
||||
value: 'enrich',
|
||||
description: 'Look up a person and company data based on an email or domain',
|
||||
action: 'Enrich a person',
|
||||
},
|
||||
],
|
||||
default: 'enrich',
|
||||
},
|
||||
];
|
||||
|
||||
export const personFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* person:enrich */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
placeholder: 'name@email.com',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['person'],
|
||||
operation: ['enrich'],
|
||||
},
|
||||
},
|
||||
description: 'The email address to look up',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['person'],
|
||||
operation: ['enrich'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Company',
|
||||
name: 'company',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The name of the person’s employer',
|
||||
},
|
||||
{
|
||||
displayName: 'Company Domain',
|
||||
name: 'companyDomain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The domain for the person’s employer',
|
||||
},
|
||||
{
|
||||
displayName: 'Facebook',
|
||||
name: 'facebook',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The Facebook URL for the person',
|
||||
},
|
||||
{
|
||||
displayName: 'Family Name',
|
||||
name: 'familyName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Last name of person. If you have this, passing this is strongly recommended to improve match rates.',
|
||||
},
|
||||
{
|
||||
displayName: 'Given Name',
|
||||
name: 'givenName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'First name of person',
|
||||
},
|
||||
{
|
||||
displayName: 'IP Address',
|
||||
name: 'ipAddress',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'IP address of the person. If you have this, passing this is strongly recommended to improve match rates.',
|
||||
},
|
||||
{
|
||||
displayName: 'Location',
|
||||
name: 'location',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The city or country where the person resides',
|
||||
},
|
||||
{
|
||||
displayName: 'LinkedIn',
|
||||
name: 'linkedIn',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The LinkedIn URL for the person',
|
||||
},
|
||||
{
|
||||
displayName: 'Twitter',
|
||||
name: 'twitter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The Twitter handle for the person',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 2
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bio": {
|
||||
"type": "null"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"emailProvider": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"employment": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"facebook": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"handle": {
|
||||
"type": "null"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fuzzy": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"googleplus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"handle": {
|
||||
"type": "null"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gravatar": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatars": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"inactiveAt": {
|
||||
"type": "null"
|
||||
},
|
||||
"indexedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"familyName": {
|
||||
"type": "string"
|
||||
},
|
||||
"fullName": {
|
||||
"type": "string"
|
||||
},
|
||||
"givenName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"site": {
|
||||
"type": "null"
|
||||
},
|
||||
"twitter": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar": {
|
||||
"type": "null"
|
||||
},
|
||||
"bio": {
|
||||
"type": "null"
|
||||
},
|
||||
"favorites": {
|
||||
"type": "null"
|
||||
},
|
||||
"followers": {
|
||||
"type": "null"
|
||||
},
|
||||
"following": {
|
||||
"type": "null"
|
||||
},
|
||||
"handle": {
|
||||
"type": "null"
|
||||
},
|
||||
"id": {
|
||||
"type": "null"
|
||||
},
|
||||
"location": {
|
||||
"type": "null"
|
||||
},
|
||||
"site": {
|
||||
"type": "null"
|
||||
},
|
||||
"statuses": {
|
||||
"type": "null"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72"><defs><linearGradient id="a" x1="50%" x2="100%" y1="0%" y2="100%"><stop offset="0%" stop-color="#DEF2FE"/><stop offset="100%" stop-color="#DBF1FE"/></linearGradient><linearGradient id="b" x1="0%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#57BCFD"/><stop offset="100%" stop-color="#51B5FD"/></linearGradient><linearGradient id="c" x1="37.5%" x2="62.5%" y1="0%" y2="100%"><stop offset="0%" stop-color="#1CA7FD"/><stop offset="100%" stop-color="#148CFC"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path fill="url(#a)" d="M72 36v16.77l-.004.868c-.06 6.035-.75 8.353-2 10.688a13.63 13.63 0 0 1-5.67 5.67l-.326.171C61.658 71.364 59.16 72 52.77 72H36V36z"/><path fill="url(#b)" d="M64.326 2.003a13.63 13.63 0 0 1 5.67 5.67l.171.327C71.364 10.342 72 12.84 72 19.23V36H36V0h16.77c6.687 0 9.112.696 11.556 2.003"/><path fill="url(#c)" d="M36 0v72H19.23l-.868-.004c-6.035-.06-8.353-.75-10.688-2a13.63 13.63 0 0 1-5.67-5.67L1.832 64C.636 61.658 0 59.16 0 52.77V19.23c0-6.687.696-9.112 2.003-11.556a13.63 13.63 0 0 1 5.67-5.67L8 1.832C10.342.636 12.84 0 19.23 0z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user