@peopl-health/nexus 1.0.3 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -0
- package/examples/basic-usage.js +22 -77
- package/lib/controllers/assistantController.js +168 -0
- package/lib/controllers/conversationController.js +582 -0
- package/lib/controllers/mediaController.js +105 -0
- package/lib/controllers/messageController.js +218 -0
- package/lib/controllers/templateController.js +631 -0
- package/lib/index.js +8 -6
- package/lib/routes/index.js +87 -0
- package/lib/utils/index.js +24 -11
- package/lib/utils/mongoAuthConfig.js +13 -3
- package/lib/utils/twilioHelper.js +0 -2
- package/lib/utils/whatsappHelper.js +0 -8
- package/package.json +14 -9
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Export route definitions for customer servers to import
|
|
2
|
+
// These are the route patterns without controller dependencies
|
|
3
|
+
|
|
4
|
+
const assistantRouteDefinitions = {
|
|
5
|
+
'POST /active': 'activeAssistantController',
|
|
6
|
+
'POST /add-instruction': 'addInsAssistantController',
|
|
7
|
+
'POST /add-msg': 'addMsgAssistantController',
|
|
8
|
+
'POST /create': 'createAssistantController',
|
|
9
|
+
'GET /info': 'getInfoAssistantController',
|
|
10
|
+
'GET /list': 'listAssistantController',
|
|
11
|
+
'POST /switch': 'switchAssistantController',
|
|
12
|
+
'POST /stop': 'stopAssistantController'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const conversationRouteDefinitions = {
|
|
16
|
+
'GET /': 'getConversationController',
|
|
17
|
+
'GET /search': 'searchConversationsController',
|
|
18
|
+
'GET /by-name': 'getConversationsByNameController',
|
|
19
|
+
'GET /:phoneNumber': 'getConversationMessagesController',
|
|
20
|
+
'GET /:phoneNumber/new': 'getNewMessagesController',
|
|
21
|
+
'POST /reply': 'getConversationReplyController',
|
|
22
|
+
'POST /send-template': 'sendTemplateToNewNumberController',
|
|
23
|
+
'POST /:phoneNumber/read': 'markMessagesAsReadController'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const mediaRouteDefinitions = {
|
|
27
|
+
'GET /:key(*)': 'getMediaController',
|
|
28
|
+
'POST /upload': 'handleFileUpload'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const messageRouteDefinitions = {
|
|
32
|
+
'POST /send': 'sendMessageController',
|
|
33
|
+
'POST /send-bulk': 'sendBulkMessageController',
|
|
34
|
+
'POST /send-bulk-airtable': 'sendBulkMessageAirtableController'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const templateRouteDefinitions = {
|
|
38
|
+
'POST /text': 'createTemplate',
|
|
39
|
+
'GET /': 'listTemplates',
|
|
40
|
+
'GET /predefined': 'getPredefinedTemplates',
|
|
41
|
+
'GET /:id': 'getTemplate',
|
|
42
|
+
'GET /complete/:sid': 'getCompleteTemplate',
|
|
43
|
+
'POST /flow': 'createFlow',
|
|
44
|
+
'DELETE /flow/:sid': 'deleteFlow',
|
|
45
|
+
'POST /approval': 'submitForApproval',
|
|
46
|
+
'GET /status/:sid': 'checkApprovalStatus',
|
|
47
|
+
'DELETE /:id': 'deleteTemplate'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Helper function to create Express router from route definitions
|
|
51
|
+
const createRouter = (routeDefinitions, controllers) => {
|
|
52
|
+
const express = require('express');
|
|
53
|
+
const router = express.Router();
|
|
54
|
+
|
|
55
|
+
for (const [route, controllerName] of Object.entries(routeDefinitions)) {
|
|
56
|
+
const [method, path] = route.split(' ');
|
|
57
|
+
const controller = controllers[controllerName];
|
|
58
|
+
|
|
59
|
+
if (controller) {
|
|
60
|
+
router[method.toLowerCase()](path, controller);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return router;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Helper function to setup all default routes with provided controllers
|
|
68
|
+
const setupDefaultRoutes = (app, controllers) => {
|
|
69
|
+
app.use('/api/assistant', createRouter(assistantRouteDefinitions, controllers));
|
|
70
|
+
app.use('/api/conversation', createRouter(conversationRouteDefinitions, controllers));
|
|
71
|
+
app.use('/api/media', createRouter(mediaRouteDefinitions, controllers));
|
|
72
|
+
app.use('/api/message', createRouter(messageRouteDefinitions, controllers));
|
|
73
|
+
app.use('/api/template', createRouter(templateRouteDefinitions, controllers));
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
// Route definitions for customers to use with their own controllers
|
|
78
|
+
assistantRoutes: assistantRouteDefinitions,
|
|
79
|
+
conversationRoutes: conversationRouteDefinitions,
|
|
80
|
+
mediaRoutes: mediaRouteDefinitions,
|
|
81
|
+
messageRoutes: messageRouteDefinitions,
|
|
82
|
+
templateRoutes: templateRouteDefinitions,
|
|
83
|
+
|
|
84
|
+
// Helper functions
|
|
85
|
+
createRouter,
|
|
86
|
+
setupDefaultRoutes
|
|
87
|
+
};
|
package/lib/utils/index.js
CHANGED
|
@@ -1,22 +1,35 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
1
|
+
const AssistantManager = require('./AssistantManager');
|
|
2
|
+
const DefaultLLMProvider = require('./DefaultLLMProvider');
|
|
3
|
+
const MessageParser = require('./MessageParser');
|
|
4
|
+
const logger = require('./logger');
|
|
5
5
|
const { useMongoDBAuthState } = require('./mongoAuthConfig');
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
convertTwilioToInternalFormat,
|
|
8
|
+
downloadMediaFromTwilio,
|
|
9
|
+
getMediaTypeFromContentType,
|
|
10
|
+
extractTitle,
|
|
11
|
+
ensureWhatsAppFormat
|
|
12
|
+
} = require('./twilioHelper');
|
|
13
|
+
const {
|
|
14
|
+
delay,
|
|
15
|
+
formatCode,
|
|
16
|
+
calculateDelay
|
|
17
|
+
} = require('./whatsappHelper');
|
|
7
18
|
|
|
8
19
|
module.exports = {
|
|
9
|
-
|
|
20
|
+
AssistantManager,
|
|
10
21
|
DefaultLLMProvider,
|
|
22
|
+
MessageParser,
|
|
11
23
|
logger,
|
|
12
|
-
createLogger,
|
|
13
|
-
delay,
|
|
14
|
-
formatCode,
|
|
15
|
-
calculateDelay,
|
|
16
24
|
useMongoDBAuthState,
|
|
25
|
+
// Twilio utilities
|
|
17
26
|
convertTwilioToInternalFormat,
|
|
18
27
|
downloadMediaFromTwilio,
|
|
19
28
|
getMediaTypeFromContentType,
|
|
20
29
|
extractTitle,
|
|
21
|
-
ensureWhatsAppFormat
|
|
30
|
+
ensureWhatsAppFormat,
|
|
31
|
+
// WhatsApp utilities
|
|
32
|
+
delay,
|
|
33
|
+
formatCode,
|
|
34
|
+
calculateDelay
|
|
22
35
|
};
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
const { MongoClient } = require('mongodb');
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let baileys;
|
|
4
|
+
try {
|
|
5
|
+
baileys = require('baileys');
|
|
6
|
+
} catch (error) {
|
|
7
|
+
baileys = null;
|
|
8
|
+
}
|
|
4
9
|
const { randomBytes } = require('crypto');
|
|
5
10
|
|
|
6
11
|
async function connectToMongo(mongoClient) {
|
|
@@ -14,6 +19,11 @@ async function connectToMongo(mongoClient) {
|
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
async function initAuthCreds() {
|
|
22
|
+
if (!baileys) {
|
|
23
|
+
throw new Error('Baileys is required for auth credentials but not installed');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { proto, Curve, signedKeyPair, generateRegistrationId } = baileys;
|
|
17
27
|
const identityKey = Curve.generateKeyPair();
|
|
18
28
|
return {
|
|
19
29
|
noiseKey: Curve.generateKeyPair(),
|
|
@@ -110,8 +120,8 @@ async function useMongoDBAuthState(uri, dbName, sessionId) {
|
|
|
110
120
|
const data = {};
|
|
111
121
|
await Promise.all(ids.map(async (id) => {
|
|
112
122
|
let value = await readData(`${type}-${id}`);
|
|
113
|
-
if (type === 'app-state-sync-key') {
|
|
114
|
-
value = proto.Message.AppStateSyncKeyData.fromObject(
|
|
123
|
+
if (type === 'app-state-sync-key' && baileys) {
|
|
124
|
+
value = baileys.proto.Message.AppStateSyncKeyData.fromObject(value);
|
|
115
125
|
}
|
|
116
126
|
data[id] = value;
|
|
117
127
|
}));
|
|
@@ -22,8 +22,6 @@ function convertTwilioToInternalFormat(twilioMessage) {
|
|
|
22
22
|
|
|
23
23
|
async function downloadMediaFromTwilio(mediaUrl, credentials) {
|
|
24
24
|
try {
|
|
25
|
-
console.log(`Downloading media from: ${mediaUrl}`);
|
|
26
|
-
|
|
27
25
|
const response = await axios({
|
|
28
26
|
method: 'GET',
|
|
29
27
|
url: mediaUrl,
|
|
@@ -5,7 +5,6 @@ function delay(ms) {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
function formatCode(codeBase) {
|
|
8
|
-
|
|
9
8
|
const [number, domain] = codeBase.split('@');
|
|
10
9
|
|
|
11
10
|
if (!number || !domain) {
|
|
@@ -44,13 +43,6 @@ function calculateDelay(sendTime, timeZone) {
|
|
|
44
43
|
const randomDelay = Math.floor(Math.random() * 15001) + 15000;
|
|
45
44
|
const delay = sendMoment.diff(now) + randomDelay;
|
|
46
45
|
|
|
47
|
-
console.log(
|
|
48
|
-
'Scheduled Time:', sendMoment.format(),
|
|
49
|
-
'Current Time:', now.format(),
|
|
50
|
-
'Delay (minutes):', delay / 60000,
|
|
51
|
-
'Remaining Seconds:', delay % 60000
|
|
52
|
-
);
|
|
53
|
-
|
|
54
46
|
if (delay <= 0) {
|
|
55
47
|
return 2500;
|
|
56
48
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peopl-health/nexus",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Core messaging and assistant library for WhatsApp communication platforms",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
"./utils": {
|
|
25
25
|
"import": "./lib/utils/index.js",
|
|
26
26
|
"require": "./lib/utils/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./routes": {
|
|
29
|
+
"import": "./lib/routes/index.js",
|
|
30
|
+
"require": "./lib/routes/index.js"
|
|
27
31
|
}
|
|
28
32
|
},
|
|
29
33
|
"scripts": {
|
|
@@ -31,7 +35,7 @@
|
|
|
31
35
|
"dev": "tsc --watch",
|
|
32
36
|
"test": "jest",
|
|
33
37
|
"lint": "eslint lib/**/*.js",
|
|
34
|
-
"prepublishOnly": "npm
|
|
38
|
+
"prepublishOnly": "npm run lint",
|
|
35
39
|
"version": "npm run prepublishOnly && git add -A lib",
|
|
36
40
|
"postversion": "git push && git push --tags"
|
|
37
41
|
},
|
|
@@ -46,23 +50,24 @@
|
|
|
46
50
|
"author": "PEOPL Health Tech",
|
|
47
51
|
"license": "MIT",
|
|
48
52
|
"dependencies": {
|
|
49
|
-
"
|
|
53
|
+
"axios": "^1.5.0",
|
|
50
54
|
"moment-timezone": "^0.5.43",
|
|
55
|
+
"mongoose": "^7.5.0",
|
|
51
56
|
"pino": "^8.15.0",
|
|
52
57
|
"pino-pretty": "^10.2.0",
|
|
53
|
-
"uuid": "^9.0.0"
|
|
54
|
-
"axios": "^1.5.0"
|
|
58
|
+
"uuid": "^9.0.0"
|
|
55
59
|
},
|
|
56
60
|
"peerDependencies": {
|
|
57
61
|
"baileys": "^6.4.0",
|
|
58
|
-
"
|
|
59
|
-
"openai": "^4.0.0"
|
|
62
|
+
"express": "4.21.2",
|
|
63
|
+
"openai": "^4.0.0",
|
|
64
|
+
"twilio": "^5.6.0"
|
|
60
65
|
},
|
|
61
66
|
"devDependencies": {
|
|
62
67
|
"@types/node": "^20.5.0",
|
|
63
|
-
"
|
|
68
|
+
"eslint": "^8.47.0",
|
|
64
69
|
"jest": "^29.6.2",
|
|
65
|
-
"
|
|
70
|
+
"typescript": "^5.1.6"
|
|
66
71
|
},
|
|
67
72
|
"engines": {
|
|
68
73
|
"node": ">=20.0.0"
|