@wirecat/tg-cli 0.0.0 → 0.43.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 +21 -0
- package/README.md +527 -0
- package/THIRD_PARTY_NOTICES +55 -0
- package/dist/app.d.ts +11 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +16 -0
- package/dist/app.js.map +1 -0
- package/dist/bin/tg.d.ts +3 -0
- package/dist/bin/tg.d.ts.map +1 -0
- package/dist/bin/tg.js +18 -0
- package/dist/bin/tg.js.map +1 -0
- package/dist/bot/adapter.d.ts +9 -0
- package/dist/bot/adapter.d.ts.map +1 -0
- package/dist/bot/adapter.js +171 -0
- package/dist/bot/adapter.js.map +1 -0
- package/dist/bot/generated/definitions.d.ts +3 -0
- package/dist/bot/generated/definitions.d.ts.map +1 -0
- package/dist/bot/generated/definitions.js +19104 -0
- package/dist/bot/generated/definitions.js.map +1 -0
- package/dist/bot/generated/manifest.d.ts +3 -0
- package/dist/bot/generated/manifest.d.ts.map +1 -0
- package/dist/bot/generated/manifest.js +15354 -0
- package/dist/bot/generated/manifest.js.map +1 -0
- package/dist/bot/generated/schemas.d.ts +1407 -0
- package/dist/bot/generated/schemas.d.ts.map +1 -0
- package/dist/bot/generated/schemas.js +5118 -0
- package/dist/bot/generated/schemas.js.map +1 -0
- package/dist/bot/generated/types.d.ts +6884 -0
- package/dist/bot/generated/types.d.ts.map +1 -0
- package/dist/bot/generated/types.js +5 -0
- package/dist/bot/generated/types.js.map +1 -0
- package/dist/bot/map.d.ts +122 -0
- package/dist/bot/map.d.ts.map +1 -0
- package/dist/bot/map.js +193 -0
- package/dist/bot/map.js.map +1 -0
- package/dist/bot/proxy.d.ts +15 -0
- package/dist/bot/proxy.d.ts.map +1 -0
- package/dist/bot/proxy.js +64 -0
- package/dist/bot/proxy.js.map +1 -0
- package/dist/bot/transport.d.ts +42 -0
- package/dist/bot/transport.d.ts.map +1 -0
- package/dist/bot/transport.js +158 -0
- package/dist/bot/transport.js.map +1 -0
- package/dist/browser.d.ts +6 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +18 -0
- package/dist/browser.js.map +1 -0
- package/dist/commands/bot-api.d.ts +3 -0
- package/dist/commands/bot-api.d.ts.map +1 -0
- package/dist/commands/bot-api.js +112 -0
- package/dist/commands/bot-api.js.map +1 -0
- package/dist/commands/bot.d.ts +7 -0
- package/dist/commands/bot.d.ts.map +1 -0
- package/dist/commands/bot.js +99 -0
- package/dist/commands/bot.js.map +1 -0
- package/dist/commands/context.d.ts +59 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +176 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/proxy-config.d.ts +9 -0
- package/dist/commands/proxy-config.d.ts.map +1 -0
- package/dist/commands/proxy-config.js +63 -0
- package/dist/commands/proxy-config.js.map +1 -0
- package/dist/commands/session.d.ts +22 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +191 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.d.ts +3 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +203 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +35 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/install/postinstall.d.ts +8 -0
- package/dist/install/postinstall.d.ts.map +1 -0
- package/dist/install/postinstall.js +62 -0
- package/dist/install/postinstall.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +11 -0
- package/dist/paths.js.map +1 -0
- package/dist/program.d.ts +8 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +138 -0
- package/dist/program.js.map +1 -0
- package/dist/proxy.d.ts +31 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +99 -0
- package/dist/proxy.js.map +1 -0
- package/dist/telegram/adapter.d.ts +432 -0
- package/dist/telegram/adapter.d.ts.map +1 -0
- package/dist/telegram/adapter.js +1898 -0
- package/dist/telegram/adapter.js.map +1 -0
- package/dist/telegram/bot-history.d.ts +18 -0
- package/dist/telegram/bot-history.d.ts.map +1 -0
- package/dist/telegram/bot-history.js +145 -0
- package/dist/telegram/bot-history.js.map +1 -0
- package/dist/telegram/comments.d.ts +18 -0
- package/dist/telegram/comments.d.ts.map +1 -0
- package/dist/telegram/comments.js +48 -0
- package/dist/telegram/comments.js.map +1 -0
- package/dist/telegram/credentials.d.ts +22 -0
- package/dist/telegram/credentials.d.ts.map +1 -0
- package/dist/telegram/credentials.js +49 -0
- package/dist/telegram/credentials.js.map +1 -0
- package/dist/telegram/errors.d.ts +6 -0
- package/dist/telegram/errors.d.ts.map +1 -0
- package/dist/telegram/errors.js +186 -0
- package/dist/telegram/errors.js.map +1 -0
- package/dist/telegram/folder-rules.d.ts +14 -0
- package/dist/telegram/folder-rules.d.ts.map +1 -0
- package/dist/telegram/folder-rules.js +23 -0
- package/dist/telegram/folder-rules.js.map +1 -0
- package/dist/telegram/format-html.d.ts +4 -0
- package/dist/telegram/format-html.d.ts.map +1 -0
- package/dist/telegram/format-html.js +29 -0
- package/dist/telegram/format-html.js.map +1 -0
- package/dist/telegram/format-markdown.d.ts +3 -0
- package/dist/telegram/format-markdown.d.ts.map +1 -0
- package/dist/telegram/format-markdown.js +160 -0
- package/dist/telegram/format-markdown.js.map +1 -0
- package/dist/telegram/join-requests.d.ts +15 -0
- package/dist/telegram/join-requests.d.ts.map +1 -0
- package/dist/telegram/join-requests.js +35 -0
- package/dist/telegram/join-requests.js.map +1 -0
- package/dist/telegram/map.d.ts +92 -0
- package/dist/telegram/map.d.ts.map +1 -0
- package/dist/telegram/map.js +471 -0
- package/dist/telegram/map.js.map +1 -0
- package/dist/telegram/poll-voters.d.ts +15 -0
- package/dist/telegram/poll-voters.d.ts.map +1 -0
- package/dist/telegram/poll-voters.js +31 -0
- package/dist/telegram/poll-voters.js.map +1 -0
- package/dist/telegram/polls.d.ts +5 -0
- package/dist/telegram/polls.d.ts.map +1 -0
- package/dist/telegram/polls.js +20 -0
- package/dist/telegram/polls.js.map +1 -0
- package/dist/telegram/profile.d.ts +9 -0
- package/dist/telegram/profile.d.ts.map +1 -0
- package/dist/telegram/profile.js +175 -0
- package/dist/telegram/profile.js.map +1 -0
- package/dist/telegram/proxy.d.ts +48 -0
- package/dist/telegram/proxy.d.ts.map +1 -0
- package/dist/telegram/proxy.js +108 -0
- package/dist/telegram/proxy.js.map +1 -0
- package/dist/telegram/registration.d.ts +31 -0
- package/dist/telegram/registration.d.ts.map +1 -0
- package/dist/telegram/registration.js +95 -0
- package/dist/telegram/registration.js.map +1 -0
- package/dist/telegram/send-as.d.ts +17 -0
- package/dist/telegram/send-as.d.ts.map +1 -0
- package/dist/telegram/send-as.js +67 -0
- package/dist/telegram/send-as.js.map +1 -0
- package/dist/telegram/stats.d.ts +13 -0
- package/dist/telegram/stats.d.ts.map +1 -0
- package/dist/telegram/stats.js +135 -0
- package/dist/telegram/stats.js.map +1 -0
- package/dist/telegram/storage.d.ts +4 -0
- package/dist/telegram/storage.d.ts.map +1 -0
- package/dist/telegram/storage.js +68 -0
- package/dist/telegram/storage.js.map +1 -0
- package/dist/telegram/upload.d.ts +9 -0
- package/dist/telegram/upload.d.ts.map +1 -0
- package/dist/telegram/upload.js +29 -0
- package/dist/telegram/upload.js.map +1 -0
- package/dist/update.d.ts +28 -0
- package/dist/update.d.ts.map +1 -0
- package/dist/update.js +56 -0
- package/dist/update.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/install/postinstall.mjs +3 -0
- package/install/windows.ps1 +161 -0
- package/package.json +71 -2
- package/skills/tg-cli/SKILL.md +489 -0
- package/spec/bot/LICENSE +21 -0
- package/spec/bot/README.md +16 -0
package/dist/bot/map.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-core";
|
|
2
|
+
const KINDS = {
|
|
3
|
+
private: "dialog",
|
|
4
|
+
group: "group",
|
|
5
|
+
supergroup: "group",
|
|
6
|
+
channel: "channel",
|
|
7
|
+
};
|
|
8
|
+
const ENTITY = { bold: "bold", italic: "italic", strike: "strikethrough", code: "code" };
|
|
9
|
+
const nameOf = (person) => person ? [person.first_name, person.last_name].filter(Boolean).join(" ") || null : null;
|
|
10
|
+
const iso = (seconds) => new Date(seconds * 1000).toISOString();
|
|
11
|
+
/**
|
|
12
|
+
* A file by Telegram's `file_id` only. ⚠ Never a download address: Telegram's has the bot token in
|
|
13
|
+
* it, and an `Attachment.url` would put the token into the store and into command output.
|
|
14
|
+
*/
|
|
15
|
+
const attachmentsOf = (message) => {
|
|
16
|
+
const files = [
|
|
17
|
+
["photo", message.photo?.at(-1)],
|
|
18
|
+
["file", message.document],
|
|
19
|
+
["voice", message.voice],
|
|
20
|
+
["video", message.video],
|
|
21
|
+
["audio", message.audio],
|
|
22
|
+
];
|
|
23
|
+
return files.flatMap(([kind, file]) => {
|
|
24
|
+
if (!file)
|
|
25
|
+
return [];
|
|
26
|
+
const attachment = { kind, providerRef: { fileId: file.file_id } };
|
|
27
|
+
if (file.file_name)
|
|
28
|
+
attachment.name = file.file_name;
|
|
29
|
+
if (file.file_size !== undefined)
|
|
30
|
+
attachment.size = file.file_size;
|
|
31
|
+
if (file.duration !== undefined)
|
|
32
|
+
attachment.duration = file.duration;
|
|
33
|
+
return [attachment];
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const quoted = (message, selfId) => ({
|
|
37
|
+
id: String(message.message_id),
|
|
38
|
+
senderId: message.from ? String(message.from.id) : null,
|
|
39
|
+
senderName: nameOf(message.from),
|
|
40
|
+
timestamp: iso(message.date),
|
|
41
|
+
text: message.text ?? message.caption ?? "",
|
|
42
|
+
attachments: attachmentsOf(message),
|
|
43
|
+
outgoing: selfId === undefined || !message.from ? null : String(message.from.id) === selfId,
|
|
44
|
+
});
|
|
45
|
+
/** `selfId` is the bot's own id, when known, so `outgoing` says whether the bot wrote it. */
|
|
46
|
+
export const toMessage = (message, selfId) => {
|
|
47
|
+
const mapped = {
|
|
48
|
+
id: String(message.message_id),
|
|
49
|
+
chatId: String(message.chat.id),
|
|
50
|
+
senderId: message.from ? String(message.from.id) : null,
|
|
51
|
+
senderName: nameOf(message.from),
|
|
52
|
+
timestamp: iso(message.date),
|
|
53
|
+
editedAt: message.edit_date === undefined ? null : iso(message.edit_date),
|
|
54
|
+
text: message.text ?? message.caption ?? "",
|
|
55
|
+
outgoing: selfId === undefined || !message.from ? null : String(message.from.id) === selfId,
|
|
56
|
+
attachments: attachmentsOf(message),
|
|
57
|
+
replyTo: message.reply_to_message ? quoted(message.reply_to_message, selfId) : null,
|
|
58
|
+
forwardedFrom: null,
|
|
59
|
+
reactions: null,
|
|
60
|
+
};
|
|
61
|
+
if (message.reply_to_message)
|
|
62
|
+
mapped.replyToId = String(message.reply_to_message.message_id);
|
|
63
|
+
return mapped;
|
|
64
|
+
};
|
|
65
|
+
export const toChat = (chat) => ({
|
|
66
|
+
id: String(chat.id),
|
|
67
|
+
title: chat.title ?? nameOf(chat),
|
|
68
|
+
kind: KINDS[chat.type] ?? "unknown",
|
|
69
|
+
unreadCount: null,
|
|
70
|
+
lastMessageAt: null,
|
|
71
|
+
participantsCount: null,
|
|
72
|
+
providerMetadata: { type: chat.type, ...(chat.username ? { username: chat.username } : {}) },
|
|
73
|
+
});
|
|
74
|
+
/** Markup is in UTF-16 positions, which is what Telegram's [entities](https://core.telegram.org/bots/api#messageentity) count. */
|
|
75
|
+
export const entitiesOf = (markup) => markup.map((span) => {
|
|
76
|
+
const base = { offset: span.from, length: span.length };
|
|
77
|
+
switch (span.type) {
|
|
78
|
+
case "bold":
|
|
79
|
+
case "italic":
|
|
80
|
+
case "strike":
|
|
81
|
+
case "code":
|
|
82
|
+
return { type: ENTITY[span.type], ...base };
|
|
83
|
+
case "underline":
|
|
84
|
+
case "spoiler":
|
|
85
|
+
case "blockquote":
|
|
86
|
+
return { type: span.type, ...base };
|
|
87
|
+
case "pre":
|
|
88
|
+
return { type: "pre", ...base, language: span.language ?? "" };
|
|
89
|
+
case "link":
|
|
90
|
+
return { type: "text_link", ...base, url: span.url };
|
|
91
|
+
default:
|
|
92
|
+
throw new CliError("validation_error", "Telegram does not support this formatting span");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* The shared admin rights in [promoteChatMember](https://core.telegram.org/bots/api#promotechatmember)'s
|
|
97
|
+
* words, as tg's personal account maps them. Telegram has no right to read: an admin always reads.
|
|
98
|
+
*/
|
|
99
|
+
export const ADMIN_RIGHT_FIELDS = {
|
|
100
|
+
members: "can_restrict_members",
|
|
101
|
+
admins: "can_promote_members",
|
|
102
|
+
info: "can_change_info",
|
|
103
|
+
pin: "can_pin_messages",
|
|
104
|
+
link: "can_invite_users",
|
|
105
|
+
post: "can_post_messages",
|
|
106
|
+
edit: "can_edit_messages",
|
|
107
|
+
delete: "can_delete_messages",
|
|
108
|
+
};
|
|
109
|
+
export const BOT_ADMIN_RIGHTS = Object.keys(ADMIN_RIGHT_FIELDS);
|
|
110
|
+
/** Every right promoteChatMember takes; all of them false demotes. */
|
|
111
|
+
export const PROMOTE_FIELDS = [
|
|
112
|
+
"is_anonymous",
|
|
113
|
+
"can_manage_chat",
|
|
114
|
+
"can_delete_messages",
|
|
115
|
+
"can_manage_video_chats",
|
|
116
|
+
"can_restrict_members",
|
|
117
|
+
"can_promote_members",
|
|
118
|
+
"can_change_info",
|
|
119
|
+
"can_invite_users",
|
|
120
|
+
"can_post_stories",
|
|
121
|
+
"can_edit_stories",
|
|
122
|
+
"can_delete_stories",
|
|
123
|
+
"can_post_messages",
|
|
124
|
+
"can_edit_messages",
|
|
125
|
+
"can_pin_messages",
|
|
126
|
+
"can_manage_topics",
|
|
127
|
+
"can_send_welcome_messages",
|
|
128
|
+
];
|
|
129
|
+
export const toAdmin = ({ status, user, custom_title, ...rights }) => ({
|
|
130
|
+
id: String(user.id),
|
|
131
|
+
name: nameOf(user),
|
|
132
|
+
username: user.username ?? null,
|
|
133
|
+
role: status === "creator" ? "owner" : "admin",
|
|
134
|
+
rights: BOT_ADMIN_RIGHTS.filter((right) => status === "creator" || rights[ADMIN_RIGHT_FIELDS[right]] === true),
|
|
135
|
+
title: custom_title ?? null,
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* Asked for every time, because Telegram keeps the last list it was given (RISK-95): without
|
|
139
|
+
* `chat_member`, nobody joining or leaving would ever arrive.
|
|
140
|
+
*/
|
|
141
|
+
export const UPDATE_TYPES = [
|
|
142
|
+
"message",
|
|
143
|
+
"edited_message",
|
|
144
|
+
"channel_post",
|
|
145
|
+
"edited_channel_post",
|
|
146
|
+
"callback_query",
|
|
147
|
+
"my_chat_member",
|
|
148
|
+
"chat_member",
|
|
149
|
+
];
|
|
150
|
+
const inChat = ({ status, is_member }) => status === "creator" ||
|
|
151
|
+
status === "administrator" ||
|
|
152
|
+
status === "member" ||
|
|
153
|
+
(status === "restricted" && is_member === true);
|
|
154
|
+
const personOf = (user) => ({ id: String(user.id), name: nameOf(user), username: user.username ?? null });
|
|
155
|
+
/** One update in the shared words; a kind not decoded here is `other`, under Telegram's own name. */
|
|
156
|
+
export const toEvent = (update, selfId) => {
|
|
157
|
+
const created = update.message ?? update.channel_post;
|
|
158
|
+
if (created)
|
|
159
|
+
return { event: "message", message: { ...toMessage(created, selfId), chatTitle: null } };
|
|
160
|
+
const edited = update.edited_message ?? update.edited_channel_post;
|
|
161
|
+
if (edited)
|
|
162
|
+
return { event: "edit", message: { ...toMessage(edited, selfId), chatTitle: null } };
|
|
163
|
+
const press = update.callback_query;
|
|
164
|
+
if (press) {
|
|
165
|
+
return {
|
|
166
|
+
event: "callback",
|
|
167
|
+
callbackId: press.id,
|
|
168
|
+
chatId: press.message ? String(press.message.chat.id) : null,
|
|
169
|
+
messageId: press.message ? String(press.message.message_id) : null,
|
|
170
|
+
from: personOf(press.from),
|
|
171
|
+
data: press.data ?? "",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const change = update.chat_member;
|
|
175
|
+
if (change) {
|
|
176
|
+
const was = inChat(change.old_chat_member);
|
|
177
|
+
const is = inChat(change.new_chat_member);
|
|
178
|
+
const person = change.new_chat_member.user;
|
|
179
|
+
const self = change.from.id === person.id;
|
|
180
|
+
if (was !== is) {
|
|
181
|
+
return {
|
|
182
|
+
event: is ? (self ? "joined" : "added") : self ? "left" : "removed",
|
|
183
|
+
chatId: String(change.chat.id),
|
|
184
|
+
person: personOf(person),
|
|
185
|
+
at: iso(change.date),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const kind = Object.keys(update).find((key) => key !== "update_id") ?? "unknown";
|
|
190
|
+
const chat = update[kind]?.chat;
|
|
191
|
+
return { event: "other", type: kind, chatId: chat ? String(chat.id) : null };
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../../src/bot/map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Dispatcher } from "undici";
|
|
2
|
+
import { type ProxyServer } from "../proxy.js";
|
|
3
|
+
import type { FetchLike } from "./transport.js";
|
|
4
|
+
/**
|
|
5
|
+
* The Bot API is HTTPS, so it can go through a SOCKS5 or an HTTP proxy — never an MTProxy, which
|
|
6
|
+
* carries only Telegram's own protocol. Credentials go as options, never in the URL, so no error
|
|
7
|
+
* undici builds from the URL can carry them.
|
|
8
|
+
*/
|
|
9
|
+
export declare const botDispatcher: (proxy: ProxyServer) => Promise<Dispatcher | undefined>;
|
|
10
|
+
/**
|
|
11
|
+
* undici's own `fetch` with its agent, not the global one: an agent from one copy of undici is not
|
|
12
|
+
* promised to work with another's fetch.
|
|
13
|
+
*/
|
|
14
|
+
export declare const proxiedFetch: (proxy: ProxyServer) => FetchLike | undefined;
|
|
15
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/bot/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,KAAK,WAAW,EAA4B,MAAM,aAAa,CAAA;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C;;;;GAIG;AACH,eAAO,MAAM,aAAa,UAAiB,WAAW,KAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAiBtF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,UAAW,WAAW,KAAG,SAAS,GAAG,SAY7D,CAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { proxyAddress, proxyError } from "../proxy.js";
|
|
2
|
+
/**
|
|
3
|
+
* The Bot API is HTTPS, so it can go through a SOCKS5 or an HTTP proxy — never an MTProxy, which
|
|
4
|
+
* carries only Telegram's own protocol. Credentials go as options, never in the URL, so no error
|
|
5
|
+
* undici builds from the URL can carry them.
|
|
6
|
+
*/
|
|
7
|
+
export const botDispatcher = async (proxy) => {
|
|
8
|
+
if (proxy.kind === "mtproxy")
|
|
9
|
+
return undefined;
|
|
10
|
+
// Loaded on use: Bun answers `import "undici"` with its own module, which has no SOCKS agent.
|
|
11
|
+
const { ProxyAgent, Socks5ProxyAgent } = await import("undici");
|
|
12
|
+
const uri = proxyAddress(proxy);
|
|
13
|
+
if (typeof ProxyAgent !== "function" || typeof Socks5ProxyAgent !== "function")
|
|
14
|
+
throw proxyError(proxy, "cannot carry the Bot API under this runtime — run tg with Node");
|
|
15
|
+
if (proxy.kind === "socks5")
|
|
16
|
+
return new Socks5ProxyAgent(uri, {
|
|
17
|
+
...(proxy.user === undefined ? {} : { username: proxy.user }),
|
|
18
|
+
...(proxy.secret === undefined ? {} : { password: proxy.secret }),
|
|
19
|
+
});
|
|
20
|
+
const basic = proxy.user === undefined
|
|
21
|
+
? undefined
|
|
22
|
+
: `Basic ${Buffer.from(`${proxy.user}:${proxy.secret ?? ""}`).toString("base64")}`;
|
|
23
|
+
return new ProxyAgent({ uri, ...(basic ? { token: basic } : {}) });
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* undici's own `fetch` with its agent, not the global one: an agent from one copy of undici is not
|
|
27
|
+
* promised to work with another's fetch.
|
|
28
|
+
*/
|
|
29
|
+
export const proxiedFetch = (proxy) => {
|
|
30
|
+
if (proxy.kind === "mtproxy")
|
|
31
|
+
return undefined;
|
|
32
|
+
let dispatcher;
|
|
33
|
+
return async (url, init) => {
|
|
34
|
+
dispatcher ??= botDispatcher(proxy);
|
|
35
|
+
const [{ fetch }, agent] = await Promise.all([import("undici"), dispatcher]);
|
|
36
|
+
try {
|
|
37
|
+
return (await fetch(url, { ...init, ...(agent ? { dispatcher: agent } : {}) }));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw proxyRefusal(proxy, error) ?? error;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* With a proxy, tg opens no connection but the one to the proxy, so a refused or unknown address is
|
|
46
|
+
* the proxy's; a tunnel the proxy would not open is too. Either way the request never left.
|
|
47
|
+
*/
|
|
48
|
+
const proxyRefusal = (proxy, error) => {
|
|
49
|
+
for (let cause = error; cause instanceof Error; cause = cause.cause) {
|
|
50
|
+
const code = cause.code;
|
|
51
|
+
const status = /Proxy response \((\d+)\)/.exec(cause.message)?.[1];
|
|
52
|
+
const reason = status !== undefined
|
|
53
|
+
? `refused the tunnel (HTTP ${status})`
|
|
54
|
+
: typeof code === "string" && code.startsWith("UND_ERR_SOCKS5")
|
|
55
|
+
? `refused (${code})`
|
|
56
|
+
: typeof code === "string" && /^(ECONN|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|ENETUNREACH|EHOSTUNREACH)/.test(code)
|
|
57
|
+
? `cannot be reached (${code})`
|
|
58
|
+
: undefined;
|
|
59
|
+
if (reason)
|
|
60
|
+
return proxyError(proxy, reason);
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/bot/proxy.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxE;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,KAAkB,EAAmC,EAAE;IACzF,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC9C,8FAA8F;IAC9F,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC/D,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IAC/B,IAAI,OAAO,UAAU,KAAK,UAAU,IAAI,OAAO,gBAAgB,KAAK,UAAU;QAC5E,MAAM,UAAU,CAAC,KAAK,EAAE,gEAAgE,CAAC,CAAA;IAC3F,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;QACzB,OAAO,IAAI,gBAAgB,CAAC,GAAG,EAAE;YAC/B,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;YAC7D,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;SAClE,CAAC,CAAA;IACJ,MAAM,KAAK,GACT,KAAK,CAAC,IAAI,KAAK,SAAS;QACtB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAA;IACtF,OAAO,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;AACpE,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAkB,EAAyB,EAAE;IACxE,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC9C,IAAI,UAAuD,CAAA;IAC3D,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,UAAU,KAAK,aAAa,CAAC,KAAK,CAAC,CAAA;QACnC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,CAAC,CAAA;QAC5E,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAI,IAAe,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAwB,CAAA;QACpH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,KAAK,CAAA;QAC3C,CAAC;IACH,CAAC,CAAA;AACH,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC,KAAkB,EAAE,KAAc,EAAqB,EAAE;IAC7E,KAAK,IAAI,KAAK,GAAG,KAAK,EAAE,KAAK,YAAY,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QACpE,MAAM,IAAI,GAAI,KAA4B,CAAC,IAAI,CAAA;QAC/C,MAAM,MAAM,GAAG,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAClE,MAAM,MAAM,GACV,MAAM,KAAK,SAAS;YAClB,CAAC,CAAC,4BAA4B,MAAM,GAAG;YACvC,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;gBAC7D,CAAC,CAAC,YAAY,IAAI,GAAG;gBACrB,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,iEAAiE,CAAC,IAAI,CAAC,IAAI,CAAC;oBACxG,CAAC,CAAC,sBAAsB,IAAI,GAAG;oBAC/B,CAAC,CAAC,SAAS,CAAA;QACnB,IAAI,MAAM;YAAE,OAAO,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC9C,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { EventSink } from "@wirecat/cli-messaging/cli";
|
|
2
|
+
export type FetchLike = (url: string, init: RequestInit) => Promise<Response>;
|
|
3
|
+
export interface BotTransportOptions {
|
|
4
|
+
token: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
fetch?: FetchLike;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
/** Ends the command's request in flight: the deadline, or Ctrl-C on a command that runs until told to. */
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
events?: EventSink;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Telegram's Bot API, method by method.
|
|
14
|
+
*
|
|
15
|
+
* ⚠ **The token is part of every address** — `/bot<token>/<method>` — so the address never leaves
|
|
16
|
+
* this class: not in an error, not in a trace line, and never by passing on a failed request's own
|
|
17
|
+
* error, whose text may hold it. A failure keeps the method, Telegram's code and Telegram's words.
|
|
18
|
+
*/
|
|
19
|
+
export declare class TelegramBotTransport {
|
|
20
|
+
#private;
|
|
21
|
+
constructor(options: BotTransportOptions);
|
|
22
|
+
/**
|
|
23
|
+
* `reads: false` for a write, so a write that got no answer is `outcome_unknown`, never retried by
|
|
24
|
+
* anyone. `file` goes up in the same request, as multipart: Telegram has no upload step of its own.
|
|
25
|
+
* `timeoutMs` replaces the transport's for one call — a long poll waits longer than any other request.
|
|
26
|
+
*/
|
|
27
|
+
call(method: string, params?: Record<string, unknown>, { reads, file, files, body, secrets, timeoutMs, }?: {
|
|
28
|
+
reads?: boolean;
|
|
29
|
+
file?: OutgoingFile;
|
|
30
|
+
files?: readonly OutgoingFile[];
|
|
31
|
+
body?: string;
|
|
32
|
+
secrets?: readonly string[];
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
}): Promise<unknown>;
|
|
35
|
+
}
|
|
36
|
+
/** A file sent with a method — `photo` for sendPhoto, `document`, `voice`. */
|
|
37
|
+
export interface OutgoingFile {
|
|
38
|
+
field: string;
|
|
39
|
+
name: string;
|
|
40
|
+
bytes: Uint8Array;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/bot/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAM3D,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAE7E,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0GAA0G;IAC1G,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAWD;;;;;;GAMG;AACH,qBAAa,oBAAoB;;IAQ/B,YAAY,OAAO,EAAE,mBAAmB,EAOvC;IAED;;;;OAIG;IACG,IAAI,CACR,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,EACE,KAAY,EACZ,IAAI,EACJ,KAAU,EACV,IAAI,EACJ,OAAY,EACZ,SAA2B,GAC5B,GAAE;QACD,KAAK,CAAC,EAAE,OAAO,CAAA;QACf,IAAI,CAAC,EAAE,YAAY,CAAA;QACnB,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;QAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;KACd,GACL,OAAO,CAAC,OAAO,CAAC,CAkElB;CAsBF;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,UAAU,CAAA;CAClB"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { CliError, isCliError } from "@wirecat/cli-core";
|
|
2
|
+
import { apiJson, apiPlainJson, parseApiJson } from "@wirecat/cli-messaging/cli";
|
|
3
|
+
const API = "https://api.telegram.org";
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
5
|
+
/**
|
|
6
|
+
* Telegram's Bot API, method by method.
|
|
7
|
+
*
|
|
8
|
+
* ⚠ **The token is part of every address** — `/bot<token>/<method>` — so the address never leaves
|
|
9
|
+
* this class: not in an error, not in a trace line, and never by passing on a failed request's own
|
|
10
|
+
* error, whose text may hold it. A failure keeps the method, Telegram's code and Telegram's words.
|
|
11
|
+
*/
|
|
12
|
+
export class TelegramBotTransport {
|
|
13
|
+
#token;
|
|
14
|
+
#baseUrl;
|
|
15
|
+
#fetch;
|
|
16
|
+
#timeoutMs;
|
|
17
|
+
#signal;
|
|
18
|
+
#events;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.#token = options.token;
|
|
21
|
+
this.#baseUrl = options.baseUrl ?? API;
|
|
22
|
+
this.#fetch = options.fetch ?? fetch;
|
|
23
|
+
this.#timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
24
|
+
this.#signal = options.signal;
|
|
25
|
+
this.#events = options.events;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* `reads: false` for a write, so a write that got no answer is `outcome_unknown`, never retried by
|
|
29
|
+
* anyone. `file` goes up in the same request, as multipart: Telegram has no upload step of its own.
|
|
30
|
+
* `timeoutMs` replaces the transport's for one call — a long poll waits longer than any other request.
|
|
31
|
+
*/
|
|
32
|
+
async call(method, params = {}, { reads = true, file, files = [], body, secrets = [], timeoutMs = this.#timeoutMs, } = {}) {
|
|
33
|
+
this.#events?.({ event: "request", operation: method });
|
|
34
|
+
const started = performance.now();
|
|
35
|
+
const signals = [AbortSignal.timeout(timeoutMs), ...(this.#signal ? [this.#signal] : [])];
|
|
36
|
+
let response;
|
|
37
|
+
try {
|
|
38
|
+
response = await this.#fetch(`${this.#baseUrl}/bot${this.#token}/${method}`, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
...(file || files.length
|
|
41
|
+
? {
|
|
42
|
+
headers: { Accept: "application/json" },
|
|
43
|
+
body: multipart(body === undefined ? params : parseApiJson(body), file ? [file, ...files] : files),
|
|
44
|
+
}
|
|
45
|
+
: {
|
|
46
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
47
|
+
body: body ?? apiJson(params),
|
|
48
|
+
}),
|
|
49
|
+
signal: AbortSignal.any(signals),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const failure = this.#unanswered(method, error, reads, timeoutMs);
|
|
54
|
+
this.#events?.({ event: "response", operation: method, outcome: "error", errorCode: failure.code });
|
|
55
|
+
throw failure;
|
|
56
|
+
}
|
|
57
|
+
let text;
|
|
58
|
+
try {
|
|
59
|
+
text = await response.text();
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
const failure = this.#unanswered(method, error, reads, timeoutMs);
|
|
63
|
+
this.#events?.({ event: "response", operation: method, outcome: "error", errorCode: failure.code });
|
|
64
|
+
throw failure;
|
|
65
|
+
}
|
|
66
|
+
const answered = {
|
|
67
|
+
event: "response",
|
|
68
|
+
operation: method,
|
|
69
|
+
status: response.status,
|
|
70
|
+
bytes: Buffer.byteLength(text),
|
|
71
|
+
durationMs: Math.round(performance.now() - started),
|
|
72
|
+
};
|
|
73
|
+
let answer;
|
|
74
|
+
try {
|
|
75
|
+
answer = apiPlainJson(parseApiJson(text));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
this.#events?.({ ...answered, outcome: "error", errorCode: "invalid_response" });
|
|
79
|
+
throw new CliError("invalid_response", `Telegram answered ${method} with something that is not JSON`, {
|
|
80
|
+
operation: method,
|
|
81
|
+
status: response.status,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (answer.ok === true) {
|
|
85
|
+
this.#events?.({ ...answered, outcome: "ok" });
|
|
86
|
+
return answer.result;
|
|
87
|
+
}
|
|
88
|
+
const secretValues = [this.#token, ...secrets];
|
|
89
|
+
if (answer.description) {
|
|
90
|
+
for (const secret of secretValues)
|
|
91
|
+
if (secret)
|
|
92
|
+
answer.description = answer.description.split(secret).join("[redacted]");
|
|
93
|
+
answer.description = answer.description.replace(/\b\d+:[A-Za-z0-9_-]{20,}\b/g, "[redacted]");
|
|
94
|
+
}
|
|
95
|
+
const refusal = refusalOf(method, answer, response.status);
|
|
96
|
+
this.#events?.({ ...answered, outcome: "error", errorCode: refusal.code });
|
|
97
|
+
throw refusal;
|
|
98
|
+
}
|
|
99
|
+
#unanswered(method, error, reads, timeoutMs) {
|
|
100
|
+
// A proxy that refused, or was not there, never passed the request on — not an unknown outcome.
|
|
101
|
+
if (isCliError(error) && error.details.proxy !== undefined)
|
|
102
|
+
return error;
|
|
103
|
+
const timedOut = error?.name === "TimeoutError";
|
|
104
|
+
if (this.#signal?.aborted && this.#signal.reason?.name !== "TimeoutError") {
|
|
105
|
+
return new CliError("cancelled", `${method} was cancelled`, { operation: method });
|
|
106
|
+
}
|
|
107
|
+
if (!reads) {
|
|
108
|
+
return new CliError("outcome_unknown", `${method} got no answer; Telegram may or may not have carried it out — check before repeating it`, { operation: method, retryable: false });
|
|
109
|
+
}
|
|
110
|
+
return new CliError(timedOut ? "timeout" : "network_error", timedOut ? `${method} got no answer within ${timeoutMs} ms` : `${method} could not reach Telegram`, { operation: method, retryable: true });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** A field that is not a string goes as JSON, as Telegram reads `reply_parameters` and `caption_entities` from a form. */
|
|
114
|
+
const multipart = (params, files) => {
|
|
115
|
+
const form = new FormData();
|
|
116
|
+
for (const [name, value] of Object.entries(params)) {
|
|
117
|
+
if (value !== undefined)
|
|
118
|
+
form.append(name, typeof value === "string" ? value : apiJson(value));
|
|
119
|
+
}
|
|
120
|
+
for (const file of files)
|
|
121
|
+
form.append(file.field, new Blob([file.bytes]), file.name);
|
|
122
|
+
return form;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Telegram's own words go into the message: they name the problem ("chat not found") and never the
|
|
126
|
+
* token. Its `error_code` is "subject to change", so the code here follows the HTTP status.
|
|
127
|
+
*/
|
|
128
|
+
const refusalOf = (method, answer, status) => {
|
|
129
|
+
const said = answer.description ?? `HTTP ${status}`;
|
|
130
|
+
const details = { operation: method, status };
|
|
131
|
+
const retryAfter = answer.parameters?.retry_after;
|
|
132
|
+
if (retryAfter !== undefined) {
|
|
133
|
+
return new CliError("rate_limited", `Telegram asks to wait ${retryAfter} s before ${method}: ${said}`, {
|
|
134
|
+
...details,
|
|
135
|
+
retryAfterMs: retryAfter * 1000,
|
|
136
|
+
retryable: true,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
const migrated = answer.parameters?.migrate_to_chat_id;
|
|
140
|
+
if (migrated !== undefined) {
|
|
141
|
+
return new CliError("not_found", `this group became a supergroup with id ${migrated} — use that id from now on (${said})`, { ...details, migratedTo: String(migrated) });
|
|
142
|
+
}
|
|
143
|
+
// A token Telegram cannot parse answers 404, a revoked one 401; the methods called are this code's own.
|
|
144
|
+
const code = status === 401 || status === 404
|
|
145
|
+
? "authentication_error"
|
|
146
|
+
: status === 403
|
|
147
|
+
? "permission_error"
|
|
148
|
+
: status >= 500
|
|
149
|
+
? "provider_unavailable"
|
|
150
|
+
: /not found/i.test(said)
|
|
151
|
+
? "not_found"
|
|
152
|
+
: status === 400
|
|
153
|
+
? "validation_error"
|
|
154
|
+
: "provider_error";
|
|
155
|
+
const message = code === "authentication_error" ? `Telegram did not accept this bot token (${said})` : `${method}: ${said}`;
|
|
156
|
+
return new CliError(code, message, details);
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/bot/transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hands a link to the system's own opener. Best effort: a server has no browser, so the caller
|
|
3
|
+
* prints the link as well and never depends on this.
|
|
4
|
+
*/
|
|
5
|
+
export declare const openInBrowser: (url: string, platform?: NodeJS.Platform) => boolean;
|
|
6
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,aAAa,QAAS,MAAM,aAAY,MAAM,CAAC,QAAQ,KAAsB,OAWzF,CAAA"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* Hands a link to the system's own opener. Best effort: a server has no browser, so the caller
|
|
4
|
+
* prints the link as well and never depends on this.
|
|
5
|
+
*/
|
|
6
|
+
export const openInBrowser = (url, platform = process.platform) => {
|
|
7
|
+
const [command, ...args] = platform === "darwin" ? ["open", url] : platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
|
|
8
|
+
try {
|
|
9
|
+
const child = spawn(command ?? "xdg-open", args, { detached: true, stdio: "ignore" });
|
|
10
|
+
child.on("error", () => { });
|
|
11
|
+
child.unref();
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAE1C;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAoB,OAAO,CAAC,QAAQ,EAAW,EAAE;IAClG,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GACtB,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;IACpH,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,IAAI,UAAU,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QACrF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC3B,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-api.d.ts","sourceRoot":"","sources":["../../src/commands/bot-api.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiBxC,eAAO,MAAM,qBAAqB,QAAO,OAyGrC,CAAA"}
|