@joshuanode/n8n-nodes-teamsbot 0.0.1 → 0.0.3

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,66 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TeamsBot = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  const GenericFunctions_1 = require("./GenericFunctions");
6
+ const operationsUsingServiceUrl = [
7
+ 'addReaction',
8
+ 'createConversation',
9
+ 'createDirectConversation',
10
+ 'deleteActivity',
11
+ 'getConversationDetails',
12
+ 'getConversationMember',
13
+ 'getConversationMembers',
14
+ 'getPagedConversationMembers',
15
+ 'removeReaction',
16
+ 'replyToActivity',
17
+ 'replyWithAdaptiveCard',
18
+ 'sendActivity',
19
+ 'sendAdaptiveCard',
20
+ 'sendFileAttachment',
21
+ 'sendInlineAttachment',
22
+ 'sendTyping',
23
+ 'updateActivity',
24
+ 'updateAdaptiveCard',
25
+ 'upsertReference',
26
+ ];
27
+ const operationsUsingConversationId = [
28
+ 'addReaction',
29
+ 'deleteActivity',
30
+ 'getConversationDetails',
31
+ 'getConversationMember',
32
+ 'getConversationMembers',
33
+ 'getPagedConversationMembers',
34
+ 'removeReaction',
35
+ 'replyToActivity',
36
+ 'replyWithAdaptiveCard',
37
+ 'sendActivity',
38
+ 'sendAdaptiveCard',
39
+ 'sendFileAttachment',
40
+ 'sendInlineAttachment',
41
+ 'sendTyping',
42
+ 'updateActivity',
43
+ 'updateAdaptiveCard',
44
+ 'upsertReference',
45
+ ];
46
+ const operationsUsingActivityId = [
47
+ 'addReaction',
48
+ 'deleteActivity',
49
+ 'removeReaction',
50
+ 'replyToActivity',
51
+ 'replyWithAdaptiveCard',
52
+ 'updateActivity',
53
+ 'updateAdaptiveCard',
54
+ ];
55
+ const operationsSendingMessage = [
56
+ 'replyToActivity',
57
+ 'replyWithAdaptiveCard',
58
+ 'sendActivity',
59
+ 'sendAdaptiveCard',
60
+ 'sendFileAttachment',
61
+ 'sendInlineAttachment',
62
+ 'sendProactiveMessage',
63
+ 'updateActivity',
64
+ 'updateAdaptiveCard',
65
+ ];
6
66
  class TeamsBot {
7
67
  constructor() {
8
68
  this.description = {
@@ -12,7 +72,7 @@ class TeamsBot {
12
72
  group: ['transform'],
13
73
  version: 1,
14
74
  subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
15
- description: 'Use Bot Framework conversation/activity APIs for Microsoft Teams bots',
75
+ description: 'Use Bot Framework conversation and activity APIs for Microsoft Teams bots',
16
76
  defaults: {
17
77
  name: 'Teams Bot',
18
78
  },
@@ -36,10 +96,26 @@ class TeamsBot {
36
96
  name: 'Activity',
37
97
  value: 'activity',
38
98
  },
99
+ {
100
+ name: 'Adaptive Card',
101
+ value: 'adaptiveCard',
102
+ },
103
+ {
104
+ name: 'Attachment',
105
+ value: 'attachment',
106
+ },
39
107
  {
40
108
  name: 'Conversation',
41
109
  value: 'conversation',
42
110
  },
111
+ {
112
+ name: 'Proactive',
113
+ value: 'proactive',
114
+ },
115
+ {
116
+ name: 'Reaction',
117
+ value: 'reaction',
118
+ },
43
119
  ],
44
120
  default: 'activity',
45
121
  },
@@ -82,6 +158,59 @@ class TeamsBot {
82
158
  ],
83
159
  default: 'sendActivity',
84
160
  },
161
+ {
162
+ displayName: 'Operation',
163
+ name: 'operation',
164
+ type: 'options',
165
+ noDataExpression: true,
166
+ displayOptions: {
167
+ show: {
168
+ resource: ['adaptiveCard'],
169
+ },
170
+ },
171
+ options: [
172
+ {
173
+ name: 'Reply With Adaptive Card',
174
+ value: 'replyWithAdaptiveCard',
175
+ action: 'Reply with adaptive card',
176
+ },
177
+ {
178
+ name: 'Send Adaptive Card',
179
+ value: 'sendAdaptiveCard',
180
+ action: 'Send adaptive card',
181
+ },
182
+ {
183
+ name: 'Update Adaptive Card',
184
+ value: 'updateAdaptiveCard',
185
+ action: 'Update adaptive card',
186
+ },
187
+ ],
188
+ default: 'sendAdaptiveCard',
189
+ },
190
+ {
191
+ displayName: 'Operation',
192
+ name: 'operation',
193
+ type: 'options',
194
+ noDataExpression: true,
195
+ displayOptions: {
196
+ show: {
197
+ resource: ['attachment'],
198
+ },
199
+ },
200
+ options: [
201
+ {
202
+ name: 'Send File Attachment',
203
+ value: 'sendFileAttachment',
204
+ action: 'Send file attachment',
205
+ },
206
+ {
207
+ name: 'Send Inline Attachment',
208
+ value: 'sendInlineAttachment',
209
+ action: 'Send inline attachment',
210
+ },
211
+ ],
212
+ default: 'sendFileAttachment',
213
+ },
85
214
  {
86
215
  displayName: 'Operation',
87
216
  name: 'operation',
@@ -98,21 +227,109 @@ class TeamsBot {
98
227
  value: 'createConversation',
99
228
  action: 'Create a conversation',
100
229
  },
230
+ {
231
+ name: 'Create Direct Conversation',
232
+ value: 'createDirectConversation',
233
+ action: 'Create direct conversation',
234
+ },
235
+ {
236
+ name: 'Get Conversation Details',
237
+ value: 'getConversationDetails',
238
+ action: 'Get conversation details',
239
+ },
240
+ {
241
+ name: 'Get Conversation Member',
242
+ value: 'getConversationMember',
243
+ action: 'Get conversation member',
244
+ },
101
245
  {
102
246
  name: 'Get Conversation Members',
103
247
  value: 'getConversationMembers',
104
248
  action: 'Get conversation members',
105
249
  },
250
+ {
251
+ name: 'Get Paged Conversation Members',
252
+ value: 'getPagedConversationMembers',
253
+ action: 'Get paged conversation members',
254
+ },
106
255
  ],
107
256
  default: 'createConversation',
108
257
  },
