feat(transcription): add transcription handling with HubSpot integration and ticket verification
parent
5b9a105b7b
commit
a1195810fe
|
@ -1,4 +1,3 @@
|
|||
|
||||
const path = require('path')
|
||||
const Sentry = require('@sentry/node')
|
||||
const omnihitV2Integration = require('../data/omihitV2IntegrationCRM.json')
|
||||
|
@ -378,6 +377,16 @@ const getCrms = async (req, res) => {
|
|||
res.status(StatusCodes.OK).send(crms)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cria um ou mais tickets para um cliente no CRM e armazena o `ticketId` no Redis associado ao `crmPhone`.
|
||||
*
|
||||
* @param {import('express').Request} req - Objeto da requisição HTTP contendo `companyId` e `crmPhone` no corpo.
|
||||
* @param {import('express').Response} res - Objeto da resposta HTTP.
|
||||
*
|
||||
* @returns {Promise<import('express').Response>} - Resposta HTTP com os links dos tickets criados.
|
||||
*
|
||||
* @throws {Error} - Lança erro em caso de falha na criação dos tickets ou requisição ao CRM.
|
||||
*/
|
||||
const createTicket = async (req, res) => {
|
||||
|
||||
let { companyId, crmPhone } = req.body
|
||||
|
@ -395,10 +404,18 @@ const createTicket = async (req, res) => {
|
|||
throw new Error(`Error on create ticket: companyID ${companyId} | crmPhone: ${crmPhone}`)
|
||||
})
|
||||
|
||||
for (const crmTicketLink of crmTicketLinks) {
|
||||
const ticketIdMatch = crmTicketLink.ticketId.match(/ticket\/(\d+)/);
|
||||
if (ticketIdMatch && ticketIdMatch[1]) {
|
||||
const ticketId = ticketIdMatch[1];
|
||||
await set(crmPhone, ticketId);
|
||||
console.log(`TicketId ${ticketId} para crmPhone ${crmPhone} salvo no Redis com sucesso.`);
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(StatusCodes.OK).json({ crmTicketLinks })
|
||||
}
|
||||
|
||||
|
||||
const webhook = async (req, res) => {
|
||||
|
||||
const originIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
||||
|
@ -540,6 +557,67 @@ const webhook_crm = async (req, res) => {
|
|||
return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml)
|
||||
}
|
||||
|
||||
const associateTicketToCaller = async (req, res) => {
|
||||
try {
|
||||
const { callerId, ticketId } = req.body;
|
||||
|
||||
if (!callerId || !ticketId) {
|
||||
return res.status(StatusCodes.BAD_REQUEST).json({
|
||||
error: 'Campos obrigatórios ausentes. É necessário fornecer callerId e ticketId.'
|
||||
});
|
||||
}
|
||||
|
||||
// Remove o zero inicial do número se existir
|
||||
const formattedCallerId = removeZeroInicial(callerId);
|
||||
|
||||
// Adiciona o prefixo 55 se não existir
|
||||
const fullCallerId = formattedCallerId.startsWith('55') ? formattedCallerId : `55${formattedCallerId}`;
|
||||
|
||||
// Salva a associação no Redis com um tempo de expiração de 5 minutos (300 segundos)
|
||||
await set(fullCallerId, ticketId, 300);
|
||||
|
||||
console.log(`Ticket ${ticketId} associado ao número ${fullCallerId} com sucesso.`);
|
||||
|
||||
return res.status(StatusCodes.OK).json({
|
||||
message: 'Ticket associado com sucesso',
|
||||
callerId: fullCallerId,
|
||||
ticketId
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Erro ao associar ticket:', error);
|
||||
Sentry.captureException(error);
|
||||
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
||||
error: 'Erro ao processar a associação do ticket'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const checkTicketByCrmPhone = async (req, res) => {
|
||||
const { crmPhone } = req.query;
|
||||
|
||||
if (!crmPhone) {
|
||||
return res.status(StatusCodes.BAD_REQUEST).json({
|
||||
error: 'O parâmetro crmPhone é obrigatório.'
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const ticketId = await get(crmPhone);
|
||||
|
||||
if (ticketId) {
|
||||
return res.status(StatusCodes.OK).json({ hasTicket: true, ticketId: ticketId });
|
||||
} else {
|
||||
return res.status(StatusCodes.OK).json({ hasTicket: false });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erro ao verificar ticket no Redis:', error);
|
||||
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
||||
error: 'Erro interno ao verificar a existência do ticket.'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
contactCreate,
|
||||
uploadCrmConfig,
|
||||
|
@ -554,7 +632,9 @@ module.exports = {
|
|||
webhook_crm,
|
||||
sfCreateCase,
|
||||
sfUpdateCase,
|
||||
createTicket
|
||||
createTicket,
|
||||
associateTicketToCaller,
|
||||
checkTicketByCrmPhone
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
const redis = require('redis');
|
||||
const HubspotService = require('../services/hubspotService');
|
||||
require('dotenv').config();
|
||||
|
||||
const redisClient = redis.createClient({
|
||||
url: process.env.REDIS_URI
|
||||
});
|
||||
|
||||
redisClient.on('error', (err) => console.log('Redis Client Error', err));
|
||||
|
||||
(async () => {
|
||||
if (!redisClient.isOpen) {
|
||||
await redisClient.connect();
|
||||
}
|
||||
})();
|
||||
|
||||
const hubspotService = new HubspotService();
|
||||
|
||||
exports.receiveTranscription = async (req, res) => {
|
||||
try {
|
||||
const { callerId, uniqueId, transcription, recordingUrl } = req.body;
|
||||
|
||||
if (!callerId || !uniqueId || !transcription || !recordingUrl) {
|
||||
return res.status(400).json({ error: 'Campos obrigatórios ausentes.' });
|
||||
}
|
||||
|
||||
console.log(`Recebida transcrição para callerId: ${callerId}, uniqueId: ${uniqueId}`);
|
||||
console.log('Transcrição:', transcription.summary);
|
||||
|
||||
// 1. Buscar ticketId no Redis
|
||||
const ticketId = await redisClient.get(callerId);
|
||||
|
||||
if (!ticketId) {
|
||||
console.warn(`Nenhum ticketId encontrado no Redis para o callerId: ${callerId}. A transcrição será salva como uma nota sem associação ao ticket.`);
|
||||
}
|
||||
|
||||
// 2. Buscar ou criar contato no HubSpot
|
||||
const contact = await hubspotService.createContactIfNotExists(callerId);
|
||||
|
||||
// 3. Criar nota no HubSpot e associar ao contato e ao ticket (se existir)
|
||||
await hubspotService.createCallNote(contact.id, {
|
||||
transcription: `${transcription.client || ''}\n${transcription.agent || ''}`,
|
||||
summary: transcription.summary,
|
||||
recordingUrl,
|
||||
callerId,
|
||||
uniqueId,
|
||||
ticketId
|
||||
});
|
||||
|
||||
return res.status(200).json({ message: 'Transcrição recebida e processada com sucesso!' });
|
||||
} catch (error) {
|
||||
console.error('Erro ao receber transcrição:', error?.response?.data || error.message || error);
|
||||
return res.status(500).json({ error: 'Erro ao processar a transcrição.' });
|
||||
}
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
PORT=6004
|
||||
TOKEN=2ivck10D3o9qAZi0pkKudVDl9bdEVXY2s8gdxZ0jYgL1DZWTgDz6wDiIjlWgYmJtVOoqf0b42ZTLBRrfo8WoAaScRsujz3jQUNXdchSg0o43YilZGmVhheGJNAeIQRknHEll4nRJ7avcFgmDGoYbEey7TSC8EHS4Z3gzeufYYSfnKNDBwwzBURIQrTOxYFe3tBHsGOzwnuD2lU5tnEx7tr2XRO4zRNYeNY4lMBOFM0mRuyAe4kuqTrKXmJ8As200
|
||||
URL_OAUTH_CALLBACK=http://localhost:6001/api/v1/crm/oauth-callback
|
||||
URL_OAUTH_FRONTEND_SUCCESS_REDIRECT=http://localhost:3000
|
||||
DB_MONGO_URL=mongodb://localhost:27017
|
||||
DB_MONGO_NAME=crm
|
||||
|
||||
REDIS_URI=redis://127.0.0.1:6379
|
||||
|
||||
IS_DEV=true
|
||||
REACT_APP_COMPANY_ID=1
|
||||
REACT_APP_URL_API=http://localhost:6001
|
||||
URL_HITPHONE_FRONTEND=https://ms-teamsapp.omnihit.app.br
|
||||
|
||||
# api hubspot
|
||||
HUBSPOT_API_KEY=pat-na1-37da6668-e0b1-44cb-bd2d-596f5f65634a
|
|
@ -9,6 +9,7 @@
|
|||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@hubspot/api-client": "^13.0.0",
|
||||
"@sentry/node": "^9.9.0",
|
||||
"@sentry/profiling-node": "^9.9.0",
|
||||
"axios": "^1.6.1",
|
||||
|
@ -27,6 +28,7 @@
|
|||
"mongoose": "^7.3.1",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"redis": "^5.5.6",
|
||||
"socket.io": "^4.7.2",
|
||||
"swagger-ui-express": "^4.1.6",
|
||||
"xss-clean": "^0.1.1",
|
||||
|
@ -36,6 +38,24 @@
|
|||
"nodemon": "^2.0.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@hubspot/api-client": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@hubspot/api-client/-/api-client-13.0.0.tgz",
|
||||
"integrity": "sha512-sXC1kRna+2uFlct1E1IQJQi53X36k24jRctmTTKzlvUM8it5VHXt6PCjVskQ4faLYGPyx9xh9GNx0GI7RMY4CQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/node-fetch": "^2.5.7",
|
||||
"bottleneck": "^2.19.5",
|
||||
"es6-promise": "^4.2.4",
|
||||
"form-data": "^2.5.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"node-fetch": "^2.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ioredis/commands": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||
|
@ -591,6 +611,66 @@
|
|||
"@opentelemetry/api": "^1.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/bloom": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.5.6.tgz",
|
||||
"integrity": "sha512-bNR3mxkwtfuCxNOzfV8B3R5zA1LiN57EH6zK4jVBIgzMzliNuReZXBFGnXvsi80/SYohajn78YdpYI+XNpqL+A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/client": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/client/-/client-5.5.6.tgz",
|
||||
"integrity": "sha512-M3Svdwt6oSfyfQdqEr0L2HOJH2vK7GgCFx1NfAQvpWAT4+ljoT1L5S5cKT3dA9NJrxrOPDkdoTPWJnIrGCOcmw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cluster-key-slot": "1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/json": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/json/-/json-5.5.6.tgz",
|
||||
"integrity": "sha512-AIsoe3SsGQagqAmSQHaqxEinm5oCWr7zxPWL90kKaEdLJ+zw8KBznf2i9oK0WUFP5pFssSQUXqnscQKe2amfDQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/search": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/search/-/search-5.5.6.tgz",
|
||||
"integrity": "sha512-JSqasYqO0mVcHL7oxvbySRBBZYRYhFl3W7f0Da7BW8M/r0Z9wCiVrdjnN4/mKBpWZkoJT/iuisLUdPGhpKxBew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/time-series": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.5.6.tgz",
|
||||
"integrity": "sha512-jkpcgq3NOI3TX7xEAJ3JgesJTxAx7k0m6lNxNsYdEM8KOl+xj7GaB/0CbLkoricZDmFSEAz7ClA1iK9XkGHf+Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^5.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/node-cpu-profiler": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/node-cpu-profiler/-/node-cpu-profiler-2.1.0.tgz",
|
||||
|
@ -751,6 +831,32 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
|
||||
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-fetch/node_modules/form-data": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
|
||||
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
|
||||
"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/@types/pg": {
|
||||
"version": "8.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
||||
|
@ -1031,6 +1137,12 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/boxen": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
|
||||
|
@ -1137,6 +1249,19 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
|
@ -1478,6 +1603,20 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
|
@ -1569,6 +1708,57 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"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/es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escape-goat": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
|
||||
|
@ -1753,6 +1943,42 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz",
|
||||
"integrity": "sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
@ -1787,6 +2013,43 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||
|
@ -1845,6 +2108,18 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/got": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
||||
|
@ -1882,6 +2157,33 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"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/has-yarn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
|
||||
|
@ -2246,6 +2548,12 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lowercase-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||
|
@ -2287,6 +2595,15 @@
|
|||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
|
@ -2326,19 +2643,21 @@
|
|||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.48.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.31",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.48.0"
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
|
@ -2589,6 +2908,48 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.9.tgz",
|
||||
|
@ -2967,6 +3328,22 @@
|
|||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-5.5.6.tgz",
|
||||
"integrity": "sha512-hbpqBfcuhWHOS9YLNcXcJ4akNr7HFX61Dq3JuFZ9S7uU7C7kvnzuH2PDIXOP62A3eevvACoG8UacuXP3N07xdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@redis/bloom": "5.5.6",
|
||||
"@redis/client": "5.5.6",
|
||||
"@redis/json": "5.5.6",
|
||||
"@redis/search": "5.5.6",
|
||||
"@redis/time-series": "5.5.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/redis-errors": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||
|
@ -3738,6 +4115,20 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@hubspot/api-client": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@hubspot/api-client/-/api-client-13.0.0.tgz",
|
||||
"integrity": "sha512-sXC1kRna+2uFlct1E1IQJQi53X36k24jRctmTTKzlvUM8it5VHXt6PCjVskQ4faLYGPyx9xh9GNx0GI7RMY4CQ==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/node-fetch": "^2.5.7",
|
||||
"bottleneck": "^2.19.5",
|
||||
"es6-promise": "^4.2.4",
|
||||
"form-data": "^2.5.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"node-fetch": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"@ioredis/commands": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||
|
@ -4091,6 +4482,38 @@
|
|||
"@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0"
|
||||
}
|
||||
},
|
||||
"@redis/bloom": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.5.6.tgz",
|
||||
"integrity": "sha512-bNR3mxkwtfuCxNOzfV8B3R5zA1LiN57EH6zK4jVBIgzMzliNuReZXBFGnXvsi80/SYohajn78YdpYI+XNpqL+A==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/client": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/client/-/client-5.5.6.tgz",
|
||||
"integrity": "sha512-M3Svdwt6oSfyfQdqEr0L2HOJH2vK7GgCFx1NfAQvpWAT4+ljoT1L5S5cKT3dA9NJrxrOPDkdoTPWJnIrGCOcmw==",
|
||||
"requires": {
|
||||
"cluster-key-slot": "1.1.2"
|
||||
}
|
||||
},
|
||||
"@redis/json": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/json/-/json-5.5.6.tgz",
|
||||
"integrity": "sha512-AIsoe3SsGQagqAmSQHaqxEinm5oCWr7zxPWL90kKaEdLJ+zw8KBznf2i9oK0WUFP5pFssSQUXqnscQKe2amfDQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/search": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/search/-/search-5.5.6.tgz",
|
||||
"integrity": "sha512-JSqasYqO0mVcHL7oxvbySRBBZYRYhFl3W7f0Da7BW8M/r0Z9wCiVrdjnN4/mKBpWZkoJT/iuisLUdPGhpKxBew==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/time-series": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.5.6.tgz",
|
||||
"integrity": "sha512-jkpcgq3NOI3TX7xEAJ3JgesJTxAx7k0m6lNxNsYdEM8KOl+xj7GaB/0CbLkoricZDmFSEAz7ClA1iK9XkGHf+Q==",
|
||||
"requires": {}
|
||||
},
|
||||
"@sentry-internal/node-cpu-profiler": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/node-cpu-profiler/-/node-cpu-profiler-2.1.0.tgz",
|
||||
|
@ -4218,6 +4641,29 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
|
||||
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
|
||||
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/pg": {
|
||||
"version": "8.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
||||
|
@ -4449,6 +4895,11 @@
|
|||
"xml2js": "^0.5.0"
|
||||
}
|
||||
},
|
||||
"bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
|
||||
},
|
||||
"boxen": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
|
||||
|
@ -4530,6 +4981,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
|
@ -4798,6 +5258,16 @@
|
|||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
||||
},
|
||||
"dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"requires": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
|
@ -4871,6 +5341,40 @@
|
|||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
|
||||
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ=="
|
||||
},
|
||||
"es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="
|
||||
},
|
||||
"es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
|
||||
},
|
||||
"es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"escape-goat": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
|
||||
|
@ -5003,6 +5507,25 @@
|
|||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
|
||||
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz",
|
||||
"integrity": "sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
@ -5028,6 +5551,32 @@
|
|||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"requires": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"requires": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||
|
@ -5068,6 +5617,11 @@
|
|||
"ini": "1.3.7"
|
||||
}
|
||||
},
|
||||
"gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
|
||||
},
|
||||
"got": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
||||
|
@ -5099,6 +5653,19 @@
|
|||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="
|
||||
},
|
||||
"has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"requires": {
|
||||
"has-symbols": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"has-yarn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
|
||||
|
@ -5381,6 +5948,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||
},
|
||||
"lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||
},
|
||||
"lowercase-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||
|
@ -5409,6 +5981,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
|
@ -5436,16 +6013,16 @@
|
|||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.48.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.31",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"requires": {
|
||||
"mime-db": "1.48.0"
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"mimic-response": {
|
||||
|
@ -5622,6 +6199,35 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"nodemon": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.9.tgz",
|
||||
|
@ -5903,6 +6509,18 @@
|
|||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"redis": {
|
||||
"version": "5.5.6",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-5.5.6.tgz",
|
||||
"integrity": "sha512-hbpqBfcuhWHOS9YLNcXcJ4akNr7HFX61Dq3JuFZ9S7uU7C7kvnzuH2PDIXOP62A3eevvACoG8UacuXP3N07xdg==",
|
||||
"requires": {
|
||||
"@redis/bloom": "5.5.6",
|
||||
"@redis/client": "5.5.6",
|
||||
"@redis/json": "5.5.6",
|
||||
"@redis/search": "5.5.6",
|
||||
"@redis/time-series": "5.5.6"
|
||||
}
|
||||
},
|
||||
"redis-errors": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@hubspot/api-client": "^13.0.0",
|
||||
"@sentry/node": "^9.9.0",
|
||||
"@sentry/profiling-node": "^9.9.0",
|
||||
"axios": "^1.6.1",
|
||||
|
@ -28,6 +29,7 @@
|
|||
"mongoose": "^7.3.1",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"redis": "^5.5.6",
|
||||
"socket.io": "^4.7.2",
|
||||
"swagger-ui-express": "^4.1.6",
|
||||
"xss-clean": "^0.1.1",
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
## Atenção
|
||||
Para rodar a aplicação esteja na pasta backend. O .env deve estar dentro da pasta backend para rodar essa api.
|
||||
## Use o env.example
|
||||
|
||||
## Nova Funcionalidade: Integração de Transcrição com HubSpot
|
||||
|
||||
Esta funcionalidade permite receber, processar e registrar transcrições de chamadas telefônicas diretamente no HubSpot, com associação automática ao contato e, se disponível, ao ticket da chamada.
|
||||
|
||||
### Fluxo Geral
|
||||
|
||||
1. Uma transcrição de chamada é recebida via endpoint REST (`/api/v1/crm/transcriptions`).
|
||||
2. O sistema consulta o Redis para verificar se há um `ticketId` associado ao `callerId`.
|
||||
3. Se existir:
|
||||
- A nota é associada ao contato e ao ticket correspondente no HubSpot.
|
||||
4. Se não existir:
|
||||
- A nota é criada e associada apenas ao contato.
|
||||
|
||||
### Exemplo de Requisição
|
||||
|
||||
**Endpoint:** `POST /api/v1/crm/transcriptions`
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"callerId": "5511987654321",
|
||||
"uniqueId": "chamada-001",
|
||||
"transcription": {
|
||||
"summary": "Cliente solicitou informações sobre o pedido.",
|
||||
"client": "Gostaria de saber como está meu pedido.",
|
||||
"agent": "Claro! Posso verificar agora."
|
||||
},
|
||||
"recordingUrl": "https://exemplo.com/gravação/audio.wav"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Verificação Prévia de Ticket
|
||||
|
||||
Antes de enviar a transcrição de uma chamada, o sistema realiza uma verificação para saber se já existe um ticket associado ao número de telefone (`callerId` / `crmPhone`).
|
||||
|
||||
**Endpoint:**
|
||||
`GET /api/v1/crm/tickets/check-by-crmphone`
|
||||
|
||||
**Parâmetros de consulta (query params):**
|
||||
|
||||
| Parâmetro | Tipo | Obrigatório | Descrição |
|
||||
|-----------|--------|-------------|----------------------------------------|
|
||||
| crmPhone | string | Sim | Número do telefone do cliente (E.164) |
|
||||
|
||||
**Exemplo de Requisição:**
|
||||
|
||||
```
|
||||
GET /api/v1/crm/tickets/check-by-crmphone?crmPhone=5511997532324
|
||||
```
|
||||
|
||||
**Resposta (200 OK):**
|
||||
|
||||
```json
|
||||
{
|
||||
"hasTicket": true,
|
||||
"ticketId": "25292628260"
|
||||
}
|
||||
```
|
||||
|
||||
### Lógica de Uso
|
||||
|
||||
- Se `hasTicket` for `true`, o `ticketId` será incluído no envio da transcrição.
|
||||
- Se `hasTicket` for `false`, a transcrição **não será enviada** para essa api para o envio ao HubSpot.
|
|
@ -1,8 +1,10 @@
|
|||
const express = require('express')
|
||||
const router = express.Router()
|
||||
const { authorization, } = require('../middleware/authentication')
|
||||
const { contactCreate, sfCreateCase, sfUpdateCase, createTicket, testTemplate, webhook_crm, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook } = require('../controllers/crmController')
|
||||
const { contactCreate, sfCreateCase, sfUpdateCase, createTicket, testTemplate, webhook_crm, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook, checkTicketByCrmPhone } = require('../controllers/crmController')
|
||||
const { receiveTranscription } = require('../controllers/transcriptionController')
|
||||
const { fileUpload } = require("../utils")
|
||||
const { associateTicketToCaller } = require('../controllers/crmController');
|
||||
|
||||
router.route('/create-contact').post(authorization, contactCreate)
|
||||
router.route('/create-ticket').post(authorization, createTicket)
|
||||
|
@ -17,7 +19,8 @@ router.route('/install').get(install)
|
|||
router.route('/test').post(testTemplate)
|
||||
router.route('/webhook').post(webhook)
|
||||
router.route('/webhook-crm').post(webhook_crm)
|
||||
router.route('/transcriptions').post( receiveTranscription)
|
||||
router.route('/:companyId').get(authorization, getCrms)
|
||||
|
||||
router.route('/tickets/check-by-crmphone').get(authorization, checkTicketByCrmPhone)
|
||||
|
||||
module.exports = router
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
const axios = require('axios');
|
||||
const Logger = console;
|
||||
require('dotenv').config();
|
||||
|
||||
/**
|
||||
* Serviço para integração com a API do HubSpot.
|
||||
*/
|
||||
class HubspotService {
|
||||
/**
|
||||
* Inicializa o serviço HubspotService com configuração da API.
|
||||
*/
|
||||
constructor() {
|
||||
this.logger = Logger;
|
||||
this.baseUrl = 'https://api.hubapi.com';
|
||||
this.apiKey = process.env.HUBSPOT_API_KEY;
|
||||
this.client = axios.create({
|
||||
baseURL: this.baseUrl,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cria uma nota de chamada no HubSpot e associa ao contato e opcionalmente a um ticket.
|
||||
*
|
||||
* @param {string} contactId - ID do contato no HubSpot.
|
||||
* @param {Object} callData - Dados da chamada.
|
||||
* @param {string} callData.transcription - Transcrição completa da chamada.
|
||||
* @param {string} callData.summary - Resumo da chamada.
|
||||
* @param {string} callData.recordingUrl - URL da gravação da chamada.
|
||||
* @param {string} callData.callerId - Número do chamador.
|
||||
* @param {string} callData.uniqueId - Identificador único da chamada.
|
||||
* @param {string} [callData.ticketId] - (Opcional) ID do ticket no HubSpot.
|
||||
* @returns {Promise<Object>} - Dados da nota criada.
|
||||
*/
|
||||
async createCallNote(contactId, callData) {
|
||||
try {
|
||||
const { transcription, summary, recordingUrl, callerId, uniqueId, ticketId } = callData;
|
||||
|
||||
const noteContent = `
|
||||
Chamada Recebida
|
||||
------------------
|
||||
Número: ${callerId}
|
||||
ID da Chamada: ${uniqueId}
|
||||
Data/Hora: ${new Date().toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' })}
|
||||
|
||||
|
||||
Resumo:
|
||||
${summary}
|
||||
|
||||
Transcrição Completa:
|
||||
${transcription}
|
||||
|
||||
Link da Gravação: ${recordingUrl}
|
||||
`.trim();
|
||||
|
||||
// 1. Cria a nota
|
||||
const response = await this.client.post('/crm/v3/objects/notes', {
|
||||
properties: {
|
||||
hs_timestamp: new Date().toISOString(),
|
||||
hs_note_body: noteContent
|
||||
}
|
||||
});
|
||||
|
||||
const noteId = response.data.id;
|
||||
|
||||
// 2. Associa a nota ao contato
|
||||
await this.client.put(`/crm/v3/objects/notes/${noteId}/associations/contact/${contactId}/note_to_contact`);
|
||||
|
||||
// 3. (Opcional) Associa a nota ao ticket, se houver
|
||||
if (ticketId) {
|
||||
await this.client.put(`/crm/v3/objects/notes/${noteId}/associations/ticket/${ticketId}/note_to_ticket`);
|
||||
this.logger.log(`Nota associada ao ticket ${ticketId}`);
|
||||
}
|
||||
|
||||
this.logger.log(`Nota ${noteId} criada com sucesso.`);
|
||||
return response.data;
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error('Erro ao criar nota:', error?.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca um contato no HubSpot pelo número de telefone.
|
||||
*
|
||||
* @param {string} phoneNumber - Número de telefone para buscar.
|
||||
* @returns {Promise<Object|null>} - Contato encontrado ou null.
|
||||
*/
|
||||
async findContactByPhone(phoneNumber) {
|
||||
try {
|
||||
const response = await this.client.post('/crm/v3/objects/contacts/search', {
|
||||
filterGroups: [{
|
||||
filters: [{
|
||||
propertyName: 'phone',
|
||||
operator: 'EQ',
|
||||
value: phoneNumber
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
return response.data.results[0] || null;
|
||||
} catch (error) {
|
||||
this.logger.error('Erro ao buscar contato:', error?.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cria um contato com o número informado caso não exista.
|
||||
*
|
||||
* @param {string} phoneNumber - Número de telefone do contato.
|
||||
* @returns {Promise<Object>} - Contato existente ou novo contato criado.
|
||||
*/
|
||||
async createContactIfNotExists(phoneNumber) {
|
||||
const existing = await this.findContactByPhone(phoneNumber);
|
||||
if (existing) return existing;
|
||||
|
||||
const response = await this.client.post('/crm/v3/objects/contacts', {
|
||||
properties: {
|
||||
phone: phoneNumber,
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.log(`Contato criado para o número ${phoneNumber}`);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HubspotService;
|
|
@ -2,9 +2,14 @@ const Redis = require("ioredis")
|
|||
const redis = new Redis(process.env.REDIS_URI)
|
||||
|
||||
// Function to set a token with expiration
|
||||
async function set(key, value, expirationInSeconds) {
|
||||
await redis.set(key, value, 'EX', expirationInSeconds)
|
||||
console.log(`Token ${key} set successfully with expiration of ${expirationInSeconds} seconds!`)
|
||||
async function set(key, value, expirationInSeconds = null) {
|
||||
if (expirationInSeconds) {
|
||||
await redis.set(key, value, 'EX', expirationInSeconds)
|
||||
console.log(`Token ${key} set successfully with expiration of ${expirationInSeconds} seconds!`)
|
||||
} else {
|
||||
await redis.set(key, value)
|
||||
console.log(`Token ${key} set successfully without expiration!`)
|
||||
}
|
||||
}
|
||||
|
||||
// Function to get a token
|
||||
|
|
Loading…
Reference in New Issue