telegix 1.1.2 → 1.1.3

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/lib/context.js CHANGED
@@ -434,6 +434,16 @@ export class Context {
434
434
  return this.telegram.sendMediaGroup(this._assertChat(), media, extra);
435
435
  }
436
436
 
437
+ /**
438
+ * Send live photo (Bot API 10.2+)
439
+ * @param {any} photo - Photo file / file_id / url / Buffer / Stream
440
+ * @param {any} video - Paired video file / file_id / url / Buffer / Stream
441
+ * @param {object} [extra]
442
+ */
443
+ replyWithLivePhoto(photo, video, extra = {}) {
444
+ return this.telegram.sendLivePhoto(this._assertChat(), photo, video, extra);
445
+ }
446
+
437
447
  /**
438
448
  * Send location coordinates
439
449
  * @param {number} latitude
@@ -912,14 +922,203 @@ export class Context {
912
922
 
913
923
  /**
914
924
  * Send an ephemeral message
915
- * @param {string} text
916
- * @param {object} ephemeralParameters
925
+ * @param {string|object} text
926
+ * @param {object|number} [ephemeralParameters]
917
927
  * @param {object} [extra]
918
928
  */
919
929
  sendEphemeralMessage(text, ephemeralParameters, extra = {}) {
920
930
  return this.telegram.sendEphemeralMessage(this._assertChat(), text, ephemeralParameters, extra);
921
931
  }
922
932
 