258
+ {
259
+ displayName: 'Operation',
260
+ name: 'operation',
261
+ type: 'options',
262
+ noDataExpression: true,
263
+ displayOptions: {
264
+ show: {
265
+ resource: ['proactive'],
266
+ },
267
+ },
268
+ options: [
269
+ {
270
+ name: 'Delete Reference',
271
+ value: 'deleteReference',
272
+ action: 'Delete proactive reference',
273
+ },
274
+ {
275
+ name: 'Get Reference',
276
+ value: 'getReference',
277
+ action: 'Get proactive reference',
278
+ },
279
+ {
280
+ name: 'List References',
281
+ value: 'listReferences',
282
+ action: 'List proactive references',
283
+ },
284
+ {
285
+ name: 'Send Proactive Message',
286
+ value: 'sendProactiveMessage',
287
+ action: 'Send proactive message',
288
+ },
289
+ {
290
+ name: 'Upsert Reference',
291
+ value: 'upsertReference',
292
+ action: 'Create or update proactive reference',
293
+ },
294
+ ],
295
+ default: 'listReferences',
296
+ },
297
+ {
298
+ displayName: 'Operation',
299
+ name: 'operation',
300
+ type: 'options',
301
+ noDataExpression: true,
302
+ displayOptions: {
303
+ show: {
304
+ resource: ['reaction'],
305
+ },
306
+ },
307
+ options: [
308
+ {
309
+ name: 'Add Reaction',
310
+ value: 'addReaction',
311
+ action: 'Add reaction to activity',
312
+ },
313
+ {
314
+ name: 'Remove Reaction',
315
+ value: 'removeReaction',
316
+ action: 'Remove reaction from activity',
317
+ },
318
+ ],
319
+ default: 'addReaction',
320
+ },
109
321
  {
110
322
  displayName: 'Service URL',
111
323
  name: 'serviceUrl',
112
324
  type: 'string',
113
325
  default: '',
114
326
  required: true,
115
- description: 'Bot Framework service URL, typically from a trigger activity output field',
327
+ displayOptions: {
328
+ show: {
329
+ operation: operationsUsingServiceUrl,
330
+ },
331
+ },
332
+ description: 'Bot Framework service URL, typically from trigger output',
116
333
  },
