@leemour/max-cli 0.13.0 → 0.14.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/README.md +53 -9
- package/dist/bot/auth.d.ts +23 -0
- package/dist/bot/auth.d.ts.map +1 -0
- package/dist/bot/auth.js +36 -0
- package/dist/bot/auth.js.map +1 -0
- package/dist/bot/client.d.ts +20 -0
- package/dist/bot/client.d.ts.map +1 -0
- package/dist/bot/client.js +91 -0
- package/dist/bot/client.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 +1232 -0
- package/dist/bot/generated/manifest.js.map +1 -0
- package/dist/bot/generated/schemas.d.ts +271 -0
- package/dist/bot/generated/schemas.d.ts.map +1 -0
- package/dist/bot/generated/schemas.js +869 -0
- package/dist/bot/generated/schemas.js.map +1 -0
- package/dist/bot/generated/types.d.ts +1088 -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/input.d.ts +10 -0
- package/dist/bot/input.d.ts.map +1 -0
- package/dist/bot/input.js +88 -0
- package/dist/bot/input.js.map +1 -0
- package/dist/bot/map.d.ts +11 -0
- package/dist/bot/map.d.ts.map +1 -0
- package/dist/bot/map.js +76 -0
- package/dist/bot/map.js.map +1 -0
- package/dist/bot/permissions.d.ts +14 -0
- package/dist/bot/permissions.d.ts.map +1 -0
- package/dist/bot/permissions.js +53 -0
- package/dist/bot/permissions.js.map +1 -0
- package/dist/bot/registry.d.ts +27 -0
- package/dist/bot/registry.d.ts.map +1 -0
- package/dist/bot/registry.js +68 -0
- package/dist/bot/registry.js.map +1 -0
- package/dist/bot/russian-trusted-root.d.ts +8 -0
- package/dist/bot/russian-trusted-root.d.ts.map +1 -0
- package/dist/bot/russian-trusted-root.js +41 -0
- package/dist/bot/russian-trusted-root.js.map +1 -0
- package/dist/bot/transport.d.ts +41 -0
- package/dist/bot/transport.d.ts.map +1 -0
- package/dist/bot/transport.js +200 -0
- package/dist/bot/transport.js.map +1 -0
- package/dist/client.d.ts +23 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +120 -12
- package/dist/client.js.map +1 -1
- package/dist/commands/bot-context.d.ts +21 -0
- package/dist/commands/bot-context.d.ts.map +1 -0
- package/dist/commands/bot-context.js +59 -0
- package/dist/commands/bot-context.js.map +1 -0
- package/dist/commands/bot-reads.d.ts +7 -0
- package/dist/commands/bot-reads.d.ts.map +1 -0
- package/dist/commands/bot-reads.js +103 -0
- package/dist/commands/bot-reads.js.map +1 -0
- package/dist/commands/bot-sends.d.ts +12 -0
- package/dist/commands/bot-sends.d.ts.map +1 -0
- package/dist/commands/bot-sends.js +225 -0
- package/dist/commands/bot-sends.js.map +1 -0
- package/dist/commands/bot.d.ts +3 -0
- package/dist/commands/bot.d.ts.map +1 -0
- package/dist/commands/bot.js +145 -0
- package/dist/commands/bot.js.map +1 -0
- package/dist/commands/chats.d.ts.map +1 -1
- package/dist/commands/chats.js +65 -1
- package/dist/commands/chats.js.map +1 -1
- package/dist/commands/context.d.ts +10 -1
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +17 -1
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/rules.d.ts +7 -0
- package/dist/commands/rules.d.ts.map +1 -0
- package/dist/commands/rules.js +69 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/domain/map.d.ts +6 -1
- package/dist/domain/map.d.ts.map +1 -1
- package/dist/domain/map.js +34 -1
- package/dist/domain/map.js.map +1 -1
- package/dist/domain/models.d.ts +51 -0
- package/dist/domain/models.d.ts.map +1 -1
- package/dist/domain/models.js.map +1 -1
- package/dist/generated/operations.generated.d.ts +3 -1
- package/dist/generated/operations.generated.d.ts.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +10 -2
- package/dist/mcp/tools.js.map +1 -1
- package/dist/moderation/rules.d.ts +56 -0
- package/dist/moderation/rules.d.ts.map +1 -0
- package/dist/moderation/rules.js +138 -0
- package/dist/moderation/rules.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +18 -3
- package/dist/program.js.map +1 -1
- package/dist/protocol/connection.d.ts.map +1 -1
- package/dist/protocol/connection.js +12 -1
- package/dist/protocol/connection.js.map +1 -1
- package/dist/review.d.ts +23 -2
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +58 -3
- package/dist/review.js.map +1 -1
- package/dist/spec/operations/chats.d.ts +4 -1
- package/dist/spec/operations/chats.d.ts.map +1 -1
- package/dist/spec/operations/chats.js +10 -4
- package/dist/spec/operations/chats.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -6
- package/skills/max-cli/SKILL.md +15 -1
package/README.md
CHANGED
|
@@ -4,13 +4,52 @@
|
|
|
4
4
|
|
|
5
5
|
# max-cli
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Ваши боты [MAX](https://max.ru) и ваш личный аккаунт — в терминале и в ИИ-агентах. `max` —
|
|
8
|
+
программа для терминала и MCP-сервер: пишите от имени бота через официальный Bot API, а в свои
|
|
9
|
+
чаты — сами или руками Claude, Codex, Cursor и других агентов.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
```sh
|
|
12
|
+
max sales bot messages send "Команда продаж" "Сборка готова" # от имени бота
|
|
13
|
+
max messages send "Иван Петров" "Опаздываю на 15 минут" # от вашего имени
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Бот
|
|
17
|
+
|
|
18
|
+
`max bot` работает с ботом через **официальный** [Bot API MAX](https://dev.max.ru/docs-api) по токену
|
|
19
|
+
бота. Ботов может быть несколько: каждый хранится под именем, которое вы выбираете, и это имя —
|
|
20
|
+
первое слово команды.
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
max sales bot auth set # токен — в скрытом вводе, MAX его проверит
|
|
24
|
+
max sales bot me # какой это бот
|
|
25
|
+
max sales bot messages send -72894839451 "Сборка готова"
|
|
26
|
+
max sales bot messages list -72894839451
|
|
27
|
+
max sales bot recipients add -72894839451 # писать только сюда
|
|
28
|
+
max bot list --check # все боты на этом компьютере
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **Сообщения и чаты.** Отправка в чат по номеру, человеку как `user:<номер>` или в чат по
|
|
32
|
+
названию; правка, удаление, чтение, закрепление. `chats list` — чаты, которые бот видел: списка
|
|
33
|
+
чатов бота у MAX нет.
|
|
34
|
+
- **Любая операция API.** Все операции Bot API доступны как `max bot api <операция>` — с флагами
|
|
35
|
+
для параметров и JSON-телом, которое сверяется со схемой до отправки.
|
|
36
|
+
- **Бот не напишет лишнего.** У каждого бота свой список чатов, куда ему можно писать, и журнал
|
|
37
|
+
всего, что он отправил, — без текста. Профиль только для чтения и `allow` действуют и на бота.
|
|
38
|
+
- **Токен не в файле.** Токен бота — в системном хранилище паролей, отдельно от вашего.
|
|
39
|
+
|
|
40
|
+
Бота создают на [business.max.ru](https://business.max.ru/self); MAX выдаёт их подтверждённым
|
|
41
|
+
организациям, ИП и самозанятым. Полностью — [docs/bot.md](docs/bot.md).
|
|
42
|
+
|
|
43
|
+
## Личный аккаунт
|
|
44
|
+
|
|
45
|
+
`max` без слова `bot` работает с вашим личным аккаунтом: как ещё одно ваше устройство, со всеми
|
|
46
|
+
чатами, историей, группами и контактами.
|
|
47
|
+
|
|
48
|
+
> ⚠️ **Для личного аккаунта max-cli использует неофициальный внутренний API MAX.** API может
|
|
49
|
+
> измениться без предупреждения, а использование инструмента может нарушать условия сервиса. Вы
|
|
50
|
+
> используете max-cli на свой риск; авторы и контрибьюторы не несут ответственности за блокировки
|
|
51
|
+
> аккаунтов, потерю данных или другие последствия. Бот работает через официальный API, и к нему
|
|
52
|
+
> это не относится.
|
|
14
53
|
|
|
15
54
|
```sh
|
|
16
55
|
max chats list --limit 5
|
|
@@ -18,6 +57,8 @@ max messages list "Иван Петров"
|
|
|
18
57
|
max messages send "Иван Петров" "Опаздываю на 15 минут"
|
|
19
58
|
```
|
|
20
59
|
|
|
60
|
+
Всё ниже, до раздела «Установка», — про личный аккаунт. Полностью — [docs/usage.md](docs/usage.md).
|
|
61
|
+
|
|
21
62
|
## Как это использовать
|
|
22
63
|
|
|
23
64
|
Самое полезное — поручить переписку агенту: Claude, Codex или другому. Он читает чаты через `max`
|
|
@@ -157,11 +198,13 @@ max messages send "Иван Петров" "Опаздываю на 15 минут
|
|
|
157
198
|
| опросы | — | ✅ | — |
|
|
158
199
|
| пароль и двухфакторный вход, фото профиля | — | ✅ | — |
|
|
159
200
|
|
|
160
|
-
|
|
161
|
-
[
|
|
201
|
+
Для бота есть `max bot` — через официальный Bot API, отдельно от личного аккаунта
|
|
202
|
+
([docs/bot.md](docs/bot.md)). Таблица выше — про личный аккаунт.
|
|
162
203
|
|
|
163
204
|
## Содержание
|
|
164
205
|
|
|
206
|
+
- [Бот](#бот)
|
|
207
|
+
- [Личный аккаунт](#личный-аккаунт)
|
|
165
208
|
- [Установка](#установка)
|
|
166
209
|
- [Вход](#вход)
|
|
167
210
|
- [Использование](#использование)
|
|
@@ -332,7 +375,8 @@ max chats list --json
|
|
|
332
375
|
## Документация
|
|
333
376
|
|
|
334
377
|
- [docs/installation.md](docs/installation.md) — установка, обновление, куда что ложится
|
|
335
|
-
- [docs/
|
|
378
|
+
- [docs/bot.md](docs/bot.md) — бот: токен, несколько ботов, сообщения, чаты, список получателей, любая операция API
|
|
379
|
+
- [docs/usage.md](docs/usage.md) — личный аккаунт: вход, чтение, отправка, машинный режим
|
|
336
380
|
- [docs/sessions.md](docs/sessions.md) — токен, хранилище паролей, профили
|
|
337
381
|
- [docs/configuration.md](docs/configuration.md) — настройки, переменные, порядок разрешения
|
|
338
382
|
- [docs/mcp.md](docs/mcp.md) — MCP-сервер: подключение, отправка, соединение с MAX
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type CredentialSource, type KeyringStore } from "@leemour/cli-core";
|
|
2
|
+
export interface BotTokenStoreOptions {
|
|
3
|
+
profile: string;
|
|
4
|
+
env?: NodeJS.ProcessEnv;
|
|
5
|
+
keyring?: KeyringStore;
|
|
6
|
+
configDir?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A bot token per profile, beside — never inside — the personal session: keyring account
|
|
10
|
+
* `bot:<profile>`, environment variable `MAX_BOT_TOKEN`, then a 0600 file (`NEED-295`).
|
|
11
|
+
*/
|
|
12
|
+
export declare class BotTokenStore {
|
|
13
|
+
#private;
|
|
14
|
+
readonly profile: string;
|
|
15
|
+
constructor({ profile, env, keyring, configDir }: BotTokenStoreOptions);
|
|
16
|
+
read(): {
|
|
17
|
+
token: string;
|
|
18
|
+
source: CredentialSource;
|
|
19
|
+
} | undefined;
|
|
20
|
+
write(token: string): CredentialSource;
|
|
21
|
+
remove(): CredentialSource[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/bot/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,YAAY,EAGlB,MAAM,mBAAmB,CAAA;AAI1B,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,qBAAa,aAAa;;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IAIxB,YAAY,EAAE,OAAO,EAAE,GAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,oBAAoB,EAanF;IAED,IAAI,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,gBAAgB,CAAA;KAAE,GAAG,SAAS,CAG9D;IAED,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAErC;IAED,MAAM,IAAI,gBAAgB,EAAE,CAE3B;CACF"}
|
package/dist/bot/auth.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Credentials, pathsAreOverridden, resolvePaths, } from "@leemour/cli-core";
|
|
2
|
+
const APP = "max-cli";
|
|
3
|
+
/**
|
|
4
|
+
* A bot token per profile, beside — never inside — the personal session: keyring account
|
|
5
|
+
* `bot:<profile>`, environment variable `MAX_BOT_TOKEN`, then a 0600 file (`NEED-295`).
|
|
6
|
+
*/
|
|
7
|
+
export class BotTokenStore {
|
|
8
|
+
profile;
|
|
9
|
+
#account;
|
|
10
|
+
#credentials;
|
|
11
|
+
constructor({ profile, env = process.env, keyring, configDir }) {
|
|
12
|
+
const paths = resolvePaths({ appName: APP, prefix: "MAX", env });
|
|
13
|
+
this.profile = profile;
|
|
14
|
+
this.#account = `bot:${profile}`;
|
|
15
|
+
this.#credentials = new Credentials({
|
|
16
|
+
configDir: configDir ?? paths.config,
|
|
17
|
+
service: APP,
|
|
18
|
+
envVar: "MAX_BOT_TOKEN",
|
|
19
|
+
isolated: pathsAreOverridden({ appName: APP, prefix: "MAX", env }),
|
|
20
|
+
...(keyring ? { keyring } : {}),
|
|
21
|
+
env,
|
|
22
|
+
warn: (message) => process.stderr.write(`${message}\n`),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
read() {
|
|
26
|
+
const stored = this.#credentials.read(this.#account);
|
|
27
|
+
return stored ? { token: stored.secret, source: stored.source } : undefined;
|
|
28
|
+
}
|
|
29
|
+
write(token) {
|
|
30
|
+
return this.#credentials.write(this.#account, token);
|
|
31
|
+
}
|
|
32
|
+
remove() {
|
|
33
|
+
return this.#credentials.remove(this.#account);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/bot/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EAEX,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAA;AAE1B,MAAM,GAAG,GAAG,SAAS,CAAA;AASrB;;;GAGG;AACH,MAAM,OAAO,aAAa;IACf,OAAO,CAAQ;IACf,QAAQ,CAAQ;IAChB,YAAY,CAAa;IAElC,YAAY,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAwB;QAClF,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;QAChE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,OAAO,OAAO,EAAE,CAAA;QAChC,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC;YAClC,SAAS,EAAE,SAAS,IAAI,KAAK,CAAC,MAAM;YACpC,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE,eAAe;YACvB,QAAQ,EAAE,kBAAkB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YAClE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,GAAG;YACH,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC;SACxD,CAAC,CAAA;IACJ,CAAC;IAED,IAAI;QACF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACpD,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IAC7E,CAAC;IAED,KAAK,CAAC,KAAa;QACjB,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IACtD,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAChD,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ManifestOperation } from "@leemour/cli-core/codegen";
|
|
2
|
+
import type { Chat, Message } from "@leemour/cli-messaging";
|
|
3
|
+
import type { BotInfo as BotInfoType } from "./generated/types.js";
|
|
4
|
+
import { type CallInput, type TransportOptions } from "./transport.js";
|
|
5
|
+
/** Every operation of the committed schema, as the manifest describes it. */
|
|
6
|
+
export declare const botOperations: readonly ManifestOperation[];
|
|
7
|
+
/** The one door to the Bot API: generated operations stay behind it. */
|
|
8
|
+
export declare class BotApiClient {
|
|
9
|
+
#private;
|
|
10
|
+
constructor(options: TransportOptions);
|
|
11
|
+
me(): Promise<BotInfoType>;
|
|
12
|
+
chat(chatId: string): Promise<Chat>;
|
|
13
|
+
message(messageId: string, selfId?: string): Promise<Message>;
|
|
14
|
+
/** Newest last, as MAX returns them. */
|
|
15
|
+
messages(chatId: string, count: number, selfId?: string): Promise<Message[]>;
|
|
16
|
+
/** A message from any answer — a send's result, an update — decoded the same way as a read. */
|
|
17
|
+
decodeMessage(raw: unknown, selfId?: string): Message;
|
|
18
|
+
call(operation: ManifestOperation, input: CallInput): Promise<unknown>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/bot/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAI3D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAyB,MAAM,sBAAsB,CAAA;AAEzF,OAAO,EAAgB,KAAK,SAAS,EAAa,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAE/F,6EAA6E;AAC7E,eAAO,MAAM,aAAa,EAAE,SAAS,iBAAiB,EAAe,CAAA;AAUrE,wEAAwE;AACxE,qBAAa,YAAY;;IAGvB,YAAY,OAAO,EAAE,gBAAgB,EAEpC;IAEK,EAAE,IAAI,OAAO,CAAC,WAAW,CAAC,CAU/B;IAEK,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxC;IAEK,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGlE;IAED,wCAAwC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAKjF;IAED,+FAA+F;IAC/F,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAEpD;IAED,IAAI,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAErE;CAyCF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { CliError } from "@leemour/cli-core";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
import { operations } from "./generated/manifest.js";
|
|
4
|
+
import { BotInfo, Chat as ChatSchema, Message as MessageSchema } from "./generated/schemas.js";
|
|
5
|
+
import { toChat, toMessage } from "./map.js";
|
|
6
|
+
import { BotTransport, plainJson } from "./transport.js";
|
|
7
|
+
/** Every operation of the committed schema, as the manifest describes it. */
|
|
8
|
+
export const botOperations = operations;
|
|
9
|
+
const operationById = new Map(operations.map((operation) => [operation.id, operation]));
|
|
10
|
+
const required = (id) => {
|
|
11
|
+
const operation = operationById.get(id);
|
|
12
|
+
if (!operation)
|
|
13
|
+
throw new CliError("configuration_error", `the generated manifest has no operation ${id}`);
|
|
14
|
+
return operation;
|
|
15
|
+
};
|
|
16
|
+
/** The one door to the Bot API: generated operations stay behind it. */
|
|
17
|
+
export class BotApiClient {
|
|
18
|
+
#transport;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.#transport = new BotTransport(options);
|
|
21
|
+
}
|
|
22
|
+
async me() {
|
|
23
|
+
const answer = await this.#transport.call(required("getMyInfo"));
|
|
24
|
+
const parsed = v.safeParse(BotInfo, answer);
|
|
25
|
+
if (!parsed.success) {
|
|
26
|
+
throw new CliError("invalid_response", "MAX answered getMyInfo in a shape this version does not know", {
|
|
27
|
+
operation: "getMyInfo",
|
|
28
|
+
fields: parsed.issues.map((issue) => v.getDotPath(issue) ?? "(root)"),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return parsed.output;
|
|
32
|
+
}
|
|
33
|
+
async chat(chatId) {
|
|
34
|
+
const answer = await this.#transport.call(required("getChat"), { path: { chatId } });
|
|
35
|
+
return toChat(this.#decode(ChatSchema, answer, "getChat"));
|
|
36
|
+
}
|
|
37
|
+
async message(messageId, selfId) {
|
|
38
|
+
const answer = await this.#transport.call(required("getMessageById"), { path: { messageId } });
|
|
39
|
+
return this.#message(answer, selfId);
|
|
40
|
+
}
|
|
41
|
+
/** Newest last, as MAX returns them. */
|
|
42
|
+
async messages(chatId, count, selfId) {
|
|
43
|
+
const answer = (await this.#transport.call(required("getMessages"), {
|
|
44
|
+
query: { chat_id: chatId, count: String(count) },
|
|
45
|
+
}));
|
|
46
|
+
return (answer?.messages ?? []).map((raw) => this.#message(raw, selfId));
|
|
47
|
+
}
|
|
48
|
+
/** A message from any answer — a send's result, an update — decoded the same way as a read. */
|
|
49
|
+
decodeMessage(raw, selfId) {
|
|
50
|
+
return this.#message(raw, selfId);
|
|
51
|
+
}
|
|
52
|
+
call(operation, input) {
|
|
53
|
+
return this.#transport.call(operation, input);
|
|
54
|
+
}
|
|
55
|
+
#decode(schema, answer, operation) {
|
|
56
|
+
const parsed = v.safeParse(schema, answer);
|
|
57
|
+
if (!parsed.success) {
|
|
58
|
+
throw new CliError("invalid_response", `MAX answered ${operation} in a shape this version does not know`, {
|
|
59
|
+
operation,
|
|
60
|
+
fields: parsed.issues.map((issue) => v.getDotPath(issue) ?? "(root)"),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return parsed.output;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* One message MAX added something new to (an attachment type newer than the schema, `RISK-51`)
|
|
67
|
+
* still shows its text and time rather than failing the whole list.
|
|
68
|
+
*/
|
|
69
|
+
#message(raw, selfId) {
|
|
70
|
+
const parsed = v.safeParse(MessageSchema, raw);
|
|
71
|
+
if (parsed.success)
|
|
72
|
+
return toMessage(parsed.output, selfId);
|
|
73
|
+
const loose = plainJson(raw);
|
|
74
|
+
return {
|
|
75
|
+
id: String(loose.body?.mid ?? "unknown"),
|
|
76
|
+
chatId: String(loose.recipient?.chat_id ?? "unknown"),
|
|
77
|
+
senderId: null,
|
|
78
|
+
senderName: null,
|
|
79
|
+
timestamp: new Date(Number(loose.timestamp ?? 0)).toISOString(),
|
|
80
|
+
editedAt: null,
|
|
81
|
+
text: loose.body?.text ?? "",
|
|
82
|
+
outgoing: null,
|
|
83
|
+
attachments: [],
|
|
84
|
+
replyTo: null,
|
|
85
|
+
forwardedFrom: null,
|
|
86
|
+
reactions: null,
|
|
87
|
+
providerMetadata: { unparsed: parsed.issues.map((issue) => v.getDotPath(issue) ?? "(root)") },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/bot/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/bot/generated/manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAElE,eAAO,MAAM,UAAU,EAAE,SAAS,iBAAiB,EA4tClD,CAAA"}
|