@effect-ak/tg-bot-client 0.6.4 → 1.1.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 +294 -0
- package/dist/index.cjs +209 -0
- package/dist/index.d.cts +98 -0
- package/dist/index.d.ts +63 -28
- package/dist/index.js +169 -1
- package/package.json +19 -56
- package/src/client-file.ts +73 -0
- package/src/client.ts +34 -0
- package/src/config.ts +10 -0
- package/src/const.ts +20 -0
- package/src/errors.ts +18 -0
- package/src/execute.ts +81 -0
- package/src/guards.ts +27 -0
- package/src/index.ts +8 -0
- package/src/utils.ts +3 -0
- package/test/execute.test.ts +102 -0
- package/test/file.test.ts +23 -0
- package/test/fixture.ts +35 -0
- package/tsconfig.json +12 -0
- package/tsup.config.json +10 -0
- package/dist/bot-bundle.js +0 -22
- package/dist/bot-bundle.mjs +0 -22
- package/dist/bot.d.ts +0 -111
- package/dist/bot.js +0 -1
- package/dist/bot.mjs +0 -1
- package/dist/config-3uU0YevV.d.ts +0 -3250
- package/dist/index.mjs +0 -1
- package/dist/webapp.d.ts +0 -392
- package/dist/webapp.js +0 -1
- package/dist/webapp.mjs +0 -0
- package/readme.md +0 -236
package/README.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# @effect-ak/tg-bot-client
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@effect-ak/tg-bot-client)
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
Type-safe HTTP client for Telegram Bot API with complete TypeScript support.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Motivation](#motivation)
|
|
13
|
+
- [Features](#features)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Quick Start](#quick-start)
|
|
16
|
+
- [Usage Examples](#usage-examples)
|
|
17
|
+
- [Sending Messages](#sending-messages)
|
|
18
|
+
- [Sending Files](#sending-files)
|
|
19
|
+
- [Downloading Files](#downloading-files)
|
|
20
|
+
- [Using Message Effects](#using-message-effects)
|
|
21
|
+
- [Error Handling](#error-handling)
|
|
22
|
+
- [API Reference](#api-reference)
|
|
23
|
+
- [Configuration](#configuration)
|
|
24
|
+
- [Related Packages](#related-packages)
|
|
25
|
+
- [Contributing](#contributing)
|
|
26
|
+
- [License](#license)
|
|
27
|
+
|
|
28
|
+
## Motivation
|
|
29
|
+
|
|
30
|
+
**Telegram** does not offer an official TypeScript **SDK** for their **API** but they provide documentation in HTML format.
|
|
31
|
+
|
|
32
|
+
This package provides a lightweight, type-safe HTTP client that uses types generated from the [official Telegram Bot API documentation](https://core.telegram.org/bots/api), ensuring it stays in sync with the latest API updates.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Type-Safe**: Full TypeScript support with types generated from official documentation
|
|
37
|
+
- **Lightweight**: Minimal dependencies
|
|
38
|
+
- **Complete API Coverage**: All Bot API methods are supported
|
|
39
|
+
- **Smart Type Conversion**: Automatic mapping of Telegram types to TypeScript:
|
|
40
|
+
- `Integer` → `number`
|
|
41
|
+
- `True` → `boolean`
|
|
42
|
+
- `String or Number` → `string | number`
|
|
43
|
+
- Enumerated types → Union of literal types (e.g., `"private" | "group" | "supergroup" | "channel"`)
|
|
44
|
+
- **File Handling**: Simplified file upload and download
|
|
45
|
+
- **Message Effects**: Built-in constants for message effects
|
|
46
|
+
- **Custom Base URL**: Support for custom Telegram Bot API servers
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @effect-ak/tg-bot-client
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pnpm add @effect-ak/tg-bot-client
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
yarn add @effect-ak/tg-bot-client
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { makeTgBotClient } from "@effect-ak/tg-bot-client"
|
|
66
|
+
|
|
67
|
+
const client = makeTgBotClient({
|
|
68
|
+
bot_token: "YOUR_BOT_TOKEN" // Token from @BotFather
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// Send a message
|
|
72
|
+
await client.execute("send_message", {
|
|
73
|
+
chat_id: "123456789",
|
|
74
|
+
text: "Hello, World!"
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Usage Examples
|
|
79
|
+
|
|
80
|
+
### Sending Messages
|
|
81
|
+
|
|
82
|
+
#### Basic Text Message
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
await client.execute("send_message", {
|
|
86
|
+
chat_id: "123456789",
|
|
87
|
+
text: "Hello from TypeScript!"
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Message with Formatting
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
await client.execute("send_message", {
|
|
95
|
+
chat_id: "123456789",
|
|
96
|
+
text: "*Bold* _italic_ `code`",
|
|
97
|
+
parse_mode: "Markdown"
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Message with Inline Keyboard
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
await client.execute("send_message", {
|
|
105
|
+
chat_id: "123456789",
|
|
106
|
+
text: "Choose an option:",
|
|
107
|
+
reply_markup: {
|
|
108
|
+
inline_keyboard: [
|
|
109
|
+
[
|
|
110
|
+
{ text: "Option 1", callback_data: "opt_1" },
|
|
111
|
+
{ text: "Option 2", callback_data: "opt_2" }
|
|
112
|
+
]
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Sending Files
|
|
119
|
+
|
|
120
|
+
#### Sending a Dice
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
await client.execute("send_dice", {
|
|
124
|
+
chat_id: "123456789",
|
|
125
|
+
emoji: "🎲"
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Sending a Document
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
await client.execute("send_document", {
|
|
133
|
+
chat_id: "123456789",
|
|
134
|
+
document: {
|
|
135
|
+
file_content: new TextEncoder().encode("Hello from file!"),
|
|
136
|
+
file_name: "hello.txt"
|
|
137
|
+
},
|
|
138
|
+
caption: "Simple text file"
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Sending a Photo
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
await client.execute("send_photo", {
|
|
146
|
+
chat_id: "123456789",
|
|
147
|
+
photo: {
|
|
148
|
+
file_content: photoBuffer,
|
|
149
|
+
file_name: "image.jpg"
|
|
150
|
+
},
|
|
151
|
+
caption: "Check out this photo!"
|
|
152
|
+
})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Downloading Files
|
|
156
|
+
|
|
157
|
+
To download a file from Telegram servers, use the `getFile` method. It handles both the API call and file download in one step:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Get file by file_id (from a message, for example)
|
|
161
|
+
const file = await client.getFile({
|
|
162
|
+
file_id: "AgACAgIAAxkBAAI..."
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// file is a standard File object
|
|
166
|
+
console.log(file.name) // filename.jpg
|
|
167
|
+
console.log(file.size) // file size in bytes
|
|
168
|
+
|
|
169
|
+
// Read file contents
|
|
170
|
+
const arrayBuffer = await file.arrayBuffer()
|
|
171
|
+
const text = await file.text()
|
|
172
|
+
const blob = await file.blob()
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Using Message Effects
|
|
176
|
+
|
|
177
|
+
The library includes built-in constants for message effects:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { MESSAGE_EFFECTS } from "@effect-ak/tg-bot-client"
|
|
181
|
+
|
|
182
|
+
await client.execute("send_message", {
|
|
183
|
+
chat_id: "123456789",
|
|
184
|
+
text: "Message with fire effect!",
|
|
185
|
+
message_effect_id: MESSAGE_EFFECTS["🔥"]
|
|
186
|
+
})
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Available effects:
|
|
190
|
+
- `MESSAGE_EFFECTS["🔥"]` - Fire
|
|
191
|
+
- `MESSAGE_EFFECTS["👍"]` - Thumbs up
|
|
192
|
+
- `MESSAGE_EFFECTS["👎"]` - Thumbs down
|
|
193
|
+
- `MESSAGE_EFFECTS["❤️"]` - Heart
|
|
194
|
+
- `MESSAGE_EFFECTS["🎉"]` - Party
|
|
195
|
+
- `MESSAGE_EFFECTS["💩"]` - Poop
|
|
196
|
+
|
|
197
|
+
## Error Handling
|
|
198
|
+
|
|
199
|
+
The client throws `TgBotClientError` for all errors:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { TgBotClientError } from "@effect-ak/tg-bot-client"
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
await client.execute("send_message", {
|
|
206
|
+
chat_id: "invalid",
|
|
207
|
+
text: "Test"
|
|
208
|
+
})
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (error instanceof TgBotClientError) {
|
|
211
|
+
console.error("Error type:", error.cause._tag)
|
|
212
|
+
|
|
213
|
+
switch (error.cause._tag) {
|
|
214
|
+
case "NotOkResponse":
|
|
215
|
+
console.error("API error:", error.cause.errorCode, error.cause.details)
|
|
216
|
+
break
|
|
217
|
+
case "UnexpectedResponse":
|
|
218
|
+
console.error("Unexpected response:", error.cause.response)
|
|
219
|
+
break
|
|
220
|
+
case "ClientInternalError":
|
|
221
|
+
console.error("Internal error:", error.cause.cause)
|
|
222
|
+
break
|
|
223
|
+
case "UnableToGetFile":
|
|
224
|
+
console.error("File download error:", error.cause.cause)
|
|
225
|
+
break
|
|
226
|
+
case "NotJsonResponse":
|
|
227
|
+
console.error("Invalid JSON response:", error.cause.response)
|
|
228
|
+
break
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## API Reference
|
|
235
|
+
|
|
236
|
+
### `makeTgBotClient(config)`
|
|
237
|
+
|
|
238
|
+
Creates a new Telegram Bot API client.
|
|
239
|
+
|
|
240
|
+
**Parameters:**
|
|
241
|
+
- `config.bot_token` (string, required): Your bot token from @BotFather
|
|
242
|
+
- `config.base_url` (string, optional): Custom API base URL (default: `https://api.telegram.org`)
|
|
243
|
+
|
|
244
|
+
**Returns:** `TgBotClient`
|
|
245
|
+
|
|
246
|
+
### `client.execute(method, input)`
|
|
247
|
+
|
|
248
|
+
Executes a Telegram Bot API method.
|
|
249
|
+
|
|
250
|
+
**Parameters:**
|
|
251
|
+
- `method` (string): API method name in snake_case (e.g., `"send_message"`, `"get_updates"`)
|
|
252
|
+
- `input` (object): Method parameters as defined in Telegram Bot API
|
|
253
|
+
|
|
254
|
+
**Returns:** `Promise<ApiResponse>` - Typed response based on the method
|
|
255
|
+
|
|
256
|
+
**Note:** Method names use snake_case (e.g., `send_message`) instead of camelCase for better readability and consistency with the Telegram API documentation.
|
|
257
|
+
|
|
258
|
+
### `client.getFile(input)`
|
|
259
|
+
|
|
260
|
+
Downloads a file from Telegram servers.
|
|
261
|
+
|
|
262
|
+
**Parameters:**
|
|
263
|
+
- `input.file_id` (string): File identifier from a message
|
|
264
|
+
|
|
265
|
+
**Returns:** `Promise<File>` - Standard [File](https://developer.mozilla.org/en-US/docs/Web/API/File) object
|
|
266
|
+
|
|
267
|
+
## Configuration
|
|
268
|
+
|
|
269
|
+
### Custom Base URL
|
|
270
|
+
|
|
271
|
+
If you're running your own Telegram Bot API server:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
const client = makeTgBotClient({
|
|
275
|
+
bot_token: "YOUR_BOT_TOKEN",
|
|
276
|
+
base_url: "https://your-custom-server.com"
|
|
277
|
+
})
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Related Packages
|
|
281
|
+
|
|
282
|
+
This package is part of the `tg-bot-client` monorepo:
|
|
283
|
+
|
|
284
|
+
- **[@effect-ak/tg-bot-api](../api)** - TypeScript types for Telegram Bot API and Mini Apps
|
|
285
|
+
- **[@effect-ak/tg-bot](../bot)** - Effect-based bot runner for building Telegram bots
|
|
286
|
+
- **[@effect-ak/tg-bot-codegen](../codegen)** - Code generator that parses official documentation
|
|
287
|
+
|
|
288
|
+
## Contributing
|
|
289
|
+
|
|
290
|
+
Contributions are welcome! Please check out the [issues](https://github.com/effect-ak/tg-bot-client/issues) or submit a pull request.
|
|
291
|
+
|
|
292
|
+
## License
|
|
293
|
+
|
|
294
|
+
MIT © [Aleksandr Kondaurov](https://github.com/effect-ak)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
MESSAGE_EFFECTS: () => MESSAGE_EFFECTS,
|
|
24
|
+
TG_BOT_API_URL: () => TG_BOT_API_URL,
|
|
25
|
+
TgBotClientError: () => TgBotClientError,
|
|
26
|
+
executeTgBotMethod: () => executeTgBotMethod,
|
|
27
|
+
getBaseUrl: () => getBaseUrl,
|
|
28
|
+
getFile: () => getFile,
|
|
29
|
+
getFileBytes: () => getFileBytes,
|
|
30
|
+
isFileContent: () => isFileContent,
|
|
31
|
+
isMessageEffect: () => isMessageEffect,
|
|
32
|
+
isTgBotApiResponse: () => isTgBotApiResponse,
|
|
33
|
+
makePayload: () => makePayload,
|
|
34
|
+
makeTgBotClient: () => makeTgBotClient,
|
|
35
|
+
messageEffectIdCodes: () => messageEffectIdCodes,
|
|
36
|
+
snakeToCamel: () => snakeToCamel
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
|
|
40
|
+
// src/errors.ts
|
|
41
|
+
var TgBotClientError = class extends Error {
|
|
42
|
+
_tag = "TgBotClientError";
|
|
43
|
+
cause;
|
|
44
|
+
constructor(options) {
|
|
45
|
+
super(`TgBotClientError: ${options.cause._tag}`);
|
|
46
|
+
this.cause = options.cause;
|
|
47
|
+
this.name = "TgBotClientError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/guards.ts
|
|
52
|
+
var isFileContent = (input) => typeof input == "object" && input != null && "file_content" in input && input.file_content instanceof Uint8Array && "file_name" in input && typeof input.file_name == "string";
|
|
53
|
+
var isTgBotApiResponse = (input) => typeof input == "object" && input != null && "ok" in input && typeof input.ok == "boolean";
|
|
54
|
+
|
|
55
|
+
// src/const.ts
|
|
56
|
+
var TG_BOT_API_URL = "https://api.telegram.org";
|
|
57
|
+
var MESSAGE_EFFECTS = {
|
|
58
|
+
"\u{1F525}": "5104841245755180586",
|
|
59
|
+
"\u{1F44D}": "5107584321108051014",
|
|
60
|
+
"\u{1F44E}": "5104858069142078462",
|
|
61
|
+
"\u2764\uFE0F": "5159385139981059251",
|
|
62
|
+
"\u{1F389}": "5046509860389126442",
|
|
63
|
+
"\u{1F4A9}": "5046589136895476101"
|
|
64
|
+
};
|
|
65
|
+
var messageEffectIdCodes = Object.keys(
|
|
66
|
+
MESSAGE_EFFECTS
|
|
67
|
+
);
|
|
68
|
+
var isMessageEffect = (input) => {
|
|
69
|
+
return typeof input === "string" && input in MESSAGE_EFFECTS;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/config.ts
|
|
73
|
+
var getBaseUrl = (config) => {
|
|
74
|
+
return config?.baseUrl ?? TG_BOT_API_URL;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/utils.ts
|
|
78
|
+
var snakeToCamel = (str) => {
|
|
79
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// src/execute.ts
|
|
83
|
+
async function executeTgBotMethod(params) {
|
|
84
|
+
const { config, method, input } = params;
|
|
85
|
+
const baseUrl = getBaseUrl(config);
|
|
86
|
+
const botToken = config.botToken;
|
|
87
|
+
let httpResponse;
|
|
88
|
+
try {
|
|
89
|
+
httpResponse = await fetch(
|
|
90
|
+
`${baseUrl}/bot${botToken}/${snakeToCamel(method)}`,
|
|
91
|
+
{
|
|
92
|
+
body: makePayload(input) ?? null,
|
|
93
|
+
method: "POST"
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
} catch (cause) {
|
|
97
|
+
throw new TgBotClientError({
|
|
98
|
+
cause: { _tag: "ClientInternalError", cause }
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
let response;
|
|
102
|
+
try {
|
|
103
|
+
response = await httpResponse.json();
|
|
104
|
+
} catch {
|
|
105
|
+
throw new TgBotClientError({
|
|
106
|
+
cause: { _tag: "NotJsonResponse", response: httpResponse }
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (!isTgBotApiResponse(response)) {
|
|
110
|
+
throw new TgBotClientError({
|
|
111
|
+
cause: { _tag: "UnexpectedResponse", response }
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (!httpResponse.ok) {
|
|
115
|
+
throw new TgBotClientError({
|
|
116
|
+
cause: {
|
|
117
|
+
_tag: "NotOkResponse",
|
|
118
|
+
...response.error_code ? { errorCode: response.error_code } : {},
|
|
119
|
+
...response.description ? { details: response.description } : {}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return response.result;
|
|
124
|
+
}
|
|
125
|
+
var makePayload = (body) => {
|
|
126
|
+
const entries = Object.entries(body);
|
|
127
|
+
if (entries.length == 0) return void 0;
|
|
128
|
+
const result = new FormData();
|
|
129
|
+
for (const [key, value] of entries) {
|
|
130
|
+
if (!value) continue;
|
|
131
|
+
if (typeof value != "object") {
|
|
132
|
+
result.append(key, `${value}`);
|
|
133
|
+
} else if (isFileContent(value)) {
|
|
134
|
+
result.append(key, new Blob([value.file_content]), value.file_name);
|
|
135
|
+
} else {
|
|
136
|
+
result.append(key, JSON.stringify(value));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// src/client-file.ts
|
|
143
|
+
var getFileBytes = async (fileId, context) => {
|
|
144
|
+
const { config, execute } = context;
|
|
145
|
+
const response = await execute("get_file", { file_id: fileId });
|
|
146
|
+
const file_path = response.file_path;
|
|
147
|
+
if (!file_path || file_path.length === 0) {
|
|
148
|
+
throw new TgBotClientError({
|
|
149
|
+
cause: {
|
|
150
|
+
_tag: "UnableToGetFile",
|
|
151
|
+
cause: "File path not defined"
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
const file_name = file_path.replaceAll("/", "-");
|
|
156
|
+
const baseUrl = getBaseUrl(config);
|
|
157
|
+
const botToken = config.botToken;
|
|
158
|
+
const url = `${baseUrl}/file/bot${botToken}/${file_path}`;
|
|
159
|
+
let content;
|
|
160
|
+
try {
|
|
161
|
+
content = await fetch(url).then((_) => _.arrayBuffer());
|
|
162
|
+
} catch (cause) {
|
|
163
|
+
throw new TgBotClientError({
|
|
164
|
+
cause: { _tag: "UnableToGetFile", cause }
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const base64String = () => Buffer.from(content).toString("base64");
|
|
168
|
+
return {
|
|
169
|
+
content,
|
|
170
|
+
file_name,
|
|
171
|
+
base64String
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
var getFile = async (input, context) => {
|
|
175
|
+
const { content, file_name } = await getFileBytes(input.fileId, context);
|
|
176
|
+
return new File([content], file_name, {
|
|
177
|
+
...input.type ? { type: input.type } : {}
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// src/client.ts
|
|
182
|
+
function makeTgBotClient(config) {
|
|
183
|
+
const tgConfig = {
|
|
184
|
+
botToken: config.bot_token,
|
|
185
|
+
...config.base_url ? { baseUrl: config.base_url } : {}
|
|
186
|
+
};
|
|
187
|
+
const execute = (method, input) => executeTgBotMethod({ config: tgConfig, method, input });
|
|
188
|
+
return {
|
|
189
|
+
execute,
|
|
190
|
+
getFile: (input) => getFile(input, { config: tgConfig, execute })
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
194
|
+
0 && (module.exports = {
|
|
195
|
+
MESSAGE_EFFECTS,
|
|
196
|
+
TG_BOT_API_URL,
|
|
197
|
+
TgBotClientError,
|
|
198
|
+
executeTgBotMethod,
|
|
199
|
+
getBaseUrl,
|
|
200
|
+
getFile,
|
|
201
|
+
getFileBytes,
|
|
202
|
+
isFileContent,
|
|
203
|
+
isMessageEffect,
|
|
204
|
+
isTgBotApiResponse,
|
|
205
|
+
makePayload,
|
|
206
|
+
makeTgBotClient,
|
|
207
|
+
messageEffectIdCodes,
|
|
208
|
+
snakeToCamel
|
|
209
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Api } from '@effect-ak/tg-bot-api';
|
|
2
|
+
|
|
3
|
+
interface TgBotConfig {
|
|
4
|
+
botToken: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const getBaseUrl: (config?: Pick<TgBotConfig, "baseUrl">) => string;
|
|
8
|
+
|
|
9
|
+
declare function executeTgBotMethod<M extends keyof Api>(params: {
|
|
10
|
+
config: TgBotConfig;
|
|
11
|
+
method: M;
|
|
12
|
+
input: Parameters<Api[M]>[0];
|
|
13
|
+
}): Promise<ReturnType<Api[M]>>;
|
|
14
|
+
declare const makePayload: (body: object) => FormData | undefined;
|
|
15
|
+
|
|
16
|
+
interface GetFile {
|
|
17
|
+
fileId: string;
|
|
18
|
+
type?: string;
|
|
19
|
+
}
|
|
20
|
+
interface FileBytes {
|
|
21
|
+
content: ArrayBuffer;
|
|
22
|
+
file_name: string;
|
|
23
|
+
base64String: () => string;
|
|
24
|
+
}
|
|
25
|
+
interface FileContext {
|
|
26
|
+
config: TgBotConfig;
|
|
27
|
+
execute: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<ReturnType<Api[M]>>;
|
|
28
|
+
}
|
|
29
|
+
declare const getFileBytes: (fileId: string, context: FileContext) => Promise<FileBytes>;
|
|
30
|
+
declare const getFile: (input: GetFile, context: FileContext) => Promise<File>;
|
|
31
|
+
|
|
32
|
+
interface TgBotClient {
|
|
33
|
+
readonly execute: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<ReturnType<Api[M]>>;
|
|
34
|
+
readonly getFile: (input: GetFile) => Promise<File>;
|
|
35
|
+
}
|
|
36
|
+
interface MakeTgClient {
|
|
37
|
+
bot_token: string;
|
|
38
|
+
base_url?: string;
|
|
39
|
+
}
|
|
40
|
+
declare function makeTgBotClient(config: MakeTgClient): TgBotClient;
|
|
41
|
+
|
|
42
|
+
type ErrorReason = {
|
|
43
|
+
_tag: "NotOkResponse";
|
|
44
|
+
errorCode?: number;
|
|
45
|
+
details?: string;
|
|
46
|
+
} | {
|
|
47
|
+
_tag: "UnexpectedResponse";
|
|
48
|
+
response: unknown;
|
|
49
|
+
} | {
|
|
50
|
+
_tag: "ClientInternalError";
|
|
51
|
+
cause: unknown;
|
|
52
|
+
} | {
|
|
53
|
+
_tag: "UnableToGetFile";
|
|
54
|
+
cause: unknown;
|
|
55
|
+
} | {
|
|
56
|
+
_tag: "BotHandlerError";
|
|
57
|
+
cause: unknown;
|
|
58
|
+
} | {
|
|
59
|
+
_tag: "NotJsonResponse";
|
|
60
|
+
response: unknown;
|
|
61
|
+
};
|
|
62
|
+
declare class TgBotClientError extends Error {
|
|
63
|
+
readonly _tag = "TgBotClientError";
|
|
64
|
+
readonly cause: ErrorReason;
|
|
65
|
+
constructor(options: {
|
|
66
|
+
cause: ErrorReason;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface FileContent {
|
|
71
|
+
file_content: Uint8Array<ArrayBuffer>;
|
|
72
|
+
file_name: string;
|
|
73
|
+
}
|
|
74
|
+
declare const isFileContent: (input: unknown) => input is FileContent;
|
|
75
|
+
interface TgBotApiResponseSchema {
|
|
76
|
+
ok: boolean;
|
|
77
|
+
error_code?: number;
|
|
78
|
+
description?: string;
|
|
79
|
+
result?: unknown;
|
|
80
|
+
}
|
|
81
|
+
declare const isTgBotApiResponse: (input: unknown) => input is TgBotApiResponseSchema;
|
|
82
|
+
|
|
83
|
+
declare const TG_BOT_API_URL = "https://api.telegram.org";
|
|
84
|
+
declare const MESSAGE_EFFECTS: {
|
|
85
|
+
readonly "\uD83D\uDD25": "5104841245755180586";
|
|
86
|
+
readonly "\uD83D\uDC4D": "5107584321108051014";
|
|
87
|
+
readonly "\uD83D\uDC4E": "5104858069142078462";
|
|
88
|
+
readonly "\u2764\uFE0F": "5159385139981059251";
|
|
89
|
+
readonly "\uD83C\uDF89": "5046509860389126442";
|
|
90
|
+
readonly "\uD83D\uDCA9": "5046589136895476101";
|
|
91
|
+
};
|
|
92
|
+
type MessageEffect = keyof typeof MESSAGE_EFFECTS;
|
|
93
|
+
declare const messageEffectIdCodes: MessageEffect[];
|
|
94
|
+
declare const isMessageEffect: (input: unknown) => input is MessageEffect;
|
|
95
|
+
|
|
96
|
+
declare const snakeToCamel: (str: string) => string;
|
|
97
|
+
|
|
98
|
+
export { type FileBytes, type FileContent, type GetFile, MESSAGE_EFFECTS, type MakeTgClient, type MessageEffect, TG_BOT_API_URL, type TgBotApiResponseSchema, type TgBotClient, TgBotClientError, type TgBotConfig, executeTgBotMethod, getBaseUrl, getFile, getFileBytes, isFileContent, isMessageEffect, isTgBotApiResponse, makePayload, makeTgBotClient, messageEffectIdCodes, snakeToCamel };
|