117
334
  {
118
335
  displayName: 'Conversation ID',
@@ -122,17 +339,10 @@ class TeamsBot {
122
339
  required: true,
123
340
  displayOptions: {
124
341
  show: {
125
- operation: [
126
- 'deleteActivity',
127
- 'getConversationMembers',
128
- 'replyToActivity',
129
- 'sendActivity',
130
- 'sendTyping',
131
- 'updateActivity',
132
- ],
342
+ operation: operationsUsingConversationId,
133
343
  },
134
344
  },
135
- description: 'Conversation ID, typically from a trigger activity output field',
345
+ description: 'Conversation ID, typically from trigger output',
136
346
  },
137
347
  {
138
348
  displayName: 'Activity ID',
@@ -142,10 +352,10 @@ class TeamsBot {
142
352
  required: true,
143
353
  displayOptions: {
144
354
  show: {
145
- operation: ['replyToActivity', 'updateActivity', 'deleteActivity'],
355
+ operation: operationsUsingActivityId,
146
356
  },
147
357
  },
148
- description: 'Activity ID to reply/update/delete, from trigger output',
358
+ description: 'Activity ID for update, delete, reply, and reaction operations',
149
359
  },
150
360
  {
151
361
  displayName: 'Activity Type',
@@ -153,26 +363,26 @@ class TeamsBot {
153
363
  type: 'options',
154
364
  options: [
155
365
  {
156
- name: 'Message',
157
- value: 'message',
158
- },
159
- {
160
- name: 'Typing',
161
- value: 'typing',
366
+ name: 'End Of Conversation',
367
+ value: 'endOfConversation',
162
368
  },
163
369
  {
164
370
  name: 'Event',
165
371
  value: 'event',
166
372
  },
167
373
  {
168
- name: 'End Of Conversation',
169
- value: 'endOfConversation',
374
+ name: 'Message',
375
+ value: 'message',
376
+ },
377
+ {
378
+ name: 'Typing',
379
+ value: 'typing',
170
380
  },
171
381
  ],
172
382
  default: 'message',
173
383
  displayOptions: {
174
384
  show: {
175
- operation: ['sendActivity', 'replyToActivity', 'updateActivity'],
385
+ operation: ['replyToActivity', 'sendActivity', 'updateActivity'],
176
386
  },
177
387
  },
178
388
  },
@@ -186,11 +396,10 @@ class TeamsBot {
186
396
  default: '',
187
397
  displayOptions: {
188
398
  show: {
189
- operation: ['sendActivity', 'replyToActivity', 'updateActivity'],
190
- activityType: ['message'],
399
+ operation: operationsSendingMessage,
191
400
  },
192
401
  },
193
- description: 'Text content when sending message activities',
402
+ description: 'Text content for message operations',
194
403
  },
195
404
  {
196
405
  displayName: 'Activity JSON',
@@ -202,12 +411,28 @@ class TeamsBot {
202
411
  default: '',
203
412
  displayOptions: {
204
413
  show: {
205
- operation: ['sendActivity', 'replyToActivity', 'updateActivity'],
414
+ operation: ['replyToActivity', 'sendActivity', 'sendProactiveMessage', 'updateActivity'],
206
415
  },
207
416
  },
208
- description: 'Optional raw activity JSON. When set, this overrides Message Text and Additional Fields.',
417
+ description: 'Optional raw activity JSON. When set, this overrides helper fields.',
209
418
  placeholder: '{"type":"message","text":"Hello from n8n"}',
210
419
  },
420
+ {
421
+ displayName: 'Adaptive Card JSON',
422
+ name: 'adaptiveCardJson',
423
+ type: 'string',
424
+ typeOptions: {
425
+ rows: 8,
426
+ },
427
+ default: '',
428
+ required: true,
429
+ displayOptions: {
430
+ show: {
431
+ operation: ['replyWithAdaptiveCard', 'sendAdaptiveCard', 'updateAdaptiveCard'],
432
+ },
433
+ },
434
+ description: 'Adaptive Card JSON content object',
435
+ },
211
436
  {
212
437
  displayName: 'Conversation JSON',
213
438
  name: 'conversationJson',
@@ -225,22 +450,313 @@ class TeamsBot {
225
450
  description: 'Raw JSON payload for POST /v3/conversations',
226
451
  },
227
452
  {
228
- displayName: 'Additional Fields',
453
+ displayName: 'Bot ID',
454
+ name: 'botId',
455
+ type: 'string',
456
+ default: '',
457
+ required: true,
458
+ displayOptions: {
459
+ show: {
460
+ operation: ['createDirectConversation'],
461
+ },
462
+ },
463
+ description: 'Bot identity ID used in direct conversation creation',
464
+ },
465
+ {
466
+ displayName: 'Target Member ID',
467
+ name: 'targetMemberId',
468
+ type: 'string',
469
+ default: '',
470
+ required: true,
471
+ displayOptions: {
472
+ show: {
473
+ operation: ['createDirectConversation'],
474
+ },
475
+ },
476
+ description: 'Teams user ID for direct conversation member',
477
+ },
478
+ {
479
+ displayName: 'Tenant ID',
480
+ name: 'tenantId',
481
+ type: 'string',
482
+ default: '',
483
+ displayOptions: {
484
+ show: {
485
+ operation: ['createDirectConversation'],
486
+ },
487
+ },
488
+ description: 'Optional tenant ID for Teams channelData',
489
+ },
490
+ {
491
+ displayName: 'Member ID',
492
+ name: 'memberId',
493
+ type: 'string',
494
+ default: '',
495
+ required: true,
496
+ displayOptions: {
497
+ show: {
498
+ operation: ['getConversationMember'],
499
+ },
500
+ },
501
+ description: 'Member ID for conversation member lookup',
502
+ },
503
+ {
504
+ displayName: 'Page Size',
505
+ name: 'pageSize',
506
+ type: 'number',
507
+ typeOptions: {
508
+ minValue: 1,
509
+ },
510
+ default: 100,
511
+ displayOptions: {
512
+ show: {
513
+ operation: ['getPagedConversationMembers'],
514
+ },
515
+ },
516
+ description: 'Page size for paged member retrieval',
517
+ },
518
+ {
519
+ displayName: 'Continuation Token',
520
+ name: 'continuationToken',
521
+ type: 'string',
522
+ typeOptions: {
523
+ password: true,
524
+ },
525
+ default: '',
526
+ displayOptions: {
527
+ show: {
528
+ operation: ['getPagedConversationMembers'],
529
+ },
530
+ },
531
+ description: 'Optional continuation token for paged member retrieval',
532
+ },
533
+ {
534
+ displayName: 'Reaction Type',
535
+ name: 'reactionType',
536
+ type: 'string',
537
+ default: 'like',
538
+ required: true,
539
+ displayOptions: {
540
+ show: {
541
+ operation: ['addReaction', 'removeReaction'],
542
+ },
543
+ },
544
+ description: 'Reaction type, for example like, heart, laugh, sad, angry',
545
+ },
546
+ {
547
+ displayName: 'Reference Key',
548
+ name: 'referenceKey',
549
+ type: 'string',
550
+ typeOptions: {
551
+ password: true,
552
+ },
553
+ default: '',
554
+ displayOptions: {
555
+ show: {
556
+ operation: ['deleteReference', 'getReference', 'sendProactiveMessage', 'upsertReference'],
557
+ },
558
+ },
559
+ description: 'Key used for proactive reference operations',
560
+ },
561
+ {
562
+ displayName: 'Reference JSON',
563
+ name: 'referenceJson',
564
+ type: 'string',
565
+ typeOptions: {
566
+ rows: 6,
567
+ },
568
+ default: '',
569
+ displayOptions: {
570
+ show: {
571
+ operation: ['upsertReference'],
572
+ },
573
+ },
574
+ description: 'Optional reference JSON. When set, this overrides service and conversation fields.',
575
+ },
576
+ {
577
+ displayName: 'Attachment Name',
578
+ name: 'attachmentName',
579
+ type: 'string',
580
+ default: '',
581
+ displayOptions: {
582
+ show: {
583
+ operation: ['sendFileAttachment', 'sendInlineAttachment'],
584
+ },
585
+ },
586
+ description: 'Optional attachment file name',
587
+ },
588
+ {
589
+ displayName: 'Attachment Content Type',
590
+ name: 'attachmentContentType',
591
+ type: 'string',
592
+ default: 'application/octet-stream',
593
+ displayOptions: {
594
+ show: {
595
+ operation: ['sendFileAttachment', 'sendInlineAttachment'],
596
+ },
597
+ },
598
+ description: 'Content type for attachment payload',
599
+ },
600
+ {
601
+ displayName: 'Attachment Content URL',
602
+ name: 'attachmentContentUrl',
603
+ type: 'string',
604
+ default: '',
605
+ required: true,
606
+ displayOptions: {
607
+ show: {
608
+ operation: ['sendFileAttachment'],
609
+ },
610
+ },
611
+ description: 'Content URL for file attachment',
612
+ },
613
+ {
614
+ displayName: 'Inline Base64',
615
+ name: 'inlineBase64',
616
+ type: 'string',
617
+ typeOptions: {
618
+ rows: 5,
619
+ },
620
+ default: '',
621
+ displayOptions: {
622
+ show: {
623
+ operation: ['sendInlineAttachment'],
624
+ },
625
+ },
626
+ description: 'Inline base64 content. Leave empty to use binary property data.',
627
+ },
628
+ {
629
+ displayName: 'Binary Property',
630
+ name: 'binaryPropertyName',
631
+ type: 'string',
632
+ default: 'data',
633
+ displayOptions: {
634
+ show: {
635
+ operation: ['sendInlineAttachment'],
636
+ },
637
+ },
638
+ description: 'Binary property name to read base64 data from input binary',
639
+ },
640
+ {
641
+ displayName: 'Mention Options',
642
+ name: 'mentionOptions',
643
+ type: 'collection',
644
+ placeholder: 'Add Option',
645
+ default: {},
646
+ displayOptions: {
647
+ show: {
648
+ operation: operationsSendingMessage,
649
+ },
650
+ },
651
+ options: [
652
+ {
653
+ displayName: 'Auto Mention Sender',
654
+ name: 'autoMentionSender',
655
+ type: 'boolean',
656
+ default: false,
657
+ description: 'Whether to mention sender from trigger input automatically',
658
+ },
659
+ {
660
+ displayName: 'Mention ID',
661
+ name: 'mentionId',
662
+ type: 'string',
663
+ default: '',
664
+ description: 'Optional user ID for mention entity generation',
665
+ },
666
+ {
667
+ displayName: 'Mention Name',
668
+ name: 'mentionName',
669
+ type: 'string',
670
+ default: '',
671
+ description: 'Optional display name for mention entity generation',
672
+ },
673
+ {
674
+ displayName: 'Prepend Mention Text',
675
+ name: 'prependMentionText',
676
+ type: 'boolean',
677
+ default: true,
678
+ description: 'Whether to prepend mention text to outgoing message text',
679
+ },
680
+ ],
681
+ },
682
+ {
683
+ displayName: 'Activity Additional Fields',
229
684
  name: 'additionalFields',
230
685
  type: 'collection',
231
686
  placeholder: 'Add Field',
232
687
  default: {},
233
688
  displayOptions: {
234
689
  show: {
235
- operation: ['sendActivity', 'replyToActivity', 'updateActivity'],
690
+ operation: ['replyToActivity', 'sendActivity', 'updateActivity'],
236
691
  },
237
692
  },
238
693
  options: additionalActivityFields,
239
694
  },
695
+ {
696
+ displayName: 'Execution Options',
697
+ name: 'executionOptions',
698
+ type: 'collection',
699
+ placeholder: 'Add Option',
700
+ default: {},
701
+ options: [
702
+ {
703
+ displayName: 'Debug Output',
704
+ name: 'debugOutput',
705
+ type: 'boolean',
706
+ default: false,
707
+ description: 'Whether to include debug metadata in output',
708
+ },
709
+ {
710
+ displayName: 'Output Mode',
711
+ name: 'outputMode',
712
+ type: 'options',
713
+ options: [
714
+ {
715
+ name: 'Pass Through',
716
+ value: 'passThrough',
717
+ description: 'Preserve incoming item JSON and append Teams Bot fields',
718
+ },
719
+ {
720
+ name: 'Merge',
721
+ value: 'merge',
722
+ description: 'Merge incoming item JSON with Teams Bot output fields',
723
+ },
724
+ {
725
+ name: 'Response Only',
726
+ value: 'responseOnly',
727
+ description: 'Return only Teams Bot output fields',
728
+ },
729
+ ],
730
+ default: 'passThrough',
731
+ description: 'How to shape output data for downstream nodes',
732
+ },
733
+ {
734
+ displayName: 'Retry Count',
735
+ name: 'retryCount',
736
+ type: 'number',
737
+ typeOptions: {
738
+ minValue: 0,
739
+ },
740
+ default: 0,
741
+ description: 'How many retries to attempt for failed API requests',
742
+ },
743
+ {
744
+ displayName: 'Retry Delay MS',
745
+ name: 'retryDelayMs',
746
+ type: 'number',
747
+ typeOptions: {
748
+ minValue: 0,
749
+ },
750
+ default: 1000,
751
+ description: 'Delay in milliseconds between retry attempts',
752
+ },
753
+ ],
754
+ },
240
755
  ],
241
756
  };
242
757
  }
243
758
  async execute() {
759
+ var _a, _b, _c, _d;
244
760
  const items = this.getInputData();
245
761
  const credentials = (await this.getCredentials('teamsBotApi'));
246
762
  const returnData = [];
@@ -248,103 +764,62 @@ class TeamsBot {
248
764
  try {
249
765
  const resource = this.getNodeParameter('resource', itemIndex);
250
766
  const operation = this.getNodeParameter('operation', itemIndex);
251
- const serviceUrl = (0, GenericFunctions_1.trimTrailingSlashes)(this.getNodeParameter('serviceUrl', itemIndex));
252
- let response = {};
253
- let requestPath = '';
254
- let requestMethod = 'POST';
255
- if (resource === 'conversation' && operation === 'createConversation') {
256
- requestPath = '/v3/conversations';
257
- requestMethod = 'POST';
258
- const conversationJson = this.getNodeParameter('conversationJson', itemIndex);
259
- const payload = (0, GenericFunctions_1.parseJsonField)(conversationJson, 'Conversation JSON');
260
- if (!payload || Array.isArray(payload)) {
261
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), '"Conversation JSON" must be a valid JSON object.', { itemIndex });
262
- }
263
- response = await GenericFunctions_1.botFrameworkRequest.call(this, credentials, requestMethod, serviceUrl, requestPath, payload);
767
+ const executionOptions = this.getNodeParameter('executionOptions', itemIndex, {});
768
+ const retryCount = Number((_a = executionOptions.retryCount) !== null && _a !== void 0 ? _a : 0);
769
+ const retryDelayMs = Number((_b = executionOptions.retryDelayMs) !== null && _b !== void 0 ? _b : 1000);
770
+ const debugOutput = Boolean((_c = executionOptions.debugOutput) !== null && _c !== void 0 ? _c : false);
771
+ const outputMode = String((_d = executionOptions.outputMode) !== null && _d !== void 0 ? _d : 'passThrough');
772
+ const result = await executeOperation(this, itemIndex, resource, operation, credentials, retryCount, retryDelayMs);
773
+ const output = {
774
+ resource,
775
+ operation,
776
+ method: result.requestMethod,
777
+ path: result.requestPath,
778
+ response: result.response,
779
+ };
780
+ if (debugOutput) {
781
+ output.debug = {
782
+ attempts: result.attempts,
783
+ retryCount,
784
+ retryDelayMs,
785
+ referenceStoreSize: Object.keys(getReferenceStore(this)).length,
786
+ };
787
+ }
788
+ let outputJson;
789
+ if (outputMode === 'responseOnly') {
790
+ outputJson = output;
791
+ }
792
+ else if (outputMode === 'merge') {
793
+ outputJson = {
794
+ ...items[itemIndex].json,
795
+ ...output,
796
+ };
264
797
  }
265
798
  else {
266
- const conversationId = this.getNodeParameter('conversationId', itemIndex);
267
- if (!conversationId.trim()) {
268
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), '"Conversation ID" is required.', {
269
- itemIndex,
270
- });
271
- }
272
- const encodedConversationId = encodeURIComponent(conversationId);
273
- const basePath = `/v3/conversations/${encodedConversationId}`;
274
- if (resource === 'activity') {
275
- switch (operation) {
276
- case 'sendActivity':
277
- requestPath = `${basePath}/activities`;
278
- requestMethod = 'POST';
279
- response = await GenericFunctions_1.botFrameworkRequest.call(this, credentials, requestMethod, serviceUrl, requestPath, buildActivityPayload(this, itemIndex));
280
- break;
281
- case 'replyToActivity': {
282
- const activityId = this.getNodeParameter('activityId', itemIndex);
283
- requestPath = `${basePath}/activities/${encodeURIComponent(activityId)}`;
284
- requestMethod = 'POST';
285
- response = await GenericFunctions_1.botFrameworkRequest.call(this, credentials, requestMethod, serviceUrl, requestPath, buildActivityPayload(this, itemIndex));
286
- break;
287
- }
288
- case 'updateActivity': {
289
- const activityId = this.getNodeParameter('activityId', itemIndex);
290
- requestPath = `${basePath}/activities/${encodeURIComponent(activityId)}`;
291
- requestMethod = 'PUT';
292
- response = await GenericFunctions_1.botFrameworkRequest.call(this, credentials, requestMethod, serviceUrl, requestPath, buildActivityPayload(this, itemIndex));
293
- break;
294
- }
295
- case 'deleteActivity': {
296
- const activityId = this.getNodeParameter('activityId', itemIndex);
297
- requestPath = `${basePath}/activities/${encodeURIComponent(activityId)}`;
298
- requestMethod = 'DELETE';
299
- response = await GenericFunctions_1.botFrameworkRequest.call(this, credentials, requestMethod, serviceUrl, requestPath);
300
- break;
301
- }
302
- case 'sendTyping':
303
- requestPath = `${basePath}/activities`;
304
- requestMethod = 'POST';
305
- response = await GenericFunctions_1.botFrameworkRequest.call(this, credentials, requestMethod, serviceUrl, requestPath, { type: 'typing' });
306
- break;
307
- default:
308
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported activity operation: ${operation}`, {
309
- itemIndex,
310
- });
311
- }
312
- }
313
- else if (resource === 'conversation') {
314
- switch (operation) {
315
- case 'getConversationMembers':
316
- requestPath = `${basePath}/members`;
317
- requestMethod = 'GET';
318
- response = await GenericFunctions_1.botFrameworkRequest.call(this, credentials, requestMethod, serviceUrl, requestPath);
319
- break;
320
- default:
321
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported conversation operation: ${operation}`, {
322
- itemIndex,
323
- });
324
- }
325
- }
326
- else {
327
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported resource: ${resource}`, {
328
- itemIndex,
329
- });
799
+ outputJson = {
800
+ ...items[itemIndex].json,
801
+ teamsBotResponse: result.response,
802
+ teamsBotMeta: {
803
+ resource,
804
+ operation,
805
+ method: result.requestMethod,
806
+ path: result.requestPath,
807
+ },
808
+ };
809
+ if (debugOutput && output.debug) {
810
+ outputJson.teamsBotDebug = output.debug;
330
811
  }
331
812
  }
332
- returnData.push({
333
- json: {
334
- resource,
335
- operation,
336
- serviceUrl,
337
- path: requestPath,
338
- method: requestMethod,
339
- response,
340
- },
341
- pairedItem: itemIndex,
342
- });
813
+ returnData.push({ json: outputJson, pairedItem: itemIndex });
343
814
  }
344
815
  catch (error) {
345
816
  if (this.continueOnFail()) {
346
817
  returnData.push({
347
- json: items[itemIndex].json,
818
+ json: {
819
+ ...items[itemIndex].json,
820
+ errorMessage: error.message,
821
+ errorType: error.name,
822
+ },
348
823
  error: error,
349
824
  pairedItem: itemIndex,
350
825
  });
@@ -358,27 +833,6 @@ class TeamsBot {
358
833
  }
359
834
  exports.TeamsBot = TeamsBot;
360
835
  const additionalActivityFields = [
361
- {
362
- displayName: 'Text Format',
363
- name: 'textFormat',
364
- type: 'options',
365
- options: [
366
- {
367
- name: 'Plain',
368
- value: 'plain',
369
- },
370
- {
371
- name: 'Markdown',
372
- value: 'markdown',
373
- },
374
- {
375
- name: 'XML/HTML',
376
- value: 'xml',
377
- },
378
- ],
379
- default: 'plain',
380
- description: 'Optional text format for message activities',
381
- },
382
836
  {
383
837
  displayName: 'Attachments',
384
838
  name: 'attachments',
@@ -391,24 +845,24 @@ const additionalActivityFields = [
391
845
  placeholder: '[{"contentType":"application/vnd.microsoft.card.adaptive","content":{}}]',
392
846
  },
393
847
  {
394
- displayName: 'Entities',
395
- name: 'entities',
848
+ displayName: 'Channel Data',
849
+ name: 'channelData',
396
850
  type: 'string',
397
851
  typeOptions: {
398
852
  rows: 4,
399
853
  },
400
854
  default: '',
401
- description: 'JSON array of entities (for example mentions)',
855
+ description: 'JSON object for Teams-specific channel data',
402
856
  },
403
857
  {
404
- displayName: 'Channel Data',
405
- name: 'channelData',
858
+ displayName: 'Entities',
859
+ name: 'entities',
406
860
  type: 'string',
407
861
  typeOptions: {
408
862
  rows: 4,
409
863
  },
410
864
  default: '',
411
- description: 'JSON object for Teams-specific channel data',
865
+ description: 'JSON array of entities (for example mentions)',
412
866
  },
413
867
  {
414
868
  displayName: 'Suggested Actions',
@@ -420,17 +874,420 @@ const additionalActivityFields = [
420
874
  default: '',
421
875
  description: 'JSON object containing suggested actions',
422
876
  },
877
+ {
878
+ displayName: 'Text Format',
879
+ name: 'textFormat',
880
+ type: 'options',
881
+ options: [
882
+ {
883
+ name: 'Markdown',
884
+ value: 'markdown',
885
+ },
886
+ {
887
+ name: 'Plain',
888
+ value: 'plain',
889
+ },
890
+ {
891
+ name: 'XML/HTML',
892
+ value: 'xml',
893
+ },
894
+ ],
895
+ default: 'plain',
896
+ description: 'Optional text format for message activities',
897
+ },
423
898
  ];
899
+ async function executeOperation(ctx, itemIndex, resource, operation, credentials, retryCount, retryDelayMs) {
900
+ if (resource === 'activity') {
901
+ return await executeActivityOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs);
902
+ }
903
+ if (resource === 'adaptiveCard') {
904
+ return await executeAdaptiveCardOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs);
905
+ }
906
+ if (resource === 'attachment') {
907
+ return await executeAttachmentOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs);
908
+ }
909
+ if (resource === 'conversation') {
910
+ return await executeConversationOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs);
911
+ }
912
+ if (resource === 'proactive') {
913
+ return await executeProactiveOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs);
914
+ }
915
+ if (resource === 'reaction') {
916
+ return await executeReactionOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs);
917
+ }
918
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Unsupported resource: ${resource}`, { itemIndex });
919
+ }
920
+ async function executeActivityOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs) {
921
+ const serviceUrl = getRequiredServiceUrl(ctx, itemIndex);
922
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
923
+ const basePath = `/v3/conversations/${encodeURIComponent(conversationId)}`;
924
+ if (operation === 'sendActivity') {
925
+ const payload = buildActivityPayload(ctx, itemIndex);
926
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `${basePath}/activities`, payload, retryCount, retryDelayMs);
927
+ }
928
+ if (operation === 'replyToActivity') {
929
+ const activityId = getRequiredActivityId(ctx, itemIndex);
930
+ const payload = buildActivityPayload(ctx, itemIndex);
931
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `${basePath}/activities/${encodeURIComponent(activityId)}`, payload, retryCount, retryDelayMs);
932
+ }
933
+ if (operation === 'updateActivity') {
934
+ const activityId = getRequiredActivityId(ctx, itemIndex);
935
+ const payload = buildActivityPayload(ctx, itemIndex);
936
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'PUT', `${basePath}/activities/${encodeURIComponent(activityId)}`, payload, retryCount, retryDelayMs);
937
+ }
938
+ if (operation === 'deleteActivity') {
939
+ const activityId = getRequiredActivityId(ctx, itemIndex);
940
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'DELETE', `${basePath}/activities/${encodeURIComponent(activityId)}`, undefined, retryCount, retryDelayMs);
941
+ }
942
+ if (operation === 'sendTyping') {
943
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `${basePath}/activities`, { type: 'typing' }, retryCount, retryDelayMs);
944
+ }
945
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Unsupported activity operation: ${operation}`, {
946
+ itemIndex,
947
+ });
948
+ }
949
+ async function executeAdaptiveCardOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs) {
950
+ const serviceUrl = getRequiredServiceUrl(ctx, itemIndex);
951
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
952
+ const basePath = `/v3/conversations/${encodeURIComponent(conversationId)}`;
953
+ const payload = buildAdaptiveCardActivity(ctx, itemIndex);
954
+ if (operation === 'sendAdaptiveCard') {
955
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `${basePath}/activities`, payload, retryCount, retryDelayMs);
956
+ }
957
+ if (operation === 'replyWithAdaptiveCard') {
958
+ const activityId = getRequiredActivityId(ctx, itemIndex);
959
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `${basePath}/activities/${encodeURIComponent(activityId)}`, payload, retryCount, retryDelayMs);
960
+ }
961
+ if (operation === 'updateAdaptiveCard') {
962
+ const activityId = getRequiredActivityId(ctx, itemIndex);
963
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'PUT', `${basePath}/activities/${encodeURIComponent(activityId)}`, payload, retryCount, retryDelayMs);
964
+ }
965
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Unsupported adaptive card operation: ${operation}`, {
966
+ itemIndex,
967
+ });
968
+ }
969
+ async function executeAttachmentOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs) {
970
+ var _a;
971
+ const serviceUrl = getRequiredServiceUrl(ctx, itemIndex);
972
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
973
+ const basePath = `/v3/conversations/${encodeURIComponent(conversationId)}`;
974
+ const messageText = ctx.getNodeParameter('messageText', itemIndex, '');
975
+ const contentType = ctx.getNodeParameter('attachmentContentType', itemIndex);
976
+ const name = ctx.getNodeParameter('attachmentName', itemIndex, '');
977
+ if (operation === 'sendFileAttachment') {
978
+ const contentUrl = ctx.getNodeParameter('attachmentContentUrl', itemIndex);
979
+ const payload = applyMentionOptions(ctx, itemIndex, {
980
+ type: 'message',
981
+ text: messageText,
982
+ attachments: [
983
+ {
984
+ contentType,
985
+ contentUrl,
986
+ name,
987
+ },
988
+ ],
989
+ });
990
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `${basePath}/activities`, payload, retryCount, retryDelayMs);
991
+ }
992
+ if (operation === 'sendInlineAttachment') {
993
+ const binaryPropertyName = ctx.getNodeParameter('binaryPropertyName', itemIndex, 'data');
994
+ const binaryData = (0, GenericFunctions_1.toDataObject)(ctx.getInputData(itemIndex)[0].binary);
995
+ const inlineBase64 = (_a = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('inlineBase64', itemIndex, ''))) !== null && _a !== void 0 ? _a : (0, GenericFunctions_1.normalizeString)((0, GenericFunctions_1.toDataObject)(binaryData[binaryPropertyName]).data);
996
+ if (!inlineBase64) {
997
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Inline base64 data is required. Provide Inline Base64 or binary property data.', { itemIndex });
998
+ }
999
+ const payload = applyMentionOptions(ctx, itemIndex, {
1000
+ type: 'message',
1001
+ text: messageText,
1002
+ attachments: [
1003
+ {
1004
+ contentType,
1005
+ contentUrl: `data:${contentType};base64,${inlineBase64}`,
1006
+ name,
1007
+ },
1008
+ ],
1009
+ });
1010
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `${basePath}/activities`, payload, retryCount, retryDelayMs);
1011
+ }
1012
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Unsupported attachment operation: ${operation}`, {
1013
+ itemIndex,
1014
+ });
1015
+ }
1016
+ async function executeConversationOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs) {
1017
+ const serviceUrl = getRequiredServiceUrl(ctx, itemIndex);
1018
+ if (operation === 'createConversation') {
1019
+ const conversationJson = ctx.getNodeParameter('conversationJson', itemIndex);
1020
+ const payload = (0, GenericFunctions_1.parseJsonField)(conversationJson, 'Conversation JSON');
1021
+ if (!payload || Array.isArray(payload)) {
1022
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Conversation JSON" must be a valid JSON object.', {
1023
+ itemIndex,
1024
+ });
1025
+ }
1026
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', '/v3/conversations', payload, retryCount, retryDelayMs);
1027
+ }
1028
+ if (operation === 'createDirectConversation') {
1029
+ const botId = ctx.getNodeParameter('botId', itemIndex);
1030
+ const targetMemberId = ctx.getNodeParameter('targetMemberId', itemIndex);
1031
+ const tenantId = ctx.getNodeParameter('tenantId', itemIndex, '');
1032
+ const payload = {
1033
+ isGroup: false,
1034
+ bot: { id: botId },
1035
+ members: [{ id: targetMemberId }],
1036
+ };
1037
+ if (tenantId.trim()) {
1038
+ payload.channelData = {
1039
+ tenant: {
1040
+ id: tenantId,
1041
+ },
1042
+ };
1043
+ }
1044
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', '/v3/conversations', payload, retryCount, retryDelayMs);
1045
+ }
1046
+ if (operation === 'getConversationDetails') {
1047
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
1048
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'GET', `/v3/conversations/${encodeURIComponent(conversationId)}`, undefined, retryCount, retryDelayMs);
1049
+ }
1050
+ if (operation === 'getConversationMembers') {
1051
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
1052
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'GET', `/v3/conversations/${encodeURIComponent(conversationId)}/members`, undefined, retryCount, retryDelayMs);
1053
+ }
1054
+ if (operation === 'getConversationMember') {
1055
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
1056
+ const memberId = ctx.getNodeParameter('memberId', itemIndex);
1057
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'GET', `/v3/conversations/${encodeURIComponent(conversationId)}/members/${encodeURIComponent(memberId)}`, undefined, retryCount, retryDelayMs);
1058
+ }
1059
+ if (operation === 'getPagedConversationMembers') {
1060
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
1061
+ const pageSize = ctx.getNodeParameter('pageSize', itemIndex);
1062
+ const continuationToken = ctx.getNodeParameter('continuationToken', itemIndex, '');
1063
+ const query = new URLSearchParams({ pageSize: String(pageSize) });
1064
+ if (continuationToken.trim()) {
1065
+ query.append('continuationToken', continuationToken.trim());
1066
+ }
1067
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'GET', `/v3/conversations/${encodeURIComponent(conversationId)}/pagedmembers?${query.toString()}`, undefined, retryCount, retryDelayMs);
1068
+ }
1069
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Unsupported conversation operation: ${operation}`, {
1070
+ itemIndex,
1071
+ });
1072
+ }
1073
+ async function executeProactiveOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs) {
1074
+ const store = getReferenceStore(ctx);
1075
+ if (operation === 'listReferences') {
1076
+ return {
1077
+ response: {
1078
+ count: Object.keys(store).length,
1079
+ references: Object.values(store),
1080
+ },
1081
+ requestMethod: 'LOCAL',
1082
+ requestPath: 'proactive://references',
1083
+ attempts: 1,
1084
+ };
1085
+ }
1086
+ if (operation === 'getReference') {
1087
+ const key = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('referenceKey', itemIndex, ''));
1088
+ if (!key) {
1089
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Reference Key is required for Get Reference.', {
1090
+ itemIndex,
1091
+ });
1092
+ }
1093
+ return {
1094
+ response: {
1095
+ key,
1096
+ reference: (0, GenericFunctions_1.toDataObject)(store[key]),
1097
+ },
1098
+ requestMethod: 'LOCAL',
1099
+ requestPath: `proactive://references/${key}`,
1100
+ attempts: 1,
1101
+ };
1102
+ }
1103
+ if (operation === 'deleteReference') {
1104
+ const key = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('referenceKey', itemIndex, ''));
1105
+ if (!key) {
1106
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Reference Key is required for Delete Reference.', {
1107
+ itemIndex,
1108
+ });
1109
+ }
1110
+ const existed = !!store[key];
1111
+ delete store[key];
1112
+ return {
1113
+ response: {
1114
+ deleted: existed,
1115
+ key,
1116
+ },
1117
+ requestMethod: 'LOCAL',
1118
+ requestPath: `proactive://references/${key}`,
1119
+ attempts: 1,
1120
+ };
1121
+ }
1122
+ if (operation === 'upsertReference') {
1123
+ const key = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('referenceKey', itemIndex, ''));
1124
+ if (!key) {
1125
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Reference Key is required for Upsert Reference.', {
1126
+ itemIndex,
1127
+ });
1128
+ }
1129
+ const referenceJson = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('referenceJson', itemIndex, ''));
1130
+ let reference;
1131
+ if (referenceJson) {
1132
+ const parsed = (0, GenericFunctions_1.parseJsonField)(referenceJson, 'Reference JSON');
1133
+ if (!parsed || Array.isArray(parsed)) {
1134
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Reference JSON" must be a valid JSON object.', {
1135
+ itemIndex,
1136
+ });
1137
+ }
1138
+ reference = {
1139
+ key,
1140
+ ...parsed,
1141
+ lastSeenAt: new Date().toISOString(),
1142
+ };
1143
+ }
1144
+ else {
1145
+ const serviceUrl = getRequiredServiceUrl(ctx, itemIndex);
1146
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
1147
+ reference = {
1148
+ key,
1149
+ serviceUrl,
1150
+ conversation: {
1151
+ id: conversationId,
1152
+ },
1153
+ lastSeenAt: new Date().toISOString(),
1154
+ };
1155
+ }
1156
+ store[key] = reference;
1157
+ return {
1158
+ response: {
1159
+ key,
1160
+ reference,
1161
+ },
1162
+ requestMethod: 'LOCAL',
1163
+ requestPath: `proactive://references/${key}`,
1164
+ attempts: 1,
1165
+ };
1166
+ }
1167
+ if (operation === 'sendProactiveMessage') {
1168
+ const key = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('referenceKey', itemIndex, ''));
1169
+ if (!key) {
1170
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Reference Key is required for Send Proactive Message.', {
1171
+ itemIndex,
1172
+ });
1173
+ }
1174
+ const reference = (0, GenericFunctions_1.toDataObject)(store[key]);
1175
+ const serviceUrl = (0, GenericFunctions_1.normalizeString)(reference.serviceUrl);
1176
+ const conversationId = (0, GenericFunctions_1.normalizeString)((0, GenericFunctions_1.toDataObject)(reference.conversation).id);
1177
+ if (!serviceUrl || !conversationId) {
1178
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Stored reference "${key}" is missing service URL or conversation ID.`, { itemIndex });
1179
+ }
1180
+ const activityJson = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('activityJson', itemIndex, ''));
1181
+ let payload;
1182
+ if (activityJson) {
1183
+ const parsed = (0, GenericFunctions_1.parseJsonField)(activityJson, 'Activity JSON');
1184
+ if (!parsed || Array.isArray(parsed)) {
1185
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Activity JSON" must be a valid JSON object.', {
1186
+ itemIndex,
1187
+ });
1188
+ }
1189
+ payload = parsed;
1190
+ }
1191
+ else {
1192
+ payload = {
1193
+ type: 'message',
1194
+ text: ctx.getNodeParameter('messageText', itemIndex, ''),
1195
+ };
1196
+ }
1197
+ payload = applyMentionOptions(ctx, itemIndex, payload);
1198
+ const result = await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', `/v3/conversations/${encodeURIComponent(conversationId)}/activities`, payload, retryCount, retryDelayMs);
1199
+ reference.lastSeenAt = new Date().toISOString();
1200
+ store[key] = reference;
1201
+ return result;
1202
+ }
1203
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Unsupported proactive operation: ${operation}`, {
1204
+ itemIndex,
1205
+ });
1206
+ }
1207
+ async function executeReactionOperation(ctx, itemIndex, operation, credentials, retryCount, retryDelayMs) {
1208
+ const serviceUrl = getRequiredServiceUrl(ctx, itemIndex);
1209
+ const conversationId = getRequiredConversationId(ctx, itemIndex);
1210
+ const activityId = getRequiredActivityId(ctx, itemIndex);
1211
+ const reactionType = ctx.getNodeParameter('reactionType', itemIndex);
1212
+ const basePath = `/v3/conversations/${encodeURIComponent(conversationId)}/activities/${encodeURIComponent(activityId)}/reactions`;
1213
+ if (operation === 'addReaction') {
1214
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'POST', basePath, { type: reactionType }, retryCount, retryDelayMs);
1215
+ }
1216
+ if (operation === 'removeReaction') {
1217
+ return await executeRequestWithRetry(ctx, credentials, serviceUrl, 'DELETE', `${basePath}/${encodeURIComponent(reactionType)}`, undefined, retryCount, retryDelayMs);
1218
+ }
1219
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Unsupported reaction operation: ${operation}`, {
1220
+ itemIndex,
1221
+ });
1222
+ }
1223
+ function getRequiredActivityId(ctx, itemIndex) {
1224
+ const value = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('activityId', itemIndex));
1225
+ if (!value) {
1226
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Activity ID is required.', { itemIndex });
1227
+ }
1228
+ return value;
1229
+ }
1230
+ function getRequiredConversationId(ctx, itemIndex) {
1231
+ const value = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('conversationId', itemIndex));
1232
+ if (!value) {
1233
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Conversation ID is required.', { itemIndex });
1234
+ }
1235
+ return value;
1236
+ }
1237
+ function getRequiredServiceUrl(ctx, itemIndex) {
1238
+ const value = (0, GenericFunctions_1.trimTrailingSlashes)(ctx.getNodeParameter('serviceUrl', itemIndex));
1239
+ if (!value) {
1240
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Service URL is required.', { itemIndex });
1241
+ }
1242
+ return value;
1243
+ }
1244
+ async function executeRequestWithRetry(ctx, credentials, serviceUrl, method, path, body, retryCount, retryDelayMs) {
1245
+ var _a;
1246
+ const retries = Math.max(0, retryCount);
1247
+ const delayMs = Math.max(0, retryDelayMs);
1248
+ let attempts = 0;
1249
+ let lastError;
1250
+ for (let attempt = 0; attempt <= retries; attempt++) {
1251
+ attempts = attempt + 1;
1252
+ try {
1253
+ const response = await GenericFunctions_1.botFrameworkRequest.call(ctx, credentials, method, serviceUrl, path, body);
1254
+ return {
1255
+ response,
1256
+ requestMethod: method,
1257
+ requestPath: path,
1258
+ attempts,
1259
+ };
1260
+ }
1261
+ catch (error) {
1262
+ lastError = error;
1263
+ if (attempt >= retries) {
1264
+ break;
1265
+ }
1266
+ if (delayMs > 0) {
1267
+ await sleep(delayMs);
1268
+ }
1269
+ }
1270
+ }
1271
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Request failed after ${attempts} attempt(s): ${(_a = lastError === null || lastError === void 0 ? void 0 : lastError.message) !== null && _a !== void 0 ? _a : 'unknown error'}`, {
1272
+ description: `Method: ${method}, Path: ${path}`,
1273
+ });
1274
+ }
1275
+ async function sleep(ms) {
1276
+ const end = Date.now() + ms;
1277
+ while (Date.now() < end) {
1278
+ await Promise.resolve();
1279
+ }
1280
+ }
424
1281
  function buildActivityPayload(ctx, itemIndex) {
425
- const activityJson = ctx.getNodeParameter('activityJson', itemIndex);
426
- if (activityJson.trim()) {
1282
+ const activityJson = (0, GenericFunctions_1.normalizeString)(ctx.getNodeParameter('activityJson', itemIndex, ''));
1283
+ if (activityJson) {
427
1284
  const parsed = (0, GenericFunctions_1.parseJsonField)(activityJson, 'Activity JSON');
428
1285
  if (!parsed || Array.isArray(parsed)) {
429
1286
  throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Activity JSON" must be a valid JSON object.', {
430
1287
  itemIndex,
431
1288
  });
432
1289
  }
433
- return parsed;
1290
+ return applyMentionOptions(ctx, itemIndex, parsed);
434
1291
  }
