core-services-sdk 1.3.49 → 1.3.51

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.
@@ -29,12 +29,25 @@ import {
29
29
  generateDeviceId,
30
30
  generateAlertId,
31
31
  generateResourceId,
32
+ generateRoleId,
33
+ generateAssetId,
34
+ generateAssetUploadId,
35
+ generateSupplierId,
36
+ generateInvoiceId,
37
+ generateInvoiceItemId,
38
+ generateInvoiceCorrectionId,
39
+ generateDocumentDataId,
40
+ generateEmailId,
41
+ generateIncomingEmailId,
42
+ generateImId,
43
+ generateBotFlowId,
32
44
  } from '../../src/ids/generators.js'
33
45
  import { ID_PREFIXES } from '../../src/ids/prefixes.js'
34
46
 
35
47
  // ULID is a 26-character Base32 string (no I, L, O, U).
36
48
  const ULID_REGEX = /^[0-9A-HJKMNP-TV-Z]{26}$/
37
49
 
50
+ // @ts-ignore
38
51
  const testPrefixFunction = (fn, expectedPrefix) => {
39
52
  const id = fn()
40
53
  expect(typeof id).toBe('string')
@@ -91,7 +104,7 @@ describe('generate*Id functions', () => {
91
104
  })
92
105
 
93
106
  it('generateRolePermissionsId returns ID with role_ prefix', () => {
94
- testPrefixFunction(generateRolePermissionsId, ID_PREFIXES.ROLE_PERMISSIONS)
107
+ testPrefixFunction(generateRolePermissionsId, ID_PREFIXES.ROLE_PERMISSION)
95
108
  })
96
109
 
97
110
  it('generateSessionId returns ID with sess_ prefix', () => {
@@ -169,4 +182,55 @@ describe('generate*Id functions', () => {
169
182
  it('generateResourceId returns ID with res_ prefix', () => {
170
183
  testPrefixFunction(generateResourceId, ID_PREFIXES.RESOURCE)
171
184
  })
185
+
186
+ it('generateRoleId returns ID with role_ prefix', () => {
187
+ testPrefixFunction(generateRoleId, ID_PREFIXES.ROLE)
188
+ })
189
+
190
+ it('generateAssetId returns ID with ast_ prefix', () => {
191
+ testPrefixFunction(generateAssetId, ID_PREFIXES.ASSET)
192
+ })
193
+
194
+ it('generateAssetUploadId returns ID with aupl_ prefix', () => {
195
+ testPrefixFunction(generateAssetUploadId, ID_PREFIXES.ASSET_UPLOAD)
196
+ })
197
+
198
+ it('generateSupplierId returns ID with sup_ prefix', () => {
199
+ testPrefixFunction(generateSupplierId, ID_PREFIXES.SUPPLIER)
200
+ })
201
+
202
+ it('generateInvoiceId returns ID with inv_ prefix', () => {
203
+ testPrefixFunction(generateInvoiceId, ID_PREFIXES.INVOICE)
204
+ })
205
+
206
+ it('generateInvoiceItemId returns ID with invi_ prefix', () => {
207
+ testPrefixFunction(generateInvoiceItemId, ID_PREFIXES.INVOICE_ITEM)
208
+ })
209
+
210
+ it('generateInvoiceCorrectionId returns ID with invc_ prefix', () => {
211
+ testPrefixFunction(
212
+ generateInvoiceCorrectionId,
213
+ ID_PREFIXES.INVOICE_CORRECTION,
214
+ )
215
+ })
216
+
217
+ it('generateDocumentDataId returns ID with docd_ prefix', () => {
218
+ testPrefixFunction(generateDocumentDataId, ID_PREFIXES.DOCUMENT_DATA)
219
+ })
220
+
221
+ it('generateEmailId returns ID with eml_ prefix', () => {
222
+ testPrefixFunction(generateEmailId, ID_PREFIXES.EMAIL)
223
+ })
224
+
225
+ it('generateIncomingEmailId returns ID with ieml_ prefix', () => {
226
+ testPrefixFunction(generateIncomingEmailId, ID_PREFIXES.INCOMING_EMAIL)
227
+ })
228
+
229
+ it('generateImId returns ID with im_ prefix', () => {
230
+ testPrefixFunction(generateImId, ID_PREFIXES.IM)
231
+ })
232
+
233
+ it('generateBotFlowId returns ID with botf_ prefix', () => {
234
+ testPrefixFunction(generateBotFlowId, ID_PREFIXES.BOT_FLOW)
235
+ })
172
236
  })
@@ -5,35 +5,44 @@ import { ID_PREFIXES } from '../../src/ids/prefixes.js'
5
5
  describe('ID_PREFIXES', () => {
6
6
  it('contains expected keys and values', () => {
7
7
  expect(ID_PREFIXES).toEqual({
8
- USER: 'usr',
9
- TENANT: 'tnt',
10
- PERMISSION: 'prm',
8
+ ALERT: 'alr',
9
+ ASSET: 'ast',
10
+ ASSET_UPLOAD: 'aupl',
11
+ AUDIT: 'adt',
12
+ BOT_FLOW: 'botf',
13
+ CONFIG: 'cfg',
11
14
  CORRELATION: 'crln',
12
- VERIFICATION: 'vrf',
13
- ROLE_PERMISSIONS: 'role',
14
- ONBOARDING: 'onb',
15
- SESSION: 'sess',
16
- FILE: 'fil',
15
+ DEVICE: 'dev',
16
+ DOCUMENT_DATA: 'docd',
17
+ EMAIL: 'eml',
17
18
  EVENT: 'evt',
19
+ FILE: 'fil',
20
+ IM: 'im',
21
+ INCOMING_EMAIL: 'ieml',
22
+ INVOICE: 'inv',
23
+ INVOICE_CORRECTION: 'invc',
24
+ INVOICE_ITEM: 'invi',
18
25
  JOB: 'job',
19
- TASK: 'task',
20
- QUEUE: 'que',
21
- MESSAGE: 'msg',
22
- NOTIFICATION: 'ntf',
23
- LOG: 'log',
24
- AUDIT: 'adt',
25
- CONFIG: 'cfg',
26
26
  KEY: 'key',
27
+ LOG: 'log',
28
+ MESSAGE: 'msg',
27
29
  METRIC: 'met',
28
- TAG: 'tag',
30
+ NOTIFICATION: 'ntf',
31
+ ONBOARDING: 'onb',
32
+ PERMISSION: 'prm',
29
33
  POLICY: 'plc',
30
34
  PROFILE: 'prf',
31
- DEVICE: 'dev',
32
- ALERT: 'alr',
35
+ QUEUE: 'que',
33
36
  RESOURCE: 'res',
34
- INCOMING_EMAIL: 'ieml',
35
- EMAIL: 'eml',
36
- IM: 'im',
37
+ ROLE: 'role',
38
+ ROLE_PERMISSION: 'rprm',
39
+ SESSION: 'sess',
40
+ SUPPLIER: 'sup',
41
+ TAG: 'tag',
42
+ TASK: 'task',
43
+ TENANT: 'tnt',
44
+ USER: 'usr',
45
+ VERIFICATION: 'vrf',
37
46
  })
38
47
  })
39
48
 
@@ -0,0 +1,157 @@
1
+ // @ts-nocheck
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
3
+ import {
4
+ getTelegramApiUrls,
5
+ telegramApis,
6
+ } from '../../src/instant-messages/telegram-apis/telegram-apis.js'
7
+ import * as httpModule from '../../src/http/http.js'
8
+
9
+ describe('getTelegramApiUrls', () => {
10
+ it('builds correct Telegram API URLs', () => {
11
+ const token = 'TEST_TOKEN'
12
+ const urls = getTelegramApiUrls({ token })
13
+
14
+ expect(urls.SEND_MESSAGE).toBe(
15
+ `https://api.telegram.org/bot${token}/sendMessage`,
16
+ )
17
+ expect(urls.FORWARD_MESSAGE).toBe(
18
+ `https://api.telegram.org/bot${token}/forwardMessage`,
19
+ )
20
+ expect(urls.SEND_PHOTO).toBe(
21
+ `https://api.telegram.org/bot${token}/sendPhoto`,
22
+ )
23
+ expect(urls.GET_FILE).toBe(`https://api.telegram.org/bot${token}/getFile`)
24
+ })
25
+
26
+ it('supports custom base URL', () => {
27
+ const token = 'X'
28
+ const baseUrl = 'http://localhost:9999'
29
+ const urls = getTelegramApiUrls({ token, telegramBaseUrl: baseUrl })
30
+
31
+ expect(urls.SEND_MESSAGE).toBe(`${baseUrl}/bot${token}/sendMessage`)
32
+ })
33
+ })
34
+
35
+ describe('telegramApis', () => {
36
+ const token = 'MOCK_TOKEN'
37
+ let postMock
38
+
39
+ beforeEach(() => {
40
+ postMock = vi.spyOn(httpModule, 'post').mockResolvedValue({
41
+ ok: true,
42
+ result: 'mock-response',
43
+ })
44
+ })
45
+
46
+ it('sends text message with correct body', async () => {
47
+ const api = telegramApis({ token })
48
+ await api.sendMessage({ text: 'hello', chatId: 123 })
49
+
50
+ expect(postMock).toHaveBeenCalledWith({
51
+ url: `https://api.telegram.org/bot${token}/sendMessage`,
52
+ body: {
53
+ chat_id: 123,
54
+ text: 'hello',
55
+ entities: undefined,
56
+ },
57
+ })
58
+ })
59
+
60
+ it('sends inline keyboard buttons', async () => {
61
+ const api = telegramApis({ token })
62
+ const options = [[{ text: 'A', callback_data: '1' }]]
63
+
64
+ await api.sendButtonsGroup({
65
+ text: 'Choose',
66
+ chatId: 10,
67
+ options,
68
+ })
69
+
70
+ expect(postMock).toHaveBeenCalledWith({
71
+ url: `https://api.telegram.org/bot${token}/sendMessage`,
72
+ body: {
73
+ chat_id: 10,
74
+ text: 'Choose',
75
+ reply_markup: {
76
+ inline_keyboard: options,
77
+ },
78
+ },
79
+ })
80
+ })
81
+
82
+ it('sends a photo with caption', async () => {
83
+ const api = telegramApis({ token })
84
+
85
+ await api.sendPhoto({
86
+ chatId: 77,
87
+ photo: 'http://photo.jpg',
88
+ caption: 'hi',
89
+ })
90
+
91
+ expect(postMock).toHaveBeenCalledWith({
92
+ url: `https://api.telegram.org/bot${token}/sendPhoto`,
93
+ body: {
94
+ chat_id: 77,
95
+ caption: 'hi',
96
+ photo: 'http://photo.jpg',
97
+ },
98
+ })
99
+ })
100
+
101
+ it('sends a video', async () => {
102
+ const api = telegramApis({ token })
103
+
104
+ await api.sendVideo({
105
+ chatId: 55,
106
+ video: 'http://video.mp4',
107
+ caption: 'watch this',
108
+ })
109
+
110
+ expect(postMock).toHaveBeenCalledWith({
111
+ url: `https://api.telegram.org/bot${token}/sendVideo`,
112
+ body: {
113
+ chat_id: 55,
114
+ caption: 'watch this',
115
+ video: 'http://video.mp4',
116
+ },
117
+ })
118
+ })
119
+
120
+ it('sends an audio file', async () => {
121
+ const api = telegramApis({ token })
122
+
123
+ await api.sendAudio({
124
+ chatId: 200,
125
+ audio: 'http://audio.mp3',
126
+ caption: 'listen',
127
+ })
128
+
129
+ expect(postMock).toHaveBeenCalledWith({
130
+ url: `https://api.telegram.org/bot${token}/sendAudio`,
131
+ body: {
132
+ chat_id: 200,
133
+ caption: 'listen',
134
+ audio: 'http://audio.mp3',
135
+ },
136
+ })
137
+ })
138
+
139
+ it('sends a document', async () => {
140
+ const api = telegramApis({ token })
141
+
142
+ await api.sendDocument({
143
+ chatId: 999,
144
+ document: 'http://file.pdf',
145
+ caption: 'file',
146
+ })
147
+
148
+ expect(postMock).toHaveBeenCalledWith({
149
+ url: `https://api.telegram.org/bot${token}/sendDocument`,
150
+ body: {
151
+ chat_id: 999,
152
+ caption: 'file',
153
+ document: 'http://file.pdf',
154
+ },
155
+ })
156
+ })
157
+ })
@@ -0,0 +1,277 @@
1
+ // @ts-nocheck
2
+ import { describe, it, expect, beforeEach, vi } from 'vitest'
3
+
4
+ import {
5
+ whatsappApis,
6
+ getWhatsAppApiUrls,
7
+ getWhatsAppMediaInfo,
8
+ downloadWhatsAppMedia,
9
+ } from '../../src/instant-messages/whatsapp-apis/whatsapp-apis.js'
10
+
11
+ import * as httpModule from '../../src/http/http.js'
12
+
13
+ global.fetch = vi.fn()
14
+
15
+ describe('getWhatsAppMediaInfo', () => {
16
+ beforeEach(() => {
17
+ fetch.mockReset()
18
+ })
19
+
20
+ it('returns media metadata correctly', async () => {
21
+ const mockResponse = {
22
+ url: 'https://cdn.whatsapp.com/file.jpg',
23
+ mime_type: 'image/jpeg',
24
+ id: 'ABC123',
25
+ }
26
+
27
+ fetch.mockResolvedValue({
28
+ ok: true,
29
+ json: async () => mockResponse,
30
+ })
31
+
32
+ const result = await getWhatsAppMediaInfo({
33
+ mediaId: 'ABC123',
34
+ token: 'TOKEN',
35
+ })
36
+
37
+ expect(fetch).toHaveBeenCalledWith(
38
+ 'https://graph.facebook.com/v21.0/ABC123',
39
+ {
40
+ headers: {
41
+ Authorization: 'Bearer TOKEN',
42
+ },
43
+ },
44
+ )
45
+
46
+ expect(result).toEqual(mockResponse)
47
+ })
48
+
49
+ it('throws on non successful response', async () => {
50
+ fetch.mockResolvedValue({
51
+ ok: false,
52
+ status: 403,
53
+ })
54
+
55
+ await expect(
56
+ getWhatsAppMediaInfo({
57
+ mediaId: 'MEDIA_ID',
58
+ token: 'TOKEN',
59
+ }),
60
+ ).rejects.toThrow('Failed to retrieve media info: 403')
61
+ })
62
+ })
63
+
64
+ describe('downloadWhatsAppMedia', () => {
65
+ beforeEach(() => {
66
+ fetch.mockReset()
67
+ })
68
+
69
+ it('downloads media as buffer', async () => {
70
+ const mockMetadata = {
71
+ url: 'https://cdn.whatsapp.com/file.jpg',
72
+ }
73
+
74
+ const mockBinary = new Uint8Array([10, 20, 30])
75
+
76
+ fetch
77
+ .mockResolvedValueOnce({
78
+ ok: true,
79
+ json: async () => mockMetadata,
80
+ })
81
+ .mockResolvedValueOnce({
82
+ ok: true,
83
+ arrayBuffer: async () => mockBinary.buffer,
84
+ })
85
+
86
+ const buffer = await downloadWhatsAppMedia({
87
+ token: 'TOKEN',
88
+ mediaId: 'MEDIA_ID',
89
+ mode: 'buffer',
90
+ })
91
+
92
+ expect(Buffer.isBuffer(buffer)).toBe(true)
93
+ expect(buffer.equals(Buffer.from(mockBinary))).toBe(true)
94
+ })
95
+
96
+ it('returns stream when mode=stream', async () => {
97
+ const mockStream = { fake: 'stream' }
98
+
99
+ fetch
100
+ .mockResolvedValueOnce({
101
+ ok: true,
102
+ json: async () => ({ url: 'http://cdn.com/x' }),
103
+ })
104
+ .mockResolvedValueOnce({
105
+ ok: true,
106
+ body: mockStream,
107
+ })
108
+
109
+ const stream = await downloadWhatsAppMedia({
110
+ token: 'TOKEN',
111
+ mediaId: 'ID',
112
+ mode: 'stream',
113
+ })
114
+
115
+ expect(stream).toBe(mockStream)
116
+ })
117
+ })
118
+
119
+ describe('getWhatsAppApiUrls', () => {
120
+ it('generates correct messages URL', () => {
121
+ const url = getWhatsAppApiUrls({
122
+ phoneNumberId: '12345',
123
+ version: 'v21.0',
124
+ })
125
+
126
+ expect(url).toBe('https://graph.facebook.com/v21.0/12345/messages')
127
+ })
128
+
129
+ it('supports custom base URL', () => {
130
+ const url = getWhatsAppApiUrls({
131
+ phoneNumberId: '99',
132
+ baseUrl: 'http://localhost:3000',
133
+ version: 'v21.0',
134
+ })
135
+
136
+ expect(url).toBe('http://localhost:3000/v21.0/99/messages')
137
+ })
138
+ })
139
+
140
+ describe('whatsappApis', () => {
141
+ let postMock
142
+
143
+ beforeEach(() => {
144
+ postMock = vi
145
+ .spyOn(httpModule, 'post')
146
+ .mockResolvedValue({ ok: true, data: 'mock-response' })
147
+ })
148
+
149
+ const token = 'TOKEN'
150
+ const phoneNumberId = '111'
151
+
152
+ const baseUrl = 'https://graph.facebook.com/v21.0/111/messages'
153
+
154
+ it('sendMessage sends correct payload', async () => {
155
+ const api = whatsappApis({ token, phoneNumberId })
156
+
157
+ await api.sendMessage({
158
+ chatId: '9725000000',
159
+ text: 'Hello',
160
+ })
161
+
162
+ expect(postMock).toHaveBeenCalledWith({
163
+ url: baseUrl,
164
+ headers: { Authorization: 'Bearer TOKEN' },
165
+ body: {
166
+ recipient_type: 'individual',
167
+ messaging_product: 'whatsapp',
168
+ to: '9725000000',
169
+ type: 'text',
170
+ text: {
171
+ preview_url: true,
172
+ body: 'Hello',
173
+ },
174
+ },
175
+ })
176
+ })
177
+
178
+ it('sendPhoto sends correct body', async () => {
179
+ const api = whatsappApis({ token, phoneNumberId })
180
+
181
+ await api.sendPhoto({
182
+ chatId: '1',
183
+ photo: 'http://img.jpg',
184
+ caption: 'Hi',
185
+ })
186
+
187
+ expect(postMock).toHaveBeenCalledWith({
188
+ url: baseUrl,
189
+ headers: { Authorization: 'Bearer TOKEN' },
190
+ body: {
191
+ recipient_type: 'individual',
192
+ messaging_product: 'whatsapp',
193
+ to: '1',
194
+ type: 'image',
195
+ image: {
196
+ link: 'http://img.jpg',
197
+ caption: 'Hi',
198
+ },
199
+ },
200
+ })
201
+ })
202
+
203
+ it('sendVideo sends filename when provided', async () => {
204
+ const api = whatsappApis({ token, phoneNumberId })
205
+
206
+ await api.sendVideo({
207
+ chatId: '77',
208
+ video: 'http://video.mp4',
209
+ caption: 'watch',
210
+ filename: 'clip.mp4',
211
+ })
212
+
213
+ expect(postMock).toHaveBeenCalledWith({
214
+ url: baseUrl,
215
+ headers: { Authorization: 'Bearer TOKEN' },
216
+ body: {
217
+ recipient_type: 'individual',
218
+ messaging_product: 'whatsapp',
219
+ to: '77',
220
+ type: 'video',
221
+ video: {
222
+ link: 'http://video.mp4',
223
+ caption: 'watch',
224
+ filename: 'clip.mp4',
225
+ },
226
+ },
227
+ })
228
+ })
229
+
230
+ it('sendDocument works without filename', async () => {
231
+ const api = whatsappApis({ token, phoneNumberId })
232
+
233
+ await api.sendDocument({
234
+ chatId: '33',
235
+ document: 'http://file.pdf',
236
+ caption: 'doc',
237
+ })
238
+
239
+ expect(postMock).toHaveBeenCalledWith({
240
+ url: baseUrl,
241
+ headers: { Authorization: 'Bearer TOKEN' },
242
+ body: {
243
+ recipient_type: 'individual',
244
+ messaging_product: 'whatsapp',
245
+ to: '33',
246
+ type: 'document',
247
+ document: {
248
+ link: 'http://file.pdf',
249
+ caption: 'doc',
250
+ },
251
+ },
252
+ })
253
+ })
254
+
255
+ it('sendAudio sends correct structure', async () => {
256
+ const api = whatsappApis({ token, phoneNumberId })
257
+
258
+ await api.sendAudio({
259
+ chatId: '555',
260
+ audio: 'http://a.mp3',
261
+ })
262
+
263
+ expect(postMock).toHaveBeenCalledWith({
264
+ url: baseUrl,
265
+ headers: { Authorization: 'Bearer TOKEN' },
266
+ body: {
267
+ recipient_type: 'individual',
268
+ messaging_product: 'whatsapp',
269
+ to: '555',
270
+ type: 'audio',
271
+ audio: {
272
+ link: 'http://a.mp3',
273
+ },
274
+ },
275
+ })
276
+ })
277
+ })
@@ -2,3 +2,5 @@ export * from './im-platform.js'
2
2
  export * from './message-type.js'
3
3
  export * from './message-types.js'
4
4
  export * from './message-unified-mapper.js'
5
+ export * from './telegram-apis/telegram-apis.js'
6
+ export * from './whatsapp-apis/whatsapp-apis.js'
@@ -0,0 +1,105 @@
1
+ export function getTelegramApiUrls({
2
+ token,
3
+ telegramBaseUrl,
4
+ }: {
5
+ token: string
6
+ telegramBaseUrl?: string
7
+ }): TelegramApiUrls
8
+ export function telegramApis({ token }: { token: string }): TelegramApis
9
+ /**
10
+ * Builds a full set of Telegram Bot API endpoint URLs
11
+ * based on the provided bot token and an optional base URL.
12
+ *
13
+ * This helper centralizes all Telegram endpoints used by the system,
14
+ * making it easier to mock, override, or customize for testing environments.
15
+ */
16
+ export type TelegramApiUrls = {
17
+ /**
18
+ * URL to send a text message to a chat using the Telegram Bot API.
19
+ */
20
+ SEND_MESSAGE: string
21
+ /**
22
+ * URL to forward an existing message from one chat to another.
23
+ */
24
+ FORWARD_MESSAGE: string
25
+ /**
26
+ * URL to send a photo to a chat.
27
+ */
28
+ SEND_PHOTO: string
29
+ /**
30
+ * URL to send an audio file.
31
+ */
32
+ SEND_AUDIO: string
33
+ /**
34
+ * URL to send files such as PDF, DOC, ZIP, and others supported by Telegram.
35
+ */
36
+ SEND_DOCUMENT: string
37
+ /**
38
+ * URL to send a sticker.
39
+ */
40
+ SEND_STICKER: string
41
+ /**
42
+ * URL to send a video file.
43
+ */
44
+ SEND_VIDEO: string
45
+ /**
46
+ * URL to send a voice note.
47
+ */
48
+ SEND_VOICE: string
49
+ /**
50
+ * URL to send a geolocation point.
51
+ */
52
+ SEND_LOCATION: string
53
+ /**
54
+ * URL to send a chat action (typing, uploading photo, etc).
55
+ */
56
+ SEND_CHAT_ACTION: string
57
+ /**
58
+ * URL to retrieve the profile photos of a specific user.
59
+ */
60
+ GET_USER_PROFILE_PHOTOS: string
61
+ /**
62
+ * URL to poll for new updates (not used when using webhooks).
63
+ */
64
+ GET_UPDATES: string
65
+ /**
66
+ * URL to fetch a file path for downloading a file uploaded to Telegram servers.
67
+ */
68
+ GET_FILE: string
69
+ }
70
+ /**
71
+ * Factory that creates a set of high level Telegram Bot API helper methods.
72
+ *
73
+ * Each method sends a specific type of message (text, photo, video, document)
74
+ * through the Telegram Bot API using the provided bot token.
75
+ *
76
+ * This abstraction wraps the raw URL generation logic and HTTP calls,
77
+ * allowing higher level services to use clean method calls instead of
78
+ * managing endpoint URLs manually.
79
+ */
80
+ export type TelegramApis = {
81
+ /**
82
+ * Sends a text message to a specific chat.
83
+ */
84
+ sendMessage: Function
85
+ /**
86
+ * Sends a text message with an inline keyboard button group.
87
+ */
88
+ sendButtonsGroup: Function
89
+ /**
90
+ * Sends a photo with an optional caption.
91
+ */
92
+ sendPhoto: Function
93
+ /**
94
+ * Sends a video with an optional caption.
95
+ */
96
+ sendVideo: Function
97
+ /**
98
+ * Sends an audio file with an optional caption.
99
+ */
100
+ sendAudio: Function
101
+ /**
102
+ * Sends a document file with an optional caption.
103
+ */
104
+ sendDocument: Function
105
+ }