Compare commits
8 Commits
e9b5011eca
...
47baefd047
Author | SHA1 | Date |
---|---|---|
|
47baefd047 | |
|
f05bfa4047 | |
|
1d300e07ca | |
|
89db3e83c9 | |
|
344dafbb48 | |
|
d337d7fec5 | |
|
c721cead8f | |
|
a1195810fe |
|
@ -43,6 +43,7 @@ const cors = require('cors')
|
||||||
|
|
||||||
// routers
|
// routers
|
||||||
const crmRouter = require('./routes/crmRoute')
|
const crmRouter = require('./routes/crmRoute')
|
||||||
|
const integrationRouter = require("./routes/integrationRoutes")
|
||||||
|
|
||||||
const notFoundMiddlware = require('./middleware/not-found')
|
const notFoundMiddlware = require('./middleware/not-found')
|
||||||
const errorHandlerMiddleware = require('./middleware/error-handler')
|
const errorHandlerMiddleware = require('./middleware/error-handler')
|
||||||
|
@ -78,6 +79,7 @@ app.get('/', (req, res) => {
|
||||||
app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(swaggerDocument))
|
app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(swaggerDocument))
|
||||||
|
|
||||||
app.use('/api/v1/crm', crmRouter)
|
app.use('/api/v1/crm', crmRouter)
|
||||||
|
app.use('/api/v1/integration', integrationRouter)
|
||||||
|
|
||||||
Sentry.setupExpressErrorHandler(app)
|
Sentry.setupExpressErrorHandler(app)
|
||||||
app.use(notFoundMiddlware)
|
app.use(notFoundMiddlware)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const Sentry = require('@sentry/node')
|
const getIntegrationsConfig = require('../utils/getIntegrationsConfig')
|
||||||
const omnihitV2Integration = require('../data/omihitV2IntegrationCRM.json')
|
|
||||||
const { StatusCodes } = require("http-status-codes")
|
const { StatusCodes } = require("http-status-codes")
|
||||||
const { createCRMContact,
|
const { createCRMContact,
|
||||||
sendMessageSocket,
|
sendMessageSocket,
|
||||||
|
@ -88,55 +87,64 @@ const callJournaling = async (req, res) => {
|
||||||
// Remove 0 from the beginning of the number. Ex: 011996067641 to 11996067641
|
// Remove 0 from the beginning of the number. Ex: 011996067641 to 11996067641
|
||||||
crmPhone = removeZeroInicial(crmPhone)
|
crmPhone = removeZeroInicial(crmPhone)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// test remove
|
||||||
|
// return res.status(StatusCodes.OK).send()
|
||||||
|
|
||||||
// Refactor this in the future.
|
// Refactor this in the future.
|
||||||
crmPhone = '55' + crmPhone
|
crmPhone = '55' + crmPhone
|
||||||
console.log('========> CRMPHONE: ', crmPhone)
|
console.log('========> CRMPHONE: ', crmPhone)
|
||||||
console.log('========> COMPANY ID before: ', companyId)
|
console.log('========> COMPANY ID before: ', companyId)
|
||||||
|
|
||||||
|
|
||||||
if (companyId == "1")
|
if (companyId == "1")
|
||||||
companyId = '99'
|
companyId = '99'
|
||||||
|
|
||||||
|
|
||||||
console.log('========> COMPANY ID after: ', companyId)
|
console.log('========> COMPANY ID after: ', companyId)
|
||||||
|
|
||||||
|
|
||||||
if (!crmAgent)
|
if (!crmAgent)
|
||||||
crmAgent = "0000"
|
crmAgent = "0000"
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
mustContainProperties(req, ['companyId', 'operation', 'crmPhone', /*'crmAgent'*/,])
|
mustContainProperties(req, ['companyId', 'operation', 'crmPhone', /*'crmAgent'*/,])
|
||||||
|
|
||||||
|
|
||||||
// if (operation == 'inboundAnsweredCall' && !crmCallDuration)
|
// if (operation == 'inboundAnsweredCall' && !crmCallDuration)
|
||||||
// throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is inboundAnsweredCall`)
|
// throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is inboundAnsweredCall`)
|
||||||
// if (operation == 'outboundAsweredCall' && !crmCallDuration)
|
// if (operation == 'outboundAsweredCall' && !crmCallDuration)
|
||||||
// throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is outboundAsweredCall`)
|
// throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is outboundAsweredCall`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!crmCallDuration || crmCallDuration.trim() == "" || crmCallDuration == "0")
|
if (!crmCallDuration || crmCallDuration.trim() == "" || crmCallDuration == "0")
|
||||||
crmCallDuration = "10"
|
crmCallDuration = "10"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (operationStatus == "hangup")
|
if (operationStatus == "hangup")
|
||||||
await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName)
|
await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName)
|
||||||
|
|
||||||
|
|
||||||
else if (operationStatus == "update-answer") {
|
else if (operationStatus == "update-answer") {
|
||||||
console.log('update-answer')
|
console.log('update-answer')
|
||||||
|
|
||||||
// Referente a cliente a gabriel, pois os tickets estao sendo abertos diretamente em um botao do hitphone
|
|
||||||
if (companyId != "12928") {
|
|
||||||
console.log(`################## CRIAÇÃO AUTOMATICA DE TICKET COMPANY ID ${companyId} ##################`)
|
|
||||||
await ticketCRM(companyId, crmPhone, crmAgent, crmFirstName)
|
await ticketCRM(companyId, crmPhone, crmAgent, crmFirstName)
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const resp = await redirectContactLinkCRM(companyId, crmPhone, crmAgent, crmFirstName)
|
const resp = await redirectContactLinkCRM(companyId, crmPhone, crmAgent, crmFirstName)
|
||||||
return res.status(StatusCodes.OK).json({ contact: resp })
|
return res.status(StatusCodes.OK).json({ contact: resp })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
res.status(StatusCodes.OK).send()
|
res.status(StatusCodes.OK).send()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log(`[ERROR - ${new Date()}] Erro no Call Journaling`, error?.response?.data)
|
// console.log(`[ERROR - ${new Date()}] Erro no Call Journaling`, error?.response?.data)
|
||||||
|
|
||||||
Sentry.captureException(error)
|
|
||||||
|
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
console.error('==================> callJournaling Erro na resposta da API:', {
|
console.error('==================> callJournaling Erro na resposta da API:', {
|
||||||
status: error.response.status,
|
status: error.response.status,
|
||||||
|
@ -379,6 +387,16 @@ const getCrms = async (req, res) => {
|
||||||
res.status(StatusCodes.OK).send(crms)
|
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) => {
|
const createTicket = async (req, res) => {
|
||||||
|
|
||||||
let { companyId, crmPhone } = req.body
|
let { companyId, crmPhone } = req.body
|
||||||
|
@ -396,9 +414,17 @@ const createTicket = async (req, res) => {
|
||||||
throw new Error(`Error on create ticket: companyID ${companyId} | crmPhone: ${crmPhone}`)
|
throw new Error(`Error on create ticket: companyID ${companyId} | crmPhone: ${crmPhone}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
return res.status(StatusCodes.OK).json({ crmTicketLinks })
|
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 webhook = async (req, res) => {
|
||||||
|
|
||||||
|
@ -428,23 +454,29 @@ const webhook = async (req, res) => {
|
||||||
|
|
||||||
let crmPhone = phone_number.replace('+', '')
|
let crmPhone = phone_number.replace('+', '')
|
||||||
|
|
||||||
const companies = [
|
const company = await Company.findOne({
|
||||||
// { companyId: "99", account_id: "1" },
|
integrations: {
|
||||||
{ companyId: "99", account_id: "15" },
|
$elemMatch: {
|
||||||
]
|
name: "omnihit",
|
||||||
|
"config.accountId": `${accountId}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const obj = companies.find(c => +c.account_id == +accountId)
|
if (!company) {
|
||||||
|
return res.status(StatusCodes.NOT_FOUND).send({ msg: "companyId not found!" })
|
||||||
|
}
|
||||||
|
|
||||||
console.log('=======> name: ', name)
|
console.log('=======> name: ', name)
|
||||||
console.log('=======> crmPhone: ', crmPhone)
|
console.log('=======> crmPhone: ', crmPhone)
|
||||||
console.log('=======> accountId: ', accountId)
|
console.log('=======> accountId: ', accountId)
|
||||||
console.log('=======> companyId: ', obj.companyId)
|
console.log('=======> companyId: ', company.companyId)
|
||||||
|
|
||||||
console.log('=======> ticketId: ', ticketId)
|
console.log('=======> ticketId: ', ticketId)
|
||||||
|
|
||||||
|
|
||||||
await whatsappJournalingCRM(
|
await whatsappJournalingCRM(
|
||||||
companyId = obj.companyId,
|
companyId = company.companyId,
|
||||||
crmPhone = crmPhone,
|
crmPhone = crmPhone,
|
||||||
crmAgent = '0000',
|
crmAgent = '0000',
|
||||||
crmFirstName = name,
|
crmFirstName = name,
|
||||||
|
@ -510,13 +542,12 @@ const webhook_crm = async (req, res) => {
|
||||||
|
|
||||||
const { phone } = contact
|
const { phone } = contact
|
||||||
|
|
||||||
const obj = omnihitV2Integration.find(o => o.companyId == companyId)
|
const config = await getIntegrationsConfig(companyId, 'omnihit')
|
||||||
|
|
||||||
if (obj) {
|
if (config) {
|
||||||
|
|
||||||
const { companyId,
|
const { accountId, api: { url, token } = {},
|
||||||
omnihit: { accountId, api: { url, token } = {},
|
createConversation: { inbox_id, status, team_id } = {} = {} } = config
|
||||||
createConversation: { inbox_id, status, team_id } = {} } = {} } = obj
|
|
||||||
|
|
||||||
const contactIdChatwoot = await getContactIdChatwoot(url, token, phone)
|
const contactIdChatwoot = await getContactIdChatwoot(url, token, phone)
|
||||||
|
|
||||||
|
@ -541,6 +572,67 @@ const webhook_crm = async (req, res) => {
|
||||||
return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml)
|
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 = {
|
module.exports = {
|
||||||
contactCreate,
|
contactCreate,
|
||||||
uploadCrmConfig,
|
uploadCrmConfig,
|
||||||
|
@ -555,7 +647,9 @@ module.exports = {
|
||||||
webhook_crm,
|
webhook_crm,
|
||||||
sfCreateCase,
|
sfCreateCase,
|
||||||
sfUpdateCase,
|
sfUpdateCase,
|
||||||
createTicket
|
createTicket,
|
||||||
|
associateTicketToCaller,
|
||||||
|
checkTicketByCrmPhone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
const { StatusCodes } = require("http-status-codes")
|
||||||
|
const { mustContainProperties } = require("../utils")
|
||||||
|
const Company = require("../models/Company")
|
||||||
|
const getIntegrationsConfig = require("../utils/getIntegrationsConfig")
|
||||||
|
|
||||||
|
const integration = async (req, res) => {
|
||||||
|
const { companyId } = req.params
|
||||||
|
const { config, name } = req.body
|
||||||
|
|
||||||
|
mustContainProperties(req, ['name', 'config'])
|
||||||
|
|
||||||
|
const company = await Company.findOne({ companyId })
|
||||||
|
|
||||||
|
if (!company) {
|
||||||
|
return res.status(StatusCodes.NOT_FOUND).send({ msg: "companyId not found!" })
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingIntegrationIndex = company.integrations.findIndex(i => i.name === name)
|
||||||
|
|
||||||
|
if (existingIntegrationIndex !== -1) {
|
||||||
|
company.integrations[existingIntegrationIndex].config = config
|
||||||
|
} else {
|
||||||
|
company.integrations.push({ name, config })
|
||||||
|
}
|
||||||
|
|
||||||
|
await company.save()
|
||||||
|
|
||||||
|
res.status(StatusCodes.OK).send({
|
||||||
|
msg: 'Integração atualizada com sucesso',
|
||||||
|
integrations: company.integrations
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
integration
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
const omnihitV2Integration = require('../data/omihitV2IntegrationCRM.json')
|
|
||||||
|
|
||||||
const obj = omnihitV2Integration.find(o => o.companyId === "99")
|
|
||||||
|
|
||||||
if (obj) {
|
|
||||||
console.log(obj)
|
|
||||||
|
|
||||||
const { companyId, omnihit: { accountId, api: { url, token } = {}, createConversation: { inbox_id, status, team_id } = {} } = {} } = obj
|
|
||||||
|
|
||||||
console.log('companyId: ', companyId, ' accountId: ', accountId, ' url: ', url, ' token: ', token, ' inbox_id: ', inbox_id, ' status: ', status, ' team_id: ', team_id)
|
|
||||||
}
|
|
|
@ -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
|
|
@ -10,7 +10,16 @@ const crmCompany = new Schema({
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
type: String
|
type: String
|
||||||
|
},
|
||||||
|
integrations: [
|
||||||
|
{
|
||||||
|
name: { type: String, required: true },
|
||||||
|
config: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
default: {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hubspot/api-client": "^13.0.0",
|
||||||
"@sentry/node": "^9.9.0",
|
"@sentry/node": "^9.9.0",
|
||||||
"@sentry/profiling-node": "^9.9.0",
|
"@sentry/profiling-node": "^9.9.0",
|
||||||
"axios": "^1.6.1",
|
"axios": "^1.6.1",
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
"mongoose": "^7.3.1",
|
"mongoose": "^7.3.1",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
|
"redis": "^5.5.6",
|
||||||
"socket.io": "^4.7.2",
|
"socket.io": "^4.7.2",
|
||||||
"swagger-ui-express": "^4.1.6",
|
"swagger-ui-express": "^4.1.6",
|
||||||
"xss-clean": "^0.1.1",
|
"xss-clean": "^0.1.1",
|
||||||
|
@ -36,6 +38,24 @@
|
||||||
"nodemon": "^2.0.9"
|
"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": {
|
"node_modules/@ioredis/commands": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||||
|
@ -591,6 +611,66 @@
|
||||||
"@opentelemetry/api": "^1.8"
|
"@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": {
|
"node_modules/@sentry-internal/node-cpu-profiler": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/node-cpu-profiler/-/node-cpu-profiler-2.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
|
||||||
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg=="
|
"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": {
|
"node_modules/@types/pg": {
|
||||||
"version": "8.6.1",
|
"version": "8.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
||||||
|
@ -1031,6 +1137,12 @@
|
||||||
"node": ">=10"
|
"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": {
|
"node_modules/boxen": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
|
||||||
|
@ -1137,6 +1249,19 @@
|
||||||
"node": ">=8"
|
"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": {
|
"node_modules/camelcase": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||||
|
@ -1478,6 +1603,20 @@
|
||||||
"node": ">=10"
|
"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": {
|
"node_modules/duplexer3": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"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": {
|
"node_modules/escape-goat": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
|
"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": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
|
@ -1787,6 +2013,43 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/get-stream": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||||
|
@ -1845,6 +2108,18 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/got": {
|
||||||
"version": "9.6.0",
|
"version": "9.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
||||||
|
@ -1882,6 +2157,33 @@
|
||||||
"node": ">=4"
|
"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": {
|
"node_modules/has-yarn": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
"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": {
|
"node_modules/lowercase-keys": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||||
|
@ -2287,6 +2595,15 @@
|
||||||
"semver": "bin/semver.js"
|
"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": {
|
"node_modules/media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
@ -2326,19 +2643,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime-db": {
|
||||||
"version": "1.48.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mime-types": {
|
"node_modules/mime-types": {
|
||||||
"version": "2.1.31",
|
"version": "2.1.35",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mime-db": "1.48.0"
|
"mime-db": "1.52.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
|
@ -2589,6 +2908,48 @@
|
||||||
"node": ">=10"
|
"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": {
|
"node_modules/nodemon": {
|
||||||
"version": "2.0.9",
|
"version": "2.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.9.tgz",
|
||||||
|
@ -2967,6 +3328,22 @@
|
||||||
"node": ">=8.10.0"
|
"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": {
|
"node_modules/redis-errors": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
@ -3738,6 +4115,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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": {
|
"@ioredis/commands": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
"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"
|
"@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": {
|
"@sentry-internal/node-cpu-profiler": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/node-cpu-profiler/-/node-cpu-profiler-2.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
|
||||||
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg=="
|
"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": {
|
"@types/pg": {
|
||||||
"version": "8.6.1",
|
"version": "8.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
||||||
|
@ -4449,6 +4895,11 @@
|
||||||
"xml2js": "^0.5.0"
|
"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": {
|
"boxen": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
|
"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": {
|
"camelcase": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
"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": {
|
"duplexer3": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
|
||||||
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ=="
|
"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": {
|
"escape-goat": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
|
||||||
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q=="
|
"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": {
|
"forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
|
"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": {
|
"get-stream": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||||
|
@ -5068,6 +5617,11 @@
|
||||||
"ini": "1.3.7"
|
"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": {
|
"got": {
|
||||||
"version": "9.6.0",
|
"version": "9.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
||||||
|
@ -5099,6 +5653,19 @@
|
||||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||||
"dev": true
|
"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": {
|
"has-yarn": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
"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": {
|
"lowercase-keys": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
"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": {
|
"media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
@ -5436,16 +6013,16 @@
|
||||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
||||||
},
|
},
|
||||||
"mime-db": {
|
"mime-db": {
|
||||||
"version": "1.48.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||||
},
|
},
|
||||||
"mime-types": {
|
"mime-types": {
|
||||||
"version": "2.1.31",
|
"version": "2.1.35",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"mime-db": "1.48.0"
|
"mime-db": "1.52.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mimic-response": {
|
"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": {
|
"nodemon": {
|
||||||
"version": "2.0.9",
|
"version": "2.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.9.tgz",
|
||||||
|
@ -5903,6 +6509,18 @@
|
||||||
"picomatch": "^2.2.1"
|
"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": {
|
"redis-errors": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hubspot/api-client": "^13.0.0",
|
||||||
"@sentry/node": "^9.9.0",
|
"@sentry/node": "^9.9.0",
|
||||||
"@sentry/profiling-node": "^9.9.0",
|
"@sentry/profiling-node": "^9.9.0",
|
||||||
"axios": "^1.6.1",
|
"axios": "^1.6.1",
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
"mongoose": "^7.3.1",
|
"mongoose": "^7.3.1",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
|
"redis": "^5.5.6",
|
||||||
"socket.io": "^4.7.2",
|
"socket.io": "^4.7.2",
|
||||||
"swagger-ui-express": "^4.1.6",
|
"swagger-ui-express": "^4.1.6",
|
||||||
"xss-clean": "^0.1.1",
|
"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 express = require('express')
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
const { authorization, } = require('../middleware/authentication')
|
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 { fileUpload } = require("../utils")
|
||||||
|
const { associateTicketToCaller } = require('../controllers/crmController');
|
||||||
|
|
||||||
router.route('/create-contact').post(authorization, contactCreate)
|
router.route('/create-contact').post(authorization, contactCreate)
|
||||||
router.route('/create-ticket').post(authorization, createTicket)
|
router.route('/create-ticket').post(authorization, createTicket)
|
||||||
|
@ -17,7 +19,8 @@ router.route('/install').get(install)
|
||||||
router.route('/test').post(testTemplate)
|
router.route('/test').post(testTemplate)
|
||||||
router.route('/webhook').post(webhook)
|
router.route('/webhook').post(webhook)
|
||||||
router.route('/webhook-crm').post(webhook_crm)
|
router.route('/webhook-crm').post(webhook_crm)
|
||||||
|
router.route('/transcriptions').post( receiveTranscription)
|
||||||
router.route('/:companyId').get(authorization, getCrms)
|
router.route('/:companyId').get(authorization, getCrms)
|
||||||
|
router.route('/tickets/check-by-crmphone').get(authorization, checkTicketByCrmPhone)
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
const express = require('express')
|
||||||
|
const router = express.Router()
|
||||||
|
const { authorization, } = require('../middleware/authentication')
|
||||||
|
const { integration } = require('../controllers/integrationController')
|
||||||
|
|
||||||
|
router.route('/:companyId').patch(authorization, integration)
|
||||||
|
|
||||||
|
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;
|
|
@ -0,0 +1,13 @@
|
||||||
|
const Company = require("../models/Company")
|
||||||
|
|
||||||
|
async function getIntegrationsConfig(companyId, name) {
|
||||||
|
const company = await Company.findOne({ companyId })
|
||||||
|
|
||||||
|
if (company){
|
||||||
|
let obj = company.integrations.find(i => i.name === name)
|
||||||
|
return obj?.config
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getIntegrationsConfig
|
|
@ -2,9 +2,14 @@ const Redis = require("ioredis")
|
||||||
const redis = new Redis(process.env.REDIS_URI)
|
const redis = new Redis(process.env.REDIS_URI)
|
||||||
|
|
||||||
// Function to set a token with expiration
|
// Function to set a token with expiration
|
||||||
async function set(key, value, expirationInSeconds) {
|
async function set(key, value, expirationInSeconds = null) {
|
||||||
|
if (expirationInSeconds) {
|
||||||
await redis.set(key, value, 'EX', expirationInSeconds)
|
await redis.set(key, value, 'EX', expirationInSeconds)
|
||||||
console.log(`Token ${key} set successfully with expiration of ${expirationInSeconds} seconds!`)
|
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
|
// Function to get a token
|
||||||
|
|
|
@ -11,8 +11,7 @@ const lookupCRMTicket = require('./lookupCRMTicket')
|
||||||
const sendEventTicketCreatedToSocket = require('./sendEventTicketCreatedToSocket')
|
const sendEventTicketCreatedToSocket = require('./sendEventTicketCreatedToSocket')
|
||||||
const journalingRequest = require('./journalingRequest')
|
const journalingRequest = require('./journalingRequest')
|
||||||
|
|
||||||
const omnihitV2Integration = require('../data/omihitV2IntegrationCRM.json')
|
const getIntegrationsConfig = require('../utils/getIntegrationsConfig')
|
||||||
|
|
||||||
|
|
||||||
async function whatsappJournalingCRM(companyId, crmPhone, crmAgent, crmFirstName = 'Username', ticketId = null) {
|
async function whatsappJournalingCRM(companyId, crmPhone, crmAgent, crmFirstName = 'Username', ticketId = null) {
|
||||||
|
|
||||||
|
@ -34,23 +33,17 @@ async function whatsappJournalingCRM(companyId, crmPhone, crmAgent, crmFirstName
|
||||||
|
|
||||||
let contact = await _lookupContact(rest, authentication, crmPhone, companyId, crmFirstName)
|
let contact = await _lookupContact(rest, authentication, crmPhone, companyId, crmFirstName)
|
||||||
|
|
||||||
const { contactId, created } = contact
|
|
||||||
|
|
||||||
let { request, chats, response } = chatJournaling
|
let { request, chats, response } = chatJournaling
|
||||||
|
|
||||||
let body = findProperty(chats, 'chatDone')
|
let body = findProperty(chats, 'chatDone')
|
||||||
|
|
||||||
|
|
||||||
|
let config = await getIntegrationsConfig(companyId, 'omnihit')
|
||||||
|
|
||||||
|
if (ticketId && config) {
|
||||||
|
|
||||||
const obj = omnihitV2Integration.find(o => o.companyId == companyId)
|
const { accountId, api: { url, urlHttps, token } = {},
|
||||||
|
createConversation: { inbox_id, status, team_id } = {} = {} } = config
|
||||||
if (ticketId && obj) {
|
|
||||||
|
|
||||||
const { companyId,
|
|
||||||
omnihit: { accountId, api: { url, urlHttps, token } = {},
|
|
||||||
createConversation: { inbox_id, status, team_id } = {} } = {} } = obj
|
|
||||||
|
|
||||||
|
|
||||||
console.log('===============> body1: ', body)
|
console.log('===============> body1: ', body)
|
||||||
body = JSON.stringify(body)
|
body = JSON.stringify(body)
|
||||||
|
|
Loading…
Reference in New Issue