435
1292
  const activityType = ctx.getNodeParameter('activityType', itemIndex);
436
1293
  const additionalFields = ctx.getNodeParameter('additionalFields', itemIndex, {});
@@ -443,35 +1300,41 @@ function buildActivityPayload(ctx, itemIndex) {
443
1300
  payload.text = messageText;
444
1301
  }
445
1302
  }
446
- const textFormat = additionalFields.textFormat;
1303
+ const textFormat = (0, GenericFunctions_1.normalizeString)(additionalFields.textFormat);
447
1304
  if (textFormat) {
448
1305
  payload.textFormat = textFormat;
449
1306
  }
450
- const attachmentsJson = additionalFields.attachments;
1307
+ const attachmentsJson = (0, GenericFunctions_1.normalizeString)(additionalFields.attachments);
451
1308
  if (attachmentsJson) {
452
1309
  const attachments = (0, GenericFunctions_1.parseJsonField)(attachmentsJson, 'Attachments');
453
1310
  if (!attachments || !Array.isArray(attachments)) {
454
- throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Attachments" must be a valid JSON array when provided.', { itemIndex });
1311
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Attachments" must be a valid JSON array when provided.', {
1312
+ itemIndex,
1313
+ });
455
1314
  }
456
1315
  payload.attachments = attachments;
