@mks2508/telegram-message-builder 0.2.0 → 0.3.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.
- package/dist/index.cjs +1057 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1022 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/builder/builder.d.ts +55 -0
- package/src/builder/builder.d.ts.map +1 -1
- package/src/builder/builder.ts +145 -10
- package/src/builder/index.d.ts +2 -1
- package/src/builder/index.d.ts.map +1 -1
- package/src/builder/index.ts +2 -1
- package/src/builder/media.d.ts +352 -0
- package/src/builder/media.d.ts.map +1 -0
- package/src/builder/media.test.ts +664 -0
- package/src/builder/media.ts +484 -0
- package/src/builder.test.ts +465 -0
- package/src/escaping.test.ts +2 -2
- package/src/formatters/index.d.ts +47 -0
- package/src/formatters/index.d.ts.map +1 -1
- package/src/formatters/index.ts +92 -1
- package/src/formatters/markdown.d.ts +179 -0
- package/src/formatters/markdown.d.ts.map +1 -0
- package/src/formatters/markdown.test.ts +417 -0
- package/src/formatters/markdown.ts +220 -0
- package/src/formatters/markdownv2.d.ts +184 -0
- package/src/formatters/markdownv2.d.ts.map +1 -0
- package/src/formatters/markdownv2.ts +235 -0
- package/src/formatters.test.ts +17 -7
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.ts +12 -0
- package/src/integration.test.ts +523 -0
- package/src/media-integration.test.ts +384 -0
- package/src/types/index.d.ts +1 -0
- package/src/types/index.d.ts.map +1 -1
- package/src/types/index.ts +1 -0
- package/src/types/media.types.d.ts +158 -0
- package/src/types/media.types.d.ts.map +1 -0
- package/src/types/media.types.ts +178 -0
- package/src/types.test.ts +539 -0
- package/src/utils/index.d.ts +1 -1
- package/src/utils/index.ts +0 -5
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Media Builder
|
|
3
|
+
* @description Fluent API for building media messages for Telegram Bot API
|
|
4
|
+
* @module telegram-message-builder/builder
|
|
5
|
+
*
|
|
6
|
+
* @see {@link https://core.telegram.org/bots/api#sendphoto | Telegram Bot API - sendPhoto}
|
|
7
|
+
* @see {@link https://core.telegram.org/bots/api#sendvideo | Telegram Bot API - sendVideo}
|
|
8
|
+
* @see {@link https://core.telegram.org/bots/api#senddocument | Telegram Bot API - sendDocument}
|
|
9
|
+
* @see {@link https://core.telegram.org/bots/api#sendaudio | Telegram Bot API - sendAudio}
|
|
10
|
+
* @see {@link https://core.telegram.org/bots/api#sendvoice | Telegram Bot API - sendVoice}
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
MediaSource,
|
|
15
|
+
MediaType,
|
|
16
|
+
IMediaCommonOptions,
|
|
17
|
+
IMediaBuildResult,
|
|
18
|
+
ParseMode,
|
|
19
|
+
} from "../types";
|
|
20
|
+
import * as fmt from "../formatters";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Telegram Media Builder - Fluent API for building media messages
|
|
24
|
+
*
|
|
25
|
+
* Provides a type-safe, fluent interface for constructing media messages
|
|
26
|
+
* compatible with Telegram Bot API v9.3+.
|
|
27
|
+
*
|
|
28
|
+
* Supports all three Telegram parse modes (HTML, Markdown, MarkdownV2) for caption formatting.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // Simple photo with caption
|
|
33
|
+
* const photo = TelegramMediaBuilder.photo("photo.jpg")
|
|
34
|
+
* .caption("My photo")
|
|
35
|
+
* .build();
|
|
36
|
+
*
|
|
37
|
+
* // Video with caption and options
|
|
38
|
+
* const video = TelegramMediaBuilder.video("video.mp4")
|
|
39
|
+
* .caption("My video")
|
|
40
|
+
* .duration(120)
|
|
41
|
+
* .thumbnail("thumb.jpg")
|
|
42
|
+
* .setParseMode("markdown")
|
|
43
|
+
* .build();
|
|
44
|
+
*
|
|
45
|
+
* // Document with custom options
|
|
46
|
+
* const doc = TelegramMediaBuilder.document("report.pdf")
|
|
47
|
+
* .caption("Q4 Report")
|
|
48
|
+
* .fileName("q4_2024.pdf")
|
|
49
|
+
* .mimeType("application/pdf")
|
|
50
|
+
* .build();
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export class TelegramMediaBuilder<T extends MediaType> {
|
|
54
|
+
protected source: MediaSource;
|
|
55
|
+
protected mediaType: T;
|
|
56
|
+
protected _caption?: string;
|
|
57
|
+
protected parseMode: ParseMode = "html";
|
|
58
|
+
protected options: IMediaCommonOptions = {};
|
|
59
|
+
|
|
60
|
+
protected constructor(source: MediaSource, mediaType: T) {
|
|
61
|
+
this.source = source;
|
|
62
|
+
this.mediaType = mediaType;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create a photo message builder
|
|
67
|
+
*
|
|
68
|
+
* @param source - File ID, URL, Buffer, or file path
|
|
69
|
+
* @returns Photo media builder with thumbnail() method
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const photo = TelegramMediaBuilder.photo("https://example.com/photo.jpg")
|
|
74
|
+
* .caption("Beautiful sunset")
|
|
75
|
+
* .thumbnail("thumb.jpg")
|
|
76
|
+
* .build();
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
static photo(source: MediaSource): PhotoBuilder {
|
|
80
|
+
return new PhotoBuilder(source, "photo");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create a video message builder
|
|
85
|
+
*
|
|
86
|
+
* @param source - File ID, URL, Buffer, or file path
|
|
87
|
+
* @returns Video media builder with duration(), width(), height(), thumbnail(), enableStreaming() methods
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const video = TelegramMediaBuilder.video("video.mp4")
|
|
92
|
+
* .caption("My video")
|
|
93
|
+
* .duration(120)
|
|
94
|
+
* .width(1920)
|
|
95
|
+
* .height(1080)
|
|
96
|
+
* .build();
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
static video(source: MediaSource): VideoBuilder {
|
|
100
|
+
return new VideoBuilder(source, "video");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Create a document message builder
|
|
105
|
+
*
|
|
106
|
+
* @param source - File ID, URL, Buffer, or file path
|
|
107
|
+
* @returns Document media builder with thumbnail(), fileName(), mimeType(), disableContentTypeDetection() methods
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const doc = TelegramMediaBuilder.document("report.pdf")
|
|
112
|
+
* .caption("Q4 Report")
|
|
113
|
+
* .fileName("q4_2024.pdf")
|
|
114
|
+
* .mimeType("application/pdf")
|
|
115
|
+
* .build();
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
static document(source: MediaSource): DocumentBuilder {
|
|
119
|
+
return new DocumentBuilder(source, "document");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Create an audio message builder
|
|
124
|
+
*
|
|
125
|
+
* @param source - File ID, URL, Buffer, or file path
|
|
126
|
+
* @returns Audio media builder with duration(), performer(), title(), thumbnail() methods
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const audio = TelegramMediaBuilder.audio("song.mp3")
|
|
131
|
+
* .caption("My favorite song")
|
|
132
|
+
* .duration(180)
|
|
133
|
+
* .performer("Artist Name")
|
|
134
|
+
* .title("Song Title")
|
|
135
|
+
* .build();
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
static audio(source: MediaSource): AudioBuilder {
|
|
139
|
+
return new AudioBuilder(source, "audio");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Create a voice message builder
|
|
144
|
+
*
|
|
145
|
+
* @param source - File ID, URL, Buffer, or file path
|
|
146
|
+
* @returns Voice media builder with duration() method
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const voice = TelegramMediaBuilder.voice("voice.ogg")
|
|
151
|
+
* .caption("Listen to this")
|
|
152
|
+
* .duration(30)
|
|
153
|
+
* .build();
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
static voice(source: MediaSource): VoiceBuilder {
|
|
157
|
+
return new VoiceBuilder(source, "voice");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Set caption for the media
|
|
162
|
+
*
|
|
163
|
+
* @param text - Caption text (0-1024 characters)
|
|
164
|
+
* @returns This builder for chaining
|
|
165
|
+
*/
|
|
166
|
+
caption(text: string): this {
|
|
167
|
+
this._caption = text;
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Set parse mode for caption formatting
|
|
173
|
+
*
|
|
174
|
+
* @param mode - Parse mode (html, markdown, or markdownv2)
|
|
175
|
+
* @returns This builder for chaining
|
|
176
|
+
*/
|
|
177
|
+
setParseMode(mode: ParseMode): this {
|
|
178
|
+
this.parseMode = mode;
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Set a custom option
|
|
184
|
+
*
|
|
185
|
+
* @param key - Option name
|
|
186
|
+
* @param value - Option value
|
|
187
|
+
* @returns This builder for chaining
|
|
188
|
+
*/
|
|
189
|
+
setOption<K extends keyof IMediaCommonOptions>(
|
|
190
|
+
key: K,
|
|
191
|
+
value: IMediaCommonOptions[K],
|
|
192
|
+
): this {
|
|
193
|
+
this.options[key] = value;
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Set multiple options at once
|
|
199
|
+
*
|
|
200
|
+
* @param opts - Object with options to set
|
|
201
|
+
* @returns This builder for chaining
|
|
202
|
+
*/
|
|
203
|
+
setOptions(opts: Partial<IMediaCommonOptions>): this {
|
|
204
|
+
this.options = { ...this.options, ...opts };
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Build the media message object
|
|
210
|
+
*
|
|
211
|
+
* @returns Complete media message ready for Telegram Bot API
|
|
212
|
+
*/
|
|
213
|
+
build(): IMediaBuildResult {
|
|
214
|
+
const result: IMediaBuildResult = {
|
|
215
|
+
media: this.source,
|
|
216
|
+
type: this.mediaType,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
if (this._caption !== undefined) {
|
|
220
|
+
result.caption = this.formatCaption(this._caption);
|
|
221
|
+
result.parse_mode = this.parseMode;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Merge in options
|
|
225
|
+
Object.assign(result, this.options);
|
|
226
|
+
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Format caption based on current parse mode
|
|
232
|
+
*
|
|
233
|
+
* @param text - Caption text to format
|
|
234
|
+
* @returns Formatted caption
|
|
235
|
+
*/
|
|
236
|
+
private formatCaption(text: string): string {
|
|
237
|
+
switch (this.parseMode) {
|
|
238
|
+
case "html":
|
|
239
|
+
return fmt.escapeHTML(text);
|
|
240
|
+
case "markdown":
|
|
241
|
+
return fmt.escapeMarkdown(text);
|
|
242
|
+
case "markdownv2":
|
|
243
|
+
return fmt.escapeMarkdownV2(text);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Photo-specific builder with convenience methods
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* const photo = TelegramMediaBuilder.photo("photo.jpg")
|
|
254
|
+
* .caption("My photo")
|
|
255
|
+
* .thumbnail("thumb.jpg")
|
|
256
|
+
* .build();
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
export class PhotoBuilder extends TelegramMediaBuilder<"photo"> {
|
|
260
|
+
/**
|
|
261
|
+
* Set thumbnail for the photo
|
|
262
|
+
*
|
|
263
|
+
* @param thumb - Thumbnail as Buffer or file path
|
|
264
|
+
* @returns This builder for chaining
|
|
265
|
+
*/
|
|
266
|
+
thumbnail(thumb: Buffer | string): this {
|
|
267
|
+
this.setOption("thumb", thumb);
|
|
268
|
+
return this;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Video-specific builder with convenience methods
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```typescript
|
|
277
|
+
* const video = TelegramMediaBuilder.video("video.mp4")
|
|
278
|
+
* .caption("My video")
|
|
279
|
+
* .duration(120)
|
|
280
|
+
* .width(1920)
|
|
281
|
+
* .height(1080)
|
|
282
|
+
* .thumbnail("thumb.jpg")
|
|
283
|
+
* .enableStreaming()
|
|
284
|
+
* .build();
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
export class VideoBuilder extends TelegramMediaBuilder<"video"> {
|
|
288
|
+
/**
|
|
289
|
+
* Set video duration
|
|
290
|
+
*
|
|
291
|
+
* @param seconds - Duration in seconds
|
|
292
|
+
* @returns This builder for chaining
|
|
293
|
+
*/
|
|
294
|
+
duration(seconds: number): this {
|
|
295
|
+
this.setOption("duration", seconds);
|
|
296
|
+
return this;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Set video width
|
|
301
|
+
*
|
|
302
|
+
* @param px - Width in pixels
|
|
303
|
+
* @returns This builder for chaining
|
|
304
|
+
*/
|
|
305
|
+
width(px: number): this {
|
|
306
|
+
this.setOption("width", px);
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Set video height
|
|
312
|
+
*
|
|
313
|
+
* @param px - Height in pixels
|
|
314
|
+
* @returns This builder for chaining
|
|
315
|
+
*/
|
|
316
|
+
height(px: number): this {
|
|
317
|
+
this.setOption("height", px);
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Set thumbnail for the video
|
|
323
|
+
*
|
|
324
|
+
* @param thumb - Thumbnail as Buffer or file path
|
|
325
|
+
* @returns This builder for chaining
|
|
326
|
+
*/
|
|
327
|
+
thumbnail(thumb: Buffer | string): this {
|
|
328
|
+
this.setOption("thumb", thumb);
|
|
329
|
+
return this;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Enable streaming for the video
|
|
334
|
+
*
|
|
335
|
+
* @returns This builder for chaining
|
|
336
|
+
*/
|
|
337
|
+
enableStreaming(): this {
|
|
338
|
+
this.setOption("support_streaming", true);
|
|
339
|
+
return this;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Document-specific builder with convenience methods
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```typescript
|
|
348
|
+
* const doc = TelegramMediaBuilder.document("report.pdf")
|
|
349
|
+
* .caption("Q4 Report")
|
|
350
|
+
* .thumbnail("thumb.jpg")
|
|
351
|
+
* .fileName("q4_2024.pdf")
|
|
352
|
+
* .mimeType("application/pdf")
|
|
353
|
+
* .disableContentTypeDetection()
|
|
354
|
+
* .build();
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
export class DocumentBuilder extends TelegramMediaBuilder<"document"> {
|
|
358
|
+
/**
|
|
359
|
+
* Set thumbnail for the document
|
|
360
|
+
*
|
|
361
|
+
* @param thumb - Thumbnail as Buffer or file path
|
|
362
|
+
* @returns This builder for chaining
|
|
363
|
+
*/
|
|
364
|
+
thumbnail(thumb: Buffer | string): this {
|
|
365
|
+
this.setOption("thumb", thumb);
|
|
366
|
+
return this;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Set original filename
|
|
371
|
+
*
|
|
372
|
+
* @param name - File name
|
|
373
|
+
* @returns This builder for chaining
|
|
374
|
+
*/
|
|
375
|
+
fileName(name: string): this {
|
|
376
|
+
this.setOption("file_name", name);
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Set MIME type
|
|
382
|
+
*
|
|
383
|
+
* @param type - MIME type string
|
|
384
|
+
* @returns This builder for chaining
|
|
385
|
+
*/
|
|
386
|
+
mimeType(type: string): this {
|
|
387
|
+
this.setOption("mime_type", type);
|
|
388
|
+
return this;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Disable automatic file type detection
|
|
393
|
+
*
|
|
394
|
+
* @returns This builder for chaining
|
|
395
|
+
*/
|
|
396
|
+
disableContentTypeDetection(): this {
|
|
397
|
+
this.setOption("disable_content_type_detection", true);
|
|
398
|
+
return this;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Audio-specific builder with convenience methods
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```typescript
|
|
407
|
+
* const audio = TelegramMediaBuilder.audio("song.mp3")
|
|
408
|
+
* .caption("My favorite song")
|
|
409
|
+
* .duration(180)
|
|
410
|
+
* .performer("Artist Name")
|
|
411
|
+
* .title("Song Title")
|
|
412
|
+
* .thumbnail("album_art.jpg")
|
|
413
|
+
* .build();
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
export class AudioBuilder extends TelegramMediaBuilder<"audio"> {
|
|
417
|
+
/**
|
|
418
|
+
* Set audio duration
|
|
419
|
+
*
|
|
420
|
+
* @param seconds - Duration in seconds
|
|
421
|
+
* @returns This builder for chaining
|
|
422
|
+
*/
|
|
423
|
+
duration(seconds: number): this {
|
|
424
|
+
this.setOption("duration", seconds);
|
|
425
|
+
return this;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Set performer name
|
|
430
|
+
*
|
|
431
|
+
* @param name - Performer name
|
|
432
|
+
* @returns This builder for chaining
|
|
433
|
+
*/
|
|
434
|
+
performer(name: string): this {
|
|
435
|
+
this.setOption("performer", name);
|
|
436
|
+
return this;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Set track title
|
|
441
|
+
*
|
|
442
|
+
* @param name - Track title
|
|
443
|
+
* @returns This builder for chaining
|
|
444
|
+
*/
|
|
445
|
+
title(name: string): this {
|
|
446
|
+
this.setOption("title", name);
|
|
447
|
+
return this;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Set thumbnail (album cover)
|
|
452
|
+
*
|
|
453
|
+
* @param thumb - Thumbnail as Buffer or file path
|
|
454
|
+
* @returns This builder for chaining
|
|
455
|
+
*/
|
|
456
|
+
thumbnail(thumb: Buffer | string): this {
|
|
457
|
+
this.setOption("thumb", thumb);
|
|
458
|
+
return this;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Voice-specific builder with convenience methods
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```typescript
|
|
467
|
+
* const voice = TelegramMediaBuilder.voice("voice.ogg")
|
|
468
|
+
* .caption("Listen to this")
|
|
469
|
+
* .duration(30)
|
|
470
|
+
* .build();
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
export class VoiceBuilder extends TelegramMediaBuilder<"voice"> {
|
|
474
|
+
/**
|
|
475
|
+
* Set voice duration
|
|
476
|
+
*
|
|
477
|
+
* @param seconds - Duration in seconds
|
|
478
|
+
* @returns This builder for chaining
|
|
479
|
+
*/
|
|
480
|
+
duration(seconds: number): this {
|
|
481
|
+
this.setOption("duration", seconds);
|
|
482
|
+
return this;
|
|
483
|
+
}
|
|
484
|
+
}
|