mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2026-01-09 21:32:20 -06:00
Compare commits
28 Commits
6277c5d084
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd800f2976 | ||
|
|
4f642e17a7 | ||
|
|
afa6d633c6 | ||
|
|
2e3e752719 | ||
|
|
de11e6f9ca | ||
|
|
26e7eefe51 | ||
|
|
b55c9fcab7 | ||
|
|
86b194af5f | ||
|
|
3c1573c400 | ||
|
|
178386594c | ||
|
|
cea1fa0979 | ||
|
|
38be0b49d9 | ||
|
|
04ac880fcc | ||
|
|
3864366e75 | ||
|
|
2756d7e61c | ||
|
|
bb36bfe424 | ||
|
|
abd0351f8f | ||
|
|
1c3a7ab027 | ||
|
|
930d32df3a | ||
|
|
fa6b5c28a6 | ||
|
|
8e7f348c12 | ||
|
|
08a4795016 | ||
|
|
53a94af3f7 | ||
|
|
302e219f7f | ||
|
|
1e036ba3ae | ||
|
|
377993e4b0 | ||
|
|
f2c2a6a64a | ||
|
|
e5a249109c |
85
CHANGELOG.md
85
CHANGELOG.md
@@ -1,4 +1,4 @@
|
|||||||
# 2.3.7 (develop)
|
# 2.3.7 (2025-12-05)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
@@ -7,6 +7,24 @@
|
|||||||
- Added DTOs and validation schemas for template management
|
- Added DTOs and validation schemas for template management
|
||||||
- Enhanced template lifecycle management capabilities
|
- Enhanced template lifecycle management capabilities
|
||||||
|
|
||||||
|
* **Events API**: Add isLatest and progress to messages.set event
|
||||||
|
- Allows consumers to know when history sync is complete (isLatest=true)
|
||||||
|
- Track sync progress percentage through webhooks
|
||||||
|
- Added extra field to EmitData type for additional payload properties
|
||||||
|
- Updated all event controllers (webhook, rabbitmq, sqs, websocket, pusher, kafka, nats)
|
||||||
|
|
||||||
|
* **N8N Integration**: Add quotedMessage to payload in sendMessageToBot
|
||||||
|
- Support for quoted messages in N8N chatbot integration
|
||||||
|
- Enhanced message context information
|
||||||
|
|
||||||
|
* **WebSocket**: Add wildcard "*" to allow all hosts to connect via websocket
|
||||||
|
- More flexible host configuration for WebSocket connections
|
||||||
|
- Improved host validation logic in WebsocketController
|
||||||
|
|
||||||
|
* **Pix Support**: Handle interactive button message for pix
|
||||||
|
- Support for interactive Pix button messages
|
||||||
|
- Enhanced payment flow integration
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
* **Baileys Message Processor**: Fix incoming message events not working after reconnection
|
* **Baileys Message Processor**: Fix incoming message events not working after reconnection
|
||||||
@@ -60,11 +78,76 @@
|
|||||||
- Fixed integration issues between Chatwoot and Baileys services
|
- Fixed integration issues between Chatwoot and Baileys services
|
||||||
- Improved message handling and delivery
|
- Improved message handling and delivery
|
||||||
|
|
||||||
|
* **Baileys Message Loss**: Prevent message loss from WhatsApp stub placeholders
|
||||||
|
- Fixed messages being lost and not saved to database, especially for channels/newsletters (@lid)
|
||||||
|
- Detects WhatsApp stubs through messageStubParameters containing 'Message absent from node'
|
||||||
|
- Prevents adding stubs to duplicate message cache
|
||||||
|
- Allows real message to be processed when it arrives after decryption
|
||||||
|
- Maintains stub discard to avoid saving empty placeholders
|
||||||
|
|
||||||
|
* **Database Contacts**: Respect DATABASE_SAVE_DATA_CONTACTS in contact updates
|
||||||
|
- Added missing conditional checks for DATABASE_SAVE_DATA_CONTACTS configuration
|
||||||
|
- Fixed profile picture updates attempting to save when database save is disabled
|
||||||
|
- Fixed unawaited promise in contacts.upsert handler
|
||||||
|
|
||||||
|
* **Prisma/PostgreSQL**: Add unique constraint to Chat model
|
||||||
|
- Generated migration to add unique index on instanceId and remoteJid
|
||||||
|
- Added deduplication step before creating index to prevent constraint violations
|
||||||
|
- Prevents chat duplication in database
|
||||||
|
|
||||||
|
* **MinIO Upload**: Handle messageContextInfo in media upload to prevent MinIO errors
|
||||||
|
- Prevents errors when uploading media with messageContextInfo metadata
|
||||||
|
- Improved error handling for media storage operations
|
||||||
|
|
||||||
|
* **Typebot**: Fix message routing for @lid JIDs
|
||||||
|
- Typebot now responds to messages from JIDs ending with @lid
|
||||||
|
- Maintains complete JID for @lid instead of extracting only number
|
||||||
|
- Fixed condition: `remoteJid.includes('@lid') ? remoteJid : remoteJid.split('@')[0]`
|
||||||
|
- Handles both @s.whatsapp.net and @lid message formats
|
||||||
|
|
||||||
|
* **Message Filtering**: Unify remoteJid filtering using OR with remoteJidAlt
|
||||||
|
- Improved message filtering with alternative JID support
|
||||||
|
- Better handling of messages with different JID formats
|
||||||
|
|
||||||
|
* **@lid Integration**: Multiple fixes for @lid problems, message events and chatwoot errors
|
||||||
|
- Reorganized imports and improved message handling in BaileysStartupService
|
||||||
|
- Enhanced remoteJid processing to handle @lid cases
|
||||||
|
- Improved jid normalization and type safety in Chatwoot integration
|
||||||
|
- Streamlined message handling logic and cache management
|
||||||
|
- Refactored message handling and polling updates with decryption logic for poll votes
|
||||||
|
- Improved event processing flow for various message types
|
||||||
|
|
||||||
|
* **Chatwoot Contacts**: Fix contact duplication error on import
|
||||||
|
- Resolved 'ON CONFLICT DO UPDATE command cannot affect row a second time' error
|
||||||
|
- Removed attempt to update identifier field in conflict (part of constraint)
|
||||||
|
- Changed to update only updated_at field: `updated_at = NOW()`
|
||||||
|
- Allows duplicate contacts to be updated correctly without errors
|
||||||
|
|
||||||
|
* **Chatwoot Service**: Fix async handling in update_last_seen method
|
||||||
|
- Added missing await for chatwootRequest in read message processing
|
||||||
|
- Prevents service failure when processing read messages
|
||||||
|
|
||||||
|
* **Metrics Access**: Fix IP validation including x-forwarded-for
|
||||||
|
- Uses all IPs including x-forwarded-for header when checking metrics access
|
||||||
|
- Improved security and access control for metrics endpoint
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
* **Baileys**: Updated to version 7.0.0-rc.9
|
||||||
|
- Latest release candidate with multiple improvements and bug fixes
|
||||||
|
|
||||||
|
* **AWS SDK**: Updated packages to version 3.936.0
|
||||||
|
- Enhanced functionality and compatibility
|
||||||
|
- Performance improvements
|
||||||
|
|
||||||
### Code Quality & Refactoring
|
### Code Quality & Refactoring
|
||||||
|
|
||||||
* **Template Management**: Remove unused template edit/delete DTOs after refactoring
|
* **Template Management**: Remove unused template edit/delete DTOs after refactoring
|
||||||
* **Proxy Utilities**: Improve makeProxyAgent for Undici compatibility
|
* **Proxy Utilities**: Improve makeProxyAgent for Undici compatibility
|
||||||
* **Code Formatting**: Enhance code formatting and consistency across services
|
* **Code Formatting**: Enhance code formatting and consistency across services
|
||||||
|
* **BaileysStartupService**: Fix indentation and remove unnecessary blank lines
|
||||||
|
* **Event Controllers**: Guard extra spread and prevent core field override in all event controllers
|
||||||
|
* **Import Organization**: Reorganize imports for better code structure and maintainability
|
||||||
|
|
||||||
# 2.3.6 (2025-10-21)
|
# 2.3.6 (2025-10-21)
|
||||||
|
|
||||||
|
|||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -8589,12 +8589,6 @@
|
|||||||
"undici": ">=6"
|
"undici": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fflate": {
|
|
||||||
"version": "0.8.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
|
||||||
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/figures": {
|
"node_modules/figures": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-- 1. Cleanup: Remove duplicate chats, keeping the most recently updated one
|
||||||
|
DELETE FROM "Chat"
|
||||||
|
WHERE id IN (
|
||||||
|
SELECT id FROM (
|
||||||
|
SELECT id,
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY "instanceId", "remoteJid"
|
||||||
|
ORDER BY "updatedAt" DESC
|
||||||
|
) as row_num
|
||||||
|
FROM "Chat"
|
||||||
|
) t
|
||||||
|
WHERE t.row_num > 1
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 2. Create the unique index (Constraint)
|
||||||
|
CREATE UNIQUE INDEX "Chat_instanceId_remoteJid_key" ON "Chat"("instanceId", "remoteJid");
|
||||||
@@ -132,6 +132,7 @@ model Chat {
|
|||||||
instanceId String
|
instanceId String
|
||||||
unreadMessages Int @default(0)
|
unreadMessages Int @default(0)
|
||||||
|
|
||||||
|
@@unique([instanceId, remoteJid])
|
||||||
@@index([instanceId])
|
@@index([instanceId])
|
||||||
@@index([remoteJid])
|
@@index([remoteJid])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -861,10 +861,12 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
this.sendDataWebhook(Events.CONTACTS_UPDATE, updatedContacts);
|
this.sendDataWebhook(Events.CONTACTS_UPDATE, updatedContacts);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
updatedContacts.map(async (contact) => {
|
updatedContacts.map(async (contact) => {
|
||||||
const update = this.prismaRepository.contact.updateMany({
|
if (this.configService.get<Database>('DATABASE').SAVE_DATA.CONTACTS) {
|
||||||
where: { remoteJid: contact.remoteJid, instanceId: this.instanceId },
|
await this.prismaRepository.contact.updateMany({
|
||||||
data: { profilePicUrl: contact.profilePicUrl },
|
where: { remoteJid: contact.remoteJid, instanceId: this.instanceId },
|
||||||
});
|
data: { profilePicUrl: contact.profilePicUrl },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot?.enabled) {
|
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot?.enabled) {
|
||||||
const instance = { instanceName: this.instance.name, instanceId: this.instance.id };
|
const instance = { instanceName: this.instance.name, instanceId: this.instance.id };
|
||||||
@@ -883,8 +885,6 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
avatar_url: contact.profilePicUrl,
|
avatar_url: contact.profilePicUrl,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return update;
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -908,14 +908,16 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
|
|
||||||
this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw);
|
this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw);
|
||||||
|
|
||||||
const updateTransactions = contactsRaw.map((contact) =>
|
if (this.configService.get<Database>('DATABASE').SAVE_DATA.CONTACTS) {
|
||||||
this.prismaRepository.contact.upsert({
|
const updateTransactions = contactsRaw.map((contact) =>
|
||||||
where: { remoteJid_instanceId: { remoteJid: contact.remoteJid, instanceId: contact.instanceId } },
|
this.prismaRepository.contact.upsert({
|
||||||
create: contact,
|
where: { remoteJid_instanceId: { remoteJid: contact.remoteJid, instanceId: contact.instanceId } },
|
||||||
update: contact,
|
create: contact,
|
||||||
}),
|
update: contact,
|
||||||
);
|
}),
|
||||||
await this.prismaRepository.$transaction(updateTransactions);
|
);
|
||||||
|
await this.prismaRepository.$transaction(updateTransactions);
|
||||||
|
}
|
||||||
|
|
||||||
//const usersContacts = contactsRaw.filter((c) => c.remoteJid.includes('@s.whatsapp'));
|
//const usersContacts = contactsRaw.filter((c) => c.remoteJid.includes('@s.whatsapp'));
|
||||||
},
|
},
|
||||||
@@ -1044,7 +1046,10 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
messagesRaw.push(this.prepareMessage(m));
|
messagesRaw.push(this.prepareMessage(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendDataWebhook(Events.MESSAGES_SET, [...messagesRaw]);
|
this.sendDataWebhook(Events.MESSAGES_SET, [...messagesRaw], true, undefined, {
|
||||||
|
isLatest,
|
||||||
|
progress,
|
||||||
|
});
|
||||||
|
|
||||||
if (this.configService.get<Database>('DATABASE').SAVE_DATA.HISTORIC) {
|
if (this.configService.get<Database>('DATABASE').SAVE_DATA.HISTORIC) {
|
||||||
await this.prismaRepository.message.createMany({ data: messagesRaw, skipDuplicates: true });
|
await this.prismaRepository.message.createMany({ data: messagesRaw, skipDuplicates: true });
|
||||||
@@ -1090,6 +1095,7 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
'Invalid PreKey ID',
|
'Invalid PreKey ID',
|
||||||
'No session record',
|
'No session record',
|
||||||
'No session found to decrypt message',
|
'No session found to decrypt message',
|
||||||
|
'Message absent from node',
|
||||||
].some((err) => param?.includes?.(err)),
|
].some((err) => param?.includes?.(err)),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@@ -1397,6 +1403,11 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
} else {
|
} else {
|
||||||
const media = await this.getBase64FromMediaMessage({ message }, true);
|
const media = await this.getBase64FromMediaMessage({ message }, true);
|
||||||
|
|
||||||
|
if (!media) {
|
||||||
|
this.logger.verbose('No valid media to upload (messageContextInfo only), skipping MinIO');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { buffer, mediaType, fileName, size } = media;
|
const { buffer, mediaType, fileName, size } = media;
|
||||||
const mimetype = mimeTypes.lookup(fileName).toString();
|
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||||
const fullName = join(
|
const fullName = join(
|
||||||
@@ -2463,6 +2474,11 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
} else {
|
} else {
|
||||||
const media = await this.getBase64FromMediaMessage({ message }, true);
|
const media = await this.getBase64FromMediaMessage({ message }, true);
|
||||||
|
|
||||||
|
if (!media) {
|
||||||
|
this.logger.verbose('No valid media to upload (messageContextInfo only), skipping MinIO');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { buffer, mediaType, fileName, size } = media;
|
const { buffer, mediaType, fileName, size } = media;
|
||||||
|
|
||||||
const mimetype = mimeTypes.lookup(fileName).toString();
|
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||||
@@ -3836,7 +3852,8 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ('messageContextInfo' in msg.message && Object.keys(msg.message).length === 1) {
|
if ('messageContextInfo' in msg.message && Object.keys(msg.message).length === 1) {
|
||||||
throw 'The message is messageContextInfo';
|
this.logger.verbose('Message contains only messageContextInfo, skipping media processing');
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mediaMessage: any;
|
let mediaMessage: any;
|
||||||
@@ -5019,7 +5036,6 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
AND: [
|
AND: [
|
||||||
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
|
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
|
||||||
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
|
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
|
||||||
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
|
|
||||||
keyFilters?.participant ? { key: { path: ['participant'], equals: keyFilters?.participant } } : {},
|
keyFilters?.participant ? { key: { path: ['participant'], equals: keyFilters?.participant } } : {},
|
||||||
{
|
{
|
||||||
OR: [
|
OR: [
|
||||||
@@ -5049,7 +5065,6 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
AND: [
|
AND: [
|
||||||
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
|
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
|
||||||
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
|
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
|
||||||
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
|
|
||||||
keyFilters?.participant ? { key: { path: ['participant'], equals: keyFilters?.participant } } : {},
|
keyFilters?.participant ? { key: { path: ['participant'], equals: keyFilters?.participant } } : {},
|
||||||
{
|
{
|
||||||
OR: [
|
OR: [
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ export class N8nService extends BaseChatbotService<N8n, N8nSetting> {
|
|||||||
pushName: pushName,
|
pushName: pushName,
|
||||||
keyId: msg?.key?.id,
|
keyId: msg?.key?.id,
|
||||||
fromMe: msg?.key?.fromMe,
|
fromMe: msg?.key?.fromMe,
|
||||||
|
quotedMessage: msg?.contextInfo?.quotedMessage,
|
||||||
instanceName: instance.instanceName,
|
instanceName: instance.instanceName,
|
||||||
serverUrl: this.configService.get<HttpServer>('SERVER').URL,
|
serverUrl: this.configService.get<HttpServer>('SERVER').URL,
|
||||||
apiKey: instance.token,
|
apiKey: instance.token,
|
||||||
|
|||||||
@@ -14,12 +14,24 @@ export type EmitData = {
|
|||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
local?: boolean;
|
local?: boolean;
|
||||||
integration?: string[];
|
integration?: string[];
|
||||||
|
extra?: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface EventControllerInterface {
|
export interface EventControllerInterface {
|
||||||
set(instanceName: string, data: any): Promise<any>;
|
set(instanceName: string, data: any): Promise<any>;
|
||||||
get(instanceName: string): Promise<any>;
|
get(instanceName: string): Promise<any>;
|
||||||
emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local }: EmitData): Promise<void>;
|
emit({
|
||||||
|
instanceName,
|
||||||
|
origin,
|
||||||
|
event,
|
||||||
|
data,
|
||||||
|
serverUrl,
|
||||||
|
dateTime,
|
||||||
|
sender,
|
||||||
|
apiKey,
|
||||||
|
local,
|
||||||
|
extra,
|
||||||
|
}: EmitData): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EventController {
|
export class EventController {
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ export class EventManager {
|
|||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
local?: boolean;
|
local?: boolean;
|
||||||
integration?: string[];
|
integration?: string[];
|
||||||
|
extra?: Record<string, any>;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
await this.websocket.emit(eventData);
|
await this.websocket.emit(eventData);
|
||||||
await this.rabbitmq.emit(eventData);
|
await this.rabbitmq.emit(eventData);
|
||||||
|
|||||||
@@ -262,6 +262,7 @@ export class KafkaController extends EventController implements EventControllerI
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (integration && !integration.includes('kafka')) {
|
if (integration && !integration.includes('kafka')) {
|
||||||
return;
|
return;
|
||||||
@@ -284,6 +285,7 @@ export class KafkaController extends EventController implements EventControllerI
|
|||||||
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
|
...(extra ?? {}),
|
||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export class NatsController extends EventController implements EventControllerIn
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (integration && !integration.includes('nats')) {
|
if (integration && !integration.includes('nats')) {
|
||||||
return;
|
return;
|
||||||
@@ -65,6 +66,7 @@ export class NatsController extends EventController implements EventControllerIn
|
|||||||
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
|
...(extra ?? {}),
|
||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export class PusherController extends EventController implements EventController
|
|||||||
apiKey,
|
apiKey,
|
||||||
local,
|
local,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (integration && !integration.includes('pusher')) {
|
if (integration && !integration.includes('pusher')) {
|
||||||
return;
|
return;
|
||||||
@@ -133,6 +134,7 @@ export class PusherController extends EventController implements EventController
|
|||||||
const enabledLog = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
const enabledLog = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
||||||
const eventName = event.replace(/_/g, '.').toLowerCase();
|
const eventName = event.replace(/_/g, '.').toLowerCase();
|
||||||
const pusherData = {
|
const pusherData = {
|
||||||
|
...(extra ?? {}),
|
||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (integration && !integration.includes('rabbitmq')) {
|
if (integration && !integration.includes('rabbitmq')) {
|
||||||
return;
|
return;
|
||||||
@@ -233,6 +234,7 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
|
...(extra ?? {}),
|
||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export class SqsController extends EventController implements EventControllerInt
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (integration && !integration.includes('sqs')) {
|
if (integration && !integration.includes('sqs')) {
|
||||||
return;
|
return;
|
||||||
@@ -128,6 +129,7 @@ export class SqsController extends EventController implements EventControllerInt
|
|||||||
const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`;
|
const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`;
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
|
...(extra ?? {}),
|
||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
apiKey,
|
apiKey,
|
||||||
local,
|
local,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (integration && !integration.includes('webhook')) {
|
if (integration && !integration.includes('webhook')) {
|
||||||
return;
|
return;
|
||||||
@@ -90,6 +91,7 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
const regex = /^(https?:\/\/)/;
|
const regex = /^(https?:\/\/)/;
|
||||||
|
|
||||||
const webhookData = {
|
const webhookData = {
|
||||||
|
...(extra ?? {}),
|
||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -33,10 +33,13 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
const { remoteAddress } = req.socket;
|
const { remoteAddress } = req.socket;
|
||||||
const websocketConfig = configService.get<Websocket>('WEBSOCKET');
|
const websocketConfig = configService.get<Websocket>('WEBSOCKET');
|
||||||
const allowedHosts = websocketConfig.ALLOWED_HOSTS || '127.0.0.1,::1,::ffff:127.0.0.1';
|
const allowedHosts = websocketConfig.ALLOWED_HOSTS || '127.0.0.1,::1,::ffff:127.0.0.1';
|
||||||
const isAllowedHost = allowedHosts
|
const allowAllHosts = allowedHosts.trim() === '*';
|
||||||
.split(',')
|
const isAllowedHost =
|
||||||
.map((h) => h.trim())
|
allowAllHosts ||
|
||||||
.includes(remoteAddress);
|
allowedHosts
|
||||||
|
.split(',')
|
||||||
|
.map((h) => h.trim())
|
||||||
|
.includes(remoteAddress);
|
||||||
|
|
||||||
if (params.has('EIO') && isAllowedHost) {
|
if (params.has('EIO') && isAllowedHost) {
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
@@ -115,6 +118,7 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (integration && !integration.includes('websocket')) {
|
if (integration && !integration.includes('websocket')) {
|
||||||
return;
|
return;
|
||||||
@@ -127,6 +131,7 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
const configEv = event.replace(/[.-]/gm, '_').toUpperCase();
|
const configEv = event.replace(/[.-]/gm, '_').toUpperCase();
|
||||||
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBSOCKET');
|
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBSOCKET');
|
||||||
const message = {
|
const message = {
|
||||||
|
...(extra ?? {}),
|
||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -432,7 +432,13 @@ export class ChannelStartupService {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendDataWebhook<T extends object = any>(event: Events, data: T, local = true, integration?: string[]) {
|
public async sendDataWebhook<T extends object = any>(
|
||||||
|
event: Events,
|
||||||
|
data: T,
|
||||||
|
local = true,
|
||||||
|
integration?: string[],
|
||||||
|
extra?: Record<string, any>,
|
||||||
|
) {
|
||||||
const serverUrl = this.configService.get<HttpServer>('SERVER').URL;
|
const serverUrl = this.configService.get<HttpServer>('SERVER').URL;
|
||||||
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
||||||
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
||||||
@@ -453,6 +459,7 @@ export class ChannelStartupService {
|
|||||||
apiKey: expose && instanceApikey ? instanceApikey : null,
|
apiKey: expose && instanceApikey ? instanceApikey : null,
|
||||||
local,
|
local,
|
||||||
integration,
|
integration,
|
||||||
|
extra,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export function makeProxyAgent(proxy: Proxy | string): HttpsProxyAgent<string> |
|
|||||||
return selectProxyAgent(proxyUrl);
|
return selectProxyAgent(proxyUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeProxyAgentUndici(proxy: Proxy | string) {
|
export function makeProxyAgentUndici(proxy: Proxy | string): ProxyAgent {
|
||||||
let proxyUrl: string;
|
let proxyUrl: string;
|
||||||
let protocol: string;
|
let protocol: string;
|
||||||
|
|
||||||
@@ -67,7 +67,10 @@ export function makeProxyAgentUndici(proxy: Proxy | string) {
|
|||||||
} else {
|
} else {
|
||||||
const { host, password, port, protocol: proto, username } = proxy;
|
const { host, password, port, protocol: proto, username } = proxy;
|
||||||
protocol = (proto || 'http').replace(':', '');
|
protocol = (proto || 'http').replace(':', '');
|
||||||
if (protocol === 'socks') protocol = 'socks5';
|
|
||||||
|
if (protocol === 'socks') {
|
||||||
|
protocol = 'socks5';
|
||||||
|
}
|
||||||
|
|
||||||
const auth = username && password ? `${username}:${password}@` : '';
|
const auth = username && password ? `${username}:${password}@` : '';
|
||||||
proxyUrl = `${protocol}://${auth}${host}:${port}`;
|
proxyUrl = `${protocol}://${auth}${host}:${port}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user