From 91685abb15b44a3e87d2f3e437f1724a60c0bdb7 Mon Sep 17 00:00:00 2001 From: iamsivin Date: Thu, 14 May 2026 15:58:32 +0530 Subject: [PATCH 1/5] chore: allow more attachment file types --- package.json | 2 +- src/fileUploadRules.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d1355e8..5a8e6f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chatwoot/utils", - "version": "0.0.52", + "version": "0.0.53", "description": "Chatwoot utils", "private": false, "license": "MIT", diff --git a/src/fileUploadRules.ts b/src/fileUploadRules.ts index 5d887cf..76180b5 100644 --- a/src/fileUploadRules.ts +++ b/src/fileUploadRules.ts @@ -110,9 +110,11 @@ const CHANNEL_CONFIGS: ChannelConfigs = { 'vnd.openxmlformats-officedocument.presentationml.presentation', 'vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'vnd.openxmlformats-officedocument.wordprocessingml.document', + 'x-pkcs12', + 'pkcs12', ], }, - extensions: ['.3gpp'], + extensions: ['.3gpp', '.xls', '.xlsx', '.pfx'], max: 40, }, From fa1262bfa654ef6da9751918f7968cd1bb371002 Mon Sep 17 00:00:00 2001 From: iamsivin Date: Thu, 14 May 2026 16:10:28 +0530 Subject: [PATCH 2/5] chore: Minor fix --- src/fileUploadRules.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fileUploadRules.ts b/src/fileUploadRules.ts index 76180b5..8a90883 100644 --- a/src/fileUploadRules.ts +++ b/src/fileUploadRules.ts @@ -135,6 +135,7 @@ const CHANNEL_CONFIGS: ChannelConfigs = { 'vnd.openxmlformats-officedocument.presentationml.presentation', ], }, + extensions: ['.xls', '.xlsx'], maxByCategory: { image: 5, video: 16, audio: 16, document: 100 }, }, }, @@ -167,6 +168,7 @@ const CHANNEL_CONFIGS: ChannelConfigs = { 'vnd.openxmlformats-officedocument.presentationml.presentation', ], }, + extensions: ['.xls', '.xlsx'], maxByCategory: { image: 8, audio: 25, video: 25, document: 25 }, }, }, From b82622e53aa8aa550d5d9e39d97eb5e25cc4c689 Mon Sep 17 00:00:00 2001 From: iamsivin Date: Thu, 14 May 2026 16:13:52 +0530 Subject: [PATCH 3/5] chore: Update version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a8e6f7..08ac257 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chatwoot/utils", - "version": "0.0.53", + "version": "0.0.54", "description": "Chatwoot utils", "private": false, "license": "MIT", From 80d3132b2ac4a2abb21bb90dfe37ae0c62b645cc Mon Sep 17 00:00:00 2001 From: iamsivin Date: Thu, 14 May 2026 21:45:51 +0530 Subject: [PATCH 4/5] chore: Clean up --- package.json | 2 +- src/fileUploadRules.ts | 57 ++++++++++++++++++++++-------------- test/fileUploadRules.test.ts | 23 +++++++++++++-- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 08ac257..0b83cd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chatwoot/utils", - "version": "0.0.54", + "version": "0.0.55", "description": "Chatwoot utils", "private": false, "license": "MIT", diff --git a/src/fileUploadRules.ts b/src/fileUploadRules.ts index 8a90883..2a2755a 100644 --- a/src/fileUploadRules.ts +++ b/src/fileUploadRules.ts @@ -54,7 +54,7 @@ export const INBOX_TYPES = { } as const; // derive key type AFTER INBOX_TYPES is declared -type ChannelKey = typeof INBOX_TYPES[keyof typeof INBOX_TYPES]; +type ChannelKey = (typeof INBOX_TYPES)[keyof typeof INBOX_TYPES]; // CHANNEL_CONFIGS shape: channels are optional; default node requires max type ChannelConfigs = Partial> & { @@ -88,33 +88,36 @@ type ChannelConfigs = Partial> & { * 2. channel + "*" fallback * 3. global default */ + +const STANDARD_TEXT_MIMES = ['csv', 'plain', 'rtf', 'xml']; +const STANDARD_APPLICATION_MIMES = [ + 'json', + 'pdf', + 'xml', + 'zip', + 'x-7z-compressed', + 'vnd.rar', + 'x-tar', + 'msword', + 'vnd.ms-excel', + 'vnd.ms-powerpoint', + 'vnd.oasis.opendocument.text', + 'vnd.openxmlformats-officedocument.presentationml.presentation', + 'vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'vnd.openxmlformats-officedocument.wordprocessingml.document', +]; +const STANDARD_EXTENSIONS = ['.3gpp', '.xls', '.xlsx']; + const CHANNEL_CONFIGS: ChannelConfigs = { default: { mimeGroups: { image: ['*'], audio: ['*'], video: ['*'], - text: ['csv', 'plain', 'rtf', 'xml'], - application: [ - 'json', - 'pdf', - 'xml', - 'zip', - 'x-7z-compressed', - 'vnd.rar', - 'x-tar', - 'msword', - 'vnd.ms-excel', - 'vnd.ms-powerpoint', - 'vnd.oasis.opendocument.text', - 'vnd.openxmlformats-officedocument.presentationml.presentation', - 'vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'vnd.openxmlformats-officedocument.wordprocessingml.document', - 'x-pkcs12', - 'pkcs12', - ], + text: STANDARD_TEXT_MIMES, + application: [...STANDARD_APPLICATION_MIMES, 'x-pkcs12', 'pkcs12'], }, - extensions: ['.3gpp', '.xls', '.xlsx', '.pfx'], + extensions: [...STANDARD_EXTENSIONS, '.pfx'], max: 40, }, @@ -193,7 +196,17 @@ const CHANNEL_CONFIGS: ChannelConfigs = { }, [INBOX_TYPES.TWILIO]: { - sms: { max: 5 }, + sms: { + mimeGroups: { + image: ['jpeg', 'png'], + audio: ['*'], + video: ['*'], + text: STANDARD_TEXT_MIMES, + application: STANDARD_APPLICATION_MIMES, + }, + extensions: STANDARD_EXTENSIONS, + max: 5, + }, whatsapp: { mimeGroups: { image: ['png', 'jpeg'], diff --git a/test/fileUploadRules.test.ts b/test/fileUploadRules.test.ts index 8a0b8af..4d2a0ea 100644 --- a/test/fileUploadRules.test.ts +++ b/test/fileUploadRules.test.ts @@ -1,7 +1,7 @@ import { - INBOX_TYPES, getAllowedFileTypesByChannel, getMaxUploadSizeByChannel, + INBOX_TYPES, } from '../src/fileUploadRules'; describe('uploadRules helper', () => { @@ -15,6 +15,9 @@ describe('uploadRules helper', () => { expect(accept).toContain('text/plain'); expect(accept).toContain('application/json'); expect(accept).toContain('.3gpp'); + expect(accept).toContain('application/x-pkcs12'); + expect(accept).toContain('application/pkcs12'); + expect(accept).toContain('.pfx'); }); it('returns WhatsApp specific accept list', () => { @@ -33,6 +36,8 @@ describe('uploadRules helper', () => { expect(accept).not.toContain('application/json'); expect(accept).not.toContain('.3gpp'); expect(accept).not.toContain('image/gif'); + expect(accept).not.toContain('application/x-pkcs12'); + expect(accept).not.toContain('.pfx'); }); it('returns Instagram specific accept list', () => { @@ -73,13 +78,25 @@ describe('uploadRules helper', () => { expect(accept).not.toContain('audio/mp3'); }); - it('falls back to default accept list for Twilio SMS (no mimeGroups)', () => { + it('returns Twilio SMS accept list (default-aligned, excluding PFX)', () => { const accept = getAllowedFileTypesByChannel({ channelType: INBOX_TYPES.TWILIO, medium: 'sms', }); - expect(accept).toContain('image/*'); + expect(accept).toContain('image/jpeg'); + expect(accept).toContain('image/png'); + expect(accept).not.toContain('image/*'); + expect(accept).not.toContain('image/gif'); + expect(accept).toContain('audio/*'); + expect(accept).toContain('video/*'); + expect(accept).toContain('text/plain'); + expect(accept).toContain('application/pdf'); + expect(accept).toContain('application/json'); expect(accept).toContain('.3gpp'); + expect(accept).toContain('.xls'); + expect(accept).not.toContain('application/x-pkcs12'); + expect(accept).not.toContain('application/pkcs12'); + expect(accept).not.toContain('.pfx'); }); it('handles empty object parameter', () => { From 8d1d3c96f8d7ad33c9e0979413a7a899f57636b6 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Fri, 15 May 2026 12:34:52 +0530 Subject: [PATCH 5/5] Apply suggestion from @iamsivin --- src/fileUploadRules.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fileUploadRules.ts b/src/fileUploadRules.ts index 2a2755a..7f18317 100644 --- a/src/fileUploadRules.ts +++ b/src/fileUploadRules.ts @@ -54,7 +54,7 @@ export const INBOX_TYPES = { } as const; // derive key type AFTER INBOX_TYPES is declared -type ChannelKey = (typeof INBOX_TYPES)[keyof typeof INBOX_TYPES]; +type ChannelKey = typeof INBOX_TYPES[keyof typeof INBOX_TYPES]; // CHANNEL_CONFIGS shape: channels are optional; default node requires max type ChannelConfigs = Partial> & {