diff --git a/README.md b/README.md index faeb512..317167a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Conversation Layer -This module contains the services that handle messaging for WhatsApp and the web chat interface. It is composed of three containers: +This module contains the services that handle messaging for WhatsApp and the web chat interface. All source code is now written in **TypeScript**. It is composed of three containers: - **openwa** – provides access to WhatsApp through the [open-wa](https://github.com/open-wa/wa-automate-nodejs) project. - **whatsapp-router** – receives webhook events from openwa and forwards messages to an external LLM agent. diff --git a/chat-ui/Dockerfile b/chat-ui/Dockerfile index 3a440eb..2553384 100644 --- a/chat-ui/Dockerfile +++ b/chat-ui/Dockerfile @@ -3,5 +3,6 @@ WORKDIR /app COPY package.json package-lock.json* ./ RUN npm install --production COPY . . +RUN npm run build EXPOSE 3000 -CMD ["node","server.js"] +CMD ["node","dist/server.js"] diff --git a/chat-ui/package-lock.json b/chat-ui/package-lock.json index c269ebf..4e6ca58 100644 --- a/chat-ui/package-lock.json +++ b/chat-ui/package-lock.json @@ -12,6 +12,120 @@ "axios": "^1.5.0", "body-parser": "^1.20.2", "express": "^4.18.2" + }, + "devDependencies": { + "@types/body-parser": "^1.19.5", + "@types/express": "^4.17.21", + "@types/node": "^20.11.19", + "typescript": "^5.4.5" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.22", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.22.tgz", + "integrity": "sha512-eZUmSnhRX9YRSkplpz0N+k6NljUUn5l3EWZIKZvYzhvMphEuNiyyy1viH/ejgt66JWgALwC/gtSUAeQKtSwW/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.17.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz", + "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" } }, "node_modules/accepts": { @@ -913,6 +1027,27 @@ "node": ">= 0.6" } }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/chat-ui/package.json b/chat-ui/package.json index e257936..936a86c 100644 --- a/chat-ui/package.json +++ b/chat-ui/package.json @@ -1,11 +1,21 @@ { "name": "chat-ui", "version": "1.0.0", - "main": "server.js", + "main": "dist/server.js", "license": "MIT", + "scripts": { + "build": "tsc", + "start": "node dist/server.js" + }, "dependencies": { "express": "^4.18.2", "axios": "^1.5.0", "body-parser": "^1.20.2" + }, + "devDependencies": { + "typescript": "^5.4.5", + "@types/express": "^4.17.21", + "@types/node": "^20.11.19", + "@types/body-parser": "^1.19.5" } } diff --git a/chat-ui/server.js b/chat-ui/src/server.ts similarity index 62% rename from chat-ui/server.js rename to chat-ui/src/server.ts index e4f70e2..ce01151 100644 --- a/chat-ui/server.js +++ b/chat-ui/src/server.ts @@ -1,16 +1,16 @@ -const express = require('express'); -const axios = require('axios'); -const bodyParser = require('body-parser'); -const path = require('path'); +import express, { Request, Response } from 'express'; +import axios from 'axios'; +import bodyParser from 'body-parser'; +import path from 'path'; const app = express(); -const port = process.env.PORT || 3000; -const agentUrl = process.env.LLM_AGENT_URL; +const port = Number(process.env.PORT) || 3000; +const agentUrl = process.env.LLM_AGENT_URL as string | undefined; app.use(bodyParser.json()); app.use(express.static(path.join(__dirname, 'public'))); -app.post('/send', async (req, res) => { +app.post('/send', async (req: Request, res: Response) => { if (!agentUrl) { return res.status(500).json({ error: 'LLM_AGENT_URL not configured' }); } @@ -18,7 +18,7 @@ app.post('/send', async (req, res) => { const { message } = req.body; const response = await axios.post(agentUrl, { message }); res.json(response.data); - } catch (err) { + } catch (err: any) { console.error('Failed to forward message', err.message); res.status(500).json({ error: 'Failed to communicate with agent' }); } diff --git a/chat-ui/tsconfig.json b/chat-ui/tsconfig.json new file mode 100644 index 0000000..2556447 --- /dev/null +++ b/chat-ui/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2019", + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/whatsapp-router/Dockerfile b/whatsapp-router/Dockerfile index a0083e7..0417ffd 100644 --- a/whatsapp-router/Dockerfile +++ b/whatsapp-router/Dockerfile @@ -3,5 +3,6 @@ WORKDIR /app COPY package.json package-lock.json* ./ RUN npm install --production COPY . . +RUN npm run build EXPOSE 3001 -CMD ["node","index.js"] +CMD ["node","dist/index.js"] diff --git a/whatsapp-router/package-lock.json b/whatsapp-router/package-lock.json index b107184..bf01b24 100644 --- a/whatsapp-router/package-lock.json +++ b/whatsapp-router/package-lock.json @@ -11,6 +11,119 @@ "dependencies": { "axios": "^1.5.0", "express": "^4.18.2" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^20.11.19", + "typescript": "^5.4.5" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.22", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.22.tgz", + "integrity": "sha512-eZUmSnhRX9YRSkplpz0N+k6NljUUn5l3EWZIKZvYzhvMphEuNiyyy1viH/ejgt66JWgALwC/gtSUAeQKtSwW/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.17.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz", + "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" } }, "node_modules/accepts": { @@ -912,6 +1025,27 @@ "node": ">= 0.6" } }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/whatsapp-router/package.json b/whatsapp-router/package.json index a7c2fa9..b2c61cf 100644 --- a/whatsapp-router/package.json +++ b/whatsapp-router/package.json @@ -1,10 +1,19 @@ { "name": "whatsapp-router", "version": "1.0.0", - "main": "index.js", + "main": "dist/index.js", "license": "MIT", + "scripts": { + "build": "tsc", + "start": "node dist/index.js" + }, "dependencies": { "express": "^4.18.2", "axios": "^1.5.0" + }, + "devDependencies": { + "typescript": "^5.4.5", + "@types/node": "^20.11.19", + "@types/express": "^4.17.21" } } diff --git a/whatsapp-router/index.js b/whatsapp-router/src/index.ts similarity index 70% rename from whatsapp-router/index.js rename to whatsapp-router/src/index.ts index 1a0f05d..6f522b3 100644 --- a/whatsapp-router/index.js +++ b/whatsapp-router/src/index.ts @@ -1,19 +1,23 @@ -const express = require('express'); -const axios = require('axios'); +import express from 'express'; +import axios from 'axios'; +import { WhatsAppMessage } from './types'; + const app = express(); -const port = process.env.PORT || 3001; -const agentUrl = process.env.LLM_AGENT_URL; -const openWaUrl = process.env.OPEN_WA_URL; +const port = Number(process.env.PORT) || 3001; +const agentUrl = process.env.LLM_AGENT_URL as string | undefined; +const openWaUrl = process.env.OPEN_WA_URL as string | undefined; const config = { - API_URL: openWaUrl, - MAX_ATTEMPTS: parseInt(process.env.MAX_ATTEMPTS || '100', 100), + API_URL: openWaUrl || '', + MAX_ATTEMPTS: parseInt(process.env.MAX_ATTEMPTS || '100', 10), RETRY_MS: parseInt(process.env.RETRY_MS || '2000', 10) }; -function log(level, ...args) { - console[level] ? console[level](...args) : console.log(...args); +function log(level: keyof Console | 'info' | 'warn' | 'error' | 'debug', ...args: unknown[]) { + const logger = (console as any)[level] as ((...args: unknown[]) => void) | undefined; + if (logger) logger(...args); + else console.log(...args); } async function waitForGateway() { @@ -41,10 +45,10 @@ async function clearWebhooks() { log('info', `Removing ${hooks.length} webhooks…`); const results = await Promise.allSettled( - hooks.map(h => axios.post(`${config.API_URL}/removeWebhook`, { args: { webhookId: h.id } })) + hooks.map((h: any) => axios.post(`${config.API_URL}/removeWebhook`, { args: { webhookId: h.id } })) ); - results.forEach((r, i) => { + results.forEach((r: PromiseSettledResult, i: number) => { const id = hooks[i].id; if (r.status === 'fulfilled' && r.value?.data?.response === true) { log('debug', `✔️ Removed webhook ${id}`); @@ -53,9 +57,9 @@ async function clearWebhooks() { } }); - const ok = results.filter(r => r.status === 'fulfilled' && r.value?.data?.response === true).length; + const ok = results.filter((r: PromiseSettledResult) => r.status === 'fulfilled' && (r as PromiseFulfilledResult).value?.data?.response === true).length; log('info', `Cleanup OK (${ok}/${hooks.length} removed)`); - } catch (e) { + } catch (e: any) { log('error', 'Failed cleaning webhooks:', e.response?.data || e.message); } } @@ -105,15 +109,16 @@ async function registerWebhook() { app.use(express.json()); -app.post('/webhook', async (req, res) => { - const { message, text, from } = req.body; +app.post('/webhook', async (req: express.Request, res: express.Response) => { + const { message, text, from } = req.body as { message?: WhatsAppMessage; text?: string; from?: string }; const incoming = message || text; try { if (!incoming) return res.sendStatus(200); + if (!agentUrl || !openWaUrl) throw new Error('Service URLs not configured'); const agentRes = await axios.post(agentUrl, { message: incoming }); const reply = agentRes.data.reply || agentRes.data; await axios.post(`${openWaUrl}/send-text`, { to: from, message: reply }); - } catch (err) { + } catch (err: any) { console.error('Error processing message', err.message); } res.sendStatus(200); @@ -125,7 +130,7 @@ app.listen(port, async () => { await waitForGateway(); await clearWebhooks(); await registerWebhook(); - } catch (err) { + } catch (err: any) { log('error', 'Webhook setup failed:', err.message); } }); diff --git a/whatsapp-router/src/types.ts b/whatsapp-router/src/types.ts new file mode 100644 index 0000000..8c76c3d --- /dev/null +++ b/whatsapp-router/src/types.ts @@ -0,0 +1,194 @@ +export interface ProfilePicThumb { + eurl?: string; + id?: string; + img?: string; + imgFull?: string; + tag?: string; +} + +export interface Sender { + id: string; + name: string; + shortName: string; + pushname: string; + type: string; + isBusiness: boolean; + isEnterprise: boolean; + isSmb: boolean; + isContactSyncCompleted: number; + disappearingModeDuration: number; + disappearingModeSettingTimestamp: number; + textStatusLastUpdateTime: number; + syncToAddressbook: boolean; + formattedName: string; + isMe: boolean; + isMyContact: boolean; + isPSA: boolean; + isUser: boolean; + status?: string; + isVerified: boolean; + isWAContact: boolean; + profilePicThumbObj?: ProfilePicThumb; + msgs: any; +} + +export interface Contact { + id: string; + name: string; + shortName: string; + pushname: string; + type: string; + isBusiness: boolean; + isEnterprise: boolean; + isSmb: boolean; + isContactSyncCompleted: number; + disappearingModeDuration: number; + disappearingModeSettingTimestamp: number; + textStatusLastUpdateTime: number; + syncToAddressbook: boolean; + formattedName: string; + isMe: boolean; + isMyContact: boolean; + isPSA: boolean; + isUser: boolean; + isVerified: boolean; + isWAContact: boolean; + profilePicThumbObj?: Partial; + msgs: any; +} + +export interface Chat { + id: string; + pendingMsgs: boolean; + lastReceivedKey?: { + fromMe: boolean; + remote: string; + id: string; + _serialized: string; + }; + t: number; + unreadCount: number; + unreadDividerOffset: number; + archive: boolean; + isReadOnly: boolean; + isLocked: boolean; + muteExpiration: number; + isAutoMuted: boolean; + name: string; + notSpam: boolean; + pin: number; + ephemeralDuration: number; + ephemeralSettingTimestamp: number; + disappearingModeInitiator: string; + disappearingModeTrigger: string; + createdLocally: boolean; + unreadMentionsOfMe: any[]; + unreadMentionCount: number; + hasUnreadMention: boolean; + archiveAtMentionViewedInDrawer: boolean; + hasChatBeenOpened: boolean; + tcToken: Record; + tcTokenTimestamp: number; + tcTokenSenderTimestamp: number; + endOfHistoryTransferType: number; + pendingInitialLoading: boolean; + chatlistPreview?: any; + unreadEditTimestampMs: number; + celebrationAnimationLastPlayed: number; + hasRequestedWelcomeMsg: boolean; + msgs: any; + canSend: boolean; + isGroup: boolean; + pic?: string; + formattedTitle: string; + contact: Contact; + groupMetadata: any; + presence?: { + id: string; + chatstates: any[]; + }; + isOnline: boolean; + participantsCount: number; +} + +export interface WhatsAppMessage { + id: string; + viewed: boolean; + body: string; + type: string; + t: number; + notifyName: string; + from: string; + to: string; + author: string | null; + invis: boolean; + isNewMsg: boolean; + star: boolean; + kicNotified: boolean; + recvFresh: boolean; + isFromTemplate: boolean; + thumbnail?: string; + pollInvalidated: boolean; + isSentCagPollCreation: boolean; + latestEditMsgKey: any; + latestEditSenderTimestampMs: any; + mentionedJidList: any[]; + groupMentions: any[]; + isEventCanceled: boolean; + eventInvalidated: boolean; + isVcardOverMmsDocument: boolean; + labels: any[]; + hasReaction: boolean; + ephemeralDuration: number; + ephemeralSettingTimestamp: number; + disappearingModeInitiator: string; + disappearingModeTrigger: string; + viewMode: string; + productHeaderImageRejected: boolean; + lastPlaybackProgress: number; + isDynamicReplyButtonsMsg: boolean; + isCarouselCard: boolean; + parentMsgId: any; + callSilenceReason: any; + isVideoCall: boolean; + callDuration: any; + callParticipants: any; + isMdHistoryMsg: boolean; + stickerSentTs: number; + isAvatar: boolean; + lastUpdateFromServerTs: number; + invokedBotWid: any; + bizBotType: any; + botResponseTargetId: any; + botPluginType: any; + botPluginReferenceIndex: any; + botPluginSearchProvider: any; + botPluginSearchUrl: any; + botPluginSearchQuery: any; + botPluginMaybeParent: boolean; + botReelPluginThumbnailCdnUrl: any; + botMessageDisclaimerText: any; + botMsgBodyType: any; + reportingTokenInfo: any; + requiresDirectConnection: boolean; + bizContentPlaceholderType: any; + hostedBizEncStateMismatch: boolean; + senderOrRecipientAccountTypeHosted: boolean; + placeholderCreatedWhenAccountIsHosted: boolean; + device: number; + local: boolean; + fromMe: boolean; + mId: string; + sender: Sender; + senderId: any; + timestamp: number; + content: string; + isGroupMsg: boolean; + isQuotedMsgAvailable: boolean; + isMedia: boolean; + chat: Chat; + isOnline: boolean; + chatId: string; + mediaData: Record; + text: string; +} diff --git a/whatsapp-router/tsconfig.json b/whatsapp-router/tsconfig.json new file mode 100644 index 0000000..b2f1581 --- /dev/null +++ b/whatsapp-router/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "lib": ["es2020"], + "moduleResolution": "node" + }, + "include": ["src"] +}