mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
feat: Add WhatsApp Business Trigger Node (#8840)
Co-authored-by: Giulio Andreini <andreini@netseven.it> Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
parent
53101960e6
commit
23a2dd08b6
|
@ -0,0 +1,41 @@
|
||||||
|
import type { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||||
|
|
||||||
|
export class WhatsAppTriggerApi implements ICredentialType {
|
||||||
|
name = 'whatsAppTriggerApi';
|
||||||
|
|
||||||
|
displayName = 'WhatsApp API';
|
||||||
|
|
||||||
|
documentationUrl = 'whatsApp';
|
||||||
|
|
||||||
|
properties: INodeProperties[] = [
|
||||||
|
{
|
||||||
|
displayName: 'Client ID',
|
||||||
|
name: 'clientId',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Client Secret',
|
||||||
|
name: 'clientSecret',
|
||||||
|
type: 'string',
|
||||||
|
typeOptions: {
|
||||||
|
password: true,
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
test: ICredentialTestRequest = {
|
||||||
|
request: {
|
||||||
|
method: 'POST',
|
||||||
|
baseURL: 'https://graph.facebook.com/v19.0/oauth/access_token',
|
||||||
|
body: {
|
||||||
|
client_id: '={{$credentials.clientId}}',
|
||||||
|
client_secret: '={{$credentials.clientSecret}}',
|
||||||
|
grant_type: 'client_credentials',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -63,6 +63,17 @@ export class FacebookTrigger implements INodeType {
|
||||||
default: '',
|
default: '',
|
||||||
description: 'Facebook APP ID',
|
description: 'Facebook APP ID',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
displayName: 'To watch Whatsapp business account events use the Whatsapp trigger node',
|
||||||
|
name: 'whatsappBusinessAccountNotice',
|
||||||
|
type: 'notice',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
object: ['whatsappBusinessAccount'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
displayName: 'Object',
|
displayName: 'Object',
|
||||||
name: 'object',
|
name: 'object',
|
||||||
|
|
103
packages/nodes-base/nodes/WhatsApp/GenericFunctions.ts
Normal file
103
packages/nodes-base/nodes/WhatsApp/GenericFunctions.ts
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import type {
|
||||||
|
IDataObject,
|
||||||
|
IExecuteFunctions,
|
||||||
|
IHookFunctions,
|
||||||
|
IHttpRequestMethods,
|
||||||
|
IHttpRequestOptions,
|
||||||
|
ILoadOptionsFunctions,
|
||||||
|
IWebhookFunctions,
|
||||||
|
JsonObject,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
import { NodeApiError } from 'n8n-workflow';
|
||||||
|
import type {
|
||||||
|
WhatsAppAppWebhookSubscriptionsResponse,
|
||||||
|
WhatsAppAppWebhookSubscription,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
async function appAccessTokenRead(
|
||||||
|
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||||
|
): Promise<{ access_token: string }> {
|
||||||
|
const credentials = await this.getCredentials('whatsAppTriggerApi');
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
body: {
|
||||||
|
client_id: credentials.clientId,
|
||||||
|
client_secret: credentials.clientSecret,
|
||||||
|
grant_type: 'client_credentials',
|
||||||
|
},
|
||||||
|
url: 'https://graph.facebook.com/v19.0/oauth/access_token',
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
return await this.helpers.httpRequest.call(this, options);
|
||||||
|
} catch (error) {
|
||||||
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function whatsappApiRequest(
|
||||||
|
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||||
|
method: IHttpRequestMethods,
|
||||||
|
resource: string,
|
||||||
|
body?: { type: 'json'; payload: IDataObject } | { type: 'form'; payload: IDataObject },
|
||||||
|
qs: IDataObject = {},
|
||||||
|
): Promise<any> {
|
||||||
|
const tokenResponse = await appAccessTokenRead.call(this);
|
||||||
|
const appAccessToken = tokenResponse.access_token;
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
headers: {
|
||||||
|
accept: 'application/json',
|
||||||
|
authorization: `Bearer ${appAccessToken}`,
|
||||||
|
},
|
||||||
|
method,
|
||||||
|
qs,
|
||||||
|
body: body?.payload,
|
||||||
|
url: `https://graph.facebook.com/v19.0${resource}`,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await this.helpers.httpRequest.call(this, options);
|
||||||
|
} catch (error) {
|
||||||
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function appWebhookSubscriptionList(
|
||||||
|
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||||
|
appId: string,
|
||||||
|
): Promise<WhatsAppAppWebhookSubscription[]> {
|
||||||
|
const response = (await whatsappApiRequest.call(
|
||||||
|
this,
|
||||||
|
'GET',
|
||||||
|
`/${appId}/subscriptions`,
|
||||||
|
)) as WhatsAppAppWebhookSubscriptionsResponse;
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function appWebhookSubscriptionCreate(
|
||||||
|
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||||
|
appId: string,
|
||||||
|
subscription: IDataObject,
|
||||||
|
) {
|
||||||
|
return await whatsappApiRequest.call(this, 'POST', `/${appId}/subscriptions`, {
|
||||||
|
type: 'form',
|
||||||
|
payload: { ...subscription },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function appWebhookSubscriptionDelete(
|
||||||
|
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
|
||||||
|
appId: string,
|
||||||
|
object: string,
|
||||||
|
) {
|
||||||
|
return await whatsappApiRequest.call(this, 'DELETE', `/${appId}/subscriptions`, {
|
||||||
|
type: 'form',
|
||||||
|
payload: { object },
|
||||||
|
});
|
||||||
|
}
|
18
packages/nodes-base/nodes/WhatsApp/WhatsAppTrigger.node.json
Normal file
18
packages/nodes-base/nodes/WhatsApp/WhatsAppTrigger.node.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"node": "n8n-nodes-base.whatsAppTrigger",
|
||||||
|
"nodeVersion": "1.0",
|
||||||
|
"codexVersion": "1.0",
|
||||||
|
"categories": ["Communication"],
|
||||||
|
"resources": {
|
||||||
|
"credentialDocumentation": [
|
||||||
|
{
|
||||||
|
"url": "https://docs.n8n.io/integrations/credentials/whatsapp/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryDocumentation": [
|
||||||
|
{
|
||||||
|
"url": "https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.whatsapptrigger/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
185
packages/nodes-base/nodes/WhatsApp/WhatsAppTrigger.node.ts
Normal file
185
packages/nodes-base/nodes/WhatsApp/WhatsAppTrigger.node.ts
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
import { createHmac } from 'crypto';
|
||||||
|
import {
|
||||||
|
NodeOperationError,
|
||||||
|
type IDataObject,
|
||||||
|
type IHookFunctions,
|
||||||
|
type INodeType,
|
||||||
|
type INodeTypeDescription,
|
||||||
|
type IWebhookFunctions,
|
||||||
|
type IWebhookResponseData,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
import {
|
||||||
|
appWebhookSubscriptionCreate,
|
||||||
|
appWebhookSubscriptionDelete,
|
||||||
|
appWebhookSubscriptionList,
|
||||||
|
} from './GenericFunctions';
|
||||||
|
import type { WhatsAppPageEvent } from './types';
|
||||||
|
import { whatsappTriggerDescription } from './WhatsappDescription';
|
||||||
|
|
||||||
|
export class WhatsAppTrigger implements INodeType {
|
||||||
|
description: INodeTypeDescription = {
|
||||||
|
displayName: 'WhatsApp Trigger',
|
||||||
|
name: 'whatsAppTrigger',
|
||||||
|
icon: 'file:whatsapp.svg',
|
||||||
|
group: ['trigger'],
|
||||||
|
version: 1,
|
||||||
|
subtitle: '={{$parameter["event"]}}',
|
||||||
|
description: 'Handle WhatsApp events via webhooks',
|
||||||
|
defaults: {
|
||||||
|
name: 'WhatsApp Trigger',
|
||||||
|
},
|
||||||
|
inputs: [],
|
||||||
|
outputs: ['main'],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'whatsAppTriggerApi',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
webhooks: [
|
||||||
|
{
|
||||||
|
name: 'setup',
|
||||||
|
httpMethod: 'GET',
|
||||||
|
responseMode: 'onReceived',
|
||||||
|
path: 'webhook',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
httpMethod: 'POST',
|
||||||
|
responseMode: 'onReceived',
|
||||||
|
path: 'webhook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName:
|
||||||
|
'Due to Facebook API limitations, you can use just one WhatsApp trigger for each Facebook App',
|
||||||
|
name: 'whatsAppNotice',
|
||||||
|
type: 'notice',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
...whatsappTriggerDescription,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
webhookMethods = {
|
||||||
|
default: {
|
||||||
|
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookUrl = this.getNodeWebhookUrl('default') as string;
|
||||||
|
const credentials = await this.getCredentials('whatsAppTriggerApi');
|
||||||
|
const updates = this.getNodeParameter('updates', []) as IDataObject[];
|
||||||
|
const subscribedEvents = updates.sort().join(',');
|
||||||
|
const appId = credentials.clientId as string;
|
||||||
|
|
||||||
|
const webhooks = await appWebhookSubscriptionList.call(this, appId);
|
||||||
|
|
||||||
|
const subscription = webhooks.find(
|
||||||
|
(webhook) =>
|
||||||
|
webhook.object === 'whatsapp_business_account' &&
|
||||||
|
webhook.fields
|
||||||
|
.map((x) => x.name)
|
||||||
|
.sort()
|
||||||
|
.join(',') === subscribedEvents &&
|
||||||
|
webhook.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!subscription) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subscription.callback_url !== webhookUrl) {
|
||||||
|
throw new NodeOperationError(
|
||||||
|
this.getNode(),
|
||||||
|
`The WhatsApp App ID ${appId} already has a webhook subscription. Delete it or use another App before executing the trigger. Due to WhatsApp API limitations, you can have just one trigger per App.`,
|
||||||
|
{ level: 'warning' },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
subscription?.fields
|
||||||
|
.map((x) => x.name)
|
||||||
|
.sort()
|
||||||
|
.join(',') !== subscribedEvents
|
||||||
|
) {
|
||||||
|
await appWebhookSubscriptionDelete.call(this, appId, 'whatsapp_business_account');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async create(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookUrl = this.getNodeWebhookUrl('default') as string;
|
||||||
|
const credentials = await this.getCredentials('whatsAppTriggerApi');
|
||||||
|
const appId = credentials.clientId as string;
|
||||||
|
const updates = this.getNodeParameter('updates', []) as IDataObject[];
|
||||||
|
const verifyToken = this.getNode().id;
|
||||||
|
|
||||||
|
await appWebhookSubscriptionCreate.call(this, appId, {
|
||||||
|
object: 'whatsapp_business_account',
|
||||||
|
callback_url: webhookUrl,
|
||||||
|
verify_token: verifyToken,
|
||||||
|
fields: JSON.stringify(updates),
|
||||||
|
include_values: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async delete(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const credentials = await this.getCredentials('whatsAppTriggerApi');
|
||||||
|
const appId = credentials.clientId as string;
|
||||||
|
|
||||||
|
await appWebhookSubscriptionDelete.call(this, appId, 'whatsapp_business_account');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||||
|
const bodyData = this.getBodyData() as unknown as WhatsAppPageEvent;
|
||||||
|
const query = this.getQueryData() as IDataObject;
|
||||||
|
const res = this.getResponseObject();
|
||||||
|
const req = this.getRequestObject();
|
||||||
|
const headerData = this.getHeaderData() as IDataObject;
|
||||||
|
const credentials = await this.getCredentials('whatsAppTriggerApi');
|
||||||
|
|
||||||
|
// Check if we're getting facebook's challenge request (https://developers.facebook.com/docs/graph-api/webhooks/getting-started)
|
||||||
|
if (this.getWebhookName() === 'setup') {
|
||||||
|
if (query['hub.challenge']) {
|
||||||
|
if (this.getNode().id !== query['hub.verify_token']) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send(query['hub.challenge']).end();
|
||||||
|
|
||||||
|
return { noWebhookResponse: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const computedSignature = createHmac('sha256', credentials.clientSecret as string)
|
||||||
|
.update(req.rawBody)
|
||||||
|
.digest('hex');
|
||||||
|
if (headerData['x-hub-signature-256'] !== `sha256=${computedSignature}`) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bodyData.object !== 'whatsapp_business_account') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const events = await Promise.all(
|
||||||
|
bodyData.entry
|
||||||
|
.map((entry) => entry.changes)
|
||||||
|
.flat()
|
||||||
|
.map((change) => ({ ...change.value, field: change.field })),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (events.length === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
workflowData: [this.helpers.returnJsonArray(events)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
53
packages/nodes-base/nodes/WhatsApp/WhatsappDescription.ts
Normal file
53
packages/nodes-base/nodes/WhatsApp/WhatsappDescription.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import type { INodeProperties } from 'n8n-workflow';
|
||||||
|
|
||||||
|
export const whatsappTriggerDescription: INodeProperties[] = [
|
||||||
|
{
|
||||||
|
displayName: 'Trigger On',
|
||||||
|
name: 'updates',
|
||||||
|
type: 'multiOptions',
|
||||||
|
required: true,
|
||||||
|
default: [],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Account Review Update',
|
||||||
|
value: 'account_review_update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Account Update',
|
||||||
|
value: 'account_update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Business Capability Update',
|
||||||
|
value: 'business_capability_update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Message Template Quality Update',
|
||||||
|
value: 'message_template_quality_update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Message Template Status Update',
|
||||||
|
value: 'message_template_status_update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Messages',
|
||||||
|
value: 'messages',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Phone Number Name Update',
|
||||||
|
value: 'phone_number_name_update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Phone Number Quality Update',
|
||||||
|
value: 'phone_number_quality_update',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Security',
|
||||||
|
value: 'security',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Template Category Update',
|
||||||
|
value: 'template_category_update',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
98
packages/nodes-base/nodes/WhatsApp/types.ts
Normal file
98
packages/nodes-base/nodes/WhatsApp/types.ts
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import type { GenericValue, IDataObject } from 'n8n-workflow';
|
||||||
|
|
||||||
|
export type BaseFacebookResponse<TData> = { data: TData };
|
||||||
|
export type BasePaginatedFacebookResponse<TData> = BaseFacebookResponse<TData> & {
|
||||||
|
paging: { cursors: { before?: string; after?: string } };
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WhatsAppAppWebhookSubscriptionsResponse = BaseFacebookResponse<
|
||||||
|
WhatsAppAppWebhookSubscription[]
|
||||||
|
>;
|
||||||
|
|
||||||
|
export interface WhatsAppAppWebhookSubscription {
|
||||||
|
object: string;
|
||||||
|
callback_url: string;
|
||||||
|
active: boolean;
|
||||||
|
fields: WhatsAppAppWebhookSubscriptionField[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WhatsAppAppWebhookSubscriptionField {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateFacebookAppWebhookSubscription {
|
||||||
|
object: string;
|
||||||
|
callback_url: string;
|
||||||
|
fields: string[];
|
||||||
|
include_values: boolean;
|
||||||
|
verify_token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FacebookPageListResponse = BasePaginatedFacebookResponse<FacebookPage[]>;
|
||||||
|
export type FacebookFormListResponse = BasePaginatedFacebookResponse<FacebookForm[]>;
|
||||||
|
|
||||||
|
export interface FacebookPage {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
access_token: string;
|
||||||
|
category: string;
|
||||||
|
category_list: FacebookPageCategory[];
|
||||||
|
tasks: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FacebookPageCategory {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FacebookFormQuestion {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FacebookForm {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
locale: string;
|
||||||
|
status: string;
|
||||||
|
page: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
questions: FacebookFormQuestion[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WhatsAppPageEvent {
|
||||||
|
object: 'whatsapp_business_account';
|
||||||
|
entry: WhatsAppEventEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WhatsAppEventEntry {
|
||||||
|
id: string;
|
||||||
|
time: number;
|
||||||
|
changes: [
|
||||||
|
{
|
||||||
|
field: string;
|
||||||
|
value: IDataObject;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FacebookFormLeadData {
|
||||||
|
id: string;
|
||||||
|
created_time: string;
|
||||||
|
ad_id: string;
|
||||||
|
ad_name: string;
|
||||||
|
adset_id: string;
|
||||||
|
adset_name: string;
|
||||||
|
form_id: string;
|
||||||
|
field_data: [
|
||||||
|
{
|
||||||
|
name: string;
|
||||||
|
values: GenericValue[];
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
|
@ -368,6 +368,7 @@
|
||||||
"dist/credentials/WebflowOAuth2Api.credentials.js",
|
"dist/credentials/WebflowOAuth2Api.credentials.js",
|
||||||
"dist/credentials/WekanApi.credentials.js",
|
"dist/credentials/WekanApi.credentials.js",
|
||||||
"dist/credentials/WhatsAppApi.credentials.js",
|
"dist/credentials/WhatsAppApi.credentials.js",
|
||||||
|
"dist/credentials/WhatsAppTriggerApi.credentials.js",
|
||||||
"dist/credentials/WiseApi.credentials.js",
|
"dist/credentials/WiseApi.credentials.js",
|
||||||
"dist/credentials/WooCommerceApi.credentials.js",
|
"dist/credentials/WooCommerceApi.credentials.js",
|
||||||
"dist/credentials/WordpressApi.credentials.js",
|
"dist/credentials/WordpressApi.credentials.js",
|
||||||
|
@ -776,6 +777,7 @@
|
||||||
"dist/nodes/Webflow/WebflowTrigger.node.js",
|
"dist/nodes/Webflow/WebflowTrigger.node.js",
|
||||||
"dist/nodes/Webhook/Webhook.node.js",
|
"dist/nodes/Webhook/Webhook.node.js",
|
||||||
"dist/nodes/Wekan/Wekan.node.js",
|
"dist/nodes/Wekan/Wekan.node.js",
|
||||||
|
"dist/nodes/WhatsApp/WhatsAppTrigger.node.js",
|
||||||
"dist/nodes/WhatsApp/WhatsApp.node.js",
|
"dist/nodes/WhatsApp/WhatsApp.node.js",
|
||||||
"dist/nodes/Wise/Wise.node.js",
|
"dist/nodes/Wise/Wise.node.js",
|
||||||
"dist/nodes/Wise/WiseTrigger.node.js",
|
"dist/nodes/Wise/WiseTrigger.node.js",
|
||||||
|
|
Loading…
Reference in a new issue