@kichat/n8n-nodes-kirimchat 1.3.6 → 1.3.7

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.
@@ -35,8 +35,8 @@ function validateInteractiveMessage(interactive) {
35
35
  if (!obj.type || !obj.body) {
36
36
  return false;
37
37
  }
38
- // type must be 'cta_url', 'button', or 'list'
39
- if (obj.type !== 'cta_url' && obj.type !== 'button' && obj.type !== 'list') {
38
+ // type must be 'cta_url', 'button', 'list', or 'carousel'
39
+ if (obj.type !== 'cta_url' && obj.type !== 'button' && obj.type !== 'list' && obj.type !== 'carousel') {
40
40
  return false;
41
41
  }
42
42
  return true;
@@ -979,6 +979,11 @@ class KirimChat {
979
979
  value: 'list',
980
980
  description: 'Scrollable list with up to 10 options in sections',
981
981
  },
982
+ {
983
+ name: 'Carousel',
984
+ value: 'carousel',
985
+ description: 'Swipeable cards with images and CTA buttons (2-10 cards)',
986
+ },
982
987
  ],
983
988
  default: 'cta_url',
984
989
  description: 'Type of interactive message',
@@ -1252,6 +1257,127 @@ class KirimChat {
1252
1257
  description: 'Array of sections (1-10). Each section has "title" (optional) and "rows" array. Each row needs "id" (max 200 chars), "title" (max 24 chars), and optional "description" (max 72 chars)',
1253
1258
  },
1254
1259
  // ============================================
1260
+ // CAROUSEL SPECIFIC FIELDS
1261
+ // ============================================
1262
+ {
1263
+ displayName: 'Use Advanced Mode (JSON)',
1264
+ name: 'carouselAdvancedMode',
1265
+ type: 'boolean',
1266
+ displayOptions: {
1267
+ show: {
1268
+ operation: ['sendMessage'],
1269
+ messageType: ['interactive'],
1270
+ interactiveType: ['carousel'],
1271
+ },
1272
+ },
1273
+ default: false,
1274
+ description: 'Enable to enter carousel cards as JSON. Disable for simple form input.',
1275
+ },
1276
+ // Simple mode - form fields for carousel cards
1277
+ {
1278
+ displayName: 'Carousel Cards',
1279
+ name: 'carouselCards',
1280
+ type: 'fixedCollection',
1281
+ typeOptions: {
1282
+ multipleValues: true,
1283
+ minValue: 2,
1284
+ maxValue: 10,
1285
+ },
1286
+ displayOptions: {
1287
+ show: {
1288
+ operation: ['sendMessage'],
1289
+ messageType: ['interactive'],
1290
+ interactiveType: ['carousel'],
1291
+ carouselAdvancedMode: [false],
1292
+ },
1293
+ },
1294
+ default: { cards: [] },
1295
+ description: 'Add 2-10 carousel cards. Each card must have an image/video and a CTA button.',
1296
+ options: [
1297
+ {
1298
+ name: 'cards',
1299
+ displayName: 'Cards',
1300
+ values: [
1301
+ {
1302
+ displayName: 'Media Type',
1303
+ name: 'mediaType',
1304
+ type: 'options',
1305
+ options: [
1306
+ { name: 'Image', value: 'image' },
1307
+ { name: 'Video', value: 'video' },
1308
+ ],
1309
+ default: 'image',
1310
+ description: 'Type of media for the card header',
1311
+ },
1312
+ {
1313
+ displayName: 'Media URL',
1314
+ name: 'mediaUrl',
1315
+ type: 'string',
1316
+ default: '',
1317
+ description: 'Public URL of the image or video',
1318
+ placeholder: 'https://example.com/image.jpg',
1319
+ },
1320
+ {
1321
+ displayName: 'Card Body Text',
1322
+ name: 'bodyText',
1323
+ type: 'string',
1324
+ default: '',
1325
+ description: 'Description text for this card (max 160 chars)',
1326
+ placeholder: 'Product description',
1327
+ },
1328
+ {
1329
+ displayName: 'Button Text',
1330
+ name: 'buttonText',
1331
+ type: 'string',
1332
+ default: '',
1333
+ description: 'CTA button text (max 20 chars)',
1334
+ placeholder: 'Buy Now',
1335
+ },
1336
+ {
1337
+ displayName: 'Button URL',
1338
+ name: 'buttonUrl',
1339
+ type: 'string',
1340
+ default: '',
1341
+ description: 'URL to open when button is clicked',
1342
+ placeholder: 'https://example.com/product',
1343
+ },
1344
+ ],
1345
+ },
1346
+ ],
1347
+ },
1348
+ // Advanced mode (JSON) for carousel
1349
+ {
1350
+ displayName: 'Carousel Cards (JSON)',
1351
+ name: 'carouselCardsJson',
1352
+ type: 'json',
1353
+ required: true,
1354
+ displayOptions: {
1355
+ show: {
1356
+ operation: ['sendMessage'],
1357
+ messageType: ['interactive'],
1358
+ interactiveType: ['carousel'],
1359
+ carouselAdvancedMode: [true],
1360
+ },
1361
+ },
1362
+ default: `[
1363
+ {
1364
+ "mediaType": "image",
1365
+ "mediaUrl": "https://example.com/image1.jpg",
1366
+ "bodyText": "Product 1 description",
1367
+ "buttonText": "Buy Now",
1368
+ "buttonUrl": "https://example.com/product1"
1369
+ },
1370
+ {
1371
+ "mediaType": "image",
1372
+ "mediaUrl": "https://example.com/image2.jpg",
1373
+ "bodyText": "Product 2 description",
1374
+ "buttonText": "View Details",
1375
+ "buttonUrl": "https://example.com/product2"
1376
+ }
1377
+ ]`,
1378
+ description: 'Array of 2-10 cards. Each card needs: mediaType (image/video), mediaUrl, bodyText (max 160 chars), buttonText (max 20 chars), buttonUrl',
1379
+ },
1380
+ // ============================================
1255
1381
  // MARK AS READ FIELDS
1256
1382
  // ============================================
1257
1383
  {
@@ -2221,6 +2347,92 @@ class KirimChat {
2221
2347
  sections: listSections,
2222
2348
  };
2223
2349
  }
2350
+ else if (interactiveType === 'carousel') {
2351
+ // Carousel interactive message
2352
+ const advancedMode = this.getNodeParameter('carouselAdvancedMode', i, false);
2353
+ let carouselCards;
2354
+ if (advancedMode) {
2355
+ // Advanced mode: parse JSON
2356
+ const carouselCardsJson = this.getNodeParameter('carouselCardsJson', i);
2357
+ try {
2358
+ carouselCards = JSON.parse(carouselCardsJson);
2359
+ }
2360
+ catch (error) {
2361
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid JSON in Carousel Cards: ${error instanceof Error ? error.message : 'Parse failed'}`, { itemIndex: i });
2362
+ }
2363
+ if (!Array.isArray(carouselCards) || carouselCards.length < 2 || carouselCards.length > 10) {
2364
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Carousel Cards must be a JSON array with 2-10 cards', { itemIndex: i });
2365
+ }
2366
+ }
2367
+ else {
2368
+ // Simple mode: build from form fields
2369
+ const carouselCardsData = this.getNodeParameter('carouselCards', i, { cards: [] });
2370
+ if (!carouselCardsData.cards || carouselCardsData.cards.length < 2) {
2371
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least 2 carousel cards are required', { itemIndex: i });
2372
+ }
2373
+ if (carouselCardsData.cards.length > 10) {
2374
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Maximum 10 carousel cards allowed', { itemIndex: i });
2375
+ }
2376
+ carouselCards = carouselCardsData.cards;
2377
+ }
2378
+ // Validate and build carousel cards in WhatsApp format
2379
+ const formattedCards = carouselCards.map((card, index) => {
2380
+ const mediaType = card.mediaType || 'image';
2381
+ const mediaUrl = (card.mediaUrl || '').trim();
2382
+ const bodyText = (card.bodyText || '').trim();
2383
+ const buttonText = (card.buttonText || '').trim();
2384
+ const buttonUrl = (card.buttonUrl || '').trim();
2385
+ // Validate required fields
2386
+ if (!mediaUrl) {
2387
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Card ${index + 1}: Media URL is required`, { itemIndex: i });
2388
+ }
2389
+ if (!isValidUrl(mediaUrl)) {
2390
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Card ${index + 1}: Invalid Media URL format. URL must start with http:// or https://`, { itemIndex: i });
2391
+ }
2392
+ if (!buttonText) {
2393
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Card ${index + 1}: Button Text is required`, { itemIndex: i });
2394
+ }
2395
+ if (buttonText.length > 20) {
2396
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Card ${index + 1}: Button Text exceeds maximum length of 20 characters`, { itemIndex: i });
2397
+ }
2398
+ if (!buttonUrl) {
2399
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Card ${index + 1}: Button URL is required`, { itemIndex: i });
2400
+ }
2401
+ if (!isValidUrl(buttonUrl)) {
2402
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Card ${index + 1}: Invalid Button URL format. URL must start with http:// or https://`, { itemIndex: i });
2403
+ }
2404
+ if (bodyText && bodyText.length > 160) {
2405
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Card ${index + 1}: Body Text exceeds maximum length of 160 characters`, { itemIndex: i });
2406
+ }
2407
+ // Build card in WhatsApp API format
2408
+ const formattedCard = {
2409
+ card_index: index,
2410
+ type: 'cta_url',
2411
+ header: {
2412
+ type: mediaType,
2413
+ [mediaType]: { link: mediaUrl },
2414
+ },
2415
+ action: {
2416
+ name: 'cta_url',
2417
+ parameters: {
2418
+ display_text: buttonText,
2419
+ url: buttonUrl,
2420
+ },
2421
+ },
2422
+ };
2423
+ // Add body if provided
2424
+ if (bodyText) {
2425
+ formattedCard.body = { text: bodyText };
2426
+ }
2427
+ return formattedCard;
2428
+ });
2429
+ // Carousel doesn't support header (it's in each card)
2430
+ // Remove header if it was added
2431
+ delete interactive.header;
2432
+ interactive.action = {
2433
+ cards: formattedCards,
2434
+ };
2435
+ }
2224
2436
  if (!validateInteractiveMessage(interactive)) {
2225
2437
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid interactive message structure', { itemIndex: i });
2226
2438
  }
@@ -1,6 +1,6 @@
1
- <svg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg">
2
- <!-- Chat Bubble - White background with Black border -->
3
- <path d="M3,9 Q3,3 9,3 H51 Q57,3 57,9 V42 Q57,48 51,48 H18 L3,57 V9 Z" fill="white" stroke="black" stroke-width="3"/>
4
- <!-- Text - Black color -->
5
- <text x="30" y="30" font-family="Arial, sans-serif" font-size="24" font-weight="900" fill="black" text-anchor="middle" dominant-baseline="middle">KC</text>
6
- </svg>
1
+ <svg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg">
2
+ <!-- Chat Bubble - White background with Black border -->
3
+ <path d="M3,9 Q3,3 9,3 H51 Q57,3 57,9 V42 Q57,48 51,48 H18 L3,57 V9 Z" fill="white" stroke="black" stroke-width="3"/>
4
+ <!-- Text - Black color -->
5
+ <text x="30" y="30" font-family="Arial, sans-serif" font-size="24" font-weight="900" fill="black" text-anchor="middle" dominant-baseline="middle">KC</text>
6
+ </svg>
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "@kichat/n8n-nodes-kirimchat",
3
- "version": "1.3.6",
4
- "description": "n8n community node for KirimChat - Send WhatsApp, Instagram & Messenger messages with interactive buttons, flexible customer lookup, and typing indicators",
5
- "keywords": [
6
- "n8n-community-node-package",
7
- "n8n",
8
- "kirimchat",
9
- "whatsapp",
10
- "instagram",
11
- "messenger",
12
- "facebook",
13
- "messaging",
14
- "chat",
15
- "automation"
16
- ],
17
- "license": "MIT",
18
- "homepage": "https://kirim.chat",
19
- "author": {
20
- "name": "KirimChat",
21
- "email": "support@kirim.chat"
22
- },
23
- "repository": {
24
- "type": "git",
25
- "url": "https://github.com/kirimchat/n8n-nodes-kirimchat.git"
26
- },
27
- "main": "dist/nodes/KirimChat/KirimChat.node.js",
28
- "scripts": {
29
- "build": "tsc && npm run copy-icons",
30
- "copy-icons": "node -e \"require('fs').cpSync('nodes/KirimChat/kirimchat.svg', 'dist/nodes/KirimChat/kirimchat.svg')\"",
31
- "dev": "tsc --watch",
32
- "format": "prettier nodes credentials --write",
33
- "lint": "eslint nodes credentials package.json",
34
- "prepublishOnly": "npm run build"
35
- },
36
- "files": [
37
- "dist"
38
- ],
39
- "n8n": {
40
- "n8nNodesApiVersion": 1,
41
- "credentials": [
42
- "dist/credentials/KirimChatApi.credentials.js"
43
- ],
44
- "nodes": [
45
- "dist/nodes/KirimChat/KirimChat.node.js"
46
- ]
47
- },
48
- "devDependencies": {
49
- "@typescript-eslint/parser": "^7.0.0",
50
- "copyfiles": "^2.4.1",
51
- "eslint": "^8.0.0",
52
- "n8n-workflow": "^1.0.0",
53
- "prettier": "^3.0.0",
54
- "typescript": "^5.0.0"
55
- },
56
- "peerDependencies": {
57
- "n8n-workflow": "*"
58
- }
59
- }
1
+ {
2
+ "name": "@kichat/n8n-nodes-kirimchat",
3
+ "version": "1.3.7",
4
+ "description": "n8n community node for KirimChat - Send WhatsApp, Instagram & Messenger messages with interactive buttons, flexible customer lookup, and typing indicators",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "kirimchat",
9
+ "whatsapp",
10
+ "instagram",
11
+ "messenger",
12
+ "facebook",
13
+ "messaging",
14
+ "chat",
15
+ "automation"
16
+ ],
17
+ "license": "MIT",
18
+ "homepage": "https://kirim.chat",
19
+ "author": {
20
+ "name": "KirimChat",
21
+ "email": "support@kirim.chat"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/kirimchat/n8n-nodes-kirimchat.git"
26
+ },
27
+ "main": "dist/nodes/KirimChat/KirimChat.node.js",
28
+ "scripts": {
29
+ "build": "tsc && npm run copy-icons",
30
+ "copy-icons": "node -e \"require('fs').cpSync('nodes/KirimChat/kirimchat.svg', 'dist/nodes/KirimChat/kirimchat.svg')\"",
31
+ "dev": "tsc --watch",
32
+ "format": "prettier nodes credentials --write",
33
+ "lint": "eslint nodes credentials package.json",
34
+ "prepublishOnly": "npm run build"
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "n8n": {
40
+ "n8nNodesApiVersion": 1,
41
+ "credentials": [
42
+ "dist/credentials/KirimChatApi.credentials.js"
43
+ ],
44
+ "nodes": [
45
+ "dist/nodes/KirimChat/KirimChat.node.js"
46
+ ]
47
+ },
48
+ "devDependencies": {
49
+ "@typescript-eslint/parser": "^7.0.0",
50
+ "copyfiles": "^2.4.1",
51
+ "eslint": "^8.0.0",
52
+ "n8n-workflow": "^1.0.0",
53
+ "prettier": "^3.0.0",
54
+ "typescript": "^5.0.0"
55
+ },
56
+ "peerDependencies": {
57
+ "n8n-workflow": "*"
58
+ }
59
+ }
@@ -1 +0,0 @@
1
- {"root":["../credentials/kirimchatapi.credentials.ts","../nodes/kirimchat/kirimchat.node.ts"],"version":"5.9.3"}