Compare commits
2 Commits
3207c84296
...
642c2b5841
| Author | SHA1 | Date | |
|---|---|---|---|
| 642c2b5841 | |||
| 9a7b19f938 |
@ -5,7 +5,7 @@
|
||||
defaults: {
|
||||
name: {value:"Chats Out"},
|
||||
whatsappLink: {value:"whatsapp-web", type:'whatsappLink'},
|
||||
number: {value: ""}
|
||||
recipient: {value:"", type:'number-recipient', required:false}
|
||||
},
|
||||
outputs:0,
|
||||
inputs:1,
|
||||
@ -27,17 +27,14 @@
|
||||
<input type="text" id="node-input-whatsappLink" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-number"><i class="fa fa-address-card-o"></i> Number</label>
|
||||
<input type="text" id="node-input-number" placeholder="Mobile or Group Number..">
|
||||
<label for="node-input-recipient"><i class="fa fa-user"></i> Recipient</label>
|
||||
<input type="text" id="node-input-recipient" placeholder="Select or add recipient">
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
<p>Don't forget to mention international dialing code befor your number.
|
||||
Number must be in format like <b>+11 99999 99999</b> without any space.</p>
|
||||
<P><b>OR</b></P>
|
||||
<P>Leave the Number blank here and provide the number along with msg.paylod
|
||||
at `msg.toNumber` with international code.</P>
|
||||
<p>To send message on multiple contacts an Arrar of number can be passed
|
||||
on `msg.toNumber` like `msg.toNumber = ["+1199999999", "+12990000099", "+1311111111"].</p>
|
||||
<p><b>Recipient:</b> Select a reusable Number Recipient configuration (optional).</p>
|
||||
<p><b>Override at runtime:</b> Provide <code>msg.toNumber</code> to override the configured recipient.</p>
|
||||
<p>Number format: <b>+11 99999 99999</b> (international dialing code, no spaces).</p>
|
||||
<p>For multiple contacts, pass an array: <code>msg.toNumber = ["+1199999999", "+12990000099"]</code></p>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
115
chats-out.js
115
chats-out.js
@ -1,8 +1,14 @@
|
||||
const { formatChatNumber, formatChatNumberSocket } = require('./whatsapp-utils');
|
||||
|
||||
module.exports = function(RED) {
|
||||
function WhatsappOut(config) {
|
||||
RED.nodes.createNode(this,config);
|
||||
var node = this;
|
||||
node.number = config.number;
|
||||
|
||||
// Get number from recipient config node if configured
|
||||
var recipientNode = RED.nodes.getNode(config.recipient);
|
||||
node.number = recipientNode ? recipientNode.number : null;
|
||||
|
||||
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
|
||||
node.waClient = whatsappLinkNode.client;
|
||||
const { MessageMedia, Buttons } = require('whatsapp-web.js');
|
||||
@ -13,103 +19,14 @@ module.exports = function(RED) {
|
||||
};
|
||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
async function webNubmerSeteing(numb){
|
||||
// Validate and clean the number
|
||||
if (!numb) {
|
||||
throw new Error('Number is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||
|
||||
// Check if it's already a formatted ID (contains @)
|
||||
if (numb.includes('@')) {
|
||||
return numb;
|
||||
}
|
||||
|
||||
// For group IDs, preserve the hyphen (format: NUMBER-TIMESTAMP@g.us)
|
||||
// Only strip non-digits and non-hyphens for cleaning
|
||||
numb = numb.replace(/[^\d-]/g, '');
|
||||
|
||||
// Check if number is valid after cleaning
|
||||
if (!numb || numb.length === 0) {
|
||||
throw new Error('Invalid number format');
|
||||
}
|
||||
|
||||
// Check if it looks like a group ID (contains hyphen)
|
||||
if (numb.includes('-')) {
|
||||
// It's a group ID, format it directly without validation
|
||||
return `${numb}@g.us`;
|
||||
}
|
||||
|
||||
// It's a regular phone number, validate with getNumberId
|
||||
try {
|
||||
var numbID = await node.waClient.getNumberId(numb);
|
||||
if(numbID) {
|
||||
return `${numbID.user}@${numbID.server}`;
|
||||
} else {
|
||||
return `${numb}@g.us`
|
||||
}
|
||||
} catch (e) {
|
||||
node.error(`Error getting number ID for ${numb}: ${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function socNubmerSeteing(numb){
|
||||
if (numb && numb.remoteJid){
|
||||
return numb.remoteJid;
|
||||
}
|
||||
|
||||
// Validate and clean the number
|
||||
if (!numb) {
|
||||
throw new Error('Number is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||
|
||||
// Check if it's already a formatted ID (contains @)
|
||||
if (numb.includes('@')) {
|
||||
return numb;
|
||||
}
|
||||
|
||||
// For group IDs, preserve the hyphen (format: NUMBER-TIMESTAMP@g.us)
|
||||
// Only strip non-digits and non-hyphens for cleaning
|
||||
numb = numb.replace(/[^\d-]/g, '');
|
||||
|
||||
// Check if number is valid after cleaning
|
||||
if (!numb || numb.length === 0) {
|
||||
throw new Error('Invalid number format');
|
||||
}
|
||||
|
||||
// Check if it looks like a group ID (contains hyphen)
|
||||
if (numb.includes('-')) {
|
||||
// It's a group ID, format it directly
|
||||
return `${numb}@g.us`;
|
||||
}
|
||||
|
||||
// It's a regular phone number, validate with onWhatsApp
|
||||
try {
|
||||
const [result] = await (await node.waClient).onWhatsApp(numb)
|
||||
if (result?.exists){
|
||||
return result.jid
|
||||
}
|
||||
return numb = `${numb}@g.us`;
|
||||
} catch (e) {
|
||||
node.error(`Error checking WhatsApp for ${numb}: ${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function whatsappMessage(numb , inputMessage){
|
||||
if (node.waClient.clientType === "waWebClient"){
|
||||
try {
|
||||
numb = await webNubmerSeteing(numb);
|
||||
numb = await formatChatNumber(numb, node.waClient, node);
|
||||
if(typeof inputMessage === "object"){
|
||||
inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer);
|
||||
}
|
||||
node.waClient.sendMessage(numb, inputMessage);
|
||||
await node.waClient.sendMessage(numb, inputMessage);
|
||||
}
|
||||
catch(e){
|
||||
node.error(`Error Sending Msg: ${e}`);
|
||||
@ -118,18 +35,18 @@ module.exports = function(RED) {
|
||||
else if (node.waClient.clientType === "waSocketClient"){
|
||||
try {
|
||||
let client = await node.waClient;
|
||||
numb = await socNubmerSeteing(numb)
|
||||
numb = await formatChatNumberSocket(numb, node.waClient, node);
|
||||
if (typeof inputMessage ==="string"){
|
||||
inputMessage = {text : inputMessage};
|
||||
}
|
||||
const msgStatus = await client.sendMessage(numb, inputMessage);
|
||||
await client.sendMessage(numb, inputMessage);
|
||||
}
|
||||
catch(e) {
|
||||
node.error(`Error Sending Msg:: ${e}`);
|
||||
node.error(`Error Sending Msg: ${e}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
node.error(`Error Sending Msg: ${e}`)
|
||||
node.error(`Error Sending Msg: Unknown client type`)
|
||||
}
|
||||
SetStatus("Message Send.", "green");
|
||||
setTimeout(()=>{
|
||||
@ -142,12 +59,12 @@ module.exports = function(RED) {
|
||||
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
||||
try {
|
||||
if (node.waClient.clientType === "waWebClient"){
|
||||
numb = await webNubmerSeteing(numb)
|
||||
numb = await formatChatNumber(numb, node.waClient, node);
|
||||
var myMessage = new MessageMedia('image/png', whatsappImageBase64, null, null);
|
||||
node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption });
|
||||
await node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption });
|
||||
}
|
||||
else {
|
||||
numb = await socNubmerSeteing(numb)
|
||||
numb = await formatChatNumberSocket(numb, node.waClient, node);
|
||||
|
||||
let imageToSend = Buffer.from(whatsappImageBase64, "base64");
|
||||
const imageMessage = {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
defaults: {
|
||||
name: {value:"Group Message"},
|
||||
whatsappLink: {value:"whatsapp-web", type:'whatsappLink'},
|
||||
gID: {value: ""}
|
||||
recipient: {value:"", type:'group-recipient', required:false}
|
||||
},
|
||||
outputs:0,
|
||||
inputs:1,
|
||||
@ -27,17 +27,14 @@
|
||||
<input type="text" id="node-input-whatsappLink" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-gID"><i class="fa fa-address-card-o"></i> Group ID </label>
|
||||
<input type="text" id="node-input-gID" placeholder="Group Chat ID..">
|
||||
<label for="node-input-recipient"><i class="fa fa-users"></i> Group Recipient</label>
|
||||
<input type="text" id="node-input-recipient" placeholder="Select or add group recipient">
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
<p>Group chat IDs are numbers given to each chats in whatsapp. <br>
|
||||
- For every message recived from whatsapp-chats-in Node,
|
||||
Chat ID may be read at <b>msg.chatID</b>.<br>
|
||||
<b>Or</b><br>
|
||||
- Chat ID of group can also be recive from whatsapp-admin Node,
|
||||
whenever the new group joined, Admin Node will notifiy the same.
|
||||
</p>
|
||||
<p><b>Recipient:</b> Select a reusable Group Recipient configuration (optional).</p>
|
||||
<p><b>Override at runtime:</b> Provide <code>msg.toNumber</code> to override the configured recipient.</p>
|
||||
<p>Group IDs are in format NUMBER-TIMESTAMP (e.g., 1234567890-1234567890).</p>
|
||||
<p>Find group IDs from <code>msg.chatID</code> in chats-in node or from the admin node when joining groups.</p>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
130
group-out.js
130
group-out.js
@ -1,8 +1,14 @@
|
||||
const { formatGroupId, formatGroupIdSocket } = require('./whatsapp-utils');
|
||||
|
||||
module.exports = function(RED) {
|
||||
function WhatsappGroupOut(config) {
|
||||
RED.nodes.createNode(this,config);
|
||||
var node = this;
|
||||
node.number = config.gID;
|
||||
|
||||
// Get group ID from recipient config node if configured
|
||||
var recipientNode = RED.nodes.getNode(config.recipient);
|
||||
node.number = recipientNode ? recipientNode.groupId : null;
|
||||
|
||||
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
|
||||
node.waClient = whatsappLinkNode.client;
|
||||
|
||||
@ -13,105 +19,16 @@ module.exports = function(RED) {
|
||||
};
|
||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
|
||||
async function webNubmerSeteing(numb){
|
||||
// Validate and clean the number
|
||||
if (!numb) {
|
||||
throw new Error('Number is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||
|
||||
// Check if it's already a formatted ID (contains @)
|
||||
if (numb.includes('@')) {
|
||||
return numb;
|
||||
}
|
||||
|
||||
// For group IDs, preserve the hyphen (format: NUMBER-TIMESTAMP@g.us)
|
||||
// Only strip non-digits and non-hyphens for cleaning
|
||||
numb = numb.replace(/[^\d-]/g, '');
|
||||
|
||||
// Check if number is valid after cleaning
|
||||
if (!numb || numb.length === 0) {
|
||||
throw new Error('Invalid number format');
|
||||
}
|
||||
|
||||
// Check if it looks like a group ID (contains hyphen)
|
||||
if (numb.includes('-')) {
|
||||
// It's a group ID, format it directly without validation
|
||||
return `${numb}@g.us`;
|
||||
}
|
||||
|
||||
// It's a regular phone number, validate with getNumberId
|
||||
try {
|
||||
var numbID = await node.waClient.getNumberId(numb);
|
||||
if(numbID) {
|
||||
return `${numbID.user}@${numbID.server}`;
|
||||
} else {
|
||||
return `${numb}@g.us`
|
||||
}
|
||||
} catch (e) {
|
||||
node.error(`Error getting number ID for ${numb}: ${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function socNubmerSeteing(numb){
|
||||
if (numb && numb.remoteJid){
|
||||
return numb.remoteJid;
|
||||
}
|
||||
|
||||
// Validate and clean the number
|
||||
if (!numb) {
|
||||
throw new Error('Number is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||
|
||||
// Check if it's already a formatted ID (contains @)
|
||||
if (numb.includes('@')) {
|
||||
return numb;
|
||||
}
|
||||
|
||||
// For group IDs, preserve the hyphen (format: NUMBER-TIMESTAMP@g.us)
|
||||
// Only strip non-digits and non-hyphens for cleaning
|
||||
numb = numb.replace(/[^\d-]/g, '');
|
||||
|
||||
// Check if number is valid after cleaning
|
||||
if (!numb || numb.length === 0) {
|
||||
throw new Error('Invalid number format');
|
||||
}
|
||||
|
||||
// Check if it looks like a group ID (contains hyphen)
|
||||
if (numb.includes('-')) {
|
||||
// It's a group ID, format it directly
|
||||
return `${numb}@g.us`;
|
||||
}
|
||||
|
||||
// It's a regular phone number, validate with onWhatsApp
|
||||
try {
|
||||
const [result] = await (await node.waClient).onWhatsApp(numb)
|
||||
if (result?.exists){
|
||||
return result.jid
|
||||
}
|
||||
return numb = `${numb}@g.us`;
|
||||
} catch (e) {
|
||||
node.error(`Error checking WhatsApp for ${numb}: ${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function whatsappMessage(numb , inputMessage){
|
||||
async function whatsappMessage(gID , inputMessage){
|
||||
if (node.waClient.clientType === "waWebClient"){
|
||||
try {
|
||||
numb = await webNubmerSeteing(numb);
|
||||
gID = await formatGroupId(gID, node.waClient, node);
|
||||
if(typeof inputMessage === "object"){
|
||||
inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer);
|
||||
node.waClient.sendMessage(numb, inputMessage);
|
||||
await node.waClient.sendMessage(gID, inputMessage);
|
||||
} else {
|
||||
await node.waClient.sendMessage(gID, inputMessage);
|
||||
}
|
||||
node.waClient.sendMessage(numb, inputMessage);
|
||||
}
|
||||
catch(e){
|
||||
node.error(`Error Sending Msg: ${e}`);
|
||||
@ -120,18 +37,18 @@ module.exports = function(RED) {
|
||||
else if (node.waClient.clientType === "waSocketClient"){
|
||||
try {
|
||||
let client = await node.waClient;
|
||||
numb = await socNubmerSeteing(numb)
|
||||
gID = await formatGroupIdSocket(gID, node.waClient, node);
|
||||
if (typeof inputMessage ==="string"){
|
||||
inputMessage = {text : inputMessage};
|
||||
}
|
||||
const msgStatus = await client.sendMessage(numb, inputMessage);
|
||||
await client.sendMessage(gID, inputMessage);
|
||||
}
|
||||
catch(e) {
|
||||
node.error(`Error Sending Msg:: ${e}`);
|
||||
node.error(`Error Sending Msg: ${e}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
node.error(`Error Sending Msg: ${e}`)
|
||||
node.error(`Error Sending Msg: Unknown client type`)
|
||||
}
|
||||
SetStatus("Message Send.", "green");
|
||||
setTimeout(()=>{
|
||||
@ -139,26 +56,25 @@ module.exports = function(RED) {
|
||||
}, 2000)
|
||||
};
|
||||
|
||||
async function whatsappMultiMediaMessage(numb, whatsappImage, whatsappCaption){
|
||||
async function whatsappMultiMediaMessage(gID, whatsappImage, whatsappCaption){
|
||||
try {
|
||||
if (node.waClient.clientType === "waWebClient"){
|
||||
numb = await webNubmerSeteing(node.number)
|
||||
gID = await formatGroupId(gID, node.waClient, node);
|
||||
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
||||
var myMessage = new MessageMedia('image/png', whatsappImageBase64, null, null);
|
||||
node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption || "Image from Node-Red"});
|
||||
await node.waClient.sendMessage(gID, myMessage, {caption : whatsappCaption || "Image from Node-Red"});
|
||||
}
|
||||
else {
|
||||
numb = await socNubmerSeteing(node.number);
|
||||
|
||||
gID = await formatGroupIdSocket(gID, node.waClient, node);
|
||||
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
||||
let imageToSend = Buffer.from(whatsappImageBase64, "base64");
|
||||
const imageMessage = {
|
||||
// image: {url : whatsappImage},
|
||||
image: imageToSend,
|
||||
caption: whatsappCaption
|
||||
caption: whatsappCaption || "Image from Node-Red"
|
||||
}
|
||||
|
||||
let client = await node.waClient;
|
||||
const msgStatus = await client.sendMessage(numb, imageMessage);
|
||||
await client.sendMessage(gID, imageMessage);
|
||||
}
|
||||
SetStatus("Message Send.", "green");
|
||||
setTimeout(()=>{
|
||||
|
||||
41
groupRecipient.html
Normal file
41
groupRecipient.html
Normal file
@ -0,0 +1,41 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('group-recipient', {
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {value: ""},
|
||||
groupId: {value: "", required: true}
|
||||
},
|
||||
label: function() {
|
||||
return this.name || this.groupId || "Group Recipient";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="group-recipient">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-groupId"><i class="fa fa-users"></i> Group ID</label>
|
||||
<input type="text" id="node-config-input-groupId" placeholder="1234567890-1234567890">
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
<strong>Tip:</strong> Enter the WhatsApp group ID in the format NUMBER-TIMESTAMP (e.g., 1234567890-1234567890).
|
||||
<br>You can find the group ID by sending a message to the group and checking the message metadata.
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="group-recipient">
|
||||
<p>Configuration node for a WhatsApp group recipient.</p>
|
||||
<h3>Details</h3>
|
||||
<p>This configuration node stores a group ID that can be reused across multiple group output nodes.</p>
|
||||
<p>The group ID can be overridden at runtime by setting <code>msg.toNumber</code> in the flow.</p>
|
||||
<h3>Configuration</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>Name <span class="property-type">string</span></dt>
|
||||
<dd>A friendly name to identify this group (optional).</dd>
|
||||
<dt>Group ID <span class="property-type">string</span></dt>
|
||||
<dd>The WhatsApp group ID in the format NUMBER-TIMESTAMP (contains a hyphen).</dd>
|
||||
</dl>
|
||||
</script>
|
||||
8
groupRecipient.js
Normal file
8
groupRecipient.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = function(RED) {
|
||||
function GroupRecipientNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
this.groupId = n.groupId;
|
||||
this.name = n.name;
|
||||
}
|
||||
RED.nodes.registerType("group-recipient", GroupRecipientNode);
|
||||
}
|
||||
40
numberRecipient.html
Normal file
40
numberRecipient.html
Normal file
@ -0,0 +1,40 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('number-recipient', {
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {value: ""},
|
||||
number: {value: "", required: true}
|
||||
},
|
||||
label: function() {
|
||||
return this.name || this.number || "Number Recipient";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="number-recipient">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-number"><i class="fa fa-phone"></i> Phone Number</label>
|
||||
<input type="text" id="node-config-input-number" placeholder="+1234567890">
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
<strong>Tip:</strong> Enter the phone number with or without country code (e.g., +1234567890 or 1234567890).
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="number-recipient">
|
||||
<p>Configuration node for a WhatsApp chat recipient.</p>
|
||||
<h3>Details</h3>
|
||||
<p>This configuration node stores a phone number that can be reused across multiple chat output nodes.</p>
|
||||
<p>The phone number can be overridden at runtime by setting <code>msg.toNumber</code> in the flow.</p>
|
||||
<h3>Configuration</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>Name <span class="property-type">string</span></dt>
|
||||
<dd>A friendly name to identify this recipient (optional).</dd>
|
||||
<dt>Phone Number <span class="property-type">string</span></dt>
|
||||
<dd>The WhatsApp phone number. Can include country code with or without + prefix.</dd>
|
||||
</dl>
|
||||
</script>
|
||||
8
numberRecipient.js
Normal file
8
numberRecipient.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = function(RED) {
|
||||
function NumberRecipientNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
this.number = n.number;
|
||||
this.name = n.name;
|
||||
}
|
||||
RED.nodes.registerType("number-recipient", NumberRecipientNode);
|
||||
}
|
||||
@ -26,7 +26,9 @@
|
||||
"whatsapp chats-out": "chats-out.js",
|
||||
"whatsapp group-out": "group-out.js",
|
||||
"whatsapp reply": "whatsappReply.js",
|
||||
"whatsapp Link": "whatsappLink.js"
|
||||
"whatsapp Link": "whatsappLink.js",
|
||||
"number-recipient": "numberRecipient.js",
|
||||
"group-recipient": "groupRecipient.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
163
whatsapp-utils.js
Normal file
163
whatsapp-utils.js
Normal file
@ -0,0 +1,163 @@
|
||||
// Shared utility functions for WhatsApp nodes
|
||||
|
||||
/**
|
||||
* Format a phone number for WhatsApp Web client (chat)
|
||||
* Assumes the recipient is a chat (@c.us)
|
||||
*/
|
||||
async function formatChatNumber(numb, waClient, nodeLogger) {
|
||||
// Validate input
|
||||
if (!numb) {
|
||||
throw new Error('Number is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||
|
||||
// If already formatted, return as-is
|
||||
if (numb.includes('@')) {
|
||||
return numb;
|
||||
}
|
||||
|
||||
// Clean: remove everything except digits
|
||||
numb = numb.replace(/\D/g, '');
|
||||
|
||||
// Validate cleaned number
|
||||
if (!numb || numb.length === 0) {
|
||||
throw new Error('Invalid number format');
|
||||
}
|
||||
|
||||
// Validate with getNumberId
|
||||
try {
|
||||
const numbID = await waClient.getNumberId(numb);
|
||||
if (numbID) {
|
||||
return `${numbID.user}@${numbID.server}`;
|
||||
} else {
|
||||
// If validation fails, assume it's a chat
|
||||
nodeLogger.warn(`getNumberId returned null for ${numb}, using @c.us`);
|
||||
return `${numb}@c.us`;
|
||||
}
|
||||
} catch (e) {
|
||||
// If error, assume it's a chat
|
||||
nodeLogger.warn(`getNumberId failed for ${numb}, using @c.us: ${e.message}`);
|
||||
return `${numb}@c.us`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a group ID for WhatsApp Web client
|
||||
* Assumes the recipient is a group (@g.us)
|
||||
*/
|
||||
async function formatGroupId(gID, waClient, nodeLogger) {
|
||||
// Validate input
|
||||
if (!gID) {
|
||||
throw new Error('Group ID is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
gID = typeof gID === 'number' ? gID.toString() : gID;
|
||||
|
||||
// If already formatted, return as-is
|
||||
if (gID.includes('@')) {
|
||||
return gID;
|
||||
}
|
||||
|
||||
// Clean: preserve hyphens (group format: NUMBER-TIMESTAMP)
|
||||
gID = gID.replace(/[^\d-]/g, '');
|
||||
|
||||
// Validate cleaned group ID
|
||||
if (!gID || gID.length === 0) {
|
||||
throw new Error('Invalid group ID format');
|
||||
}
|
||||
|
||||
// Groups always use @g.us
|
||||
return `${gID}@g.us`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a phone number for Socket client (chat)
|
||||
* Assumes the recipient is a chat
|
||||
*/
|
||||
async function formatChatNumberSocket(numb, waClient, nodeLogger) {
|
||||
// Handle message object with remoteJid
|
||||
if (numb && numb.remoteJid) {
|
||||
return numb.remoteJid;
|
||||
}
|
||||
|
||||
// Validate input
|
||||
if (!numb) {
|
||||
throw new Error('Number is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||
|
||||
// If already formatted, return as-is
|
||||
if (numb.includes('@')) {
|
||||
return numb;
|
||||
}
|
||||
|
||||
// Clean: remove everything except digits
|
||||
numb = numb.replace(/\D/g, '');
|
||||
|
||||
// Validate cleaned number
|
||||
if (!numb || numb.length === 0) {
|
||||
throw new Error('Invalid number format');
|
||||
}
|
||||
|
||||
// Check if number exists on WhatsApp
|
||||
try {
|
||||
const client = await waClient;
|
||||
const [result] = await client.onWhatsApp(numb);
|
||||
if (result?.exists) {
|
||||
return result.jid;
|
||||
}
|
||||
// If not found, assume chat
|
||||
nodeLogger.warn(`onWhatsApp returned no results for ${numb}, using @s.whatsapp.net`);
|
||||
return `${numb}@s.whatsapp.net`;
|
||||
} catch (e) {
|
||||
nodeLogger.warn(`onWhatsApp failed for ${numb}, using @s.whatsapp.net: ${e.message}`);
|
||||
return `${numb}@s.whatsapp.net`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a group ID for Socket client
|
||||
* Assumes the recipient is a group (@g.us)
|
||||
*/
|
||||
async function formatGroupIdSocket(gID, waClient, nodeLogger) {
|
||||
// Handle message object with remoteJid
|
||||
if (gID && gID.remoteJid) {
|
||||
return gID.remoteJid;
|
||||
}
|
||||
|
||||
// Validate input
|
||||
if (!gID) {
|
||||
throw new Error('Group ID is required');
|
||||
}
|
||||
|
||||
// Convert to string if number
|
||||
gID = typeof gID === 'number' ? gID.toString() : gID;
|
||||
|
||||
// If already formatted, return as-is
|
||||
if (gID.includes('@')) {
|
||||
return gID;
|
||||
}
|
||||
|
||||
// Clean: preserve hyphens (group format: NUMBER-TIMESTAMP)
|
||||
gID = gID.replace(/[^\d-]/g, '');
|
||||
|
||||
// Validate cleaned group ID
|
||||
if (!gID || gID.length === 0) {
|
||||
throw new Error('Invalid group ID format');
|
||||
}
|
||||
|
||||
// Groups always use @g.us
|
||||
return `${gID}@g.us`;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatChatNumber,
|
||||
formatGroupId,
|
||||
formatChatNumberSocket,
|
||||
formatGroupIdSocket
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user