Add Twilio WhatsApp integration
Build Curio HMS / build-and-deploy (push) Successful in 57s
Details
Build Curio HMS / build-and-deploy (push) Successful in 57s
Details
This commit is contained in:
parent
1b3911ee94
commit
75562d6ffe
Binary file not shown.
|
|
@ -66,10 +66,29 @@ class ClinicAgent {
|
|||
if (text.includes("book") || text.includes("today")) {
|
||||
return {
|
||||
reply: "I can help with that. Which time works best for you?",
|
||||
buttons: ["10:00 AM", "11:00 AM", "06:00 PM"]
|
||||
buttons: ["10:00 AM", "11:00 AM", "06:00 PM"],
|
||||
nextStep: "AWAIT_TIME"
|
||||
};
|
||||
}
|
||||
|
||||
// Scenario 3.1: Handling time selection
|
||||
if (context.lastStep === "AWAIT_TIME") {
|
||||
let time = "";
|
||||
if (text.includes("1") || text.includes("10")) time = "10:00";
|
||||
else if (text.includes("2") || text.includes("11")) time = "11:00";
|
||||
else if (text.includes("3") || text.includes("6") || text.includes("06")) time = "18:00";
|
||||
|
||||
if (time) {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const result = await queueManager.bookOnline(today, time, phone, 'sharma-clinic');
|
||||
if (result.success) {
|
||||
return { reply: `Awesome! Your token is ${result.token}. You should receive a confirmation message shortly.` };
|
||||
} else {
|
||||
return { reply: `Sorry, ${result.message}` };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scenario 3.5: Medicine Query
|
||||
if (text.includes("have") || text.includes("medicine") || text.includes("syrup") || text.includes("tablet")) {
|
||||
const pharmacyReply = pharmacyAgent.handlePatientQuery(message);
|
||||
|
|
|
|||
|
|
@ -1,25 +1,33 @@
|
|||
/**
|
||||
* NotificationManager: Handles mock WhatsApp notifications for Curio
|
||||
* NotificationManager: Handles WhatsApp notifications for Curio
|
||||
*/
|
||||
|
||||
const whatsappService = require('./whatsappService');
|
||||
|
||||
class NotificationManager {
|
||||
constructor() {
|
||||
this.notificationsSent = [];
|
||||
}
|
||||
|
||||
sendRescheduleAlert(patientPhone, tenantName, oldTime, newTime) {
|
||||
const message = `🔔 *Curio Alert*: A slot has just opened up at ${tenantName} for today at ${newTime}!
|
||||
|
||||
Would you like to move your ${oldTime} appointment to this earlier slot?
|
||||
|
||||
Reply:
|
||||
1. Yes, move me!
|
||||
2. No, keep my current time.`;
|
||||
|
||||
console.log(`[WhatsApp to ${patientPhone}]: ${message}`);
|
||||
this.notificationsSent.push({ phone: patientPhone, message, timestamp: new Date() });
|
||||
|
||||
return { success: true, message: "Notification sent." };
|
||||
async sendRescheduleAlert(patientPhone, tenantName, oldTime, newTime) {
|
||||
this.notificationsSent.push({ phone: patientPhone, type: 'reschedule', timestamp: new Date() });
|
||||
return await whatsappService.sendRescheduleOffer(patientPhone, tenantName, oldTime, newTime);
|
||||
}
|
||||
|
||||
async sendTokenNotification(patientPhone, tokenData) {
|
||||
this.notificationsSent.push({ phone: patientPhone, type: 'token', timestamp: new Date() });
|
||||
return await whatsappService.sendTokenConfirmation(
|
||||
patientPhone,
|
||||
tokenData.token,
|
||||
tokenData.clinicName,
|
||||
tokenData.slotTime,
|
||||
tokenData.fee
|
||||
);
|
||||
}
|
||||
|
||||
async sendQueueUpdate(patientPhone, clinicName, position, eta) {
|
||||
this.notificationsSent.push({ phone: patientPhone, type: 'queue', timestamp: new Date() });
|
||||
return await whatsappService.sendQueueUpdate(patientPhone, clinicName, position, eta);
|
||||
}
|
||||
|
||||
getRecentNotifications() {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class QueueManager {
|
|||
return this.slots[key];
|
||||
}
|
||||
|
||||
bookOnline(date, time, tenantId = 'default') {
|
||||
async bookOnline(date, time, patientPhone, tenantId = 'default') {
|
||||
if (!this.isAvailable(tenantId, date, time)) {
|
||||
return { success: false, message: "The clinic is closed at this time / on this day." };
|
||||
}
|
||||
|
|
@ -72,9 +72,18 @@ class QueueManager {
|
|||
const config = getTenantConfig(tenantId);
|
||||
if (status.online < status.maxOnline) {
|
||||
status.online++;
|
||||
const token = `ON-${status.online}`;
|
||||
if (patientPhone) {
|
||||
await notificationManager.sendTokenNotification(patientPhone, {
|
||||
token,
|
||||
clinicName: config.name,
|
||||
slotTime: time,
|
||||
fee: config.consultationFee
|
||||
});
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
token: `ON-${status.online}`,
|
||||
token,
|
||||
slot: this.getSlotKey(tenantId, date, time),
|
||||
status: 'PENDING_PAYMENT',
|
||||
fee: config.consultationFee
|
||||
|
|
@ -83,7 +92,7 @@ class QueueManager {
|
|||
return { success: false, message: "Slot full for online booking. Try next slot." };
|
||||
}
|
||||
|
||||
bookWalkin(date, time, tenantId = 'default') {
|
||||
async bookWalkin(date, time, patientPhone, tenantId = 'default') {
|
||||
if (!this.isAvailable(tenantId, date, time)) {
|
||||
return { success: false, message: "The clinic is closed at this time / on this day." };
|
||||
}
|
||||
|
|
@ -91,9 +100,18 @@ class QueueManager {
|
|||
const config = getTenantConfig(tenantId);
|
||||
if (status.walkin < status.maxWalkin) {
|
||||
status.walkin++;
|
||||
const token = `WK-${status.walkin}`;
|
||||
if (patientPhone) {
|
||||
await notificationManager.sendTokenNotification(patientPhone, {
|
||||
token,
|
||||
clinicName: config.name,
|
||||
slotTime: time,
|
||||
fee: config.consultationFee
|
||||
});
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
token: `WK-${status.walkin}`,
|
||||
token,
|
||||
status: 'PENDING_PAYMENT',
|
||||
fee: config.consultationFee
|
||||
};
|
||||
|
|
@ -110,24 +128,24 @@ class QueueManager {
|
|||
];
|
||||
}
|
||||
|
||||
cancelBooking(date, time, tenantId = 'default') {
|
||||
async cancelBooking(date, time, tenantId = 'default') {
|
||||
const status = this.getSlotStatus(tenantId, date, time);
|
||||
if (status.online > 0) {
|
||||
status.online--;
|
||||
this.notifyAvailableSlot(tenantId, date, time);
|
||||
await this.notifyAvailableSlot(tenantId, date, time);
|
||||
return { success: true, message: "Booking cancelled and slot opened." };
|
||||
}
|
||||
return { success: false, message: "No bookings found for this slot." };
|
||||
}
|
||||
|
||||
notifyAvailableSlot(tenantId, date, time) {
|
||||
async notifyAvailableSlot(tenantId, date, time) {
|
||||
const config = getTenantConfig(tenantId);
|
||||
console.log(`[Queue] Triggering notifications for open slot: ${time}`);
|
||||
|
||||
// Mock finding a patient with a later slot
|
||||
const mockLaterPatient = { phone: "9876543210", appointmentTime: "19:00" };
|
||||
const mockLaterPatient = { phone: "+918500176938", appointmentTime: "19:00" };
|
||||
|
||||
notificationManager.sendRescheduleAlert(
|
||||
await notificationManager.sendRescheduleAlert(
|
||||
mockLaterPatient.phone,
|
||||
config.name,
|
||||
mockLaterPatient.appointmentTime,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
require('dotenv').config();
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const twilio = require('twilio');
|
||||
|
||||
const whatsappService = require('./whatsappService');
|
||||
const botLogic = require('./botLogic');
|
||||
const { getTenantConfig, updateTenantConfig } = require('./configManager');
|
||||
const { getTemporalClient } = require('./temporalClient');
|
||||
|
|
@ -487,7 +490,10 @@ app.patch('/api/clinic/settings', requireAuth('OWNER'), async (req, res) => {
|
|||
|
||||
// ── WHATSAPP WEBHOOK ──────────────────────────────────────────────────────────
|
||||
|
||||
app.post('/whatsapp/webhook', async (req, res) => {
|
||||
// Using twilio.webhook() middleware for request validation
|
||||
// Disable validation in local environment to allow testing via ngrok/local tools
|
||||
const shouldValidate = process.env.NODE_ENV === 'production';
|
||||
app.post('/whatsapp/webhook', twilio.webhook({ validate: shouldValidate }), async (req, res) => {
|
||||
const from = req.body.From || req.body.from;
|
||||
const body = req.body.Body || req.body.body;
|
||||
|
||||
|
|
@ -513,8 +519,51 @@ app.post('/whatsapp/webhook', async (req, res) => {
|
|||
});
|
||||
res.type('text/xml').send('<Response></Response>');
|
||||
} catch (err) {
|
||||
console.error('[WhatsApp Webhook] Error:', err);
|
||||
res.status(500).send('Internal Server Error');
|
||||
console.error('[WhatsApp Webhook] Temporal unavailable, falling back to local botLogic. Error:', err.message);
|
||||
|
||||
// Fallback to local bot logic if Temporal is not running
|
||||
try {
|
||||
const botResponse = await botLogic.handleMessage(from, body);
|
||||
let replyText = botResponse.reply;
|
||||
|
||||
// Format buttons for standard WhatsApp text since we aren't using Twilio Content Templates
|
||||
if (botResponse.buttons && botResponse.buttons.length > 0) {
|
||||
replyText += '\n\n' + botResponse.buttons.map((b, i) => `${i + 1}. ${b}`).join('\n');
|
||||
}
|
||||
|
||||
await whatsappService.sendWhatsApp(from, replyText);
|
||||
res.type('text/xml').send('<Response></Response>');
|
||||
} catch (botErr) {
|
||||
console.error('[WhatsApp Webhook] Fallback logic error:', botErr);
|
||||
res.status(500).send('Internal Server Error');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ── MANUAL TOKEN NOTIFICATION ──────────────────────────────────────────────────
|
||||
|
||||
app.post('/api/whatsapp/send-token', requireAuth(), async (req, res) => {
|
||||
const { patientPhone, tokenNumber, clinicName, slotTime, fee } = req.body;
|
||||
if (!patientPhone || !tokenNumber || !clinicName || !slotTime) {
|
||||
return res.status(400).json({ error: 'Missing required fields' });
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await whatsappService.sendTokenConfirmation(
|
||||
patientPhone,
|
||||
tokenNumber,
|
||||
clinicName,
|
||||
slotTime,
|
||||
fee || 0
|
||||
);
|
||||
if (result.success) {
|
||||
res.json({ success: true, sid: result.sid });
|
||||
} else {
|
||||
res.status(500).json({ error: result.error });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Send Token]', err);
|
||||
res.status(500).json({ error: 'Failed to send token via WhatsApp' });
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
require('dotenv').config();
|
||||
const twilio = require('twilio');
|
||||
|
||||
// Initialize Twilio using API Key
|
||||
// Account SID is still required for API Key auth
|
||||
const accountSid = process.env.TWILIO_ACCOUNT_SID;
|
||||
const apiKey = process.env.TWILIO_API_KEY_SID;
|
||||
const apiSecret = process.env.TWILIO_API_KEY_SECRET;
|
||||
|
||||
const client = twilio(apiKey, apiSecret, { accountSid });
|
||||
const fromNumber = process.env.TWILIO_WHATSAPP_FROM || 'whatsapp:+14155238886'; // Fallback to sandbox if not set
|
||||
|
||||
class WhatsAppService {
|
||||
async sendWhatsApp(to, body) {
|
||||
if (!to) {
|
||||
console.error('[WhatsAppService] Missing destination phone number');
|
||||
return { success: false, error: 'Missing phone number' };
|
||||
}
|
||||
|
||||
// Ensure "whatsapp:" prefix
|
||||
const toFormatted = to.startsWith('whatsapp:') ? to : `whatsapp:${to.startsWith('+') ? to : '+' + to}`;
|
||||
|
||||
try {
|
||||
const message = await client.messages.create({
|
||||
body: body,
|
||||
from: fromNumber,
|
||||
to: toFormatted
|
||||
});
|
||||
console.log(`[WhatsAppService] Message sent to ${toFormatted}. SID: ${message.sid}`);
|
||||
return { success: true, sid: message.sid };
|
||||
} catch (error) {
|
||||
console.error(`[WhatsAppService] Failed to send message to ${toFormatted}:`, error.message);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async sendTokenConfirmation(phone, tokenNumber, clinicName, slotTime, fee) {
|
||||
const message = `🏥 *CuraFlow Token Confirmed*\n\n🔢 Token: ${tokenNumber}\n🏨 Clinic: ${clinicName}\n🕐 Slot: ${slotTime}\n💰 Fee: ₹${fee}\n\nPlease arrive 10 mins early.`;
|
||||
return this.sendWhatsApp(phone, message);
|
||||
}
|
||||
|
||||
async sendQueueUpdate(phone, clinicName, position, estimatedTime) {
|
||||
const message = `📋 *Queue Update*\n\nYou are #${position} in line at ${clinicName}.\n⏱ Estimated wait: ~${estimatedTime} mins`;
|
||||
return this.sendWhatsApp(phone, message);
|
||||
}
|
||||
|
||||
async sendRescheduleOffer(phone, clinicName, oldTime, newTime) {
|
||||
const message = `🔔 *Slot Available!*\n\nA slot opened at ${clinicName} for ${newTime}!\nYour current: ${oldTime}\n\nReply:\n1. Yes, move me!\n2. No, keep my current time.`;
|
||||
return this.sendWhatsApp(phone, message);
|
||||
}
|
||||
|
||||
async sendCancellationConfirmation(phone, clinicName, slotTime) {
|
||||
const message = `✅ *Booking Cancelled*\n\nYour token at ${clinicName} for ${slotTime} has been cancelled.`;
|
||||
return this.sendWhatsApp(phone, message);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new WhatsAppService();
|
||||
|
|
@ -26,6 +26,14 @@ spec:
|
|||
value: "postgres://postgres:curio_secret@curio-db:5432/curio"
|
||||
- name: TEMPORAL_URL
|
||||
value: "temporal-frontend.ai-core.svc.cluster.local:7233"
|
||||
- name: TWILIO_ACCOUNT_SID
|
||||
value: "AC601e1962dc8417ddb3ae53cd8d865020"
|
||||
- name: TWILIO_API_KEY_SID
|
||||
value: "SK48dd3d06318997be3a809a6ef0cd761d"
|
||||
- name: TWILIO_API_KEY_SECRET
|
||||
value: "rN5RpKAbFVCv0G45ehluf1JbTWt2dgNW"
|
||||
- name: TWILIO_WHATSAPP_FROM
|
||||
value: "whatsapp:+14155238886"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
|
|
|
|||
|
|
@ -201,6 +201,41 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base/node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
|
|
@ -231,6 +266,24 @@
|
|||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz",
|
||||
"integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.16.0",
|
||||
"form-data": "^4.0.5",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bcryptjs": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz",
|
||||
|
|
@ -340,6 +393,18 @@
|
|||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
|
|
@ -376,6 +441,12 @@
|
|||
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.20",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz",
|
||||
"integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
|
@ -391,6 +462,15 @@
|
|||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
|
|
@ -410,6 +490,18 @@
|
|||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.4.2",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
|
||||
"integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
|
|
@ -484,6 +576,21 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
|
|
@ -581,6 +688,42 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
|
@ -678,6 +821,21 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
|
||||
|
|
@ -710,6 +868,42 @@
|
|||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent/node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
|
|
@ -1162,6 +1356,15 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.15.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
|
||||
|
|
@ -1236,6 +1439,13 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scmp": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz",
|
||||
"integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==",
|
||||
"deprecated": "Just use Node.js's crypto.timingSafeEqual()",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
|
||||
|
|
@ -1424,6 +1634,24 @@
|
|||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/twilio": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/twilio/-/twilio-6.0.2.tgz",
|
||||
"integrity": "sha512-RN3TZxUtxLz2HBZVt62+LdZxQbrMVgYKtuzLgwmO7nqKvR+gQS5mCackD9hf4Y7MmoK/bX7tCm7kaJC8kC8zFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.13.5",
|
||||
"dayjs": "^1.11.9",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"qs": "^6.14.1",
|
||||
"scmp": "^2.1.0",
|
||||
"xmlbuilder": "^13.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
|
|
@ -1500,6 +1728,15 @@
|
|||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlbuilder": {
|
||||
"version": "13.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
|
||||
"integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@
|
|||
"dependencies": {
|
||||
"@temporalio/client": "^1.16.2",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"dotenv": "^17.4.2",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"pg": "^8.21.0",
|
||||
"twilio": "^6.0.2",
|
||||
"uuid": "^14.0.0"
|
||||
}
|
||||
},
|
||||
|
|
@ -213,6 +215,41 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base/node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
|
|
@ -243,6 +280,24 @@
|
|||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz",
|
||||
"integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.16.0",
|
||||
"form-data": "^4.0.5",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bcryptjs": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz",
|
||||
|
|
@ -352,6 +407,18 @@
|
|||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
|
|
@ -388,6 +455,12 @@
|
|||
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.20",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz",
|
||||
"integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
|
@ -403,6 +476,15 @@
|
|||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
|
|
@ -422,6 +504,18 @@
|
|||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.4.2",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
|
||||
"integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
|
|
@ -496,6 +590,21 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
|
|
@ -593,6 +702,42 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
|
@ -690,6 +835,21 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
|
||||
|
|
@ -722,6 +882,42 @@
|
|||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent/node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
|
|
@ -1174,6 +1370,15 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.15.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
|
||||
|
|
@ -1248,6 +1453,13 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scmp": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz",
|
||||
"integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==",
|
||||
"deprecated": "Just use Node.js's crypto.timingSafeEqual()",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
|
||||
|
|
@ -1436,6 +1648,24 @@
|
|||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/twilio": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/twilio/-/twilio-6.0.2.tgz",
|
||||
"integrity": "sha512-RN3TZxUtxLz2HBZVt62+LdZxQbrMVgYKtuzLgwmO7nqKvR+gQS5mCackD9hf4Y7MmoK/bX7tCm7kaJC8kC8zFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.13.5",
|
||||
"dayjs": "^1.11.9",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"qs": "^6.14.1",
|
||||
"scmp": "^2.1.0",
|
||||
"xmlbuilder": "^13.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
|
|
@ -1512,6 +1742,15 @@
|
|||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlbuilder": {
|
||||
"version": "13.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
|
||||
"integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@
|
|||
"dependencies": {
|
||||
"@temporalio/client": "^1.16.2",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"dotenv": "^17.4.2",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"pg": "^8.21.0",
|
||||
"twilio": "^6.0.2",
|
||||
"uuid": "^14.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
const whatsappService = require('./backend/whatsappService');
|
||||
|
||||
async function test() {
|
||||
console.log('Sending test token message...');
|
||||
const result = await whatsappService.sendTokenConfirmation(
|
||||
'+918500176938',
|
||||
'ON-777',
|
||||
'CuraFlow Testing Clinic',
|
||||
'04:30 PM',
|
||||
500
|
||||
);
|
||||
console.log('Result:', result);
|
||||
}
|
||||
|
||||
test();
|
||||
Loading…
Reference in New Issue