457
1316
  }
458
- const entitiesJson = additionalFields.entities;
1317
+ const entitiesJson = (0, GenericFunctions_1.normalizeString)(additionalFields.entities);
459
1318
  if (entitiesJson) {
460
1319
  const entities = (0, GenericFunctions_1.parseJsonField)(entitiesJson, 'Entities');
461
1320
  if (!entities || !Array.isArray(entities)) {
462
- throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Entities" must be a valid JSON array when provided.', { itemIndex });
1321
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Entities" must be a valid JSON array when provided.', {
1322
+ itemIndex,
1323
+ });
463
1324
  }
464
1325
  payload.entities = entities;
465
1326
  }
466
- const channelDataJson = additionalFields.channelData;
1327
+ const channelDataJson = (0, GenericFunctions_1.normalizeString)(additionalFields.channelData);
467
1328
  if (channelDataJson) {
468
1329
  const channelData = (0, GenericFunctions_1.parseJsonField)(channelDataJson, 'Channel Data');
469
1330
  if (!channelData || Array.isArray(channelData)) {
470
- throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Channel Data" must be a valid JSON object when provided.', { itemIndex });
1331
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Channel Data" must be a valid JSON object when provided.', {
1332
+ itemIndex,
1333
+ });
471
1334
  }
