@catalogicus-international/n8n-nodes-telegram-advance 0.1.16 → 0.2.1
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.
- package/dist/credentials/TelegramAdvanceApi.credentials.js +8 -0
- package/dist/credentials/TelegramAdvanceApi.credentials.js.map +1 -1
- package/dist/nodes/TelegramAdvance/TelegramAdvance.node.js +10 -599
- package/dist/nodes/TelegramAdvance/TelegramAdvance.node.js.map +1 -1
- package/dist/nodes/TelegramAdvanceTrigger/TelegramAdvanceTrigger.node.js +6 -76
- package/dist/nodes/TelegramAdvanceTrigger/TelegramAdvanceTrigger.node.js.map +1 -1
- package/dist/nodes/TelegramAdvanceWebhook/TelegramAdvanceWebhook.node.d.ts +10 -0
- package/dist/nodes/TelegramAdvanceWebhook/TelegramAdvanceWebhook.node.js +49 -0
- package/dist/nodes/TelegramAdvanceWebhook/TelegramAdvanceWebhook.node.js.map +1 -0
- package/dist/nodes/TelegramAdvanceWebhook/TelegramAdvanceWebhook.node.json +22 -0
- package/dist/nodes/TelegramAdvanceWebhookTrigger/TelegramAdvanceWebhookTrigger.node.d.ts +17 -0
- package/dist/nodes/TelegramAdvanceWebhookTrigger/TelegramAdvanceWebhookTrigger.node.js +165 -0
- package/dist/nodes/TelegramAdvanceWebhookTrigger/TelegramAdvanceWebhookTrigger.node.js.map +1 -0
- package/dist/nodes/TelegramAdvanceWebhookTrigger/TelegramAdvanceWebhookTrigger.node.json +19 -0
- package/dist/nodes/actionShared.d.ts +4 -0
- package/dist/nodes/actionShared.js +604 -0
- package/dist/nodes/actionShared.js.map +1 -0
- package/dist/nodes/coordinator/BotPoller.d.ts +6 -2
- package/dist/nodes/coordinator/BotPoller.js +35 -8
- package/dist/nodes/coordinator/BotPoller.js.map +1 -1
- package/dist/nodes/coordinator/PollingCoordinator.d.ts +5 -4
- package/dist/nodes/coordinator/PollingCoordinator.js +27 -16
- package/dist/nodes/coordinator/PollingCoordinator.js.map +1 -1
- package/dist/nodes/transport.d.ts +9 -2
- package/dist/nodes/transport.js +6 -0
- package/dist/nodes/transport.js.map +1 -1
- package/dist/nodes/triggerShared.d.ts +12 -0
- package/dist/nodes/triggerShared.js +97 -0
- package/dist/nodes/triggerShared.js.map +1 -0
- package/package.json +4 -2
|
@@ -25,6 +25,14 @@ class TelegramAdvanceApi {
|
|
|
25
25
|
required: true,
|
|
26
26
|
description: 'Telegram Bot API base URL, or the URL of a local Bot API server',
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
displayName: 'Webhook Secret Token',
|
|
30
|
+
name: 'webhookSecret',
|
|
31
|
+
type: 'string',
|
|
32
|
+
typeOptions: { password: true },
|
|
33
|
+
default: '',
|
|
34
|
+
description: 'Optional secret used only by the Telegram Advance Webhook nodes. When set, it is passed to setWebhook as secret_token and every incoming update is verified against the X-Telegram-Bot-Api-Secret-Token header, so only Telegram can deliver updates to your webhook. Ignored by the long-polling nodes. 1–256 chars of A-Z, a-z, 0-9, _ and -.',
|
|
35
|
+
},
|
|
28
36
|
{
|
|
29
37
|
displayName: 'Redis (Optional — Multi-Worker Coordination & Deduplication)',
|
|
30
38
|
name: 'redisNotice',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TelegramAdvanceApi.credentials.js","sourceRoot":"","sources":["../../credentials/TelegramAdvanceApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,kBAAkB;IAA/B;QACC,SAAI,GAAG,oBAAoB,CAAC;QAE5B,gBAAW,GAAG,sBAAsB,CAAC;QAErC,SAAI,GAAS,4BAA4B,CAAC;QAE1C,qBAAgB,GAAG,4DAA4D,CAAC;QAEhF,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,kBAAkB;gBAC/B,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,6BAA6B;aAC1C;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,0BAA0B;gBACnC,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,iEAAiE;aAC9E;YACD;gBACC,WAAW,EAAE,8DAA8D;gBAC3E,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,k3BAAk3B;aACn3B;YACD;gBACC,WAAW,EAAE,sBAAsB;gBACnC,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,8CAA8C;gBAC3D,WAAW,EACV,0UAA0U;aAC3U;YACD;gBACC,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,qIAAqI;gBACtI,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE;aAC/D;YACD;gBACC,WAAW,EAAE,qBAAqB;gBAClC,IAAI,EAAE,gBAAgB;gBACtB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI;gBACb,WAAW,EACV,+JAA+J;gBAChK,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE;aAC/D;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,EAAE;SACd,CAAC;IACH,CAAC;CAAA;
|
|
1
|
+
{"version":3,"file":"TelegramAdvanceApi.credentials.js","sourceRoot":"","sources":["../../credentials/TelegramAdvanceApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,kBAAkB;IAA/B;QACC,SAAI,GAAG,oBAAoB,CAAC;QAE5B,gBAAW,GAAG,sBAAsB,CAAC;QAErC,SAAI,GAAS,4BAA4B,CAAC;QAE1C,qBAAgB,GAAG,4DAA4D,CAAC;QAEhF,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,kBAAkB;gBAC/B,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,6BAA6B;aAC1C;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,0BAA0B;gBACnC,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,iEAAiE;aAC9E;YACD;gBACC,WAAW,EAAE,sBAAsB;gBACnC,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,iVAAiV;aAClV;YACD;gBACC,WAAW,EAAE,8DAA8D;gBAC3E,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,k3BAAk3B;aACn3B;YACD;gBACC,WAAW,EAAE,sBAAsB;gBACnC,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,8CAA8C;gBAC3D,WAAW,EACV,0UAA0U;aAC3U;YACD;gBACC,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,qIAAqI;gBACtI,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE;aAC/D;YACD;gBACC,WAAW,EAAE,qBAAqB;gBAClC,IAAI,EAAE,gBAAgB;gBACtB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI;gBACb,WAAW,EACV,+JAA+J;gBAChK,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE;aAC/D;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,EAAE;SACd,CAAC;IACH,CAAC;CAAA;AA9ED,gDA8EC"}
|
|
@@ -2,27 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TelegramAdvance = void 0;
|
|
4
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
-
const
|
|
6
|
-
const shared_1 = require("../shared");
|
|
7
|
-
const transport_1 = require("../transport");
|
|
8
|
-
const PollingCoordinator_1 = require("../coordinator/PollingCoordinator");
|
|
9
|
-
const attachStore_1 = require("../coordinator/attachStore");
|
|
5
|
+
const actionShared_1 = require("../actionShared");
|
|
10
6
|
const credentialTest_1 = require("../credentialTest");
|
|
11
|
-
function getWaitLimitMs(amount, unit) {
|
|
12
|
-
const multipliers = {
|
|
13
|
-
minutes: 60 * 1000,
|
|
14
|
-
hours: 60 * 60 * 1000,
|
|
15
|
-
days: 24 * 60 * 60 * 1000,
|
|
16
|
-
};
|
|
17
|
-
return Math.max(0, amount) * multipliers[unit];
|
|
18
|
-
}
|
|
19
|
-
async function bestEffort(operation) {
|
|
20
|
-
try {
|
|
21
|
-
await operation();
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
7
|
class TelegramAdvance {
|
|
27
8
|
constructor() {
|
|
28
9
|
this.description = {
|
|
@@ -45,402 +26,14 @@ class TelegramAdvance {
|
|
|
45
26
|
testedBy: 'telegramAdvanceApiCredentialTest',
|
|
46
27
|
},
|
|
47
28
|
],
|
|
48
|
-
properties:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
name: 'Send and Wait for Response',
|
|
57
|
-
value: 'sendAndWait',
|
|
58
|
-
description: 'Ask a question in Telegram and wait for an in-chat response (approval, choice, or text)',
|
|
59
|
-
action: 'Send a question and wait for a response',
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: 'Send Message',
|
|
63
|
-
value: 'send',
|
|
64
|
-
description: 'Send a plain text message without waiting for a response',
|
|
65
|
-
action: 'Send a text message',
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
default: 'sendAndWait',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
displayName: 'Self-Contained Wait',
|
|
72
|
-
name: 'waitNotice',
|
|
73
|
-
type: 'notice',
|
|
74
|
-
default: '',
|
|
75
|
-
description: 'This node sends the question and waits for an in-chat answer (inline button or reply) until the wait limit is reached. A single shared poller per bot handles getUpdates, so multiple questions can wait on the same bot at once. No public URL or separate trigger is required. Telegram allows only one getUpdates consumer per bot, so do not run a Telegram webhook or another poller on the same bot while a question is waiting.',
|
|
76
|
-
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
displayName: 'Chat ID',
|
|
80
|
-
name: 'chatId',
|
|
81
|
-
type: 'string',
|
|
82
|
-
default: '={{ $json.message?.chat?.id || $json.chatId }}',
|
|
83
|
-
required: true,
|
|
84
|
-
description: 'Target Telegram chat ID',
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
displayName: 'Text',
|
|
88
|
-
name: 'text',
|
|
89
|
-
type: 'string',
|
|
90
|
-
typeOptions: { rows: 4 },
|
|
91
|
-
default: '',
|
|
92
|
-
required: true,
|
|
93
|
-
description: 'Message text sent to the Telegram chat',
|
|
94
|
-
displayOptions: { show: { operation: ['send'] } },
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
displayName: 'Question',
|
|
98
|
-
name: 'question',
|
|
99
|
-
type: 'string',
|
|
100
|
-
typeOptions: { rows: 4 },
|
|
101
|
-
default: '',
|
|
102
|
-
required: true,
|
|
103
|
-
description: 'Message shown to the Telegram user',
|
|
104
|
-
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
displayName: 'Response Type',
|
|
108
|
-
name: 'responseType',
|
|
109
|
-
type: 'options',
|
|
110
|
-
noDataExpression: true,
|
|
111
|
-
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
112
|
-
options: [
|
|
113
|
-
{
|
|
114
|
-
name: 'Approval',
|
|
115
|
-
value: 'approval',
|
|
116
|
-
description: 'Show approve and decline buttons',
|
|
117
|
-
action: 'Wait for approval',
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
name: 'Checkboxes',
|
|
121
|
-
value: 'checkbox',
|
|
122
|
-
description: 'Let the user select multiple items and confirm them with the submit button',
|
|
123
|
-
action: 'Wait for selected items',
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: 'Choice',
|
|
127
|
-
value: 'choice',
|
|
128
|
-
description: 'Show one or more custom choices, such as products',
|
|
129
|
-
action: 'Wait for a choice',
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
name: 'Free Text',
|
|
133
|
-
value: 'text',
|
|
134
|
-
description: 'Ask the user to reply to the Telegram message',
|
|
135
|
-
action: 'Wait for a text reply',
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: 'Radio Buttons',
|
|
139
|
-
value: 'radio',
|
|
140
|
-
description: 'Let the user select one item and confirm it with the submit button',
|
|
141
|
-
action: 'Wait for one selected item',
|
|
142
|
-
},
|
|
143
|
-
],
|
|
144
|
-
default: 'approval',
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
displayName: 'Approve Label',
|
|
148
|
-
name: 'approveLabel',
|
|
149
|
-
type: 'string',
|
|
150
|
-
default: '✅ Approve',
|
|
151
|
-
displayOptions: { show: { operation: ['sendAndWait'], responseType: ['approval'] } },
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
displayName: 'Approve Value',
|
|
155
|
-
name: 'approveValue',
|
|
156
|
-
type: 'string',
|
|
157
|
-
default: 'approved',
|
|
158
|
-
displayOptions: { show: { operation: ['sendAndWait'], responseType: ['approval'] } },
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
displayName: 'Decline Label',
|
|
162
|
-
name: 'declineLabel',
|
|
163
|
-
type: 'string',
|
|
164
|
-
default: '❌ Decline',
|
|
165
|
-
displayOptions: { show: { operation: ['sendAndWait'], responseType: ['approval'] } },
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
displayName: 'Decline Value',
|
|
169
|
-
name: 'declineValue',
|
|
170
|
-
type: 'string',
|
|
171
|
-
default: 'declined',
|
|
172
|
-
displayOptions: { show: { operation: ['sendAndWait'], responseType: ['approval'] } },
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
displayName: 'Display List',
|
|
176
|
-
name: 'displayList',
|
|
177
|
-
type: 'json',
|
|
178
|
-
default: '[]',
|
|
179
|
-
required: true,
|
|
180
|
-
description: 'Optional non-clickable list shown above the approval buttons. Use an expression that returns strings, numbers, or objects with a label field.',
|
|
181
|
-
displayOptions: {
|
|
182
|
-
show: {
|
|
183
|
-
operation: ['sendAndWait'],
|
|
184
|
-
responseType: ['approval'],
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
displayName: 'Choice Source',
|
|
190
|
-
name: 'choiceSource',
|
|
191
|
-
type: 'options',
|
|
192
|
-
noDataExpression: true,
|
|
193
|
-
default: 'fixed',
|
|
194
|
-
displayOptions: {
|
|
195
|
-
show: {
|
|
196
|
-
operation: ['sendAndWait'],
|
|
197
|
-
responseType: ['choice', 'radio', 'checkbox'],
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
options: [
|
|
201
|
-
{
|
|
202
|
-
name: 'Define Below',
|
|
203
|
-
value: 'fixed',
|
|
204
|
-
description: 'Add labels and values manually',
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
name: 'Expression',
|
|
208
|
-
value: 'expression',
|
|
209
|
-
description: 'Build the choices from an array returned by an expression',
|
|
210
|
-
},
|
|
211
|
-
],
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
displayName: 'Choices',
|
|
215
|
-
name: 'choices',
|
|
216
|
-
type: 'fixedCollection',
|
|
217
|
-
typeOptions: { multipleValues: true },
|
|
218
|
-
placeholder: 'Add Choice',
|
|
219
|
-
default: {},
|
|
220
|
-
displayOptions: {
|
|
221
|
-
show: {
|
|
222
|
-
operation: ['sendAndWait'],
|
|
223
|
-
responseType: ['choice', 'radio', 'checkbox'],
|
|
224
|
-
choiceSource: ['fixed'],
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
options: [
|
|
228
|
-
{
|
|
229
|
-
displayName: 'Choice',
|
|
230
|
-
name: 'choice',
|
|
231
|
-
values: [
|
|
232
|
-
{
|
|
233
|
-
displayName: 'Label',
|
|
234
|
-
name: 'label',
|
|
235
|
-
type: 'string',
|
|
236
|
-
default: '',
|
|
237
|
-
required: true,
|
|
238
|
-
description: 'Text shown on the Telegram button',
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
displayName: 'Value',
|
|
242
|
-
name: 'value',
|
|
243
|
-
type: 'string',
|
|
244
|
-
default: '',
|
|
245
|
-
required: true,
|
|
246
|
-
description: 'Value returned to the workflow',
|
|
247
|
-
},
|
|
248
|
-
],
|
|
249
|
-
},
|
|
250
|
-
],
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
displayName: 'Dynamic Choices',
|
|
254
|
-
name: 'dynamicChoices',
|
|
255
|
-
type: 'json',
|
|
256
|
-
default: '[]',
|
|
257
|
-
required: true,
|
|
258
|
-
description: 'A JSON array of objects with label and value fields. An expression can map source items and use their array index as the value.',
|
|
259
|
-
displayOptions: {
|
|
260
|
-
show: {
|
|
261
|
-
operation: ['sendAndWait'],
|
|
262
|
-
responseType: ['choice', 'radio', 'checkbox'],
|
|
263
|
-
choiceSource: ['expression'],
|
|
264
|
-
},
|
|
265
|
-
},
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
displayName: 'Buttons Per Row',
|
|
269
|
-
name: 'buttonsPerRow',
|
|
270
|
-
type: 'number',
|
|
271
|
-
typeOptions: { minValue: 1, maxValue: 8 },
|
|
272
|
-
default: 1,
|
|
273
|
-
displayOptions: {
|
|
274
|
-
show: {
|
|
275
|
-
operation: ['sendAndWait'],
|
|
276
|
-
responseType: ['approval', 'choice', 'radio', 'checkbox'],
|
|
277
|
-
},
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
displayName: 'Submit Button Label',
|
|
282
|
-
name: 'submitLabel',
|
|
283
|
-
type: 'string',
|
|
284
|
-
default: 'Отправить',
|
|
285
|
-
required: true,
|
|
286
|
-
description: 'Button that confirms the selected radio button or checkboxes',
|
|
287
|
-
displayOptions: {
|
|
288
|
-
show: {
|
|
289
|
-
operation: ['sendAndWait'],
|
|
290
|
-
responseType: ['radio', 'checkbox'],
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
displayName: 'Reply Placeholder',
|
|
296
|
-
name: 'inputPlaceholder',
|
|
297
|
-
type: 'string',
|
|
298
|
-
default: 'Type your answer…',
|
|
299
|
-
displayOptions: { show: { operation: ['sendAndWait'], responseType: ['text'] } },
|
|
300
|
-
description: 'Placeholder shown in the Telegram reply field',
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
displayName: 'Options',
|
|
304
|
-
name: 'sendOptions',
|
|
305
|
-
type: 'collection',
|
|
306
|
-
placeholder: 'Add Option',
|
|
307
|
-
default: {},
|
|
308
|
-
displayOptions: { show: { operation: ['send'] } },
|
|
309
|
-
options: [
|
|
310
|
-
{
|
|
311
|
-
displayName: 'Disable Notification',
|
|
312
|
-
name: 'disableNotification',
|
|
313
|
-
type: 'boolean',
|
|
314
|
-
default: false,
|
|
315
|
-
description: 'Whether to send the message silently',
|
|
316
|
-
},
|
|
317
|
-
{
|
|
318
|
-
displayName: 'Disable Link Preview',
|
|
319
|
-
name: 'disableLinkPreview',
|
|
320
|
-
type: 'boolean',
|
|
321
|
-
default: false,
|
|
322
|
-
description: 'Whether to disable link previews for links in the message',
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
displayName: 'Parse Mode',
|
|
326
|
-
name: 'parseMode',
|
|
327
|
-
type: 'options',
|
|
328
|
-
options: [
|
|
329
|
-
{ name: 'None', value: 'none' },
|
|
330
|
-
{ name: 'HTML', value: 'HTML' },
|
|
331
|
-
{ name: 'MarkdownV2', value: 'MarkdownV2' },
|
|
332
|
-
],
|
|
333
|
-
default: 'none',
|
|
334
|
-
description: 'How Telegram should parse formatting in the message',
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
displayName: 'Reply To Message ID',
|
|
338
|
-
name: 'replyToMessageId',
|
|
339
|
-
type: 'number',
|
|
340
|
-
default: 0,
|
|
341
|
-
description: 'If set, the message is sent as a reply to this message ID in the chat',
|
|
342
|
-
},
|
|
343
|
-
],
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
displayName: 'Options',
|
|
347
|
-
name: 'options',
|
|
348
|
-
type: 'collection',
|
|
349
|
-
placeholder: 'Add Option',
|
|
350
|
-
default: {},
|
|
351
|
-
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
352
|
-
options: [
|
|
353
|
-
{
|
|
354
|
-
displayName: 'Acknowledgement Text',
|
|
355
|
-
name: 'acknowledgementText',
|
|
356
|
-
type: 'string',
|
|
357
|
-
default: 'Response recorded',
|
|
358
|
-
description: 'Toast shown for a button response, or message sent after a free-text response',
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
displayName: 'Allowed User IDs',
|
|
362
|
-
name: 'allowedUserIds',
|
|
363
|
-
type: 'string',
|
|
364
|
-
default: '',
|
|
365
|
-
placeholder: '123456789, 987654321',
|
|
366
|
-
description: 'Optional comma-separated Telegram user IDs. Empty allows any user in the chat.',
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
displayName: 'Disable Notification',
|
|
370
|
-
name: 'disableNotification',
|
|
371
|
-
type: 'boolean',
|
|
372
|
-
default: false,
|
|
373
|
-
description: 'Whether to send the question silently',
|
|
374
|
-
},
|
|
375
|
-
{
|
|
376
|
-
displayName: 'Expired Notice',
|
|
377
|
-
name: 'expiredNotice',
|
|
378
|
-
type: 'string',
|
|
379
|
-
default: 'Запрос уже истёк',
|
|
380
|
-
description: 'Toast shown to a user who taps a button after the wait limit has already passed',
|
|
381
|
-
},
|
|
382
|
-
{
|
|
383
|
-
displayName: 'Parse Mode',
|
|
384
|
-
name: 'parseMode',
|
|
385
|
-
type: 'options',
|
|
386
|
-
options: [
|
|
387
|
-
{ name: 'None', value: 'none' },
|
|
388
|
-
{ name: 'HTML', value: 'HTML' },
|
|
389
|
-
{ name: 'MarkdownV2', value: 'MarkdownV2' },
|
|
390
|
-
],
|
|
391
|
-
default: 'none',
|
|
392
|
-
description: 'How Telegram should parse formatting in the question',
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
displayName: 'Remove Buttons After Response',
|
|
396
|
-
name: 'removeButtons',
|
|
397
|
-
type: 'boolean',
|
|
398
|
-
default: true,
|
|
399
|
-
description: 'Whether to remove inline buttons after the first response',
|
|
400
|
-
},
|
|
401
|
-
],
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
displayName: 'Wait Limit Amount',
|
|
405
|
-
name: 'waitAmount',
|
|
406
|
-
type: 'number',
|
|
407
|
-
typeOptions: { minValue: 0.1, numberPrecision: 2 },
|
|
408
|
-
default: 5,
|
|
409
|
-
description: 'How long to keep polling Telegram for an answer before giving up. The node holds the execution open for this whole time, so prefer minutes for human-in-the-loop approvals.',
|
|
410
|
-
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
displayName: 'Wait Limit Unit',
|
|
414
|
-
name: 'waitUnit',
|
|
415
|
-
type: 'options',
|
|
416
|
-
options: [
|
|
417
|
-
{ name: 'Days', value: 'days' },
|
|
418
|
-
{ name: 'Hours', value: 'hours' },
|
|
419
|
-
{ name: 'Minutes', value: 'minutes' },
|
|
420
|
-
],
|
|
421
|
-
default: 'minutes',
|
|
422
|
-
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
423
|
-
},
|
|
424
|
-
{
|
|
425
|
-
displayName: 'On Timeout',
|
|
426
|
-
name: 'onTimeout',
|
|
427
|
-
type: 'options',
|
|
428
|
-
options: [
|
|
429
|
-
{
|
|
430
|
-
name: 'Return Timeout Item',
|
|
431
|
-
value: 'return',
|
|
432
|
-
description: 'Continue the workflow with a timed-out item so you can branch on it',
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
name: 'Throw Error',
|
|
436
|
-
value: 'error',
|
|
437
|
-
description: 'Fail the node if nobody answers within the wait limit',
|
|
438
|
-
},
|
|
439
|
-
],
|
|
440
|
-
default: 'return',
|
|
441
|
-
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
442
|
-
},
|
|
443
|
-
],
|
|
29
|
+
properties: (0, actionShared_1.buildActionProperties)({
|
|
30
|
+
displayName: 'Self-Contained Wait',
|
|
31
|
+
name: 'waitNotice',
|
|
32
|
+
type: 'notice',
|
|
33
|
+
default: '',
|
|
34
|
+
description: 'This node sends the question and waits for an in-chat answer (inline button or reply) until the wait limit is reached. A single shared poller per bot handles getUpdates, so multiple questions can wait on the same bot at once. No public URL or separate trigger is required. Telegram allows only one getUpdates consumer per bot, so do not run a Telegram webhook or another poller on the same bot while a question is waiting.',
|
|
35
|
+
displayOptions: { show: { operation: ['sendAndWait'] } },
|
|
36
|
+
}),
|
|
444
37
|
};
|
|
445
38
|
this.methods = {
|
|
446
39
|
credentialTest: {
|
|
@@ -449,189 +42,7 @@ class TelegramAdvance {
|
|
|
449
42
|
};
|
|
450
43
|
}
|
|
451
44
|
async execute() {
|
|
452
|
-
|
|
453
|
-
const operation = this.getNodeParameter('operation', 0);
|
|
454
|
-
const inputData = this.getInputData();
|
|
455
|
-
if (operation === 'sendAndWait') {
|
|
456
|
-
let releaseReservation;
|
|
457
|
-
try {
|
|
458
|
-
if (inputData.length === 0)
|
|
459
|
-
return [[]];
|
|
460
|
-
const chatId = String(this.getNodeParameter('chatId', 0)).trim();
|
|
461
|
-
const question = String(this.getNodeParameter('question', 0)).trim();
|
|
462
|
-
const responseType = this.getNodeParameter('responseType', 0);
|
|
463
|
-
const choiceSource = this.getNodeParameter('choiceSource', 0, 'fixed');
|
|
464
|
-
const buttonsPerRow = this.getNodeParameter('buttonsPerRow', 0, 1);
|
|
465
|
-
const inputPlaceholder = this.getNodeParameter('inputPlaceholder', 0, '');
|
|
466
|
-
const submitLabel = String(this.getNodeParameter('submitLabel', 0, 'Отправить')).trim();
|
|
467
|
-
const options = this.getNodeParameter('options', 0, {});
|
|
468
|
-
const parseMode = String(options.parseMode || 'none');
|
|
469
|
-
if (!chatId || !question) {
|
|
470
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Chat ID and Question are required');
|
|
471
|
-
}
|
|
472
|
-
const messageText = responseType === 'approval'
|
|
473
|
-
? (0, question_1.appendDisplayList)(question, (0, question_1.parseDisplayList)(this.getNodeParameter('displayList', 0, [])), parseMode)
|
|
474
|
-
: question;
|
|
475
|
-
const responseOptions = (0, question_1.buildResponseOptions)(responseType, {
|
|
476
|
-
approveLabel: this.getNodeParameter('approveLabel', 0, ''),
|
|
477
|
-
approveValue: this.getNodeParameter('approveValue', 0, ''),
|
|
478
|
-
declineLabel: this.getNodeParameter('declineLabel', 0, ''),
|
|
479
|
-
declineValue: this.getNodeParameter('declineValue', 0, ''),
|
|
480
|
-
choices: this.getNodeParameter('choices', 0, {}),
|
|
481
|
-
choiceSource,
|
|
482
|
-
dynamicChoices: choiceSource === 'expression'
|
|
483
|
-
? this.getNodeParameter('dynamicChoices', 0, [])
|
|
484
|
-
: undefined,
|
|
485
|
-
});
|
|
486
|
-
const token = PollingCoordinator_1.PollingCoordinator.newToken();
|
|
487
|
-
const replyMarkup = (0, question_1.buildReplyMarkup)(responseType, token, responseOptions, Math.max(1, Math.min(8, buttonsPerRow)), inputPlaceholder, responseType === 'radio' || responseType === 'checkbox'
|
|
488
|
-
? { selectedIndices: [], submitLabel }
|
|
489
|
-
: undefined);
|
|
490
|
-
const body = {
|
|
491
|
-
chat_id: chatId,
|
|
492
|
-
text: messageText,
|
|
493
|
-
disable_notification: options.disableNotification === true,
|
|
494
|
-
reply_markup: replyMarkup,
|
|
495
|
-
};
|
|
496
|
-
if (parseMode !== 'none')
|
|
497
|
-
body.parse_mode = parseMode;
|
|
498
|
-
const transport = await (0, transport_1.createTransport)(this);
|
|
499
|
-
const coordinator = PollingCoordinator_1.PollingCoordinator.getInstance();
|
|
500
|
-
await transport.call('deleteWebhook', { drop_pending_updates: false });
|
|
501
|
-
await (0, attachStore_1.attachRedisStore)(this, coordinator);
|
|
502
|
-
const expiredNotice = String((_a = options.expiredNotice) !== null && _a !== void 0 ? _a : '');
|
|
503
|
-
const waitLimitMs = getWaitLimitMs(this.getNodeParameter('waitAmount', 0, 5), this.getNodeParameter('waitUnit', 0, 'minutes'));
|
|
504
|
-
coordinator.reserve(transport, token);
|
|
505
|
-
releaseReservation = () => coordinator.cancelReservation(transport, token);
|
|
506
|
-
const sentMessage = await transport.call('sendMessage', body);
|
|
507
|
-
const pending = {
|
|
508
|
-
token,
|
|
509
|
-
chatId,
|
|
510
|
-
messageId: sentMessage.message_id,
|
|
511
|
-
responseType,
|
|
512
|
-
options: responseOptions,
|
|
513
|
-
allowedUserIds: (0, question_1.parseUserIds)(options.allowedUserIds),
|
|
514
|
-
expiredNotice,
|
|
515
|
-
...(responseType === 'radio' || responseType === 'checkbox'
|
|
516
|
-
? {
|
|
517
|
-
selection: {
|
|
518
|
-
selectedIndices: [],
|
|
519
|
-
buttonsPerRow: Math.max(1, Math.min(8, buttonsPerRow)),
|
|
520
|
-
submitLabel,
|
|
521
|
-
},
|
|
522
|
-
}
|
|
523
|
-
: {}),
|
|
524
|
-
};
|
|
525
|
-
const acknowledgementText = String((_b = options.acknowledgementText) !== null && _b !== void 0 ? _b : 'Response recorded');
|
|
526
|
-
const removeButtons = options.removeButtons !== false;
|
|
527
|
-
const { wait } = await coordinator.register(transport, pending, waitLimitMs);
|
|
528
|
-
releaseReservation = undefined;
|
|
529
|
-
const matched = await wait;
|
|
530
|
-
if (!matched) {
|
|
531
|
-
if (this.getNodeParameter('onTimeout', 0, 'return') === 'error') {
|
|
532
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No Telegram response received before the wait limit');
|
|
533
|
-
}
|
|
534
|
-
return [
|
|
535
|
-
[
|
|
536
|
-
{
|
|
537
|
-
json: {
|
|
538
|
-
timedOut: true,
|
|
539
|
-
questionMessageId: sentMessage.message_id,
|
|
540
|
-
chat: { id: chatId },
|
|
541
|
-
},
|
|
542
|
-
pairedItem: { item: 0 },
|
|
543
|
-
},
|
|
544
|
-
],
|
|
545
|
-
];
|
|
546
|
-
}
|
|
547
|
-
if (matched.callbackQueryId) {
|
|
548
|
-
await bestEffort(() => (0, shared_1.telegramApiRequest)(this, 'answerCallbackQuery', {
|
|
549
|
-
callback_query_id: matched.callbackQueryId,
|
|
550
|
-
...(acknowledgementText ? { text: acknowledgementText.slice(0, 200) } : {}),
|
|
551
|
-
}));
|
|
552
|
-
if (removeButtons) {
|
|
553
|
-
const chosenLabel = String((_c = matched.response.label) !== null && _c !== void 0 ? _c : '').trim();
|
|
554
|
-
const editBody = {
|
|
555
|
-
chat_id: chatId,
|
|
556
|
-
message_id: sentMessage.message_id,
|
|
557
|
-
reply_markup: { inline_keyboard: [] },
|
|
558
|
-
};
|
|
559
|
-
if (chosenLabel) {
|
|
560
|
-
editBody.text = `${question}\n\n${chosenLabel}`;
|
|
561
|
-
if (parseMode !== 'none')
|
|
562
|
-
editBody.parse_mode = parseMode;
|
|
563
|
-
}
|
|
564
|
-
await bestEffort(() => (0, shared_1.telegramApiRequest)(this, chosenLabel ? 'editMessageText' : 'editMessageReplyMarkup', editBody));
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
else if (acknowledgementText) {
|
|
568
|
-
await bestEffort(() => (0, shared_1.telegramApiRequest)(this, 'sendMessage', {
|
|
569
|
-
chat_id: chatId,
|
|
570
|
-
text: acknowledgementText,
|
|
571
|
-
reply_parameters: { message_id: matched.response.responseMessageId },
|
|
572
|
-
}));
|
|
573
|
-
}
|
|
574
|
-
return [[{ json: { response: matched.response }, pairedItem: { item: 0 } }]];
|
|
575
|
-
}
|
|
576
|
-
catch (error) {
|
|
577
|
-
releaseReservation === null || releaseReservation === void 0 ? void 0 : releaseReservation();
|
|
578
|
-
if (this.continueOnFail()) {
|
|
579
|
-
return [
|
|
580
|
-
[
|
|
581
|
-
{
|
|
582
|
-
json: { error: error instanceof Error ? error.message : String(error) },
|
|
583
|
-
pairedItem: { item: 0 },
|
|
584
|
-
},
|
|
585
|
-
],
|
|
586
|
-
];
|
|
587
|
-
}
|
|
588
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: 0 });
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
const returnData = [];
|
|
592
|
-
for (let itemIndex = 0; itemIndex < inputData.length; itemIndex++) {
|
|
593
|
-
try {
|
|
594
|
-
const chatId = String(this.getNodeParameter('chatId', itemIndex)).trim();
|
|
595
|
-
const text = String(this.getNodeParameter('text', itemIndex)).trim();
|
|
596
|
-
const options = this.getNodeParameter('sendOptions', itemIndex, {});
|
|
597
|
-
if (!chatId || !text) {
|
|
598
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Chat ID and Text are required', {
|
|
599
|
-
itemIndex,
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
const parseMode = String(options.parseMode || 'none');
|
|
603
|
-
const replyToMessageId = Number(options.replyToMessageId || 0);
|
|
604
|
-
const body = {
|
|
605
|
-
chat_id: chatId,
|
|
606
|
-
text,
|
|
607
|
-
disable_notification: options.disableNotification === true,
|
|
608
|
-
};
|
|
609
|
-
if (parseMode !== 'none')
|
|
610
|
-
body.parse_mode = parseMode;
|
|
611
|
-
if (options.disableLinkPreview === true) {
|
|
612
|
-
body.link_preview_options = { is_disabled: true };
|
|
613
|
-
}
|
|
614
|
-
if (replyToMessageId > 0) {
|
|
615
|
-
body.reply_parameters = { message_id: replyToMessageId };
|
|
616
|
-
}
|
|
617
|
-
const sentMessage = await (0, shared_1.telegramApiRequest)(this, 'sendMessage', body);
|
|
618
|
-
returnData.push({
|
|
619
|
-
json: sentMessage,
|
|
620
|
-
pairedItem: { item: itemIndex },
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
catch (error) {
|
|
624
|
-
if (this.continueOnFail()) {
|
|
625
|
-
returnData.push({
|
|
626
|
-
json: { error: error instanceof Error ? error.message : String(error) },
|
|
627
|
-
pairedItem: { item: itemIndex },
|
|
628
|
-
});
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex });
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
return [returnData];
|
|
45
|
+
return (0, actionShared_1.runAction)(this, 'polling');
|
|
635
46
|
}
|
|
636
47
|
}
|
|
637
48
|
exports.TelegramAdvance = TelegramAdvance;
|