@mks2508/telegram-message-builder 0.2.0 → 0.3.1

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.
Files changed (57) hide show
  1. package/dist/builder/builder.d.ts +87 -0
  2. package/dist/builder/index.d.ts +2 -0
  3. package/dist/builder/media.d.ts +351 -0
  4. package/dist/formatters/index.d.ts +86 -0
  5. package/dist/formatters/markdown.d.ts +178 -0
  6. package/dist/formatters/markdownv2.d.ts +183 -0
  7. package/dist/index.cjs +1057 -12
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +11 -0
  10. package/dist/index.js +1022 -13
  11. package/dist/index.js.map +1 -1
  12. package/dist/keyboard/index.d.ts +113 -0
  13. package/dist/types/constants.d.ts +13 -0
  14. package/dist/types/core.types.d.ts +74 -0
  15. package/dist/types/index.d.ts +4 -0
  16. package/dist/types/keyboard-types.index.d.ts +1 -0
  17. package/dist/types/keyboard.types.d.ts +95 -0
  18. package/dist/types/main.types.d.ts +22 -0
  19. package/dist/types/media.types.d.ts +157 -0
  20. package/package.json +1 -1
  21. package/src/builder/builder.d.ts +55 -0
  22. package/src/builder/builder.d.ts.map +1 -1
  23. package/src/builder/builder.ts +145 -10
  24. package/src/builder/index.d.ts +2 -1
  25. package/src/builder/index.d.ts.map +1 -1
  26. package/src/builder/index.ts +2 -1
  27. package/src/builder/media.d.ts +352 -0
  28. package/src/builder/media.d.ts.map +1 -0
  29. package/src/builder/media.test.ts +664 -0
  30. package/src/builder/media.ts +484 -0
  31. package/src/builder.test.ts +465 -0
  32. package/src/escaping.test.ts +2 -2
  33. package/src/formatters/index.d.ts +47 -0
  34. package/src/formatters/index.d.ts.map +1 -1
  35. package/src/formatters/index.ts +92 -1
  36. package/src/formatters/markdown.d.ts +179 -0
  37. package/src/formatters/markdown.d.ts.map +1 -0
  38. package/src/formatters/markdown.test.ts +417 -0
  39. package/src/formatters/markdown.ts +220 -0
  40. package/src/formatters/markdownv2.d.ts +184 -0
  41. package/src/formatters/markdownv2.d.ts.map +1 -0
  42. package/src/formatters/markdownv2.ts +235 -0
  43. package/src/formatters.test.ts +17 -7
  44. package/src/index.d.ts +2 -0
  45. package/src/index.d.ts.map +1 -1
  46. package/src/index.ts +12 -0
  47. package/src/integration.test.ts +523 -0
  48. package/src/media-integration.test.ts +384 -0
  49. package/src/types/index.d.ts +1 -0
  50. package/src/types/index.d.ts.map +1 -1
  51. package/src/types/index.ts +1 -0
  52. package/src/types/media.types.d.ts +158 -0
  53. package/src/types/media.types.d.ts.map +1 -0
  54. package/src/types/media.types.ts +178 -0
  55. package/src/types.test.ts +539 -0
  56. package/src/utils/index.d.ts +1 -1
  57. 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
+ }