472
1335
  payload.channelData = channelData;
473
1336
  }
474
- const suggestedActionsJson = additionalFields.suggestedActions;
1337
+ const suggestedActionsJson = (0, GenericFunctions_1.normalizeString)(additionalFields.suggestedActions);
475
1338
  if (suggestedActionsJson) {
476
1339
  const suggestedActions = (0, GenericFunctions_1.parseJsonField)(suggestedActionsJson, 'Suggested Actions');
477
1340
  if (!suggestedActions || Array.isArray(suggestedActions)) {
@@ -479,6 +1342,69 @@ function buildActivityPayload(ctx, itemIndex) {
479
1342
  }
480
1343
  payload.suggestedActions = suggestedActions;
481
1344
  }
1345
+ return applyMentionOptions(ctx, itemIndex, payload);
1346
+ }
1347
+ function buildAdaptiveCardActivity(ctx, itemIndex) {
1348
+ const cardJson = ctx.getNodeParameter('adaptiveCardJson', itemIndex);
1349
+ const parsed = (0, GenericFunctions_1.parseJsonField)(cardJson, 'Adaptive Card JSON');
1350
+ if (!parsed || Array.isArray(parsed)) {
1351
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), '"Adaptive Card JSON" must be a valid JSON object.', {
1352
+ itemIndex,
1353
+ });
1354
+ }
1355
+ const messageText = ctx.getNodeParameter('messageText', itemIndex, '');
1356
+ return applyMentionOptions(ctx, itemIndex, {
1357
+ type: 'message',
1358
+ text: messageText,
1359
+ attachments: [
1360
+ {
1361
+ contentType: 'application/vnd.microsoft.card.adaptive',
1362
+ content: parsed,
1363
+ },
1364
+ ],
1365
+ });
1366
+ }
1367
+ function applyMentionOptions(ctx, itemIndex, payload) {
1368
+ var _a, _b, _c, _d, _e, _f;
1369
+ const mentionOptions = ctx.getNodeParameter('mentionOptions', itemIndex, {});
1370
+ const autoMentionSender = Boolean((_a = mentionOptions.autoMentionSender) !== null && _a !== void 0 ? _a : false);
1371
+ const prependMentionText = Boolean((_b = mentionOptions.prependMentionText) !== null && _b !== void 0 ? _b : true);
1372
+ let mentionId = (0, GenericFunctions_1.normalizeString)(mentionOptions.mentionId);
1373
+ let mentionName = (0, GenericFunctions_1.normalizeString)(mentionOptions.mentionName);
1374
+ if (autoMentionSender) {
1375
+ const itemJson = (_d = (_c = ctx.getInputData(itemIndex)[0]) === null || _c === void 0 ? void 0 : _c.json) !== null && _d !== void 0 ? _d : {};
1376
+ const from = (0, GenericFunctions_1.toDataObject)(itemJson.from);
1377
+ mentionId = (_e = (0, GenericFunctions_1.normalizeString)(from.id)) !== null && _e !== void 0 ? _e : mentionId;
1378
+ mentionName = (_f = (0, GenericFunctions_1.normalizeString)(from.name)) !== null && _f !== void 0 ? _f : mentionName;
1379
+ }
1380
+ if (!mentionId || !mentionName) {
1381
+ return payload;
1382
+ }
1383
+ const mentionText = `<at>${mentionName}</at>`;
1384
+ const mentionEntity = {
1385
+ type: 'mention',
1386
+ mentioned: {
1387
+ id: mentionId,
1388
+ name: mentionName,
1389
+ },
1390
+ text: mentionText,
1391
+ };
1392
+ const existingEntities = Array.isArray(payload.entities) ? payload.entities : [];
1393
+ payload.entities = [...existingEntities, mentionEntity];
1394
+ const currentText = (0, GenericFunctions_1.normalizeString)(payload.text);
1395
+ if (prependMentionText) {
1396
+ payload.text = currentText ? `${mentionText} ${currentText}` : mentionText;
1397
+ }
482
1398
  return payload;
483
1399
  }
1400
+ function getReferenceStore(ctx) {
1401
+ const staticData = ctx.getWorkflowStaticData('global');
1402
+ if (!staticData[GenericFunctions_1.CONVERSATION_REFERENCE_STORE_KEY] ||
1403
+ typeof staticData[GenericFunctions_1.CONVERSATION_REFERENCE_STORE_KEY] !== 'object') {
1404
+ staticData[GenericFunctions_1.CONVERSATION_REFERENCE_STORE_KEY] = {};
1405
+ }
1406
+ const store = (0, GenericFunctions_1.toDataObject)(staticData[GenericFunctions_1.CONVERSATION_REFERENCE_STORE_KEY]);
1407
+ staticData[GenericFunctions_1.CONVERSATION_REFERENCE_STORE_KEY] = store;
1408
+ return store;
1409
+ }
484
1410
  //# sourceMappingURL=TeamsBot.node.js.map