@wesell/n8n-nodes-confirmx 0.1.0

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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/credentials/ConfirmXApi.credentials.d.ts +18 -0
  4. package/credentials/ConfirmXApi.credentials.js +31 -0
  5. package/credentials/ConfirmXApi.credentials.js.map +1 -0
  6. package/credentials/ConfirmXApi.credentials.ts +40 -0
  7. package/index.d.ts +14 -0
  8. package/index.js +26 -0
  9. package/nodes/ConfirmX/ConfirmXAccount.node.d.ts +5 -0
  10. package/nodes/ConfirmX/ConfirmXAccount.node.js +81 -0
  11. package/nodes/ConfirmX/ConfirmXAccount.node.js.map +1 -0
  12. package/nodes/ConfirmX/ConfirmXAccount.node.ts +81 -0
  13. package/nodes/ConfirmX/ConfirmXConversation.node.d.ts +13 -0
  14. package/nodes/ConfirmX/ConfirmXConversation.node.js +266 -0
  15. package/nodes/ConfirmX/ConfirmXConversation.node.js.map +1 -0
  16. package/nodes/ConfirmX/ConfirmXConversation.node.ts +263 -0
  17. package/nodes/ConfirmX/ConfirmXMessage.node.d.ts +13 -0
  18. package/nodes/ConfirmX/ConfirmXMessage.node.js +364 -0
  19. package/nodes/ConfirmX/ConfirmXMessage.node.js.map +1 -0
  20. package/nodes/ConfirmX/ConfirmXMessage.node.ts +361 -0
  21. package/nodes/ConfirmX/ConfirmXShippingZone.node.d.ts +5 -0
  22. package/nodes/ConfirmX/ConfirmXShippingZone.node.js +100 -0
  23. package/nodes/ConfirmX/ConfirmXShippingZone.node.js.map +1 -0
  24. package/nodes/ConfirmX/ConfirmXShippingZone.node.ts +103 -0
  25. package/nodes/ConfirmX/ConfirmXTemplate.node.d.ts +13 -0
  26. package/nodes/ConfirmX/ConfirmXTemplate.node.js +310 -0
  27. package/nodes/ConfirmX/ConfirmXTemplate.node.js.map +1 -0
  28. package/nodes/ConfirmX/ConfirmXTemplate.node.ts +310 -0
  29. package/nodes/ConfirmX/ConfirmXTrigger.node.d.ts +29 -0
  30. package/nodes/ConfirmX/ConfirmXTrigger.node.js +190 -0
  31. package/nodes/ConfirmX/ConfirmXTrigger.node.js.map +1 -0
  32. package/nodes/ConfirmX/ConfirmXTrigger.node.ts +245 -0
  33. package/nodes/ConfirmX/ConfirmXWebhook.node.d.ts +5 -0
  34. package/nodes/ConfirmX/ConfirmXWebhook.node.js +169 -0
  35. package/nodes/ConfirmX/ConfirmXWebhook.node.js.map +1 -0
  36. package/nodes/ConfirmX/ConfirmXWebhook.node.ts +163 -0
  37. package/nodes/ConfirmX/confirmx.svg +4 -0
  38. package/package.json +69 -0
  39. package/transports/http.d.ts +43 -0
  40. package/transports/http.js +117 -0
  41. package/transports/http.js.map +1 -0
  42. package/transports/http.ts +170 -0
  43. package/transports/signature.d.ts +21 -0
  44. package/transports/signature.js +50 -0
  45. package/transports/signature.js.map +1 -0
  46. package/transports/signature.ts +55 -0
  47. package/types/api.d.ts +199 -0
  48. package/types/api.js +21 -0
  49. package/types/api.js.map +1 -0
  50. package/types/api.ts +238 -0
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfirmXConversation = void 0;
4
+ const http_1 = require("../../transports/http");
5
+ class ConfirmXConversation {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: 'ConfirmX Conversation',
9
+ name: 'confirmXConversation',
10
+ icon: 'file:confirmx.svg',
11
+ group: ['transform'],
12
+ version: 1,
13
+ subtitle: '={{$parameter["operation"]}}',
14
+ description: 'Read and manage WhatsApp conversations: list, view, mark read, change status, assign to a teammate.',
15
+ defaults: { name: 'ConfirmX Conversation' },
16
+ inputs: ['main'],
17
+ outputs: ['main'],
18
+ credentials: [{ name: 'confirmXApi', required: true }],
19
+ properties: [
20
+ {
21
+ displayName: 'Operation',
22
+ name: 'operation',
23
+ type: 'options',
24
+ noDataExpression: true,
25
+ options: [
26
+ {
27
+ name: 'List',
28
+ value: 'list',
29
+ action: 'List conversations',
30
+ description: 'List recent WhatsApp conversations for the org. Use to discover open conversations, find a conversation by contact phone or name, or check unread counts. Supports `status` filter (open/resolved/archived), free-text `q` search, and tag CSV. Returns up to 100 per page with `messages[0]` as the latest preview.',
31
+ },
32
+ {
33
+ name: 'Get',
34
+ value: 'get',
35
+ action: 'Get conversation',
36
+ description: 'Fetch a single conversation by id. Use when you already have a `conversationId` (from a webhook, from List, or from an upstream node) and need the contact, account, and latest message. Requires `conversationId`.',
37
+ },
38
+ {
39
+ name: 'Mark Read',
40
+ value: 'markRead',
41
+ action: 'Mark as read',
42
+ description: 'Zero the unread counter on a conversation. Use after a human or AI finishes handling the thread so the badge clears. Requires `conversationId`.',
43
+ },
44
+ {
45
+ name: 'Update Status',
46
+ value: 'updateStatus',
47
+ action: 'Update status',
48
+ description: 'Set a conversation\'s status (`open`, `resolved`, `archived`). Use `resolved` when the issue is closed and `archived` to remove from default views. Requires `conversationId` and `status`.',
49
+ },
50
+ {
51
+ name: 'Assign',
52
+ value: 'assign',
53
+ action: 'Assign to user',
54
+ description: 'Assign a conversation to a teammate by `assignToUserId` (or pass `null` to unassign). Requires `conversationId`. Returns the updated conversation with the `assignedTo` relation.',
55
+ },
56
+ ],
57
+ default: 'list',
58
+ },
59
+ // --- Account (optional for list, not needed for the others) ---
60
+ {
61
+ displayName: 'Account',
62
+ name: 'accountId',
63
+ type: 'resourceLocator',
64
+ default: { mode: 'list', value: '' },
65
+ displayOptions: { show: { operation: ['list'] } },
66
+ modes: [
67
+ { displayName: 'From List', name: 'list', type: 'list', typeOptions: { searchable: true } },
68
+ { displayName: 'By ID', name: 'id', type: 'string' },
69
+ ],
70
+ typeOptions: { loadOptionsMethod: 'getAccounts' },
71
+ description: 'Restrict list to one WhatsApp account (optional — leave empty for org-wide)',
72
+ },
73
+ // --- List filters ---
74
+ {
75
+ displayName: 'Status',
76
+ name: 'status',
77
+ type: 'options',
78
+ default: '',
79
+ options: [
80
+ { name: 'All', value: '' },
81
+ { name: 'Open', value: 'open' },
82
+ { name: 'Resolved', value: 'resolved' },
83
+ { name: 'Archived', value: 'archived' },
84
+ ],
85
+ displayOptions: { show: { operation: ['list'] } },
86
+ },
87
+ {
88
+ displayName: 'Search',
89
+ name: 'q',
90
+ type: 'string',
91
+ default: '',
92
+ displayOptions: { show: { operation: ['list'] } },
93
+ description: 'Free-text search over contact phone + name + last message body',
94
+ },
95
+ {
96
+ displayName: 'Sort By',
97
+ name: 'sortBy',
98
+ type: 'options',
99
+ default: 'lastMessageAt',
100
+ options: [
101
+ { name: 'Last Message At', value: 'lastMessageAt' },
102
+ { name: 'Unread Count', value: 'unreadCount' },
103
+ { name: 'Created At', value: 'createdAt' },
104
+ ],
105
+ displayOptions: { show: { operation: ['list'] } },
106
+ },
107
+ {
108
+ displayName: 'Sort Order',
109
+ name: 'sortOrder',
110
+ type: 'options',
111
+ default: 'desc',
112
+ options: [
113
+ { name: 'Descending', value: 'desc' },
114
+ { name: 'Ascending', value: 'asc' },
115
+ ],
116
+ displayOptions: { show: { operation: ['list'] } },
117
+ },
118
+ {
119
+ displayName: 'Page',
120
+ name: 'page',
121
+ type: 'number',
122
+ default: 1,
123
+ typeOptions: { minValue: 1 },
124
+ displayOptions: { show: { operation: ['list'] } },
125
+ },
126
+ {
127
+ displayName: 'Return All',
128
+ name: 'returnAll',
129
+ type: 'boolean',
130
+ default: false,
131
+ displayOptions: { show: { operation: ['list'] } },
132
+ },
133
+ {
134
+ displayName: 'Limit',
135
+ name: 'limit',
136
+ type: 'number',
137
+ default: 30,
138
+ typeOptions: { minValue: 1, maxValue: 100 },
139
+ displayOptions: { show: { operation: ['list'], returnAll: [false] } },
140
+ },
141
+ // --- Conversation ID (get / markRead / updateStatus / assign) ---
142
+ {
143
+ displayName: 'Conversation ID',
144
+ name: 'conversationId',
145
+ type: 'string',
146
+ default: '',
147
+ required: true,
148
+ displayOptions: { show: { operation: ['get', 'markRead', 'updateStatus', 'assign'] } },
149
+ },
150
+ // --- Update Status ---
151
+ {
152
+ displayName: 'Status',
153
+ name: 'newStatus',
154
+ type: 'options',
155
+ default: 'open',
156
+ options: [
157
+ { name: 'Open', value: 'open' },
158
+ { name: 'Resolved', value: 'resolved' },
159
+ { name: 'Archived', value: 'archived' },
160
+ ],
161
+ displayOptions: { show: { operation: ['updateStatus'] } },
162
+ },
163
+ // --- Assign ---
164
+ {
165
+ displayName: 'Assign To User ID',
166
+ name: 'assignToUserId',
167
+ type: 'string',
168
+ default: '',
169
+ displayOptions: { show: { operation: ['assign'] } },
170
+ description: 'User ID to assign to. Leave empty or pass "null" (string) to unassign.',
171
+ },
172
+ ],
173
+ usableAsTool: true,
174
+ };
175
+ this.methods = {
176
+ loadOptions: {
177
+ async getAccounts() {
178
+ return await (0, http_1.loadAccountOptions)(this);
179
+ },
180
+ },
181
+ };
182
+ }
183
+ async execute() {
184
+ const items = this.getInputData();
185
+ const returnData = [];
186
+ const resolveAccountId = (i) => {
187
+ const v = this.getNodeParameter('accountId', i, '');
188
+ if (!v)
189
+ return undefined;
190
+ return typeof v === 'string' ? v : v?.value;
191
+ };
192
+ for (let i = 0; i < items.length; i++) {
193
+ const operation = this.getNodeParameter('operation', i);
194
+ if (operation === 'list') {
195
+ const qs = {};
196
+ const accountId = resolveAccountId(i);
197
+ if (accountId)
198
+ qs.accountId = accountId;
199
+ const status = this.getNodeParameter('status', i, '');
200
+ if (status)
201
+ qs.status = status;
202
+ const q = this.getNodeParameter('q', i, '').trim();
203
+ if (q)
204
+ qs.q = q;
205
+ qs.sortBy = this.getNodeParameter('sortBy', i);
206
+ qs.sortOrder = this.getNodeParameter('sortOrder', i);
207
+ const returnAll = this.getNodeParameter('returnAll', i);
208
+ const limit = this.getNodeParameter('limit', i) || 30;
209
+ qs.limit = returnAll ? 100 : limit;
210
+ qs.page = this.getNodeParameter('page', i);
211
+ const res = await (0, http_1.confirmxApiRequest)(this, {
212
+ method: 'GET',
213
+ endpoint: '/conversations',
214
+ qs,
215
+ });
216
+ const list = res.conversations || [];
217
+ const sliced = returnAll ? list : list.slice(0, limit);
218
+ returnData.push(...sliced.map((c) => ({ json: c })));
219
+ }
220
+ else if (operation === 'get') {
221
+ const id = this.getNodeParameter('conversationId', i);
222
+ const res = await (0, http_1.confirmxApiRequest)(this, {
223
+ method: 'GET',
224
+ endpoint: `/conversations/${id}`,
225
+ });
226
+ returnData.push({ json: res.conversation });
227
+ }
228
+ else if (operation === 'markRead') {
229
+ const id = this.getNodeParameter('conversationId', i);
230
+ const res = await (0, http_1.confirmxApiRequest)(this, {
231
+ method: 'POST',
232
+ endpoint: `/conversations/${id}/read`,
233
+ });
234
+ returnData.push({ json: { conversationId: id, ...res } });
235
+ }
236
+ else if (operation === 'updateStatus') {
237
+ const id = this.getNodeParameter('conversationId', i);
238
+ const status = this.getNodeParameter('newStatus', i);
239
+ const res = await (0, http_1.confirmxApiRequest)(this, {
240
+ method: 'PATCH',
241
+ endpoint: `/conversations/${id}/status`,
242
+ body: { status },
243
+ });
244
+ returnData.push({ json: res.conversation });
245
+ }
246
+ else if (operation === 'assign') {
247
+ const id = this.getNodeParameter('conversationId', i);
248
+ let raw = this.getNodeParameter('assignToUserId', i, '').trim();
249
+ let assignToUserId;
250
+ if (!raw || raw.toLowerCase() === 'null')
251
+ assignToUserId = null;
252
+ else
253
+ assignToUserId = raw;
254
+ const res = await (0, http_1.confirmxApiRequest)(this, {
255
+ method: 'PATCH',
256
+ endpoint: `/conversations/${id}/assign`,
257
+ body: { assignToUserId },
258
+ });
259
+ returnData.push({ json: res.conversation });
260
+ }
261
+ }
262
+ return [returnData];
263
+ }
264
+ }
265
+ exports.ConfirmXConversation = ConfirmXConversation;
266
+ //# sourceMappingURL=ConfirmXConversation.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmXConversation.node.js","sourceRoot":"","sources":["ConfirmXConversation.node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,263 @@
1
+ import type { INodeType, INodeTypeDescription } from 'n8n-workflow'
2
+ import { confirmxApiRequest, loadAccountOptions } from '../../transports/http'
3
+
4
+ export class ConfirmXConversation implements INodeType {
5
+ description: INodeTypeDescription = {
6
+ displayName: 'ConfirmX Conversation',
7
+ name: 'confirmXConversation',
8
+ icon: 'file:confirmx.svg',
9
+ group: ['transform'],
10
+ version: 1,
11
+ subtitle: '={{$parameter["operation"]}}',
12
+ description:
13
+ 'Read and manage WhatsApp conversations: list, view, mark read, change status, assign to a teammate.',
14
+ defaults: { name: 'ConfirmX Conversation' },
15
+ inputs: ['main'],
16
+ outputs: ['main'],
17
+ credentials: [{ name: 'confirmXApi', required: true }],
18
+ properties: [
19
+ {
20
+ displayName: 'Operation',
21
+ name: 'operation',
22
+ type: 'options',
23
+ noDataExpression: true,
24
+ options: [
25
+ {
26
+ name: 'List',
27
+ value: 'list',
28
+ action: 'List conversations',
29
+ description:
30
+ 'List recent WhatsApp conversations for the org. Use to discover open conversations, find a conversation by contact phone or name, or check unread counts. Supports `status` filter (open/resolved/archived), free-text `q` search, and tag CSV. Returns up to 100 per page with `messages[0]` as the latest preview.',
31
+ },
32
+ {
33
+ name: 'Get',
34
+ value: 'get',
35
+ action: 'Get conversation',
36
+ description:
37
+ 'Fetch a single conversation by id. Use when you already have a `conversationId` (from a webhook, from List, or from an upstream node) and need the contact, account, and latest message. Requires `conversationId`.',
38
+ },
39
+ {
40
+ name: 'Mark Read',
41
+ value: 'markRead',
42
+ action: 'Mark as read',
43
+ description:
44
+ 'Zero the unread counter on a conversation. Use after a human or AI finishes handling the thread so the badge clears. Requires `conversationId`.',
45
+ },
46
+ {
47
+ name: 'Update Status',
48
+ value: 'updateStatus',
49
+ action: 'Update status',
50
+ description:
51
+ 'Set a conversation\'s status (`open`, `resolved`, `archived`). Use `resolved` when the issue is closed and `archived` to remove from default views. Requires `conversationId` and `status`.',
52
+ },
53
+ {
54
+ name: 'Assign',
55
+ value: 'assign',
56
+ action: 'Assign to user',
57
+ description:
58
+ 'Assign a conversation to a teammate by `assignToUserId` (or pass `null` to unassign). Requires `conversationId`. Returns the updated conversation with the `assignedTo` relation.',
59
+ },
60
+ ],
61
+ default: 'list',
62
+ },
63
+ // --- Account (optional for list, not needed for the others) ---
64
+ {
65
+ displayName: 'Account',
66
+ name: 'accountId',
67
+ type: 'resourceLocator',
68
+ default: { mode: 'list', value: '' },
69
+ displayOptions: { show: { operation: ['list'] } },
70
+ modes: [
71
+ { displayName: 'From List', name: 'list', type: 'list', typeOptions: { searchable: true } },
72
+ { displayName: 'By ID', name: 'id', type: 'string' },
73
+ ],
74
+ typeOptions: { loadOptionsMethod: 'getAccounts' },
75
+ description: 'Restrict list to one WhatsApp account (optional — leave empty for org-wide)',
76
+ },
77
+ // --- List filters ---
78
+ {
79
+ displayName: 'Status',
80
+ name: 'status',
81
+ type: 'options',
82
+ default: '',
83
+ options: [
84
+ { name: 'All', value: '' },
85
+ { name: 'Open', value: 'open' },
86
+ { name: 'Resolved', value: 'resolved' },
87
+ { name: 'Archived', value: 'archived' },
88
+ ],
89
+ displayOptions: { show: { operation: ['list'] } },
90
+ },
91
+ {
92
+ displayName: 'Search',
93
+ name: 'q',
94
+ type: 'string',
95
+ default: '',
96
+ displayOptions: { show: { operation: ['list'] } },
97
+ description: 'Free-text search over contact phone + name + last message body',
98
+ },
99
+ {
100
+ displayName: 'Sort By',
101
+ name: 'sortBy',
102
+ type: 'options',
103
+ default: 'lastMessageAt',
104
+ options: [
105
+ { name: 'Last Message At', value: 'lastMessageAt' },
106
+ { name: 'Unread Count', value: 'unreadCount' },
107
+ { name: 'Created At', value: 'createdAt' },
108
+ ],
109
+ displayOptions: { show: { operation: ['list'] } },
110
+ },
111
+ {
112
+ displayName: 'Sort Order',
113
+ name: 'sortOrder',
114
+ type: 'options',
115
+ default: 'desc',
116
+ options: [
117
+ { name: 'Descending', value: 'desc' },
118
+ { name: 'Ascending', value: 'asc' },
119
+ ],
120
+ displayOptions: { show: { operation: ['list'] } },
121
+ },
122
+ {
123
+ displayName: 'Page',
124
+ name: 'page',
125
+ type: 'number',
126
+ default: 1,
127
+ typeOptions: { minValue: 1 },
128
+ displayOptions: { show: { operation: ['list'] } },
129
+ },
130
+ {
131
+ displayName: 'Return All',
132
+ name: 'returnAll',
133
+ type: 'boolean',
134
+ default: false,
135
+ displayOptions: { show: { operation: ['list'] } },
136
+ },
137
+ {
138
+ displayName: 'Limit',
139
+ name: 'limit',
140
+ type: 'number',
141
+ default: 30,
142
+ typeOptions: { minValue: 1, maxValue: 100 },
143
+ displayOptions: { show: { operation: ['list'], returnAll: [false] } },
144
+ },
145
+ // --- Conversation ID (get / markRead / updateStatus / assign) ---
146
+ {
147
+ displayName: 'Conversation ID',
148
+ name: 'conversationId',
149
+ type: 'string',
150
+ default: '',
151
+ required: true,
152
+ displayOptions: { show: { operation: ['get', 'markRead', 'updateStatus', 'assign'] } },
153
+ },
154
+ // --- Update Status ---
155
+ {
156
+ displayName: 'Status',
157
+ name: 'newStatus',
158
+ type: 'options',
159
+ default: 'open',
160
+ options: [
161
+ { name: 'Open', value: 'open' },
162
+ { name: 'Resolved', value: 'resolved' },
163
+ { name: 'Archived', value: 'archived' },
164
+ ],
165
+ displayOptions: { show: { operation: ['updateStatus'] } },
166
+ },
167
+ // --- Assign ---
168
+ {
169
+ displayName: 'Assign To User ID',
170
+ name: 'assignToUserId',
171
+ type: 'string',
172
+ default: '',
173
+ displayOptions: { show: { operation: ['assign'] } },
174
+ description: 'User ID to assign to. Leave empty or pass "null" (string) to unassign.',
175
+ },
176
+ ],
177
+ usableAsTool: true,
178
+ }
179
+
180
+ methods = {
181
+ loadOptions: {
182
+ async getAccounts(this: any) {
183
+ return await loadAccountOptions(this)
184
+ },
185
+ },
186
+ }
187
+
188
+ async execute(this: any) {
189
+ const items = this.getInputData()
190
+ const returnData: any[] = []
191
+ const resolveAccountId = (i: number) => {
192
+ const v = this.getNodeParameter('accountId', i, '') as any
193
+ if (!v) return undefined
194
+ return typeof v === 'string' ? v : v?.value
195
+ }
196
+
197
+ for (let i = 0; i < items.length; i++) {
198
+ const operation = this.getNodeParameter('operation', i) as string
199
+
200
+ if (operation === 'list') {
201
+ const qs: Record<string, any> = {}
202
+ const accountId = resolveAccountId(i)
203
+ if (accountId) qs.accountId = accountId
204
+ const status = this.getNodeParameter('status', i, '') as string
205
+ if (status) qs.status = status
206
+ const q = (this.getNodeParameter('q', i, '') as string).trim()
207
+ if (q) qs.q = q
208
+ qs.sortBy = this.getNodeParameter('sortBy', i) as string
209
+ qs.sortOrder = this.getNodeParameter('sortOrder', i) as string
210
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean
211
+ const limit = (this.getNodeParameter('limit', i) as number) || 30
212
+ qs.limit = returnAll ? 100 : limit
213
+ qs.page = this.getNodeParameter('page', i) as number
214
+
215
+ const res = await confirmxApiRequest<{ conversations: any[] }>(this, {
216
+ method: 'GET',
217
+ endpoint: '/conversations',
218
+ qs,
219
+ })
220
+ const list = res.conversations || []
221
+ const sliced = returnAll ? list : list.slice(0, limit)
222
+ returnData.push(...sliced.map((c) => ({ json: c })))
223
+ } else if (operation === 'get') {
224
+ const id = this.getNodeParameter('conversationId', i) as string
225
+ const res = await confirmxApiRequest<{ conversation: any }>(this, {
226
+ method: 'GET',
227
+ endpoint: `/conversations/${id}`,
228
+ })
229
+ returnData.push({ json: res.conversation })
230
+ } else if (operation === 'markRead') {
231
+ const id = this.getNodeParameter('conversationId', i) as string
232
+ const res = await confirmxApiRequest<any>(this, {
233
+ method: 'POST',
234
+ endpoint: `/conversations/${id}/read`,
235
+ })
236
+ returnData.push({ json: { conversationId: id, ...res } })
237
+ } else if (operation === 'updateStatus') {
238
+ const id = this.getNodeParameter('conversationId', i) as string
239
+ const status = this.getNodeParameter('newStatus', i) as string
240
+ const res = await confirmxApiRequest<{ conversation: any }>(this, {
241
+ method: 'PATCH',
242
+ endpoint: `/conversations/${id}/status`,
243
+ body: { status },
244
+ })
245
+ returnData.push({ json: res.conversation })
246
+ } else if (operation === 'assign') {
247
+ const id = this.getNodeParameter('conversationId', i) as string
248
+ let raw = (this.getNodeParameter('assignToUserId', i, '') as string).trim()
249
+ let assignToUserId: string | null
250
+ if (!raw || raw.toLowerCase() === 'null') assignToUserId = null
251
+ else assignToUserId = raw
252
+ const res = await confirmxApiRequest<{ conversation: any }>(this, {
253
+ method: 'PATCH',
254
+ endpoint: `/conversations/${id}/assign`,
255
+ body: { assignToUserId },
256
+ })
257
+ returnData.push({ json: res.conversation })
258
+ }
259
+ }
260
+
261
+ return [returnData]
262
+ }
263
+ }
@@ -0,0 +1,13 @@
1
+ import type { INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class ConfirmXMessage implements INodeType {
3
+ description: INodeTypeDescription;
4
+ methods: {
5
+ loadOptions: {
6
+ getAccounts(this: any): Promise<{
7
+ name: string;
8
+ value: string;
9
+ }[]>;
10
+ };
11
+ };
12
+ execute(this: any): Promise<any[][]>;
13
+ }