n8n-nodes-chat2crm 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,5 @@ export declare class Chat2CrmSend implements INodeType {
3
3
  description: INodeTypeDescription;
4
4
  getStreams(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
5
5
  private static createRedisConnectionForLoadOptions;
6
- private static getStreamDb;
7
6
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
8
7
  }
@@ -7,6 +7,7 @@ exports.Chat2CrmSend = void 0;
7
7
  const n8n_workflow_1 = require("n8n-workflow");
8
8
  const ioredis_1 = __importDefault(require("ioredis"));
9
9
  const RedisConnection_1 = require("../Chat2CrmTrigger/Infra/RedisConnection");
10
+ const StreamConfig_1 = require("../Chat2CrmTrigger/Infra/StreamConfig");
10
11
  class Chat2CrmSend {
11
12
  constructor() {
12
13
  this.description = {
@@ -35,63 +36,7 @@ class Chat2CrmSend {
35
36
  type: 'multiOptions',
36
37
  required: true,
37
38
  description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
38
- options: [
39
- {
40
- name: 'Chat Incoming Message',
41
- value: 'chat_incoming_message',
42
- description: 'Messages to chat (DB 0)',
43
- },
44
- {
45
- name: 'Chat Outgoing Message',
46
- value: 'chat_outgoing_message',
47
- description: 'Messages from chat to CRM (DB 0)',
48
- },
49
- {
50
- name: 'Chat Outgoing Status',
51
- value: 'chat_outgoing_status',
52
- description: 'Status messages from chat (DB 0)',
53
- },
54
- {
55
- name: 'CRM Contacts',
56
- value: 'crm_contacts',
57
- description: 'CRM contacts stream (DB 1)',
58
- },
59
- {
60
- name: 'CRM Incoming Message',
61
- value: 'crm_incoming_message',
62
- description: 'Messages to CRM (DB 1)',
63
- },
64
- {
65
- name: 'CRM Incoming Status',
66
- value: 'crm_incoming_status',
67
- description: 'Status messages to CRM (DB 0)',
68
- },
69
- {
70
- name: 'CRM Lazy Incoming Message',
71
- value: 'crm_lazy_incoming_message',
72
- description: 'Lazy incoming messages to CRM (DB 1)',
73
- },
74
- {
75
- name: 'CRM Outgoing Message',
76
- value: 'crm_outgoing_message',
77
- description: 'Messages from CRM to chat (DB 1)',
78
- },
79
- {
80
- name: 'CRM Outgoing Status',
81
- value: 'crm_outgoing_status',
82
- description: 'Status messages from CRM (DB 0)',
83
- },
84
- {
85
- name: 'N8N Incoming Message',
86
- value: 'n8n_incoming_message',
87
- description: 'Incoming messages to N8N (DB 0)',
88
- },
89
- {
90
- name: 'N8N Outgoing Message',
91
- value: 'n8n_outgoing_message',
92
- description: 'Outgoing messages from N8N (DB 0)',
93
- },
94
- ],
39
+ options: (0, StreamConfig_1.getStreamOptions)(),
95
40
  default: [],
96
41
  },
97
42
  {
@@ -292,37 +237,21 @@ class Chat2CrmSend {
292
237
  });
293
238
  return redis;
294
239
  }
295
- // Определяем базу данных для стрима
296
- static getStreamDb(stream) {
297
- // Streams в DB 1 (CrmWorker)
298
- if (stream === 'crm_outgoing_message' ||
299
- stream === 'crm_incoming_message' ||
300
- stream === 'crm_lazy_incoming_message' ||
301
- stream === 'crm_contacts') {
302
- return 1;
303
- }
304
- // Все остальные streams находятся в DB 0
305
- return 0;
306
- }
307
240
  async execute() {
308
241
  const items = this.getInputData();
309
242
  const returnData = [];
310
243
  const credentials = await this.getCredentials('chat2CrmRedisApi');
311
244
  const selectedStreams = this.getNodeParameter('streams', 0);
312
245
  const messageId = this.getNodeParameter('messageId', 0);
313
- // Проверяем, что выбраны streams
246
+ // Валидация входных данных
314
247
  if (!selectedStreams || selectedStreams.length === 0) {
315
248
  throw new n8n_workflow_1.ApplicationError('Please select at least one stream to send message to', { level: 'warning' });
316
249
  }
317
- // Группируем выбранные streams по базам данных
318
- const streamsByDb = new Map();
319
- selectedStreams.forEach(stream => {
320
- const db = Chat2CrmSend.getStreamDb(stream);
321
- if (!streamsByDb.has(db)) {
322
- streamsByDb.set(db, []);
323
- }
324
- streamsByDb.get(db).push(stream);
325
- });
250
+ if (messageId && typeof messageId !== 'string') {
251
+ throw new n8n_workflow_1.ApplicationError('Message ID must be a string', { level: 'error' });
252
+ }
253
+ // Группируем выбранные streams по базам данных используя общую функцию
254
+ const streamsByDb = (0, StreamConfig_1.groupStreamsByDb)(selectedStreams);
326
255
  // Создаем подключения к Redis только для нужных баз данных
327
256
  const redisConnections = new Map();
328
257
  try {
@@ -3,6 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Chat2CrmTrigger = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  const RedisConnection_1 = require("./Infra/RedisConnection");
6
+ const StreamConfig_1 = require("./Infra/StreamConfig");
7
+ // Константы для валидации
8
+ const MIN_POLL_INTERVAL_SECONDS = 0.01;
9
+ const MAX_POLL_INTERVAL_SECONDS = 60;
10
+ const MIN_BLOCK_TIME_MS = 0;
11
+ const MAX_BLOCK_TIME_MS = 60000; // 60 секунд
12
+ const MIN_COUNT = 1;
13
+ const MAX_COUNT = 1000;
14
+ const MAX_BLOCK_TIME_FOR_RESPONSIVENESS_MS = 500;
6
15
  class Chat2CrmTrigger {
7
16
  constructor() {
8
17
  this.description = {
@@ -29,70 +38,9 @@ class Chat2CrmTrigger {
29
38
  displayName: 'Streams',
30
39
  name: 'streams',
31
40
  type: 'multiOptions',
32
- required: true, // Вернули required: true
41
+ required: true,
33
42
  description: 'Select Redis streams to listen to',
34
- options: [
35
- {
36
- name: 'Chat Incoming Message',
37
- value: 'chat_incoming_message',
38
- description: 'Messages to chat (DB 0)',
39
- },
40
- {
41
- name: 'Chat Outgoing Message',
42
- value: 'chat_outgoing_message',
43
- description: 'Messages from chat to CRM (DB 0)',
44
- },
45
- {
46
- name: 'Chat Outgoing Status',
47
- value: 'chat_outgoing_status',
48
- description: 'Status messages from chat (DB 0)',
49
- },
50
- {
51
- name: 'Chat Outgoing Status (CRM)',
52
- value: 'chat_outgoing_status',
53
- description: 'Chat outgoing status in CRM DB (DB 1)',
54
- },
55
- {
56
- name: 'CRM Contacts',
57
- value: 'crm_contacts',
58
- description: 'CRM contacts stream (DB 1)',
59
- },
60
- {
61
- name: 'CRM Incoming Message',
62
- value: 'crm_incoming_message',
63
- description: 'Messages to CRM (DB 1)',
64
- },
65
- {
66
- name: 'CRM Incoming Status',
67
- value: 'crm_incoming_status',
68
- description: 'Status messages to CRM (DB 0)',
69
- },
70
- {
71
- name: 'CRM Lazy Incoming Message',
72
- value: 'crm_lazy_incoming_message',
73
- description: 'Lazy incoming messages to CRM (DB 1)',
74
- },
75
- {
76
- name: 'CRM Outgoing Message',
77
- value: 'crm_outgoing_message',
78
- description: 'Messages from CRM to chat (DB 1)',
79
- },
80
- {
81
- name: 'CRM Outgoing Status',
82
- value: 'crm_outgoing_status',
83
- description: 'Status messages from CRM (DB 1)',
84
- },
85
- {
86
- name: 'N8N Incoming Message',
87
- value: 'n8n_incoming_message',
88
- description: 'Incoming messages to N8N (DB 0)',
89
- },
90
- {
91
- name: 'N8N Outgoing Message',
92
- value: 'n8n_outgoing_message',
93
- description: 'Outgoing messages from N8N (DB 0)',
94
- },
95
- ],
43
+ options: (0, StreamConfig_1.getStreamOptions)(),
96
44
  default: ['chat_outgoing_message'],
97
45
  },
98
46
  {
@@ -125,29 +73,22 @@ class Chat2CrmTrigger {
125
73
  const block = this.getNodeParameter('block', 1000);
126
74
  const count = this.getNodeParameter('count', 10);
127
75
  const pollIntervalSeconds = this.getNodeParameter('pollInterval', 0.5);
128
- const pollInterval = Math.min(pollIntervalSeconds * 1000, 500); // Максимум 500ms
129
- // Проверяем, что выбраны streams
76
+ // Валидация входных данных
130
77
  if (!selectedStreams || selectedStreams.length === 0) {
131
78
  throw new n8n_workflow_1.ApplicationError('Please select at least one stream to monitor', { level: 'warning' });
132
79
  }
133
- // Группируем выбранные streams по базам данных
134
- const streamsByDb = new Map();
135
- selectedStreams.forEach(stream => {
136
- let db = 0; // По умолчанию DB 0
137
- // Streams в DB 1 (CrmWorker)
138
- if (stream === 'crm_outgoing_message' ||
139
- stream === 'crm_incoming_message' ||
140
- stream === 'crm_lazy_incoming_message' ||
141
- stream === 'crm_contacts') {
142
- db = 1;
143
- }
144
- // Все остальные streams (chat_incoming_message, chat_outgoing_message,
145
- // crm_incoming_status, crm_outgoing_status) находятся в DB 0
146
- if (!streamsByDb.has(db)) {
147
- streamsByDb.set(db, []);
148
- }
149
- streamsByDb.get(db).push(stream);
150
- });
80
+ if (pollIntervalSeconds < MIN_POLL_INTERVAL_SECONDS || pollIntervalSeconds > MAX_POLL_INTERVAL_SECONDS) {
81
+ throw new n8n_workflow_1.ApplicationError(`Poll interval must be between ${MIN_POLL_INTERVAL_SECONDS} and ${MAX_POLL_INTERVAL_SECONDS} seconds`, { level: 'error' });
82
+ }
83
+ if (block < MIN_BLOCK_TIME_MS || block > MAX_BLOCK_TIME_MS) {
84
+ throw new n8n_workflow_1.ApplicationError(`Block time must be between ${MIN_BLOCK_TIME_MS} and ${MAX_BLOCK_TIME_MS} milliseconds`, { level: 'error' });
85
+ }
86
+ if (count < MIN_COUNT || count > MAX_COUNT) {
87
+ throw new n8n_workflow_1.ApplicationError(`Count must be between ${MIN_COUNT} and ${MAX_COUNT}`, { level: 'error' });
88
+ }
89
+ const pollInterval = Math.min(pollIntervalSeconds * 1000, MAX_BLOCK_TIME_FOR_RESPONSIVENESS_MS);
90
+ // Группируем выбранные streams по базам данных используя общую функцию
91
+ const streamsByDb = (0, StreamConfig_1.groupStreamsByDb)(selectedStreams);
151
92
  // Создаем подключения к Redis только для нужных баз данных
152
93
  const redisConnections = new Map();
153
94
  for (const db of streamsByDb.keys()) {
@@ -241,7 +182,7 @@ class Chat2CrmTrigger {
241
182
  try {
242
183
  const lastId = lastReadIds.get(stream) || '$';
243
184
  // Используем более короткий block time для возможности быстрого закрытия
244
- const blockTime = isClosing ? 0 : Math.min(block, 500); // Максимум 500ms для более быстрого отклика
185
+ const blockTime = isClosing ? 0 : Math.min(block, MAX_BLOCK_TIME_FOR_RESPONSIVENESS_MS);
245
186
  // Используем XREAD чтобы читать все сообщения напрямую из stream
246
187
  // Это позволяет читать сообщения даже если они уже обработаны другими consumer'ами
247
188
  const messages = await redis.xread('COUNT', count, 'BLOCK', blockTime, 'STREAMS', stream, lastId);
@@ -0,0 +1,35 @@
1
+ import { INodePropertyOptions } from 'n8n-workflow';
2
+ /**
3
+ * Интерфейс для определения stream
4
+ */
5
+ export interface StreamDefinition {
6
+ name: string;
7
+ value: string;
8
+ description: string;
9
+ db: number;
10
+ }
11
+ /**
12
+ * Полный список всех доступных streams с их конфигурацией
13
+ */
14
+ export declare const STREAM_DEFINITIONS: StreamDefinition[];
15
+ /**
16
+ * Маппинг stream names к номерам баз данных
17
+ */
18
+ export declare const STREAM_DB_MAP: Record<string, number>;
19
+ /**
20
+ * Определяет номер базы данных для указанного stream
21
+ * @param stream - Имя stream
22
+ * @returns Номер базы данных (0 или 1)
23
+ */
24
+ export declare function getStreamDb(stream: string): number;
25
+ /**
26
+ * Группирует streams по базам данных
27
+ * @param streams - Массив имен streams
28
+ * @returns Map с ключом - номер DB, значением - массив streams
29
+ */
30
+ export declare function groupStreamsByDb(streams: string[]): Map<number, string[]>;
31
+ /**
32
+ * Возвращает опции streams для n8n properties
33
+ * @returns Массив опций для multiOptions
34
+ */
35
+ export declare function getStreamOptions(): INodePropertyOptions[];
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STREAM_DB_MAP = exports.STREAM_DEFINITIONS = void 0;
4
+ exports.getStreamDb = getStreamDb;
5
+ exports.groupStreamsByDb = groupStreamsByDb;
6
+ exports.getStreamOptions = getStreamOptions;
7
+ /**
8
+ * Полный список всех доступных streams с их конфигурацией
9
+ */
10
+ exports.STREAM_DEFINITIONS = [
11
+ {
12
+ name: 'Chat Incoming Message',
13
+ value: 'chat_incoming_message',
14
+ description: 'Messages to chat (DB 0)',
15
+ db: 0,
16
+ },
17
+ {
18
+ name: 'Chat Outgoing Message',
19
+ value: 'chat_outgoing_message',
20
+ description: 'Messages from chat to CRM (DB 0)',
21
+ db: 0,
22
+ },
23
+ {
24
+ name: 'Chat Outgoing Status',
25
+ value: 'chat_outgoing_status',
26
+ description: 'Status messages from chat (DB 0)',
27
+ db: 0,
28
+ },
29
+ {
30
+ name: 'Chat Outgoing Status (CRM)',
31
+ value: 'chat_outgoing_status',
32
+ description: 'Chat outgoing status in CRM DB (DB 1)',
33
+ db: 1,
34
+ },
35
+ {
36
+ name: 'CRM Contacts',
37
+ value: 'crm_contacts',
38
+ description: 'CRM contacts stream (DB 1)',
39
+ db: 1,
40
+ },
41
+ {
42
+ name: 'CRM Incoming Message',
43
+ value: 'crm_incoming_message',
44
+ description: 'Messages to CRM (DB 1)',
45
+ db: 1,
46
+ },
47
+ {
48
+ name: 'CRM Incoming Status',
49
+ value: 'crm_incoming_status',
50
+ description: 'Status messages to CRM (DB 0)',
51
+ db: 0,
52
+ },
53
+ {
54
+ name: 'CRM Lazy Incoming Message',
55
+ value: 'crm_lazy_incoming_message',
56
+ description: 'Lazy incoming messages to CRM (DB 1)',
57
+ db: 1,
58
+ },
59
+ {
60
+ name: 'CRM Outgoing Message',
61
+ value: 'crm_outgoing_message',
62
+ description: 'Messages from CRM to chat (DB 1)',
63
+ db: 1,
64
+ },
65
+ {
66
+ name: 'CRM Outgoing Status',
67
+ value: 'crm_outgoing_status',
68
+ description: 'Status messages from CRM (DB 1)',
69
+ db: 1,
70
+ },
71
+ {
72
+ name: 'N8N Incoming Message',
73
+ value: 'n8n_incoming_message',
74
+ description: 'Incoming messages to N8N (DB 0)',
75
+ db: 0,
76
+ },
77
+ {
78
+ name: 'N8N Outgoing Message',
79
+ value: 'n8n_outgoing_message',
80
+ description: 'Outgoing messages from N8N (DB 0)',
81
+ db: 0,
82
+ },
83
+ ];
84
+ /**
85
+ * Маппинг stream names к номерам баз данных
86
+ */
87
+ exports.STREAM_DB_MAP = {
88
+ crm_outgoing_message: 1,
89
+ crm_incoming_message: 1,
90
+ crm_lazy_incoming_message: 1,
91
+ crm_contacts: 1,
92
+ crm_outgoing_status: 1,
93
+ };
94
+ /**
95
+ * Определяет номер базы данных для указанного stream
96
+ * @param stream - Имя stream
97
+ * @returns Номер базы данных (0 или 1)
98
+ */
99
+ function getStreamDb(stream) {
100
+ return exports.STREAM_DB_MAP[stream] ?? 0;
101
+ }
102
+ /**
103
+ * Группирует streams по базам данных
104
+ * @param streams - Массив имен streams
105
+ * @returns Map с ключом - номер DB, значением - массив streams
106
+ */
107
+ function groupStreamsByDb(streams) {
108
+ const streamsByDb = new Map();
109
+ streams.forEach(stream => {
110
+ const db = getStreamDb(stream);
111
+ if (!streamsByDb.has(db)) {
112
+ streamsByDb.set(db, []);
113
+ }
114
+ streamsByDb.get(db).push(stream);
115
+ });
116
+ return streamsByDb;
117
+ }
118
+ /**
119
+ * Возвращает опции streams для n8n properties
120
+ * @returns Массив опций для multiOptions
121
+ */
122
+ function getStreamOptions() {
123
+ return exports.STREAM_DEFINITIONS.map(def => ({
124
+ name: def.name,
125
+ value: def.value,
126
+ description: def.description,
127
+ }));
128
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-chat2crm",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "n8n node for Chat2Crm Redis integration",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",