933
+ /**
934
+ * Reply with an ephemeral message
935
+ * @param {string|object} text
936
+ * @param {object|number} [ephemeralParameters]
937
+ * @param {object} [extra]
938
+ */
939
+ replyEphemeral(text, ephemeralParameters, extra = {}) {
940
+ return this.sendEphemeralMessage(text, ephemeralParameters, extra);
941
+ }
942
+
943
+ /**
944
+ * Reply with a formatted table (Bot API 10.3 / HTML Table)
945
+ * @param {Array<string>|object} headersOrTable
946
+ * @param {Array<Array<any>>} [rows=[]]
947
+ * @param {object} [options={}]
948
+ */
949
+ replyWithTable(headersOrTable, rows = [], options = {}) {
950
+ return this.telegram.sendTable(this._assertChat(), headersOrTable, rows, options);
951
+ }
952
+
953
+ /**
954
+ * Reply with a formatted table (alias)
955
+ */
956
+ replyTable(headersOrTable, rows = [], options = {}) {
957
+ return this.replyWithTable(headersOrTable, rows, options);
958
+ }
959
+
960
+ /**
961
+ * Reply with a native Bot API 10.3 Rich Message Table
962
+ * @param {Array<string>|object} headersOrTable
963
+ * @param {Array<Array<any>>} [rows=[]]
964
+ * @param {object} [options={}]
965
+ */
966
+ replyWithRichTable(headersOrTable, rows = [], options = {}) {
967
+ return this.telegram.sendRichTable(this._assertChat(), headersOrTable, rows, options);
968
+ }
969
+
970
+ /**
971
+ * Reply with a modern Telegram Card Table (matching bot UI with rounded container and grid lines)
972
+ * @param {Array<string>|object} headersOrTable
973
+ * @param {Array<Array<any>>} [rows=[]]
974
+ * @param {object} [options={}]
975
+ */
976
+ replyWithTableCard(headersOrTable, rows = [], options = {}) {
977
+ return this.telegram.sendTableCard(this._assertChat(), headersOrTable, rows, options);
978
+ }
979
+
980
+ /**
981
+ * Reply with multiple stacked card tables (e.g. SYSTEM and PROFILE cards)
982
+ * @param {Array<object>} tables
983
+ * @param {object} [options={}]
984
+ */
985
+ replyWithCardTables(tables, options = {}) {
986
+ return this.telegram.sendCardTables(this._assertChat(), tables, options);
987
+ }
988
+
989
+ /**
990
+ * Reply with System Status Card (matching Telegram bot screenshot)
991
+ * All fields, labels, titles, and values are fully customizable
992
+ * @param {object|Array<Array<any>>} [data={}] - Custom status fields or rows matrix
993
+ * @param {object} [options={}] - Options including title, subtitle, asImage, etc.
994
+ */
995
+ replyWithSystemStatus(data = {}, options = {}) {
996
+ const title = options.title || data.title || options.header || '🤖 SYSTEM';
997
+ const subtitle = options.subtitle || data.subtitle || options.subHeader || 'Status';
998
+
999
+ let rows;
1000
+ if (Array.isArray(data)) {
1001
+ rows = data;
1002
+ } else if (data.rows && Array.isArray(data.rows)) {
1003
+ rows = data.rows;
1004
+ } else if (data.fields && Array.isArray(data.fields)) {
1005
+ rows = data.fields;
1006
+ } else {
1007
+ const keys = Object.keys(data).filter(
1008
+ (k) => !['title', 'subtitle', 'header', 'subHeader', 'rows', 'fields'].includes(k)
1009
+ );
1010
+ if (keys.length > 0) {
1011
+ rows = keys.map((key) => {
1012
+ const formattedLabel = key
1013
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
1014
+ .replace(/_/g, ' ')
1015
+ .replace(/\b\w/g, (c) => c.toUpperCase());
1016
+ return [formattedLabel, data[key]];
1017
+ });
1018
+ } else {
1019
+ rows = [
1020
+ ['Engine', data.engine || 'Telegix'],
1021
+ ['Runtime', data.runtime || '0h 19m 32s'],
1022
+ ['Node', data.node || process.version || 'v23.11'],
1023
+ ['Features', data.features ?? 514],
1024
+ ['Groups', data.groups ?? 168],
1025
+ ['Users', data.users ?? 9528],
1026
+ ];
1027
+ }
1028
+ }
1029
+
1030
+ return this.replyWithTableCard([title, subtitle], rows, {
1031
+ title,
1032
+ ...options,
1033
+ });
1034
+ }
1035
+
1036
+ /**
1037
+ * Reply with User Profile Card (matching Telegram bot screenshot)
1038
+ * All fields, labels, titles, and values are fully customizable
1039
+ * @param {object|Array<Array<any>>} [data={}] - Custom profile fields or rows matrix
1040
+ * @param {object} [options={}] - Options including title, subtitle, asImage, etc.
1041
+ */
1042
+ replyWithUserProfile(data = {}, options = {}) {
1043
+ const title = options.title || data.title || options.header || '👤 PROFILE';
1044
+ const subtitle = options.subtitle || data.subtitle || options.subHeader || 'Info';
1045
+
1046
+ let rows;
1047
+ if (Array.isArray(data)) {
1048
+ rows = data;
1049
+ } else if (data.rows && Array.isArray(data.rows)) {
1050
+ rows = data.rows;
1051
+ } else if (data.fields && Array.isArray(data.fields)) {
1052
+ rows = data.fields;
1053
+ } else {
1054
+ const keys = Object.keys(data).filter(
1055
+ (k) => !['title', 'subtitle', 'header', 'subHeader', 'rows', 'fields'].includes(k)
1056
+ );
1057
+ if (keys.length > 0) {
1058
+ rows = keys.map((key) => {
1059
+ const formattedLabel = key
1060
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
1061
+ .replace(/_/g, ' ')
1062
+ .replace(/\b\w/g, (c) => c.toUpperCase());
1063
+ return [formattedLabel, data[key]];
1064
+ });
1065
+ } else {
1066
+ const username = data.username || (this.from?.username ? `@${this.from.username}` : '@seventynn');
1067
+ rows = [
1068
+ ['Username', username],
1069
+ ['Status', data.status || 'Free User'],
1070
+ ['Limit', data.limit ?? 0],
1071
+ ['Points', data.points ?? 0],
1072
+ ['Time', data.time || 'Selasa, 8 September 2026'],
1073
+ ];
1074
+ }
1075
+ }
1076
+
1077
+ return this.replyWithTableCard([title, subtitle], rows, {
1078
+ title,
1079
+ ...options,
1080
+ });
1081
+ }
1082
+
1083
+ /**
1084
+ * Edit ephemeral message text
1085
+ * @param {string|object} text
1086
+ * @param {object} [extra]
1087
+ */
1088
+ editEphemeralMessageText(text, extra = {}) {
1089
+ const msgId = this._assertMessage();
1090
+ return this.telegram.editEphemeralMessageText(this._assertChat(), msgId, text, extra);
1091
+ }
1092
+
1093
+ /**
1094
+ * Edit ephemeral message media
1095
+ * @param {object} media
1096
+ * @param {object} [extra]
1097
+ */
1098
+ editEphemeralMessageMedia(media, extra = {}) {
1099
+ const msgId = this._assertMessage();
1100
+ return this.telegram.editEphemeralMessageMedia(this._assertChat(), msgId, media, extra);
1101
+ }
1102
+
1103
+ /**
1104
+ * Edit ephemeral message caption
1105
+ * @param {string} caption
1106
+ * @param {object} [extra]
1107
+ */
1108
+ editEphemeralMessageCaption(caption, extra = {}) {
1109
+ const msgId = this._assertMessage();
1110
+ return this.telegram.editEphemeralMessageCaption(this._assertChat(), msgId, caption, extra);
1111
+ }
1112
+
1113
+ /**
1114
+ * Delete an ephemeral message
1115
+ * @param {number} [messageId]
1116
+ */
1117
+ deleteEphemeralMessage(messageId) {
1118
+ const msgId = messageId || this._assertMessage();
1119
+ return this.telegram.deleteEphemeralMessage(this._assertChat(), msgId);
1120
+ }
1121
+
923
1122
  /**
924
1123
  * Get user personal chat messages
925
1124
  * @param {number} [userId=this.userId]
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Telegix - Ephemeral Messages Engine (Telegram Bot API 10.3)
3
+ * Provides EphemeralMessageParameters class and helpers for temporary / disappearing messages.
4
+ * @module telegix/ephemeral
5
+ */
6
+
7
+ export class EphemeralMessageParameters {
8
+ /**
9
+ * @param {object|number} [options={}]
10
+ * @param {number} [options.lifetime] - Message lifetime in seconds before disappearing
11
+ * @param {number} [options.lifetime_seconds] - Alias for lifetime
12
+ * @param {number} [options.receiver_user_id] - User identifier who sees the message
13
+ * @param {string} [options.callback_query_id] - Callback query identifier
14
+ * @param {boolean} [options.replace_callback_query_message=false] - Replace original callback message
15
+ */
16
+ constructor(options = {}) {
17
+ if (typeof options === 'number') {
18
+ this.lifetime = options;
19
+ this.receiver_user_id = undefined;
20
+ this.callback_query_id = undefined;
21
+ this.replace_callback_query_message = false;
22
+ } else if (options && typeof options === 'object') {
23
+ this.lifetime = options.lifetime ?? options.lifetime_seconds;
24
+ this.receiver_user_id = options.receiver_user_id ?? options.receiver;
25
+ this.callback_query_id = options.callback_query_id ?? options.callbackQueryId;
26
+ this.replace_callback_query_message = Boolean(
27
+ options.replace_callback_query_message ?? options.replaceMessage ?? false
28
+ );
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Set lifetime in seconds
34
+ * @param {number} seconds
35
+ * @returns {this}
36
+ */
37
+ setLifetime(seconds) {
38
+ this.lifetime = seconds;
39
+ return this;
40
+ }
41
+
42
+ /**
43
+ * Set lifetime in seconds (fluent alias)
44
+ * @param {number} seconds
45
+ * @returns {this}
46
+ */
47
+ lifetime(seconds) {
48
+ this.lifetime = seconds;
49
+ return this;
50
+ }
51
+
52
+ /**
53
+ * Target specific receiver user ID
54
+ * @param {number|string} userId
55
+ * @returns {this}
56
+ */
57
+ receiver(userId) {
58
+ this.receiver_user_id = Number(userId);
59
+ return this;
60
+ }
61
+
62
+ /**
63
+ * Associate with callback query
64
+ * @param {string} queryId
65
+ * @returns {this}
66
+ */
67
+ callbackQuery(queryId) {
68
+ this.callback_query_id = String(queryId);
69
+ return this;
70
+ }
71
+
72
+ /**
73
+ * Allow bots to show an ephemeral message in place of the original message (Bot API 10.3)
74
+ * @param {boolean} [replace=true]
75
+ * @returns {this}
76
+ */
77
+ replaceCallbackQueryMessage(replace = true) {
78
+ this.replace_callback_query_message = Boolean(replace);
79
+ return this;
80
+ }
81
+
82
+ /**
83
+ * Convert to Telegram API payload JSON object
84
+ * @returns {object}
85
+ */
86
+ toJSON() {
87
+ const res = {};
88
+ if (this.lifetime !== undefined && this.lifetime !== null) {
89
+ res.lifetime = Number(this.lifetime);
90
+ }
91
+ if (this.receiver_user_id !== undefined && this.receiver_user_id !== null) {
92
+ res.receiver_user_id = Number(this.receiver_user_id);
93
+ }
94
+ if (this.callback_query_id !== undefined && this.callback_query_id !== null) {
95
+ res.callback_query_id = String(this.callback_query_id);
96
+ }
97
+ if (this.replace_callback_query_message) {
98
+ res.replace_callback_query_message = true;
99
+ }
100
+ return res;
101
+ }
102
+
103
+ /**
104
+ * Factory method to create parameters
105
+ * @param {object|number} [options]
106
+ * @returns {EphemeralMessageParameters}
107
+ */
108
+ static create(options) {
109
+ return new EphemeralMessageParameters(options);
110
+ }
111
+
112
+ /**
113
+ * Create ephemeral parameters replacing the callback query message
114
+ * @param {string} callbackQueryId
115
+ * @param {object} [options]
116
+ * @returns {EphemeralMessageParameters}
117
+ */
118
+ static replace(callbackQueryId, options = {}) {
119
+ return new EphemeralMessageParameters({
120
+ callback_query_id: callbackQueryId,
121
+ replace_callback_query_message: true,
122
+ ...options,
123
+ });
124
+ }
125
+
126
+ /**
127
+ * Create ephemeral parameters for a specific receiver user
128
+ * @param {number|string} userId
129
+ * @param {number} [lifetimeSeconds=60]
130
+ * @param {object} [options]
131
+ * @returns {EphemeralMessageParameters}
132
+ */
133
+ static forUser(userId, lifetimeSeconds = 60, options = {}) {
134
+ return new EphemeralMessageParameters({
135
+ receiver_user_id: userId,
136
+ lifetime: lifetimeSeconds,
137
+ ...options,
138
+ });
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Telegram Bot API ReplyParameters class (Bot API 10.2+)
144
+ * Describes reply parameters for a message, including replying to ephemeral messages.
145
+ */
146
+ export class ReplyParameters {
147
+ /**
148
+ * @param {number|object} [messageIdOrOptions]
149
+ * @param {number} [ephemeralMessageId]
150
+ */
151
+ constructor(messageIdOrOptions = {}, ephemeralMessageId) {
152
+ if (typeof messageIdOrOptions === 'number') {
153
+ this.message_id = messageIdOrOptions;
154
+ if (ephemeralMessageId !== undefined) {
155
+ this.ephemeral_message_id = ephemeralMessageId;
156
+ }
157
+ } else if (messageIdOrOptions && typeof messageIdOrOptions === 'object') {
158
+ this.message_id = messageIdOrOptions.message_id ?? messageIdOrOptions.messageId;
159
+ this.chat_id = messageIdOrOptions.chat_id ?? messageIdOrOptions.chatId;
160
+ this.allow_sending_without_reply = Boolean(
161
+ messageIdOrOptions.allow_sending_without_reply ?? messageIdOrOptions.allowSendingWithoutReply
162
+ );
163
+ this.quote = messageIdOrOptions.quote;
164
+ this.quote_parse_mode = messageIdOrOptions.quote_parse_mode ?? messageIdOrOptions.quoteParseMode;
165
+ this.quote_entities = messageIdOrOptions.quote_entities ?? messageIdOrOptions.quoteEntities;
166
+ this.quote_position = messageIdOrOptions.quote_position ?? messageIdOrOptions.quotePosition;
167
+ this.ephemeral_message_id = messageIdOrOptions.ephemeral_message_id ?? messageIdOrOptions.ephemeralMessageId ?? ephemeralMessageId;
168
+ this.checklist_task_id = messageIdOrOptions.checklist_task_id ?? messageIdOrOptions.checklistTaskId;
169
+ this.poll_option_id = messageIdOrOptions.poll_option_id ?? messageIdOrOptions.pollOptionId;
170
+ this.is_ephemeral = messageIdOrOptions.is_ephemeral ?? messageIdOrOptions.isEphemeral;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Set ephemeral message ID to reply to (Bot API 10.2)
176
+ * @param {number} id
177
+ * @returns {this}
178
+ */
179
+ setEphemeralMessageId(id) {
180
+ this.ephemeral_message_id = id;
181
+ return this;
182
+ }
183
+
184
+ /**
185
+ * Set ephemeral message ID (fluent alias)
186
+ * @param {number} id
187
+ * @returns {this}
188
+ */
189
+ ephemeralMessageId(id) {
190
+ return this.setEphemeralMessageId(id);
191
+ }
192
+
193
+ /**
194
+ * Set target message ID
195
+ * @param {number} id
196
+ * @returns {this}
197
+ */
198
+ messageId(id) {
199
+ this.message_id = id;
200
+ return this;
201
+ }
202
+
203
+ /**
204
+ * Set target chat ID
205
+ * @param {number|string} chatId
206
+ * @returns {this}
207
+ */
208
+ chatId(chatId) {
209
+ this.chat_id = chatId;
210
+ return this;
211
+ }
212
+
213
+ /**
214
+ * Allow sending without reply if original message is deleted
215
+ * @param {boolean} [allow=true]
216
+ * @returns {this}
217
+ */
218
+ allowWithoutReply(allow = true) {
219
+ this.allow_sending_without_reply = Boolean(allow);
220
+ return this;
221
+ }
222
+
223
+ /**
224
+ * Quote a part of the original message
225
+ * @param {string} text
226
+ * @param {object} [options={}]
227
+ * @returns {this}
228
+ */
229
+ quoteText(text, options = {}) {
230
+ this.quote = String(text);
231
+ if (options.parse_mode) this.quote_parse_mode = options.parse_mode;
232
+ if (options.position !== undefined) this.quote_position = options.position;
233
+ return this;
234
+ }
235
+
236
+ /**
237
+ * Convert to Telegram API payload JSON object
238
+ * @returns {object}
239
+ */
240
+ toJSON() {
241
+ const res = {};
242
+ if (this.message_id !== undefined && this.message_id !== null) {
243
+ res.message_id = Number(this.message_id);
244
+ }
245
+ if (this.chat_id !== undefined && this.chat_id !== null) {
246
+ res.chat_id = this.chat_id;
247
+ }
248
+ if (this.allow_sending_without_reply) {
249
+ res.allow_sending_without_reply = true;
250
+ }
251
+ if (this.quote !== undefined && this.quote !== null) {
252
+ res.quote = String(this.quote);
253
+ }
254
+ if (this.quote_parse_mode) {
255
+ res.quote_parse_mode = this.quote_parse_mode;
256
+ }
257
+ if (this.quote_entities) {
258
+ res.quote_entities = this.quote_entities;
259
+ }
260
+ if (this.quote_position !== undefined && this.quote_position !== null) {
261
+ res.quote_position = Number(this.quote_position);
262
+ }
263
+ if (this.ephemeral_message_id !== undefined && this.ephemeral_message_id !== null) {
264
+ res.ephemeral_message_id = Number(this.ephemeral_message_id);
265
+ }
266
+ if (this.checklist_task_id !== undefined && this.checklist_task_id !== null) {
267
+ res.checklist_task_id = Number(this.checklist_task_id);
268
+ }
269
+ if (this.poll_option_id !== undefined && this.poll_option_id !== null) {
270
+ res.poll_option_id = this.poll_option_id;
271
+ }
272
+ if (this.is_ephemeral !== undefined && this.is_ephemeral !== null) {
273
+ res.is_ephemeral = Boolean(this.is_ephemeral);
274
+ }
275
+ return res;
276
+ }
277
+
278
+ /**
279
+ * Static factory to reply to a standard message
280
+ * @param {number} messageId
281
+ * @param {object} [options]
282
+ * @returns {ReplyParameters}
283
+ */
284
+ static to(messageId, options = {}) {
285
+ return new ReplyParameters({ message_id: messageId, ...options });
286
+ }
287
+
288
+ /**
289
+ * Static factory to reply to an ephemeral message (Bot API 10.2)
290
+ * @param {number} ephemeralMessageId
291
+ * @param {object} [options]
292
+ * @returns {ReplyParameters}
293
+ */
294
+ static ephemeral(ephemeralMessageId, options = {}) {
295
+ return new ReplyParameters({ ephemeral_message_id: ephemeralMessageId, ...options });
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Telegram Bot API BotCommand class (Bot API 10.2+)
301
+ * Represents a bot command with optional is_ephemeral support for private bot command visibility.
302
+ */
303
+ export class BotCommand {
304
+ /**
305
+ * @param {string} command - Text of the command; 1-32 characters
306
+ * @param {string} description - Description of the command; 1-256 characters
307
+ * @param {boolean} [is_ephemeral=false] - True, if the command should be ephemeral (Bot API 10.2)
308
+ */
309
+ constructor(command, description, is_ephemeral = false) {
310
+ this.command = String(command || '').replace(/^\//, '').toLowerCase();
311
+ this.description = String(description || '');
312
+ this.is_ephemeral = Boolean(is_ephemeral);
313
+ }
314
+
315
+ /**
316
+ * Mark command as ephemeral or not (Bot API 10.2)
317
+ * @param {boolean} [val=true]
318
+ * @returns {this}
319
+ */
320
+ ephemeral(val = true) {
321
+ this.is_ephemeral = Boolean(val);
322
+ return this;
323
+ }
324
+
325
+ toJSON() {
326
+ return {
327
+ command: this.command,
328
+ description: this.description,
329
+ ...(this.is_ephemeral ? { is_ephemeral: true } : {}),
330
+ };
331
+ }
332
+
333
+ /**
334
+ * Create a standard bot command
335
+ * @param {string} command
336
+ * @param {string} description
337
+ * @param {boolean} [is_ephemeral=false]
338
+ * @returns {BotCommand}
339
+ */
340
+ static create(command, description, is_ephemeral = false) {
341
+ return new BotCommand(command, description, is_ephemeral);
342
+ }
343
+
344
+ /**
345
+ * Create an ephemeral bot command (Bot API 10.2)
346
+ * @param {string} command
347
+ * @param {string} description
348
+ * @returns {BotCommand}
349
+ */
350
+ static ephemeral(command, description) {
351
+ return new BotCommand(command, description, true);
352
+ }
353
+ }