Kirim reaction ke saluran WhatsApp sebanyak 1.2k+ dengan mudah menggunakan NvRCH2
npm install nvch-reactorconst { auth } = require('nvch-reactor');
// Inisialisasi client dengan API Key
const client = auth('your-api-key');
async function sendReaction() {
try {
const result = await client.sendReaction(
'https://whatsapp.com/channel/0029VbAzDjIBFLgbEyadQb3y/178',
'๐,โค๏ธ,๐ฅ'
);
console.log('โ
Berhasil:', result.message);
console.log('๐ค Bot:', result.data.botResponse);
console.log('๐ญ Emoji dikirim:', result.details.reacts);
} catch (error) {
console.error('โ Error:', error.message);
if (error.status) console.log('Status:', error.status);
}
}
sendReaction();๐ง Menggunakan createClient() dengan Konfigurasi Lengkap
const { createClient } = require('nvch-reactor');
// Dengan konfigurasi lengkap
const client = createClient({
apiKey: 'your-api-key',
timeout: 20000, // 20 detik
delay: 1000 // 1 detik untuk batch
});
// Kirim reaksi dengan timeout custom
await client.sendReaction(
'https://whatsapp.com/channel/CHANNEL_ID/POST_ID',
['๐', '๐คฉ'],
{ timeout: 15000 }
);๐ Batch Reactions - Kirim Multiple Reactions Sekaligus
const { auth } = require('nvch-reactor');
const client = auth('your-api-key');
const reactions = [
{
url: 'https://whatsapp.com/channel/CHANNEL_ID/178',
emojis: '๐'
},
{
url: 'https://whatsapp.com/channel/CHANNEL_ID/179',
emojis: ['โค๏ธ', '๐ฅ']
},
{
url: 'https://whatsapp.com/channel/CHANNEL_ID/180',
emojis: '๐,๐คฉ'
}
];
async function sendBatch() {
try {
const results = await client.sendBatchReactions(reactions, {
delay: 2000, // Delay 2 detik antar request
timeout: 30000 // Timeout per request
});
console.log(`๐ Total: ${results.length} reactions`);
results.forEach((result, index) => {
if (result.success) {
console.log(`โ
${index + 1}. Success: ${result.data.message}`);
} else {
console.log(`โ ${index + 1}. Failed: ${result.error}`);
}
});
} catch (error) {
console.error('Batch error:', error.message);
}
}
sendBatch();๐ ๏ธ Menggunakan Class NVRCH Langsung
const { NVRCH } = require('nvch-reactor');
// Instantiasi langsung
const client = new NVRCH('your-api-key');
// Dapatkan konfigurasi
console.log('Config:', client.getConfig());
// Update konfigurasi dinamis
client.setConfig({ timeout: 25000 });
// Validasi URL
const isValid = client.validateUrl('https://whatsapp.com/channel/...');
console.log('URL valid?', isValid);๐ Validasi URL WhatsApp Channel
const { validateUrl } = require('nvch-reactor');
const urls = [
'https://whatsapp.com/channel/0029VbAzDjIBFLgbEyadQb3y/178', // โ
Valid
'https://invalid-url.com/test', // โ Invalid
'https://whatsapp.com/not-channel/123' // โ Invalid
];
urls.forEach(url => {
const isValid = validateUrl(url);
console.log(`${isValid ? 'โ
' : 'โ'} ${url}`);
});๐ Error Handling & Auto Retry
const { auth } = require('nvch-reactor');
async function sendReactionWithRetry(url, emojis, retries = 3) {
const client = auth('your-api-key');
for (let i = 0; i < retries; i++) {
try {
const result = await client.sendReaction(url, emojis, { timeout: 15000 });
return { success: true, attempt: i + 1, data: result };
} catch (error) {
console.log(`โ Attempt ${i + 1} failed: ${error.message}`);
// Jangan retry untuk error tertentu
if (error.message.includes('tidak valid') || error.status === 401) {
return { success: false, error: error.message, final: true };
}
// Exponential backoff delay
if (i < retries - 1) {
const delay = 1000 * Math.pow(2, i); // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
return { success: false, error: 'Semua percobaan gagal' };
}
// Contoh penggunaan
(async () => {
const result = await sendReactionWithRetry(
'https://whatsapp.com/channel/0029VbAzDjIBFLgbEyadQb3y/178',
'๐'
);
console.log(result.success ? 'โ
Berhasil' : 'โ Gagal');
if (result.data) console.log('Data:', result.data);
})();๐ Monitoring & Logging System
const { auth, getPackageInfo } = require('nvch-reactor');
const fs = require('fs').promises;
class ReactionLogger {
constructor(apiKey, logFile = 'reactions.log') {
this.client = auth(apiKey);
this.logFile = logFile;
}
async sendAndLog(url, emojis) {
const startTime = Date.now();
try {
const result = await this.client.sendReaction(url, emojis);
const duration = Date.now() - startTime;
await this.log({
timestamp: new Date().toISOString(),
status: 'success',
url,
emojis,
duration: `${duration}ms`,
message: result.message
});
return result;
} catch (error) {
const duration = Date.now() - startTime;
await this.log({
timestamp: new Date().toISOString(),
status: 'error',
url,
emojis,
duration: `${duration}ms`,
error: error.message,
statusCode: error.status
});
throw error;
}
}
async log(data) {
const logEntry = JSON.stringify(data) + '\n';
await fs.appendFile(this.logFile, logEntry, 'utf8');
console.log('๐ Logged:', data);
}
async getStats() {
try {
const content = await fs.readFile(this.logFile, 'utf8');
const logs = content.trim().split('\n').map(line => JSON.parse(line));
return {
total: logs.length,
success: logs.filter(l => l.status === 'success').length,
failed: logs.filter(l => l.status === 'error').length,
avgDuration: logs.reduce((sum, l) => sum + parseInt(l.duration), 0) / logs.length
};
} catch (error) {
return { error: 'Log file not found' };
}
}
}
// Penggunaan
(async () => {
const logger = new ReactionLogger('your-api-key');
await logger.sendAndLog(
'https://whatsapp.com/channel/0029VbAzDjIBFLgbEyadQb3y/178',
'๐,๐ฏ'
);
const stats = await logger.getStats();
console.log('๐ Stats:', stats);
})();๐ฏ Advanced Configuration & Factory Pattern
const { createClient, getPackageInfo } = require('nvch-reactor');
// Factory pattern untuk multiple clients
function createReactionClient(config) {
const client = createClient(config);
return {
// Wrapper sederhana
send: (url, emojis) => client.sendReaction(url, emojis),
validate: (url) => client.validateUrl(url),
// Informasi client
getStats: () => ({
config: client.getConfig(),
apiInfo: getPackageInfo()
}),
// Batch dengan auto-retry dan better error handling
async sendBatchWithRetry(reactions, options = {}) {
const maxRetries = options.maxRetries || 3;
const results = [];
for (const [index, reaction] of reactions.entries()) {
let lastError;
let success = false;
console.log(`๐ Processing ${index + 1}/${reactions.length}`);
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const result = await client.sendReaction(
reaction.url,
reaction.emojis,
{ timeout: options.timeout || 20000 }
);
results.push({
...reaction,
success: true,
data: result,
attempts: attempt + 1
});
success = true;
break;
} catch (error) {
lastError = error;
console.log(` โ ๏ธ Attempt ${attempt + 1} failed: ${error.message}`);
// Jangan retry untuk error yang tidak bisa diperbaiki
if (error.status === 401 || error.status === 403) {
break;
}
if (attempt < maxRetries - 1) {
const backoff = 1000 * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, backoff));
}
}
}
if (!success) {
results.push({
...reaction,
success: false,
error: lastError?.message || 'Unknown error',
statusCode: lastError?.status
});
}
// Delay antar request dalam batch
if (options.delay && index < reactions.length - 1) {
await new Promise(resolve => setTimeout(resolve, options.delay));
}
}
return results;
}
};
}
// Penggunaan
(async () => {
const advancedClient = createReactionClient({
apiKey: 'your-api-key',
timeout: 30000
});
const results = await advancedClient.sendBatchWithRetry(
[
{ url: 'https://whatsapp.com/channel/.../178', emojis: '๐' },
{ url: 'https://whatsapp.com/channel/.../179', emojis: 'โค๏ธ,๐ฅ' }
],
{ delay: 1000, maxRetries: 2 }
);
console.log('\n๐ Summary:');
console.log(`โ
Success: ${results.filter(r => r.success).length}`);
console.log(`โ Failed: ${results.filter(r => !r.success).length}`);
})();๐ Integrasi dengan Express.js REST API
const express = require('express');
const { auth, validateUrl } = require('nvch-reactor');
const app = express();
app.use(express.json());
// Middleware untuk validasi API Key
const validateApiKey = (req, res, next) => {
const apiKey = req.headers['x-api-key'] || req.query.apiKey;
if (!apiKey) {
return res.status(401).json({
success: false,
error: 'API Key diperlukan. Gunakan header X-API-Key atau query parameter apiKey'
});
}
try {
req.reactionClient = auth(apiKey);
next();
} catch (error) {
res.status(400).json({
success: false,
error: 'API Key tidak valid'
});
}
};
// Middleware untuk validasi request body
const validateReactionRequest = (req, res, next) => {
const { url, emojis } = req.body;
if (!url || !emojis) {
return res.status(400).json({
success: false,
error: 'Field "url" dan "emojis" wajib diisi'
});
}
if (!validateUrl(url)) {
return res.status(400).json({
success: false,
error: 'Format URL tidak valid. Gunakan format: https://whatsapp.com/channel/{CHANNEL_ID}/{POST_ID}'
});
}
next();
};
// Route: Health check
app.get('/api/health', (req, res) => {
res.json({
success: true,
status: 'ok',
timestamp: new Date().toISOString()
});
});
// Route: Kirim reaksi tunggal
app.post('/api/send', validateApiKey, validateReactionRequest, async (req, res) => {
try {
const { url, emojis, timeout } = req.body;
const result = await req.reactionClient.sendReaction(
url,
emojis,
timeout ? { timeout } : undefined
);
res.json({
success: true,
message: 'Reaksi berhasil dikirim',
data: result,
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(error.status || 500).json({
success: false,
error: error.message,
statusCode: error.status,
timestamp: new Date().toISOString()
});
}
});
// Route: Batch reactions
app.post('/api/batch', validateApiKey, async (req, res) => {
try {
const { reactions, delay = 1000, timeout } = req.body;
if (!Array.isArray(reactions) || reactions.length === 0) {
return res.status(400).json({
success: false,
error: 'Field "reactions" harus berupa array yang tidak kosong'
});
}
// Validasi setiap reaction
for (const reaction of reactions) {
if (!reaction.url || !reaction.emojis) {
return res.status(400).json({
success: false,
error: 'Setiap reaction harus memiliki "url" dan "emojis"'
});
}
}
const results = await req.reactionClient.sendBatchReactions(
reactions,
{ delay, timeout }
);
const summary = {
total: results.length,
success: results.filter(r => r.success).length,
failed: results.filter(r => !r.success).length
};
res.json({
success: true,
message: 'Batch reactions selesai',
summary,
data: results,
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
}
});
// Route: Validasi URL
app.post('/api/validate', (req, res) => {
const { url } = req.body;
if (!url) {
return res.status(400).json({
success: false,
error: 'Field "url" wajib diisi'
});
}
const isValid = validateUrl(url);
res.json({
success: true,
valid: isValid,
url,
message: isValid ? 'URL valid' : 'URL tidak valid'
});
});
// Error handler global
app.use((err, req, res, next) => {
console.error('โ Error:', err);
res.status(500).json({
success: false,
error: 'Internal server error',
message: err.message
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`๐ Server berjalan di http://localhost:${PORT}`);
console.log(`๐ API Documentation:`);
console.log(` GET /api/health - Health check`);
console.log(` POST /api/send - Kirim reaksi tunggal`);
console.log(` POST /api/batch - Batch reactions`);
console.log(` POST /api/validate - Validasi URL`);
});Contoh Request dengan cURL:
# Kirim reaksi tunggal
curl -X POST http://localhost:3000/api/send \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"url": "https://whatsapp.com/channel/0029VbAzDjIBFLgbEyadQb3y/178",
"emojis": "๐,โค๏ธ"
}'
# Batch reactions
curl -X POST http://localhost:3000/api/batch \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"reactions": [
{"url": "https://whatsapp.com/channel/.../178", "emojis": "๐"},
{"url": "https://whatsapp.com/channel/.../179", "emojis": "โค๏ธ"}
],
"delay": 1000
}'๐ Unit Testing dengan Jest
// test/nvch-reactor.test.js
const nvchReactor = require('nvch-reactor');
// Mock module
jest.mock('nvch-reactor');
describe('NVCH Reactor Tests', () => {
let mockClient;
beforeEach(() => {
// Setup mock client
mockClient = {
sendReaction: jest.fn(),
sendBatchReactions: jest.fn(),
validateUrl: jest.fn(),
getConfig: jest.fn()
};
nvchReactor.auth.mockReturnValue(mockClient);
});
afterEach(() => {
jest.clearAllMocks();
});
test('auth() should create client instance', () => {
const client = nvchReactor.auth('test-api-key');
expect(nvchReactor.auth).toHaveBeenCalledWith('test-api-key');
expect(client).toBeDefined();
});
test('sendReaction() should send reaction successfully', async () => {
mockClient.sendReaction.mockResolvedValue({
success: true,
message: 'Reaction sent successfully',
data: { botResponse: 'Success' },
details: { reacts: '๐' }
});
const result = await mockClient.sendReaction(
'https://whatsapp.com/channel/test/123',
'๐'
);
expect(result.success).toBe(true);
expect(result.data.botResponse).toBe('Success');
expect(mockClient.sendReaction).toHaveBeenCalledWith(
'https://whatsapp.com/channel/test/123',
'๐'
);
});
test('sendReaction() should handle errors', async () => {
mockClient.sendReaction.mockRejectedValue(
new Error('API request failed')
);
await expect(
mockClient.sendReaction('invalid-url', '๐')
).rejects.toThrow('API request failed');
});
test('sendBatchReactions() should process multiple reactions', async () => {
mockClient.sendBatchReactions.mockResolvedValue([
{ success: true, data: { message: 'Success 1' } },
{ success: true, data: { message: 'Success 2' } },
{ success: false, error: 'Failed' }
]);
const reactions = [
{ url: 'https://whatsapp.com/channel/test/1', emojis: '๐' },
{ url: 'https://whatsapp.com/channel/test/2', emojis: 'โค๏ธ' },
{ url: 'https://whatsapp.com/channel/test/3', emojis: '๐ฅ' }
];
const results = await mockClient.sendBatchReactions(reactions);
expect(results).toHaveLength(3);
expect(results.filter(r => r.success)).toHaveLength(2);
expect(results.filter(r => !r.success)).toHaveLength(1);
});
test('validateUrl() should validate URL format', () => {
nvchReactor.validateUrl.mockImplementation((url) => {
return url.includes('whatsapp.com/channel/');
});
expect(nvchReactor.validateUrl('https://whatsapp.com/channel/test/123')).toBe(true);
expect(nvchReactor.validateUrl('https://invalid.com/test')).toBe(false);
});
});Jalankan test:
npm testโก Rate Limiting & Queue Management
const { auth } = require('nvch-reactor');
class RateLimitedClient {
constructor(apiKey, requestsPerMinute = 30) {
this.client = auth(apiKey);
this.requestsPerMinute = requestsPerMinute;
this.queue = [];
this.processing = false;
this.requestCount = 0;
this.resetTime = Date.now() + 60000;
}
async addToQueue(url, emojis) {
return new Promise((resolve, reject) => {
this.queue.push({ url, emojis, resolve, reject });
this.processQueue();
});
}
async processQueue() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
// Reset counter jika sudah 1 menit
if (Date.now() >= this.resetTime) {
this.requestCount = 0;
this.resetTime = Date.now() + 60000;
}
// Tunggu jika sudah mencapai limit
if (this.requestCount >= this.requestsPerMinute) {
const waitTime = this.resetTime - Date.now();
console.log(`โณ Rate limit reached. Waiting ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
this.requestCount = 0;
this.resetTime = Date.now() + 60000;
}
const task = this.queue.shift();
try {
const result = await this.client.sendReaction(task.url, task.emojis);
this.requestCount++;
task.resolve(result);
} catch (error) {
task.reject(error);
}
// Delay kecil antar request
await new Promise(resolve => setTimeout(resolve, 100));
}
this.processing = false;
}
getStats() {
return {
queueLength: this.queue.length,
requestCount: this.requestCount,
limit: this.requestsPerMinute,
resetIn: Math.max(0, this.resetTime - Date.now())
};
}
}
// Penggunaan
(async () => {
const rateLimitedClient = new RateLimitedClient('your-api-key', 30);
// Kirim banyak request sekaligus
const promises = [];
for (let i = 1; i <= 50; i++) {
promises.push(
rateLimitedClient.addToQueue(
`https://whatsapp.com/channel/test/${i}`,
'๐'
)
);
}
// Monitor progress
const interval = setInterval(() => {
const stats = rateLimitedClient.getStats();
console.log(`๐ Queue: ${stats.queueLength}, Sent: ${stats.requestCount}/${stats.limit}`);
if (stats.queueLength === 0 && stats.requestCount > 0) {
clearInterval(interval);
}
}, 1000);
await Promise.all(promises);
console.log('โ
Semua request selesai!');
})();Membuat client instance dengan API Key.
Parameters:
apiKey(string) - API Key untuk autentikasi
Returns: Client instance dengan methods lengkap
Membuat client dengan konfigurasi lengkap.
Parameters:
config(object)apiKey(string) - API Keytimeout(number, optional) - Request timeout dalam ms (default: 20000)delay(number, optional) - Delay untuk batch requests dalam ms (default: 1000)
Returns: Client instance
Mengirim reaksi tunggal ke post WhatsApp Channel.
Parameters:
url(string) - URL WhatsApp Channel postemojis(string | array) - Emoji atau array emoji untuk dikirimoptions(object, optional)timeout(number) - Custom timeout untuk request ini
Returns: Promise dengan result object
Example:
await client.sendReaction(
'https://whatsapp.com/channel/ID/POST',
'๐,โค๏ธ'
);Mengirim multiple reactions sekaligus.
Parameters:
reactions(array) - Array of reaction objectsurl(string) - WhatsApp Channel URLemojis(string | array) - Emoji untuk dikirim
options(object, optional)delay(number) - Delay antar request dalam mstimeout(number) - Timeout per request dalam ms
Returns: Promise dengan array of results
Validasi format URL WhatsApp Channel.
Parameters:
url(string) - URL untuk divalidasi
Returns: Boolean (true jika valid)
Mendapatkan informasi package NVCH Reactor.
Returns: Object dengan name dan version
Mendapatkan konfigurasi client saat ini.
Returns: Object konfigurasi
Update konfigurasi client.
Parameters:
config(object) - Konfigurasi baru (partial update)
https://whatsapp.com/channel/{CHANNEL_ID}/{POST_ID}
Contoh:
https://whatsapp.com/channel/0029VbAzDjIBFLgbEyadQb3y/178
Emoji dapat dikirim dalam berbagai format:
// String dengan comma separator
'๐,โค๏ธ,๐ฅ'
// Array of strings
['๐', 'โค๏ธ', '๐ฅ']
// Single emoji
'๐'Library ini akan throw error dalam kondisi berikut:
| Error Type | Status Code | Description |
|---|---|---|
| Invalid URL | - | Format URL tidak sesuai |
| API Error | 4xx/5xx | Error dari API server |
| Timeout | - | Request melebihi timeout |
| Network Error | - | Masalah koneksi jaringan |
Best Practice:
try {
const result = await client.sendReaction(url, emojis);
// Handle success
} catch (error) {
if (error.status === 401) {
console.error('API Key tidak valid');
} else if (error.message.includes('timeout')) {
console.error('Request timeout, coba lagi');
} else {
console.error('Error:', error.message);
}
}โ ๏ธ Jangan commit API Key ke repository- โ Gunakan environment variables untuk menyimpan API Key
- โ
Gunakan
.envfile untuk development - โ Implementasi rate limiting untuk production
Contoh menggunakan environment variables:
// .env
NVCH_REACTOR_API_KEY=your-api-key-here
// app.js
require('dotenv').config();
const { auth } = require('nvch-reactor');
const client = auth(process.env.NVCH_REACTOR_API_KEY);Lebih efisien menggunakan sendBatchReactions() daripada multiple sendReaction() calls.
// โ Tidak efisien
for (const url of urls) {
await client.sendReaction(url, '๐');
}
// โ
Lebih baik
await client.sendBatchReactions(
urls.map(url => ({ url, emojis: '๐' })),
{ delay: 1000 }
);Selalu implement retry untuk handling network issues atau temporary failures.
Default timeout adalah 20 detik, sesuaikan dengan kebutuhan:
- Fast operations: 10-15 detik
- Batch operations: 30-60 detik
Implement logging untuk tracking success/failure rate dan debugging.
Hormati rate limits untuk menghindari API blocking.
{
success: true,
message: "Reaction sent successfully",
data: {
botResponse: "...",
// ... data lainnya
},
details: {
reacts: "๐,โค๏ธ"
}
}{
success: false,
message: "Error message",
status: 400,
error: "Detailed error information"
}๐ฑ Bot WhatsApp Auto React
const { auth } = require('nvch-reactor');
const client = auth(process.env.API_KEY);
// Auto react ke semua post baru di channel
class AutoReactBot {
constructor(channelId, emojis) {
this.channelId = channelId;
this.emojis = emojis;
this.processedPosts = new Set();
}
async checkNewPosts() {
// Implementasi untuk mendapatkan post terbaru
// (ini contoh, sesuaikan dengan cara Anda mendapat post ID)
const newPosts = await this.getNewPosts();
for (const postId of newPosts) {
if (!this.processedPosts.has(postId)) {
try {
const url = `https://whatsapp.com/channel/${this.channelId}/${postId}`;
await client.sendReaction(url, this.emojis);
this.processedPosts.add(postId);
console.log(`โ
Reacted to post ${postId}`);
} catch (error) {
console.error(`โ Failed to react to post ${postId}:`, error.message);
}
}
}
}
start(intervalMinutes = 5) {
console.log(`๐ค Bot started. Checking every ${intervalMinutes} minutes...`);
this.checkNewPosts(); // Run immediately
setInterval(() => this.checkNewPosts(), intervalMinutes * 60000);
}
}
// Penggunaan
const bot = new AutoReactBot('0029VbAzDjIBFLgbEyadQb3y', '๐,โค๏ธ');
bot.start(5); // Check setiap 5 menit๐ Analytics & Reporting
const { auth } = require('nvch-reactor');
const fs = require('fs').promises;
class ReactionAnalytics {
constructor(apiKey) {
this.client = auth(apiKey);
this.stats = {
total: 0,
success: 0,
failed: 0,
byEmoji: {},
byHour: Array(24).fill(0),
errors: []
};
}
async sendWithTracking(url, emojis) {
const hour = new Date().getHours();
const startTime = Date.now();
try {
const result = await this.client.sendReaction(url, emojis);
this.stats.total++;
this.stats.success++;
this.stats.byHour[hour]++;
// Track per emoji
const emojiList = Array.isArray(emojis) ? emojis : emojis.split(',');
emojiList.forEach(emoji => {
this.stats.byEmoji[emoji.trim()] = (this.stats.byEmoji[emoji.trim()] || 0) + 1;
});
return { success: true, duration: Date.now() - startTime, data: result };
} catch (error) {
this.stats.total++;
this.stats.failed++;
this.stats.errors.push({
timestamp: new Date().toISOString(),
url,
emojis,
error: error.message
});
return { success: false, duration: Date.now() - startTime, error: error.message };
}
}
getReport() {
const successRate = ((this.stats.success / this.stats.total) * 100).toFixed(2);
return {
summary: {
total: this.stats.total,
success: this.stats.success,
failed: this.stats.failed,
successRate: `${successRate}%`
},
topEmojis: Object.entries(this.stats.byEmoji)
.sort(([, a], [, b]) => b - a)
.slice(0, 5),
peakHours: this.stats.byHour
.map((count, hour) => ({ hour, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 3),
recentErrors: this.stats.errors.slice(-5)
};
}
async exportReport(filename = 'reaction-report.json') {
const report = this.getReport();
await fs.writeFile(filename, JSON.stringify(report, null, 2));
console.log(`๐ Report exported to ${filename}`);
}
}
// Penggunaan
(async () => {
const analytics = new ReactionAnalytics(process.env.API_KEY);
// Send reactions dengan tracking
await analytics.sendWithTracking('https://whatsapp.com/channel/.../178', '๐');
await analytics.sendWithTracking('https://whatsapp.com/channel/.../179', 'โค๏ธ');
// Lihat report
console.log('๐ Report:', analytics.getReport());
// Export ke file
await analytics.exportReport();
})();๐ Scheduled Reactions (Cron Job)
const { auth } = require('nvrch2');
const cron = require('node-cron');
const client = auth(process.env.API_KEY);
// Konfigurasi scheduled reactions
const scheduledReactions = [
{
name: 'Morning Boost',
cron: '0 8 * * *', // Setiap hari jam 8 pagi
reactions: [
{ url: 'https://whatsapp.com/channel/.../178', emojis: 'โ๏ธ,๐ช' },
{ url: 'https://whatsapp.com/channel/.../179', emojis: '๐
' }
]
},
{
name: 'Evening Support',
cron: '0 20 * * *', // Setiap hari jam 8 malam
reactions: [
{ url: 'https://whatsapp.com/channel/.../180', emojis: '๐,โญ' }
]
}
];
// Setup cron jobs
scheduledReactions.forEach(schedule => {
cron.schedule(schedule.cron, async () => {
console.log(`โฐ Running: ${schedule.name}`);
try {
const results = await client.sendBatchReactions(schedule.reactions, {
delay: 1000
});
const success = results.filter(r => r.success).length;
console.log(`โ
${schedule.name}: ${success}/${results.length} succeeded`);
} catch (error) {
console.error(`โ ${schedule.name} failed:`, error.message);
}
});
console.log(`๐
Scheduled: ${schedule.name} (${schedule.cron})`);
});
console.log('๐ Scheduler started. Press Ctrl+C to stop.');Install dependencies:
npm install node-cron๐ฎ Interactive CLI Tool
#!/usr/bin/env node
const { auth, validateUrl } = require('nvch-reactor');
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const question = (prompt) => new Promise((resolve) => {
rl.question(prompt, resolve);
});
async function main() {
console.log('๐ NVCH Reactor Interactive CLI\n');
// Get API Key
const apiKey = await question('Enter your API Key: ');
if (!apiKey) {
console.log('โ API Key is required!');
rl.close();
return;
}
const client = auth(apiKey);
console.log('โ
Client initialized\n');
while (true) {
console.log('\n๐ Options:');
console.log('1. Send single reaction');
console.log('2. Send batch reactions');
console.log('3. Validate URL');
console.log('4. Exit');
const choice = await question('\nSelect option (1-4): ');
switch (choice.trim()) {
case '1': {
const url = await question('Enter WhatsApp Channel URL: ');
if (!validateUrl(url)) {
console.log('โ Invalid URL format!');
break;
}
const emojis = await question('Enter emojis (comma-separated): ');
try {
console.log('โณ Sending reaction...');
const result = await client.sendReaction(url, emojis);
console.log('โ
Success:', result.message);
} catch (error) {
console.log('โ Error:', error.message);
}
break;
}
case '2': {
const count = parseInt(await question('How many reactions? '));
const reactions = [];
for (let i = 0; i < count; i++) {
console.log(`\nReaction ${i + 1}/${count}:`);
const url = await question(' URL: ');
const emojis = await question(' Emojis: ');
reactions.push({ url, emojis });
}
const delay = parseInt(await question('\nDelay between requests (ms): ') || '1000');
try {
console.log('\nโณ Sending batch reactions...');
const results = await client.sendBatchReactions(reactions, { delay });
const success = results.filter(r => r.success).length;
console.log(`\nโ
Completed: ${success}/${results.length} succeeded`);
} catch (error) {
console.log('โ Error:', error.message);
}
break;
}
case '3': {
const url = await question('Enter URL to validate: ');
const isValid = validateUrl(url);
console.log(isValid ? 'โ
URL is valid' : 'โ URL is invalid');
break;
}
case '4': {
console.log('\n๐ Goodbye!');
rl.close();
return;
}
default: {
console.log('โ Invalid option!');
}
}
}
}
main().catch(error => {
console.error('Fatal error:', error);
rl.close();
});Buat executable:
chmod +x cli.js
./cli.js- Pastikan API Key Anda benar
- Cek apakah API Key sudah expired
- Verify API Key di dashboard
- Format harus:
https://whatsapp.com/channel/{CHANNEL_ID}/{POST_ID} - Pastikan tidak ada spasi atau karakter tambahan
- Gunakan
validateUrl()untuk memverifikasi
- Coba tingkatkan timeout:
{ timeout: 30000 } - Cek koneksi internet Anda
- Server mungkin sedang sibuk, retry setelah beberapa saat
- Kurangi delay antar request
- Gunakan concurrency yang lebih tinggi
- Implement parallel processing
- Implementasi rate limiting di client side
- Tambahkan delay yang lebih besar
- Gunakan queue system
Penggunaan library ini sepenuhnya menjadi tanggung jawab pengguna. Pastikan Anda mematuhi Terms of Service WhatsApp dan tidak melakukan spam atau abuse.
ยฉ 2025 Nine | Made with โค๏ธ for the community
