@jep182/n8n-nodes-whatsthat 0.5.1 → 0.5.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jep182/n8n-nodes-whatsthat",
3
- "version": "0.5.1",
3
+ "version": "0.5.4",
4
4
  "description": "n8n community nodes with embedded Baileys runtime for multi-session chat automation",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "package.json"
29
29
  ],
30
30
  "scripts": {
31
- "build": "tsc -p tsconfig.json && mkdir -p dist/nodes/WhatsThatSession && cp nodes/WhatsThatSession/whatsthat.svg dist/nodes/WhatsThatSession/whatsthat.svg",
31
+ "build": "rm -rf dist && tsc -p tsconfig.json && mkdir -p dist/nodes/WhatsThatSession && cp nodes/WhatsThatSession/whatsthat.svg dist/nodes/WhatsThatSession/whatsthat.svg",
32
32
  "prepublishOnly": "pnpm build"
33
33
  },
34
34
  "peerDependencies": {
@@ -1,10 +0,0 @@
1
- import type { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
- export declare class WhatsThat implements INodeType {
3
- methods: {
4
- loadOptions: {
5
- getLinkedAliases(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
6
- };
7
- };
8
- description: INodeTypeDescription;
9
- execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
10
- }
@@ -1,647 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WhatsThat = void 0;
4
- const n8n_workflow_1 = require("n8n-workflow");
5
- const access_1 = require("../../shared/access");
6
- const runtime_1 = require("../../shared/runtime");
7
- const validation_1 = require("../../shared/validation");
8
- function buildPayload(context, itemIndex) {
9
- const messageType = context.getNodeParameter('messageType', itemIndex);
10
- const sendMessageTo = context.getNodeParameter('sendMessageTo', itemIndex);
11
- const deliveryMode = context.getNodeParameter('deliveryMode', itemIndex, 'native');
12
- const payload = {
13
- sessionId: (0, validation_1.requireSessionId)(context.getNodeParameter('sessionId', itemIndex)),
14
- type: messageType,
15
- };
16
- if (sendMessageTo === 'linkedChat') {
17
- payload.channelAlias = context.getNodeParameter('linkedAlias', itemIndex);
18
- }
19
- else if (sendMessageTo === 'jid') {
20
- payload.jid = context.getNodeParameter('jid', itemIndex);
21
- }
22
- else if (sendMessageTo === 'number') {
23
- payload.phoneNumber = (0, validation_1.requireWhatsappNumber)(context.getNodeParameter('phoneNumber', itemIndex));
24
- }
25
- else if (sendMessageTo === 'yourself') {
26
- payload.sendToSelf = true;
27
- }
28
- payload.message = context.getNodeParameter('message', itemIndex, '');
29
- payload.replyToMessageId = context.getNodeParameter('replyToMessageId', itemIndex, '');
30
- if (['image', 'video', 'audio', 'document'].includes(messageType)) {
31
- payload.mediaUrl = context.getNodeParameter('mediaUrl', itemIndex);
32
- payload.mimetype = context.getNodeParameter('mimetype', itemIndex, '');
33
- payload.fileName = context.getNodeParameter('fileName', itemIndex, '');
34
- }
35
- if (['image', 'video'].includes(messageType)) {
36
- payload.sendAsDocument = deliveryMode === 'document';
37
- }
38
- if (['image', 'video', 'document'].includes(messageType)) {
39
- payload.caption = context.getNodeParameter('caption', itemIndex, '');
40
- }
41
- if (messageType === 'reaction') {
42
- payload.reactionText = context.getNodeParameter('reactionText', itemIndex, '👍');
43
- }
44
- if (messageType === 'location') {
45
- payload.location = {
46
- degreesLatitude: context.getNodeParameter('latitude', itemIndex),
47
- degreesLongitude: context.getNodeParameter('longitude', itemIndex),
48
- name: context.getNodeParameter('locationName', itemIndex, ''),
49
- address: context.getNodeParameter('locationAddress', itemIndex, ''),
50
- };
51
- }
52
- if (messageType === 'contact') {
53
- payload.contact = {
54
- displayName: context.getNodeParameter('contactName', itemIndex),
55
- vcard: context.getNodeParameter('contactVcard', itemIndex),
56
- };
57
- }
58
- if (messageType === 'poll') {
59
- const raw = context.getNodeParameter('pollOptions', itemIndex);
60
- payload.poll = {
61
- name: context.getNodeParameter('pollName', itemIndex),
62
- values: raw.split(',').map((value) => value.trim()).filter(Boolean),
63
- selectableCount: context.getNodeParameter('pollSelectableCount', itemIndex, 1),
64
- };
65
- }
66
- return payload;
67
- }
68
- function formatSessionOutput(value) {
69
- if (Array.isArray(value)) {
70
- return value.map((item) => formatSessionOutput(item));
71
- }
72
- if (!value || typeof value !== 'object') {
73
- return value;
74
- }
75
- const record = value;
76
- if (!('sessionId' in record) || !('status' in record)) {
77
- return value;
78
- }
79
- return {
80
- qrCodeUrl: record.qrCodeUrl,
81
- sessionId: record.sessionId,
82
- status: record.status,
83
- pairingCode: record.pairingCode,
84
- qr: record.qr,
85
- qrDataUrl: record.qrDataUrl,
86
- phone: record.phone,
87
- label: record.label,
88
- phoneNumberForPairing: record.phoneNumberForPairing,
89
- lastDisconnectReason: record.lastDisconnectReason,
90
- createdAt: record.createdAt,
91
- updatedAt: record.updatedAt,
92
- lastSeenAt: record.lastSeenAt,
93
- };
94
- }
95
- class WhatsThat {
96
- constructor() {
97
- this.methods = {
98
- loadOptions: {
99
- async getLinkedAliases() {
100
- const access = await (0, access_1.buildAccess)(this);
101
- const sessionId = (0, validation_1.requireSessionId)(this.getNodeParameter('sessionId'));
102
- const linked = await runtime_1.registry.listLinkedTargets(access, sessionId);
103
- return linked.map((item) => ({
104
- name: `${item.alias} (${item.displayName})`,
105
- value: item.alias,
106
- }));
107
- },
108
- },
109
- };
110
- this.description = {
111
- displayName: 'WhatsThat',
112
- name: 'whatsThat',
113
- icon: 'file:../WhatsThatSession/whatsthat.svg',
114
- group: ['transform'],
115
- version: 1,
116
- description: 'Manage sessions, chat links, and messages for WhatsThat',
117
- defaults: { name: 'WhatsThat' },
118
- inputs: ['main'],
119
- outputs: ['main'],
120
- credentials: [{ name: 'whatsThatRuntime', required: true }],
121
- properties: [
122
- {
123
- displayName: 'Resource',
124
- name: 'resource',
125
- type: 'options',
126
- default: 'session',
127
- noDataExpression: true,
128
- options: [
129
- { name: 'Session', value: 'session' },
130
- { name: 'Linked Chat', value: 'linkChat' },
131
- { name: 'Send Message', value: 'sendMessage' },
132
- ],
133
- },
134
- {
135
- displayName: 'Operation',
136
- name: 'sessionOperation',
137
- type: 'options',
138
- default: 'connect',
139
- displayOptions: {
140
- show: { resource: ['session'] },
141
- },
142
- options: [
143
- { name: 'Connect Session', value: 'connect' },
144
- { name: 'Wait Until Connect', value: 'ensure' },
145
- { name: 'List Sessions', value: 'list' },
146
- { name: 'Get Session', value: 'status' },
147
- { name: 'Disconnect Session', value: 'disconnect' },
148
- { name: 'Remove Session', value: 'remove' },
149
- ],
150
- },
151
- {
152
- displayName: 'Operation',
153
- name: 'linkChatOperation',
154
- type: 'options',
155
- default: 'listDiscovered',
156
- displayOptions: {
157
- show: { resource: ['linkChat'] },
158
- },
159
- options: [
160
- { name: 'List Discovered Chats', value: 'listDiscovered' },
161
- { name: 'List Linked Chats', value: 'listLinked' },
162
- { name: 'Link Chat', value: 'link' },
163
- { name: 'Unlink Chat', value: 'unlink' },
164
- ],
165
- },
166
- {
167
- displayName: 'Session Name',
168
- name: 'sessionId',
169
- type: 'string',
170
- default: '',
171
- required: true,
172
- description: 'Required unique ID for this session. Use a stable internal value such as "main-phone" or "support-team".',
173
- displayOptions: {
174
- hide: {
175
- resource: ['session'],
176
- sessionOperation: ['list'],
177
- },
178
- },
179
- },
180
- {
181
- displayName: 'Display Name',
182
- name: 'label',
183
- type: 'string',
184
- default: '',
185
- description: 'Human-readable name shown in results. Example: "Luca personal phone" or "Support number".',
186
- displayOptions: {
187
- show: {
188
- resource: ['session'],
189
- sessionOperation: ['connect'],
190
- },
191
- },
192
- },
193
- {
194
- displayName: 'WhatsApp Number',
195
- name: 'phoneNumberForPairing',
196
- type: 'string',
197
- default: '',
198
- description: 'Optional. Full phone number with country code, digits only, without 00 or +. Example: 393331234567.',
199
- displayOptions: {
200
- show: {
201
- resource: ['session'],
202
- sessionOperation: ['connect'],
203
- },
204
- },
205
- },
206
- {
207
- displayName: 'Timeout Seconds',
208
- name: 'timeoutSeconds',
209
- type: 'number',
210
- default: 300,
211
- typeOptions: {
212
- minValue: 1,
213
- },
214
- description: 'Maximum time to wait before returning the latest known session status.',
215
- displayOptions: {
216
- show: {
217
- resource: ['session'],
218
- sessionOperation: ['ensure'],
219
- },
220
- },
221
- },
222
- {
223
- displayName: 'Chat JID',
224
- name: 'linkJid',
225
- type: 'string',
226
- default: '',
227
- description: 'The raw WhatsApp JID to link. Usually taken from List Discovered Chats.',
228
- displayOptions: {
229
- show: {
230
- resource: ['linkChat'],
231
- linkChatOperation: ['link'],
232
- },
233
- },
234
- },
235
- {
236
- displayName: 'Linked Chat',
237
- name: 'linkAlias',
238
- type: 'string',
239
- default: '',
240
- description: 'Friendly name you will use later when sending messages by alias.',
241
- displayOptions: {
242
- show: {
243
- resource: ['linkChat'],
244
- linkChatOperation: ['link', 'unlink'],
245
- },
246
- },
247
- },
248
- {
249
- displayName: 'Send Message To',
250
- name: 'sendMessageTo',
251
- type: 'options',
252
- default: 'linkedChat',
253
- description: 'Choose how to resolve the destination chat.',
254
- options: [
255
- { name: 'Linked Chat', value: 'linkedChat' },
256
- { name: 'WhatsApp Number', value: 'number' },
257
- { name: 'Raw JID', value: 'jid' },
258
- { name: 'Yourself', value: 'yourself' },
259
- ],
260
- displayOptions: {
261
- show: { resource: ['sendMessage'] },
262
- },
263
- },
264
- {
265
- displayName: 'Linked Chat',
266
- name: 'linkedAlias',
267
- type: 'options',
268
- default: '',
269
- description: 'Choose one of the linked chats saved for this session.',
270
- typeOptions: {
271
- loadOptionsMethod: 'getLinkedAliases',
272
- },
273
- displayOptions: {
274
- show: {
275
- resource: ['sendMessage'],
276
- sendMessageTo: ['linkedChat'],
277
- },
278
- },
279
- },
280
- {
281
- displayName: 'WhatsApp Number',
282
- name: 'phoneNumber',
283
- type: 'string',
284
- default: '',
285
- description: 'Full phone number with country code, digits only, without 00 or +. Example: 393331234567.',
286
- displayOptions: {
287
- show: {
288
- resource: ['sendMessage'],
289
- sendMessageTo: ['number'],
290
- },
291
- },
292
- },
293
- {
294
- displayName: 'JID',
295
- name: 'jid',
296
- type: 'string',
297
- default: '',
298
- description: 'Raw WhatsApp JID, for example 393331234567@s.whatsapp.net or a group JID.',
299
- displayOptions: {
300
- show: {
301
- resource: ['sendMessage'],
302
- sendMessageTo: ['jid'],
303
- },
304
- },
305
- },
306
- {
307
- displayName: 'Yourself',
308
- name: 'yourselfNotice',
309
- type: 'notice',
310
- default: '',
311
- description: 'Send the message to the WhatsApp number already connected for this session.',
312
- displayOptions: {
313
- show: {
314
- resource: ['sendMessage'],
315
- sendMessageTo: ['yourself'],
316
- },
317
- },
318
- },
319
- {
320
- displayName: 'Message Type',
321
- name: 'messageType',
322
- type: 'options',
323
- default: 'text',
324
- description: 'The kind of outbound message to send.',
325
- displayOptions: {
326
- show: { resource: ['sendMessage'] },
327
- },
328
- options: [
329
- { name: 'Text', value: 'text' },
330
- { name: 'Image', value: 'image' },
331
- { name: 'Video', value: 'video' },
332
- { name: 'Audio', value: 'audio' },
333
- { name: 'Document', value: 'document' },
334
- { name: 'Reaction', value: 'reaction' },
335
- { name: 'Location', value: 'location' },
336
- { name: 'Contact', value: 'contact' },
337
- { name: 'Poll', value: 'poll' },
338
- ],
339
- },
340
- {
341
- displayName: 'Delivery Mode',
342
- name: 'deliveryMode',
343
- type: 'options',
344
- default: 'native',
345
- displayOptions: {
346
- show: {
347
- resource: ['sendMessage'],
348
- messageType: ['image', 'video'],
349
- },
350
- },
351
- options: [
352
- { name: 'Native Media', value: 'native' },
353
- { name: 'As File', value: 'document' },
354
- ],
355
- },
356
- {
357
- displayName: 'Message',
358
- name: 'message',
359
- type: 'string',
360
- typeOptions: { rows: 4 },
361
- default: '',
362
- description: 'Main text body for the outbound message.',
363
- displayOptions: {
364
- show: { resource: ['sendMessage'] },
365
- hide: { messageType: ['location', 'contact', 'poll'] },
366
- },
367
- },
368
- {
369
- displayName: 'Media URL',
370
- name: 'mediaUrl',
371
- type: 'string',
372
- default: '',
373
- description: 'Public URL or reachable file URL for the media to send.',
374
- displayOptions: {
375
- show: {
376
- resource: ['sendMessage'],
377
- messageType: ['image', 'video', 'audio', 'document'],
378
- },
379
- },
380
- },
381
- {
382
- displayName: 'Caption',
383
- name: 'caption',
384
- type: 'string',
385
- default: '',
386
- displayOptions: {
387
- show: {
388
- resource: ['sendMessage'],
389
- messageType: ['image', 'video', 'document'],
390
- },
391
- },
392
- },
393
- {
394
- displayName: 'Mimetype',
395
- name: 'mimetype',
396
- type: 'string',
397
- default: '',
398
- displayOptions: {
399
- show: {
400
- resource: ['sendMessage'],
401
- messageType: ['image', 'video', 'audio', 'document'],
402
- },
403
- },
404
- },
405
- {
406
- displayName: 'File Name',
407
- name: 'fileName',
408
- type: 'string',
409
- default: '',
410
- displayOptions: {
411
- show: {
412
- resource: ['sendMessage'],
413
- messageType: ['image', 'video', 'document'],
414
- },
415
- },
416
- },
417
- {
418
- displayName: 'Reply To Message ID',
419
- name: 'replyToMessageId',
420
- type: 'string',
421
- default: '',
422
- description: 'Optional. Reply or react to a specific WhatsApp message ID.',
423
- displayOptions: {
424
- show: { resource: ['sendMessage'] },
425
- },
426
- },
427
- {
428
- displayName: 'Reaction Text',
429
- name: 'reactionText',
430
- type: 'string',
431
- default: '👍',
432
- displayOptions: {
433
- show: {
434
- resource: ['sendMessage'],
435
- messageType: ['reaction'],
436
- },
437
- },
438
- },
439
- {
440
- displayName: 'Latitude',
441
- name: 'latitude',
442
- type: 'number',
443
- default: 0,
444
- displayOptions: {
445
- show: {
446
- resource: ['sendMessage'],
447
- messageType: ['location'],
448
- },
449
- },
450
- },
451
- {
452
- displayName: 'Longitude',
453
- name: 'longitude',
454
- type: 'number',
455
- default: 0,
456
- displayOptions: {
457
- show: {
458
- resource: ['sendMessage'],
459
- messageType: ['location'],
460
- },
461
- },
462
- },
463
- {
464
- displayName: 'Location Name',
465
- name: 'locationName',
466
- type: 'string',
467
- default: '',
468
- displayOptions: {
469
- show: {
470
- resource: ['sendMessage'],
471
- messageType: ['location'],
472
- },
473
- },
474
- },
475
- {
476
- displayName: 'Location Address',
477
- name: 'locationAddress',
478
- type: 'string',
479
- default: '',
480
- displayOptions: {
481
- show: {
482
- resource: ['sendMessage'],
483
- messageType: ['location'],
484
- },
485
- },
486
- },
487
- {
488
- displayName: 'Contact Name',
489
- name: 'contactName',
490
- type: 'string',
491
- default: '',
492
- displayOptions: {
493
- show: {
494
- resource: ['sendMessage'],
495
- messageType: ['contact'],
496
- },
497
- },
498
- },
499
- {
500
- displayName: 'Contact VCard',
501
- name: 'contactVcard',
502
- type: 'string',
503
- typeOptions: { rows: 4 },
504
- default: '',
505
- displayOptions: {
506
- show: {
507
- resource: ['sendMessage'],
508
- messageType: ['contact'],
509
- },
510
- },
511
- },
512
- {
513
- displayName: 'Poll Name',
514
- name: 'pollName',
515
- type: 'string',
516
- default: '',
517
- displayOptions: {
518
- show: {
519
- resource: ['sendMessage'],
520
- messageType: ['poll'],
521
- },
522
- },
523
- },
524
- {
525
- displayName: 'Poll Options',
526
- name: 'pollOptions',
527
- type: 'string',
528
- default: '',
529
- displayOptions: {
530
- show: {
531
- resource: ['sendMessage'],
532
- messageType: ['poll'],
533
- },
534
- },
535
- },
536
- {
537
- displayName: 'Selectable Count',
538
- name: 'pollSelectableCount',
539
- type: 'number',
540
- default: 1,
541
- displayOptions: {
542
- show: {
543
- resource: ['sendMessage'],
544
- messageType: ['poll'],
545
- },
546
- },
547
- },
548
- ],
549
- };
550
- }
551
- async execute() {
552
- const items = this.getInputData();
553
- const returnData = [];
554
- const access = await (0, access_1.buildAccess)(this);
555
- for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
556
- try {
557
- const resource = this.getNodeParameter('resource', itemIndex);
558
- const rawSessionId = this.getNodeParameter('sessionId', itemIndex, '');
559
- let json;
560
- if (resource === 'session') {
561
- const operation = this.getNodeParameter('sessionOperation', itemIndex);
562
- const sessionId = operation === 'list' ? (0, validation_1.normalizeSessionId)(rawSessionId) : (0, validation_1.requireSessionId)(rawSessionId);
563
- switch (operation) {
564
- case 'connect': {
565
- const label = this.getNodeParameter('label', itemIndex, '').trim();
566
- const phoneNumberForPairing = this.getNodeParameter('phoneNumberForPairing', itemIndex, '').trim();
567
- await runtime_1.registry.ensureSession(access.paths.root, access, {
568
- sessionId,
569
- label: label || sessionId,
570
- phoneNumberForPairing,
571
- });
572
- json = await runtime_1.registry.connectSession(access.paths.root, access, sessionId);
573
- break;
574
- }
575
- case 'ensure': {
576
- const label = this.getNodeParameter('label', itemIndex, '').trim();
577
- const phoneNumberForPairing = this.getNodeParameter('phoneNumberForPairing', itemIndex, '').trim();
578
- const timeoutSeconds = this.getNodeParameter('timeoutSeconds', itemIndex, 300);
579
- json = await runtime_1.registry.ensureConnectedSession(access.paths.root, access, {
580
- sessionId,
581
- label: label || sessionId,
582
- phoneNumberForPairing,
583
- }, {
584
- waitFor: 'connected',
585
- timeoutMs: timeoutSeconds * 1000,
586
- });
587
- break;
588
- }
589
- case 'list':
590
- json = await runtime_1.registry.listSessions(access);
591
- break;
592
- case 'status':
593
- json = (await runtime_1.registry.getSession(access, sessionId)) ?? null;
594
- break;
595
- case 'disconnect':
596
- json = (await runtime_1.registry.disconnectSession(access, sessionId)) ?? null;
597
- break;
598
- case 'remove':
599
- json = { removed: await runtime_1.registry.removeSession(access, sessionId) };
600
- break;
601
- default:
602
- throw new Error(`Unsupported session operation ${operation}`);
603
- }
604
- json = formatSessionOutput(json);
605
- }
606
- else if (resource === 'linkChat') {
607
- const operation = this.getNodeParameter('linkChatOperation', itemIndex);
608
- const sessionId = (0, validation_1.requireSessionId)(rawSessionId);
609
- switch (operation) {
610
- case 'listDiscovered':
611
- json = await runtime_1.registry.listTargets(access, sessionId);
612
- break;
613
- case 'listLinked':
614
- json = await runtime_1.registry.listLinkedTargets(access, sessionId);
615
- break;
616
- case 'link':
617
- json = await runtime_1.registry.connectTarget(access, sessionId, this.getNodeParameter('linkAlias', itemIndex), this.getNodeParameter('linkJid', itemIndex));
618
- break;
619
- case 'unlink':
620
- json = {
621
- removed: await runtime_1.registry.unlinkTarget(access, sessionId, this.getNodeParameter('linkAlias', itemIndex)),
622
- };
623
- break;
624
- default:
625
- throw new Error(`Unsupported link chat operation ${operation}`);
626
- }
627
- }
628
- else if (resource === 'sendMessage') {
629
- json = await runtime_1.registry.sendMessage(access, buildPayload(this, itemIndex));
630
- }
631
- else {
632
- throw new Error(`Unsupported resource ${resource}`);
633
- }
634
- returnData.push({ json: json, pairedItem: itemIndex });
635
- }
636
- catch (error) {
637
- if (this.continueOnFail()) {
638
- returnData.push({ json: { error: error.message }, pairedItem: itemIndex });
639
- continue;
640
- }
641
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex });
642
- }
643
- }
644
- return [returnData];
645
- }
646
- }
647
- exports.WhatsThat = WhatsThat;