@volter/twin-telegram 1.0.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/LICENSE +202 -0
- package/README.md +53 -0
- package/dist/generated/pack-facts.json +53 -0
- package/dist/journeys/coverage.json +138 -0
- package/dist/journeys/customer-life.json +1229 -0
- package/dist/journeys/customer-life.outline.md +99 -0
- package/dist/journeys/customer-life.outline.verdict.json +76 -0
- package/dist/journeys/customer-life.verdict.json +134 -0
- package/dist/journeys/decisions.json +95 -0
- package/dist/journeys/demand.json +152 -0
- package/dist/journeys/score.json +163 -0
- package/dist/journeys/unreachable.json +29 -0
- package/dist/journeys/vendor-examples.json +1554 -0
- package/dist/journeys/vendor-examples.verdict.json +14 -0
- package/dist/spec/SOURCE.md +51 -0
- package/dist/spec/bot-api.html.gz +0 -0
- package/dist/spec/doc-examples.json +344 -0
- package/dist/spec/grouping.json +1 -0
- package/dist/spec/openapi.json.gz +0 -0
- package/dist/spec/page-to-openapi.ts +258 -0
- package/dist/spec/patches.json +289 -0
- package/dist/spec/sources.json +416 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +21 -0
- package/dist/src/engine/media.d.ts +17 -0
- package/dist/src/engine/media.js +75 -0
- package/dist/src/engine/text.d.ts +45 -0
- package/dist/src/engine/text.js +512 -0
- package/dist/src/fetch.d.ts +2 -0
- package/dist/src/fetch.js +17 -0
- package/dist/src/generated/surface.gen.json +1 -0
- package/dist/src/generated/ui.gen.json +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +9 -0
- package/dist/src/manifest.d.ts +2 -0
- package/dist/src/manifest.js +104 -0
- package/dist/src/semantics/around.d.ts +2 -0
- package/dist/src/semantics/around.js +32 -0
- package/dist/src/semantics/available-methods.d.ts +12 -0
- package/dist/src/semantics/available-methods.js +266 -0
- package/dist/src/semantics/doors.d.ts +18 -0
- package/dist/src/semantics/doors.js +292 -0
- package/dist/src/semantics/getting-updates.d.ts +3 -0
- package/dist/src/semantics/getting-updates.js +68 -0
- package/dist/src/semantics/index.d.ts +2 -0
- package/dist/src/semantics/index.js +19 -0
- package/dist/src/semantics/shared.d.ts +112 -0
- package/dist/src/semantics/shared.js +424 -0
- package/dist/src/semantics/states.d.ts +18 -0
- package/dist/src/semantics/states.js +37 -0
- package/dist/src/semantics/updating-messages.d.ts +2 -0
- package/dist/src/semantics/updating-messages.js +48 -0
- package/dist/src/server.d.ts +7 -0
- package/dist/src/server.js +24 -0
- package/generated/pack-facts.json +53 -0
- package/journeys/coverage.json +138 -0
- package/journeys/customer-life.json +1229 -0
- package/journeys/customer-life.outline.md +99 -0
- package/journeys/customer-life.outline.verdict.json +76 -0
- package/journeys/customer-life.verdict.json +134 -0
- package/journeys/decisions.json +95 -0
- package/journeys/demand.json +152 -0
- package/journeys/score.json +163 -0
- package/journeys/unreachable.json +29 -0
- package/journeys/vendor-examples.json +1554 -0
- package/journeys/vendor-examples.verdict.json +14 -0
- package/package.json +37 -0
- package/spec/SOURCE.md +51 -0
- package/spec/bot-api.html.gz +0 -0
- package/spec/doc-examples.json +344 -0
- package/spec/grouping.json +1 -0
- package/spec/openapi.json.gz +0 -0
- package/spec/page-to-openapi.ts +258 -0
- package/spec/patches.json +289 -0
- package/spec/sources.json +416 -0
- package/src/cli.ts +22 -0
- package/src/engine/media.ts +67 -0
- package/src/engine/text.ts +409 -0
- package/src/fetch.ts +18 -0
- package/src/generated/surface.gen.json +1 -0
- package/src/generated/ui.gen.json +1 -0
- package/src/index.ts +11 -0
- package/src/manifest.ts +114 -0
- package/src/semantics/around.ts +33 -0
- package/src/semantics/available-methods.ts +253 -0
- package/src/semantics/doors.ts +277 -0
- package/src/semantics/getting-updates.ts +64 -0
- package/src/semantics/index.ts +23 -0
- package/src/semantics/shared.ts +428 -0
- package/src/semantics/states.ts +38 -0
- package/src/semantics/updating-messages.ts +41 -0
- package/src/server.ts +17 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
{
|
|
2
|
+
"https://core.telegram.org/bots/api#accent-colors": {
|
|
3
|
+
"status": 200,
|
|
4
|
+
"checked": "2026-10-02",
|
|
5
|
+
"quotes": {
|
|
6
|
+
"Colors with identifiers 0 (red), 1 (orange), 2 (purple/violet), 3 (green), 4 (cyan), 5 (blue), 6 (pink) can be customized by app themes.": true
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"https://core.telegram.org/bots/api#chat": {
|
|
10
|
+
"status": 200,
|
|
11
|
+
"checked": "2026-10-02",
|
|
12
|
+
"quotes": {
|
|
13
|
+
"Unique identifier for this chat.": true,
|
|
14
|
+
"Type of the chat, can be either": true
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"https://core.telegram.org/bots/api#chatmember": {
|
|
18
|
+
"status": 200,
|
|
19
|
+
"checked": "2026-10-02",
|
|
20
|
+
"quotes": {
|
|
21
|
+
"Currently, the following 6 types of chat members are supported": true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"https://core.telegram.org/bots/api#chatmemberadministrator": {
|
|
25
|
+
"status": 200,
|
|
26
|
+
"checked": "2026-10-02",
|
|
27
|
+
"quotes": {
|
|
28
|
+
"True , if the administrator can post messages in the channel": true,
|
|
29
|
+
"Represents a chat member that has some additional privileges.": true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"https://core.telegram.org/bots/api#chatmemberbanned": {
|
|
33
|
+
"status": 200,
|
|
34
|
+
"checked": "2026-10-02",
|
|
35
|
+
"quotes": {
|
|
36
|
+
"If 0, then the user is banned forever": true,
|
|
37
|
+
"Date when restrictions will be lifted for this user; Unix time. If 0, then the user is banned forever": true,
|
|
38
|
+
"Represents a chat member that was banned in the chat and can't return to the chat or view chat messages.": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"https://core.telegram.org/bots/api#chatmembermember": {
|
|
42
|
+
"status": 200,
|
|
43
|
+
"checked": "2026-10-02",
|
|
44
|
+
"quotes": {
|
|
45
|
+
"Represents a chat member that has no additional privileges or restrictions.": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"https://core.telegram.org/bots/api#chatmemberowner": {
|
|
49
|
+
"status": 200,
|
|
50
|
+
"checked": "2026-10-02",
|
|
51
|
+
"quotes": {
|
|
52
|
+
"Represents a chat member that owns the chat and has all administrator privileges.": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"https://core.telegram.org/bots/api#chatphoto": {
|
|
56
|
+
"status": 200,
|
|
57
|
+
"checked": "2026-10-02",
|
|
58
|
+
"quotes": {
|
|
59
|
+
"File identifier of small (160x160) chat photo.": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"https://core.telegram.org/bots/api#deletemessage": {
|
|
63
|
+
"status": 200,
|
|
64
|
+
"checked": "2026-10-02",
|
|
65
|
+
"quotes": {
|
|
66
|
+
"Use this method to delete a message, including service messages, with the following limitations:": true,
|
|
67
|
+
"A message can only be deleted if it was sent less than 48 hours ago.": true,
|
|
68
|
+
"Service messages about a supergroup, channel, or forum topic creation can't be deleted.": true,
|
|
69
|
+
"Bots can delete outgoing messages in private chats, groups, and supergroups.": true,
|
|
70
|
+
"Bots can delete incoming messages in private chats.": true,
|
|
71
|
+
"Bots granted can_post_messages permissions can delete outgoing messages in channels.": true,
|
|
72
|
+
"If the bot is an administrator of a group, it can delete any message there.": true,
|
|
73
|
+
"If the bot has can_delete_messages administrator right in a supergroup or a channel, it can delete any message there.": true
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"https://core.telegram.org/bots/api#deletewebhook": {
|
|
77
|
+
"status": 200,
|
|
78
|
+
"checked": "2026-10-02",
|
|
79
|
+
"quotes": {
|
|
80
|
+
"Pass True to drop all pending updates": true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"https://core.telegram.org/bots/api#file": {
|
|
84
|
+
"status": 200,
|
|
85
|
+
"checked": "2026-10-02",
|
|
86
|
+
"quotes": {
|
|
87
|
+
"Optional. File path. Use https://api.telegram.org/file/bot<token>/<file_path> to get the file.": true,
|
|
88
|
+
"Unique identifier for this file, which is supposed to be the same over time and for different bots.": true
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"https://core.telegram.org/bots/api#formatting-options": {
|
|
92
|
+
"status": 200,
|
|
93
|
+
"checked": "2026-10-02",
|
|
94
|
+
"quotes": {
|
|
95
|
+
"Custom emoji entities can only be used by bots that purchased additional usernames on Fragment or in the messages directly sent by the bot to private, group and supergroup chats if the owner of the bot has a Telegram Premium subscription.": true,
|
|
96
|
+
"Links tg://user?id=<user_id> can be used to mention a user by their identifier without using a username.": true
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"https://core.telegram.org/bots/api#getchat": {
|
|
100
|
+
"status": 200,
|
|
101
|
+
"checked": "2026-10-02",
|
|
102
|
+
"quotes": {
|
|
103
|
+
"Use this method to get up-to-date information about the chat. Returns a ChatFullInfo object on success.": true
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"https://core.telegram.org/bots/api#getchatmember": {
|
|
107
|
+
"status": 200,
|
|
108
|
+
"checked": "2026-10-02",
|
|
109
|
+
"quotes": {
|
|
110
|
+
"Use this method to get information about a member of a chat.": true
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"https://core.telegram.org/bots/api#getfile": {
|
|
114
|
+
"status": 200,
|
|
115
|
+
"checked": "2026-10-02",
|
|
116
|
+
"quotes": {
|
|
117
|
+
"Use this method to get basic information about a file and prepare it for downloading. For the moment, bots can download files of up to 20MB in size.": true,
|
|
118
|
+
"The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path> , where <file_path> is taken from the response.": true
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"https://core.telegram.org/bots/api#getme": {
|
|
122
|
+
"status": 200,
|
|
123
|
+
"checked": "2026-10-02",
|
|
124
|
+
"quotes": {
|
|
125
|
+
"Returns basic information about the bot in form of a User object.": true
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"https://core.telegram.org/bots/api#getting-updates": {
|
|
129
|
+
"status": 200,
|
|
130
|
+
"checked": "2026-10-02",
|
|
131
|
+
"quotes": {
|
|
132
|
+
"Incoming updates are stored on the server until the bot receives them either way, but they will not be kept longer than 24 hours.": true
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"https://core.telegram.org/bots/api#getupdates": {
|
|
136
|
+
"status": 200,
|
|
137
|
+
"checked": "2026-10-02",
|
|
138
|
+
"quotes": {
|
|
139
|
+
"Limits the number of updates to be retrieved. Values between 1-100 are accepted. Defaults to 100.": true,
|
|
140
|
+
"Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling.": true,
|
|
141
|
+
"If not specified, the previous setting will be used.": true,
|
|
142
|
+
"The negative offset can be specified to retrieve updates starting from -offset update from the end of the updates queue. All previous updates will be forgotten.": true,
|
|
143
|
+
"An update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id.": true,
|
|
144
|
+
"Should be positive, short polling should be used for testing purposes only.": true,
|
|
145
|
+
"Specify an empty list to receive all update types except chat_member, message_reaction, and message_reaction_count (default).": true,
|
|
146
|
+
"Please note that this parameter doesn't affect updates created before the call to getUpdates, so unwanted updates may be received for a short period of time.": true,
|
|
147
|
+
"Values between 1-100 are accepted. Defaults to 100.": true
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
"https://core.telegram.org/bots/api#making-requests": {
|
|
151
|
+
"status": 200,
|
|
152
|
+
"checked": "2026-10-02",
|
|
153
|
+
"quotes": {
|
|
154
|
+
"We support GET and POST HTTP methods.": true,
|
|
155
|
+
"All methods in the Bot API are case-insensitive.": true,
|
|
156
|
+
"If 'ok' equals True, the request was successful and the result of the query can be found in the 'result' field.": true,
|
|
157
|
+
"We support four ways of passing parameters in Bot API requests": true,
|
|
158
|
+
"In case of an unsuccessful request, 'ok' equals False and the error is explained in the 'description'.": true,
|
|
159
|
+
"https://api.telegram.org/bot<token>/METHOD_NAME": true
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"https://core.telegram.org/bots/api#markdown-style": {
|
|
163
|
+
"status": 200,
|
|
164
|
+
"checked": "2026-10-02",
|
|
165
|
+
"quotes": {
|
|
166
|
+
"This is a legacy mode, retained for backward compatibility.": true
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"https://core.telegram.org/bots/api#markdownv2-style": {
|
|
170
|
+
"status": 200,
|
|
171
|
+
"checked": "2026-10-02",
|
|
172
|
+
"quotes": {
|
|
173
|
+
"To use this mode, pass MarkdownV2 in the parse_mode field.": true
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"https://core.telegram.org/bots/api#message": {
|
|
177
|
+
"status": 200,
|
|
178
|
+
"checked": "2026-10-02",
|
|
179
|
+
"quotes": {
|
|
180
|
+
"Optional. Message is a photo, available sizes of the photo": true,
|
|
181
|
+
"Optional. The unique identifier inside this chat of a media message group this message belongs to": true,
|
|
182
|
+
"Optional. Sender of the message when sent on behalf of a chat. For example, the supergroup itself for messages sent by its anonymous administrators or a linked channel for messages automatically forwarded to the channel's discussion group.": true,
|
|
183
|
+
"Optional. Service message: the group has been created": true,
|
|
184
|
+
"Optional. New members that were added to the group or supergroup and information about them (the bot itself may be one of these members)": true,
|
|
185
|
+
"Optional. A member was removed from the group, information about them (this member may be the bot itself)": true,
|
|
186
|
+
"Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply.": true,
|
|
187
|
+
"Unique message identifier inside this chat;": true,
|
|
188
|
+
"Optional. Sender of the message; may be empty for messages sent to channels.": true,
|
|
189
|
+
"Date the message was sent in Unix time": true
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"https://core.telegram.org/bots/api#sendchataction": {
|
|
193
|
+
"status": 200,
|
|
194
|
+
"checked": "2026-10-02",
|
|
195
|
+
"quotes": {
|
|
196
|
+
"Use this method when you need to tell the user that something is happening on the bot's side.": true,
|
|
197
|
+
"The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.": true
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"https://core.telegram.org/bots/api#senddocument": {
|
|
201
|
+
"status": 200,
|
|
202
|
+
"checked": "2026-10-02",
|
|
203
|
+
"quotes": {
|
|
204
|
+
"Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.": true,
|
|
205
|
+
"Use this method to send general files. On success, the sent Message is returned.": true
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"https://core.telegram.org/bots/api#sending-files": {
|
|
209
|
+
"status": 200,
|
|
210
|
+
"checked": "2026-10-02",
|
|
211
|
+
"quotes": {
|
|
212
|
+
"It is not possible to change the file type when resending by file_id .": true,
|
|
213
|
+
"file_id is unique for each individual bot and can't be transferred from one bot to another.": true
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"https://core.telegram.org/bots/api#sendmediagroup": {
|
|
217
|
+
"status": 200,
|
|
218
|
+
"checked": "2026-10-02",
|
|
219
|
+
"quotes": {
|
|
220
|
+
"On success, an Array of Message objects that were sent is returned.": true,
|
|
221
|
+
"Documents and audio files can be only grouped in an album with messages of the same type.": true
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
"https://core.telegram.org/bots/api#sendmessage": {
|
|
225
|
+
"status": 200,
|
|
226
|
+
"checked": "2026-10-02",
|
|
227
|
+
"quotes": {
|
|
228
|
+
"Text of the message to be sent, 1-4096 characters after entities parsing": true
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"https://core.telegram.org/bots/api#sendphoto": {
|
|
232
|
+
"status": 200,
|
|
233
|
+
"checked": "2026-10-02",
|
|
234
|
+
"quotes": {
|
|
235
|
+
"Photo caption (may also be used when resending photos by file_id), 0-1024 characters after entities parsing": true,
|
|
236
|
+
"The photo must be at most 10 MB in size.": true,
|
|
237
|
+
"The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20.": true,
|
|
238
|
+
"Use this method to send photos. On success, the sent Message is returned.": true
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
"https://core.telegram.org/bots/api#sendvideo": {
|
|
242
|
+
"status": 200,
|
|
243
|
+
"checked": "2026-10-02",
|
|
244
|
+
"quotes": {
|
|
245
|
+
"Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.": true,
|
|
246
|
+
"Duration of sent video in seconds": true,
|
|
247
|
+
"Use this method to send video files, Telegram clients support MPEG4 videos (other formats may be sent as Document).": true
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"https://core.telegram.org/bots/api#update": {
|
|
251
|
+
"status": 200,
|
|
252
|
+
"checked": "2026-10-02",
|
|
253
|
+
"quotes": {
|
|
254
|
+
"Optional. The bot's chat member status was updated in a chat.": true,
|
|
255
|
+
"Optional. New incoming channel post of any kind - text, photo, sticker, etc.": true,
|
|
256
|
+
"For private chats, this update is received only when the bot is blocked or unblocked by the user.": true,
|
|
257
|
+
"Update identifiers start from a certain positive number and increase sequentially.": true
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
"https://core.telegram.org/bots/api#user": {
|
|
261
|
+
"status": 200,
|
|
262
|
+
"checked": "2026-10-02",
|
|
263
|
+
"quotes": {
|
|
264
|
+
"Optional. User's or bot's username": true,
|
|
265
|
+
"Optional. True, if the bot can be invited to groups. Returned only in getMe.": true,
|
|
266
|
+
"Unique identifier for this user or bot.": true
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"https://core.telegram.org/bots/faq": {
|
|
270
|
+
"status": 200,
|
|
271
|
+
"checked": "2026-10-02",
|
|
272
|
+
"quotes": {
|
|
273
|
+
"bots are not able to broadcast more than about 30 messages per second": true
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
"https://core.telegram.org/bots/features#botfather": {
|
|
277
|
+
"status": 200,
|
|
278
|
+
"checked": "2026-10-02",
|
|
279
|
+
"quotes": {
|
|
280
|
+
"Usernames are 5-32 characters long and not case sensitive – but may only include Latin characters, numbers, and underscores. Your bot's username must end in 'bot’, like 'tetris_bot' or 'TetrisBot'.": true,
|
|
281
|
+
"If your existing token is compromised or you lost it for some reason, use the /token command to generate a new one.": true,
|
|
282
|
+
"Users will see a Start button the first time they open a chat with your bot.": true,
|
|
283
|
+
"The token is a string, like 110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw": true
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
"https://core.telegram.org/bots/features#privacy-mode": {
|
|
287
|
+
"status": 200,
|
|
288
|
+
"checked": "2026-10-02",
|
|
289
|
+
"quotes": {
|
|
290
|
+
"Privacy mode is enabled by default for all bots": true,
|
|
291
|
+
"All messages from channels where they are a member.": true,
|
|
292
|
+
"Privacy mode is enabled by default for all bots, except bots that were added to a group as admins (bot admins always receive all messages ).": true,
|
|
293
|
+
"All service messages.": true,
|
|
294
|
+
"Commands explicitly meant for them (e.g., /command@this_bot ).": true,
|
|
295
|
+
"General commands (e.g. /start ) if the bot was the last bot to send a message to the group.": true,
|
|
296
|
+
"Replies to any messages implicitly or explicitly meant for this bot.": true
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
"https://core.telegram.org/bots/samples": {
|
|
300
|
+
"status": 200,
|
|
301
|
+
"checked": "2026-10-02",
|
|
302
|
+
"quotes": {
|
|
303
|
+
"these projects are not maintained by Telegram": true
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
"https://core.telegram.org/method/messages.sendMedia": {
|
|
307
|
+
"status": 200,
|
|
308
|
+
"checked": "2026-10-02",
|
|
309
|
+
"quotes": {
|
|
310
|
+
"Failure while processing image.": true
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
"https://raw.githubusercontent.com/tdlib/td/42e6a5259551178d1dab54a22ad96d14bd906e20/td/telegram/DialogManager.cpp": {
|
|
314
|
+
"status": 200,
|
|
315
|
+
"checked": "2026-10-02",
|
|
316
|
+
"quotes": {
|
|
317
|
+
"Need administrator rights in the channel chat": true
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
"https://raw.githubusercontent.com/tdlib/td/42e6a5259551178d1dab54a22ad96d14bd906e20/td/telegram/files/FileManager.cpp": {
|
|
321
|
+
"status": 200,
|
|
322
|
+
"checked": "2026-10-02",
|
|
323
|
+
"quotes": {
|
|
324
|
+
"Can't use file of type": true
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
"https://raw.githubusercontent.com/tdlib/td/42e6a5259551178d1dab54a22ad96d14bd906e20/td/telegram/MessageContent.cpp": {
|
|
328
|
+
"status": 200,
|
|
329
|
+
"checked": "2026-10-02",
|
|
330
|
+
"quotes": {
|
|
331
|
+
"There are no messages to send": true,
|
|
332
|
+
"Too many messages to send as an album": true,
|
|
333
|
+
"Invalid message content type": true,
|
|
334
|
+
"can't be mixed with other media types": true,
|
|
335
|
+
"Not enough rights to send": true
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
"https://raw.githubusercontent.com/tdlib/td/42e6a5259551178d1dab54a22ad96d14bd906e20/td/telegram/MessageEntity.cpp": {
|
|
339
|
+
"status": 200,
|
|
340
|
+
"checked": "2026-10-02",
|
|
341
|
+
"quotes": {
|
|
342
|
+
"Text must be non-empty": true,
|
|
343
|
+
"Unsupported start tag": true,
|
|
344
|
+
"is reserved and must be escaped with the preceding": true,
|
|
345
|
+
"add_entities(MessageEntity::Type::Mention, find_mentions);": true
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
"https://raw.githubusercontent.com/tdlib/td/42e6a5259551178d1dab54a22ad96d14bd906e20/td/telegram/MessagesManager.cpp": {
|
|
349
|
+
"status": 200,
|
|
350
|
+
"checked": "2026-10-02",
|
|
351
|
+
"quotes": {
|
|
352
|
+
"Message is too long": true,
|
|
353
|
+
"Message caption is too long": true,
|
|
354
|
+
"Bot can't initiate conversation with a user": true,
|
|
355
|
+
"Wrong file identifier/HTTP URL specified": true
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
"https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp": {
|
|
359
|
+
"status": 200,
|
|
360
|
+
"checked": "2026-10-02",
|
|
361
|
+
"quotes": {
|
|
362
|
+
"result.code = 401;": true,
|
|
363
|
+
"Message text is empty": true,
|
|
364
|
+
"Bad Request: file is too big": true,
|
|
365
|
+
"(error_message[1] == '_' || ('A' <= error_message[1] && error_message[1] <= 'Z'))) {": true,
|
|
366
|
+
"Can't parse media JSON object": true,
|
|
367
|
+
"Wrong parameter action in request": true,
|
|
368
|
+
"user not found": true,
|
|
369
|
+
"invalid file_id": true,
|
|
370
|
+
"auto allowed_update_types = get_allowed_update_types(query->arg(": true,
|
|
371
|
+
"Webhook is already deleted": true,
|
|
372
|
+
"Bad Request: chat not found": true,
|
|
373
|
+
"Bad Request: chat_id is empty": true,
|
|
374
|
+
"Forbidden: bot was kicked from the group chat": true,
|
|
375
|
+
"Forbidden: bot was kicked from the channel chat": true,
|
|
376
|
+
"bool need_more_access_rights = is_public ? need_edit_access : need_read_access;": true,
|
|
377
|
+
"Forbidden: bot is not a member of the channel chat": true,
|
|
378
|
+
"Text is too long": true,
|
|
379
|
+
"text_parse_mode = make_object<td_api::textParseModeMarkdown>(2);": true,
|
|
380
|
+
"Unsupported parse_mode": true,
|
|
381
|
+
"Can't parse reply parameters JSON object": true,
|
|
382
|
+
"result.reply_to_message_id = get_message_id(query,": true,
|
|
383
|
+
"message to be replied not found": true,
|
|
384
|
+
"Failed to get HTTP URL content": true,
|
|
385
|
+
"message to delete": true,
|
|
386
|
+
"message can't be deleted": true,
|
|
387
|
+
"error_code = 403;": true,
|
|
388
|
+
"Not Found: method not found": true,
|
|
389
|
+
"result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");": true
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
"https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.h": {
|
|
393
|
+
"status": 200,
|
|
394
|
+
"checked": "2026-10-02",
|
|
395
|
+
"quotes": {
|
|
396
|
+
"static constexpr int32 LONG_POLL_MAX_TIMEOUT = 50;": true
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
"https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/ClientManager.cpp": {
|
|
400
|
+
"status": 200,
|
|
401
|
+
"checked": "2026-10-02",
|
|
402
|
+
"quotes": {
|
|
403
|
+
"Unauthorized: invalid token specified": true,
|
|
404
|
+
"if (token[0] == '0' || token.size() > 80u || token.find('/') != td::string::npos ||": true,
|
|
405
|
+
"auto r_user_id = td::to_integer_safe<td::int64>(query->token().substr(0, token.find(':')));": true
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
"https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/HttpConnection.cpp": {
|
|
409
|
+
"status": 200,
|
|
410
|
+
"checked": "2026-10-02",
|
|
411
|
+
"quotes": {
|
|
412
|
+
"if (!url_path_parser.try_skip(": true,
|
|
413
|
+
"return send_http_error(404,": true
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// world-telegram: serve the telegram twin.
|
|
3
|
+
import { hasFlag, optionValue } from '@volter/world-core/args';
|
|
4
|
+
import { keepProcessAlive } from '@volter/world-core/lifecycle';
|
|
5
|
+
import { createTelegramTwinServer } from "./server.js";
|
|
6
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
7
|
+
const port = Number(optionValue(rest, '--port', '0')) || undefined;
|
|
8
|
+
const root = optionValue(rest, '--root') || undefined;
|
|
9
|
+
const readOnly = hasFlag(rest, '--read-only');
|
|
10
|
+
// the World's managed Postgres, which the runtime binds a pack declaring managedDatabase to
|
|
11
|
+
const database = optionValue(rest, '--database') || undefined;
|
|
12
|
+
// the World's scenario file, for a model vendor's turns
|
|
13
|
+
const scenarioPath = optionValue(rest, '--scenario') || undefined;
|
|
14
|
+
if (cmd === 'serve' || cmd === undefined) {
|
|
15
|
+
const s = await createTelegramTwinServer({ readOnly, ...(root ? { root } : {}), ...(port ? { port } : {}), ...(database ? { database } : {}), ...(scenarioPath ? { scenarioPath } : {}) });
|
|
16
|
+
process.stdout.write(`telegram twin${readOnly ? ' [read-only]' : ''} at http://127.0.0.1:${s.port}\n`);
|
|
17
|
+
await keepProcessAlive();
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
process.stdout.write('Usage: world-telegram serve [--port N] [--root DIR] [--read-only] [--database URL] [--scenario FILE]\n');
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ImageSize = {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
mime: string;
|
|
5
|
+
};
|
|
6
|
+
export type VideoInfo = {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
duration: number;
|
|
10
|
+
};
|
|
11
|
+
/** An image's size from its header: PNG (IHDR), GIF (logical screen), JPEG (the first start-of-frame); undefined for
|
|
12
|
+
* anything else (a photo Telegram takes is a .jpg, .jpeg, .gif, .png, .tif or .bmp, MessagesManager.cpp's
|
|
13
|
+
* PHOTO_EXT_INVALID; the twin reads the first three). */
|
|
14
|
+
export declare function imageSize(b: Uint8Array): ImageSize | undefined;
|
|
15
|
+
/** An MP4's (ISO base media) duration in whole seconds from its movie header (mvhd), and the first track with a size
|
|
16
|
+
* from its track header (tkhd: 16.16 fixed-point width and height); undefined for a file that is not one. */
|
|
17
|
+
export declare function mp4Info(b: Uint8Array): VideoInfo | undefined;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// What Telegram reads from an uploaded file's own bytes: an image's width and height (a PhotoSize), and a video's width,
|
|
2
|
+
// height and duration (a Video), each from the format's header as that format defines it. Pure computation over bytes.
|
|
3
|
+
const u16be = (b, i) => (b[i] << 8) | b[i + 1];
|
|
4
|
+
const u32be = (b, i) => ((b[i] << 24) >>> 0) + (b[i + 1] << 16) + (b[i + 2] << 8) + b[i + 3];
|
|
5
|
+
const u16le = (b, i) => b[i] | (b[i + 1] << 8);
|
|
6
|
+
const ascii = (b, i, n) => String.fromCharCode(...b.subarray(i, i + n));
|
|
7
|
+
/** An image's size from its header: PNG (IHDR), GIF (logical screen), JPEG (the first start-of-frame); undefined for
|
|
8
|
+
* anything else (a photo Telegram takes is a .jpg, .jpeg, .gif, .png, .tif or .bmp, MessagesManager.cpp's
|
|
9
|
+
* PHOTO_EXT_INVALID; the twin reads the first three). */
|
|
10
|
+
export function imageSize(b) {
|
|
11
|
+
if (b.length >= 24 && b[0] === 0x89 && ascii(b, 1, 3) === 'PNG' && ascii(b, 12, 4) === 'IHDR')
|
|
12
|
+
return { width: u32be(b, 16), height: u32be(b, 20), mime: 'image/png' };
|
|
13
|
+
if (b.length >= 10 && ascii(b, 0, 3) === 'GIF')
|
|
14
|
+
return { width: u16le(b, 6), height: u16le(b, 8), mime: 'image/gif' };
|
|
15
|
+
// a JPEG's markers are walked to its first frame header; a JPEG with none, like any other file, has no size
|
|
16
|
+
const jpeg = b.length >= 4 && b[0] === 0xff && b[1] === 0xd8;
|
|
17
|
+
for (let i = 2; jpeg && i + 9 < b.length; i += b[i] !== 0xff ? 1 : jpegStep(b, i)) {
|
|
18
|
+
const marker = b[i + 1];
|
|
19
|
+
// SOF0-SOF15 but DHT (C4), JPG (C8) and DAC (CC) carry the frame's height and width
|
|
20
|
+
if (b[i] === 0xff && marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc)
|
|
21
|
+
return { height: u16be(b, i + 5), width: u16be(b, i + 7), mime: 'image/jpeg' };
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
/** How far a JPEG's marker at `i` reaches: a marker with no length (SOI, TEM, RSTn) is its two bytes, any other its
|
|
26
|
+
* length after them. */
|
|
27
|
+
const jpegStep = (b, i) => {
|
|
28
|
+
const marker = b[i + 1];
|
|
29
|
+
return marker === 0xd8 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7) ? 2 : 2 + u16be(b, i + 2);
|
|
30
|
+
};
|
|
31
|
+
/** An MP4's (ISO base media) duration in whole seconds from its movie header (mvhd), and the first track with a size
|
|
32
|
+
* from its track header (tkhd: 16.16 fixed-point width and height); undefined for a file that is not one. */
|
|
33
|
+
export function mp4Info(b) {
|
|
34
|
+
if (b.length < 12 || ascii(b, 4, 4) !== 'ftyp')
|
|
35
|
+
return undefined;
|
|
36
|
+
let duration;
|
|
37
|
+
let width = 0;
|
|
38
|
+
let height = 0;
|
|
39
|
+
const walk = (start, end) => {
|
|
40
|
+
let i = start;
|
|
41
|
+
while (i + 8 <= end) {
|
|
42
|
+
let size = u32be(b, i);
|
|
43
|
+
const type = ascii(b, i + 4, 4);
|
|
44
|
+
let header = 8;
|
|
45
|
+
if (size === 1 && i + 16 <= end) {
|
|
46
|
+
size = u32be(b, i + 8) * 2 ** 32 + u32be(b, i + 12);
|
|
47
|
+
header = 16;
|
|
48
|
+
}
|
|
49
|
+
if (size === 0)
|
|
50
|
+
size = end - i;
|
|
51
|
+
if (size < header || i + size > end)
|
|
52
|
+
return;
|
|
53
|
+
if (type === 'moov' || type === 'trak')
|
|
54
|
+
walk(i + header, i + size);
|
|
55
|
+
else if (type === 'mvhd') {
|
|
56
|
+
const v = b[i + header];
|
|
57
|
+
const timescale = v === 1 ? u32be(b, i + header + 20) : u32be(b, i + header + 12);
|
|
58
|
+
const units = v === 1 ? u32be(b, i + header + 24) * 2 ** 32 + u32be(b, i + header + 28) : u32be(b, i + header + 16);
|
|
59
|
+
if (timescale)
|
|
60
|
+
duration = Math.round(units / timescale);
|
|
61
|
+
}
|
|
62
|
+
else if (type === 'tkhd' && !width) {
|
|
63
|
+
const v = b[i + header];
|
|
64
|
+
const at = i + header + (v === 1 ? 88 : 76);
|
|
65
|
+
if (at + 8 <= i + size) {
|
|
66
|
+
width = u32be(b, at) >>> 16;
|
|
67
|
+
height = u32be(b, at + 4) >>> 16;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
i += size;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
walk(0, b.length);
|
|
74
|
+
return duration === undefined ? undefined : { width, height, duration };
|
|
75
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type Entity = {
|
|
2
|
+
type: string;
|
|
3
|
+
offset: number;
|
|
4
|
+
length: number;
|
|
5
|
+
url?: string;
|
|
6
|
+
language?: string;
|
|
7
|
+
custom_emoji_id?: string;
|
|
8
|
+
unix_time?: number;
|
|
9
|
+
date_time_format?: string;
|
|
10
|
+
user_id?: number;
|
|
11
|
+
};
|
|
12
|
+
export type Formatted = {
|
|
13
|
+
text: string;
|
|
14
|
+
entities: Entity[];
|
|
15
|
+
};
|
|
16
|
+
/** The HTML parse mode: the text and its entities, or the parser's refusal in TDLib's words. */
|
|
17
|
+
export declare function parseHtml(input: string): Formatted | {
|
|
18
|
+
error: string;
|
|
19
|
+
};
|
|
20
|
+
/** The MarkdownV2 parse mode: the text and its entities, or the parser's refusal in TDLib's words. A backslash escapes
|
|
21
|
+
* any ASCII character; outside code every one of `_*[]()~`>#+-=|{}.!` that opens no mark must be escaped; inside code
|
|
22
|
+
* only the backquote is reserved. */
|
|
23
|
+
export declare function parseMarkdownV2(input: string): Formatted | {
|
|
24
|
+
error: string;
|
|
25
|
+
};
|
|
26
|
+
/** The legacy Markdown parse mode: *bold*, _italic_, `code`, ```pre``` (a language after its opening), [text](link),
|
|
27
|
+
* none nested; a backslash escapes only _ * ` and [. The text and its entities, or the parser's refusal in TDLib's
|
|
28
|
+
* words. */
|
|
29
|
+
export declare function parseMarkdown(input: string): Formatted | {
|
|
30
|
+
error: string;
|
|
31
|
+
};
|
|
32
|
+
/** Entities in TDLib's order: by offset, the longer first. */
|
|
33
|
+
export declare function sortEntities(entities: Entity[]): Entity[];
|
|
34
|
+
/** The entities the server finds in a text by itself: mentions (@name, 2-32 letters, digits and underscores, not
|
|
35
|
+
* inside a word), bot commands (/command, 1-64, optionally @bot), hashtags (#tag with a letter), cashtags ($ABC),
|
|
36
|
+
* links (http, https, or www.) and e-mail addresses. Where the twin stops: TDLib's own link matcher also takes bare
|
|
37
|
+
* domains by their top-level domain, and finds bank card numbers; the twin does not. */
|
|
38
|
+
export declare function findEntities(text: string, skipBotCommands: boolean): Entity[];
|
|
39
|
+
/** What the server keeps of a formatted text (TDLib's fix_formatted_text): whitespace trimmed from both ends (the
|
|
40
|
+
* entities moved and cut with it), the entities it finds itself added where they cross none given, sorted. Empty
|
|
41
|
+
* is the caller's to refuse. */
|
|
42
|
+
export declare function finish(f: Formatted, opts: {
|
|
43
|
+
find: boolean;
|
|
44
|
+
skipBotCommands: boolean;
|
|
45
|
+
}): Formatted;
|