@effect-ak/tg-bot-client 1.2.0 → 1.3.1
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/dist/index.cjs +34 -44
- package/dist/index.d.cts +29 -30
- package/dist/index.d.ts +29 -30
- package/dist/index.js +34 -42
- package/effect-ak-tg-bot-client-1.2.0.tgz +0 -0
- package/package.json +4 -3
- package/src/client-file.ts +23 -39
- package/src/client.ts +16 -15
- package/src/execute.ts +13 -9
- package/src/index.ts +0 -1
- package/test/execute.test.ts +7 -12
- package/test/fixture.ts +6 -8
- package/vitest.config.ts +11 -0
- package/src/config.ts +0 -10
- /package/{README.md → readme.md} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -24,9 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
TG_BOT_API_URL: () => TG_BOT_API_URL,
|
|
25
25
|
TgBotClientError: () => TgBotClientError,
|
|
26
26
|
executeTgBotMethod: () => executeTgBotMethod,
|
|
27
|
-
getBaseUrl: () => getBaseUrl,
|
|
28
27
|
getFile: () => getFile,
|
|
29
|
-
getFileBytes: () => getFileBytes,
|
|
30
28
|
isFileContent: () => isFileContent,
|
|
31
29
|
isMessageEffect: () => isMessageEffect,
|
|
32
30
|
isTgBotApiResponse: () => isTgBotApiResponse,
|
|
@@ -52,28 +50,6 @@ var TgBotClientError = class extends Error {
|
|
|
52
50
|
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
51
|
var isTgBotApiResponse = (input) => typeof input == "object" && input != null && "ok" in input && typeof input.ok == "boolean";
|
|
54
52
|
|
|
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
53
|
// src/utils.ts
|
|
78
54
|
var snakeToCamel = (str) => {
|
|
79
55
|
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
@@ -82,12 +58,10 @@ var snakeToCamel = (str) => {
|
|
|
82
58
|
// src/execute.ts
|
|
83
59
|
async function executeTgBotMethod(params) {
|
|
84
60
|
const { config, method, input } = params;
|
|
85
|
-
const baseUrl = getBaseUrl(config);
|
|
86
|
-
const botToken = config.botToken;
|
|
87
61
|
let httpResponse;
|
|
88
62
|
try {
|
|
89
63
|
httpResponse = await fetch(
|
|
90
|
-
`${
|
|
64
|
+
`${config.base_url}/bot${config.bot_token}/${snakeToCamel(method)}`,
|
|
91
65
|
{
|
|
92
66
|
body: makePayload(input) ?? null,
|
|
93
67
|
method: "POST"
|
|
@@ -140,8 +114,8 @@ var makePayload = (body) => {
|
|
|
140
114
|
};
|
|
141
115
|
|
|
142
116
|
// src/client-file.ts
|
|
143
|
-
var
|
|
144
|
-
const { config, execute } =
|
|
117
|
+
var getFile = async (params) => {
|
|
118
|
+
const { fileId, config, execute } = params;
|
|
145
119
|
const response = await execute("get_file", { file_id: fileId });
|
|
146
120
|
const file_path = response.file_path;
|
|
147
121
|
if (!file_path || file_path.length === 0) {
|
|
@@ -153,9 +127,7 @@ var getFileBytes = async (fileId, context) => {
|
|
|
153
127
|
});
|
|
154
128
|
}
|
|
155
129
|
const file_name = file_path.replaceAll("/", "-");
|
|
156
|
-
const
|
|
157
|
-
const botToken = config.botToken;
|
|
158
|
-
const url = `${baseUrl}/file/bot${botToken}/${file_path}`;
|
|
130
|
+
const url = `${config.base_url}/file/bot${config.bot_token}/${file_path}`;
|
|
159
131
|
let content;
|
|
160
132
|
try {
|
|
161
133
|
content = await fetch(url).then((_) => _.arrayBuffer());
|
|
@@ -165,29 +137,49 @@ var getFileBytes = async (fileId, context) => {
|
|
|
165
137
|
});
|
|
166
138
|
}
|
|
167
139
|
const base64String = () => Buffer.from(content).toString("base64");
|
|
140
|
+
const file = () => new File([content], file_name, {
|
|
141
|
+
...params.type ? { type: params.type } : {}
|
|
142
|
+
});
|
|
168
143
|
return {
|
|
169
144
|
content,
|
|
170
145
|
file_name,
|
|
171
|
-
base64String
|
|
146
|
+
base64String,
|
|
147
|
+
file
|
|
172
148
|
};
|
|
173
149
|
};
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
150
|
+
|
|
151
|
+
// src/const.ts
|
|
152
|
+
var TG_BOT_API_URL = "https://api.telegram.org";
|
|
153
|
+
var MESSAGE_EFFECTS = {
|
|
154
|
+
"\u{1F525}": "5104841245755180586",
|
|
155
|
+
"\u{1F44D}": "5107584321108051014",
|
|
156
|
+
"\u{1F44E}": "5104858069142078462",
|
|
157
|
+
"\u2764\uFE0F": "5159385139981059251",
|
|
158
|
+
"\u{1F389}": "5046509860389126442",
|
|
159
|
+
"\u{1F4A9}": "5046589136895476101"
|
|
160
|
+
};
|
|
161
|
+
var messageEffectIdCodes = Object.keys(
|
|
162
|
+
MESSAGE_EFFECTS
|
|
163
|
+
);
|
|
164
|
+
var isMessageEffect = (input) => {
|
|
165
|
+
return typeof input === "string" && input in MESSAGE_EFFECTS;
|
|
179
166
|
};
|
|
180
167
|
|
|
181
168
|
// src/client.ts
|
|
182
169
|
function makeTgBotClient(config) {
|
|
183
170
|
const tgConfig = {
|
|
184
|
-
|
|
185
|
-
|
|
171
|
+
bot_token: config.bot_token,
|
|
172
|
+
base_url: config.base_url ?? TG_BOT_API_URL
|
|
186
173
|
};
|
|
187
|
-
const execute = (method, input) => executeTgBotMethod({
|
|
174
|
+
const execute = (method, input) => executeTgBotMethod({
|
|
175
|
+
config: tgConfig,
|
|
176
|
+
method,
|
|
177
|
+
input
|
|
178
|
+
});
|
|
188
179
|
return {
|
|
180
|
+
config: tgConfig,
|
|
189
181
|
execute,
|
|
190
|
-
getFile: (input) => getFile(input,
|
|
182
|
+
getFile: (input) => getFile({ ...input, config: tgConfig, execute })
|
|
191
183
|
};
|
|
192
184
|
}
|
|
193
185
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -196,9 +188,7 @@ function makeTgBotClient(config) {
|
|
|
196
188
|
TG_BOT_API_URL,
|
|
197
189
|
TgBotClientError,
|
|
198
190
|
executeTgBotMethod,
|
|
199
|
-
getBaseUrl,
|
|
200
191
|
getFile,
|
|
201
|
-
getFileBytes,
|
|
202
192
|
isFileContent,
|
|
203
193
|
isMessageEffect,
|
|
204
194
|
isTgBotApiResponse,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
import { Api } from '@effect-ak/tg-bot-api';
|
|
2
2
|
|
|
3
|
-
interface
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
interface TgFile {
|
|
4
|
+
readonly content: ArrayBuffer;
|
|
5
|
+
readonly file_name: string;
|
|
6
|
+
readonly base64String: () => string;
|
|
7
|
+
readonly file: () => File;
|
|
6
8
|
}
|
|
7
|
-
declare const
|
|
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 {
|
|
9
|
+
declare const getFile: (params: {
|
|
17
10
|
fileId: string;
|
|
11
|
+
config: {
|
|
12
|
+
bot_token: string;
|
|
13
|
+
base_url: string;
|
|
14
|
+
};
|
|
18
15
|
type?: string;
|
|
19
|
-
|
|
20
|
-
|
|
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>;
|
|
16
|
+
execute: ExecuteMethod;
|
|
17
|
+
}) => Promise<TgFile>;
|
|
31
18
|
|
|
32
19
|
interface TgBotClient {
|
|
33
|
-
readonly
|
|
34
|
-
readonly
|
|
20
|
+
readonly config: Required<TgClientConfig>;
|
|
21
|
+
readonly execute: ExecuteMethod;
|
|
22
|
+
readonly getFile: (input: {
|
|
23
|
+
fileId: string;
|
|
24
|
+
type?: string;
|
|
25
|
+
}) => Promise<TgFile>;
|
|
35
26
|
}
|
|
36
|
-
interface
|
|
27
|
+
interface TgClientConfig {
|
|
37
28
|
bot_token: string;
|
|
38
29
|
base_url?: string;
|
|
39
30
|
}
|
|
40
|
-
declare function makeTgBotClient(config:
|
|
31
|
+
declare function makeTgBotClient(config: TgClientConfig): TgBotClient;
|
|
32
|
+
|
|
33
|
+
type ExecuteMethod = <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<ReturnType<Api[M]>>;
|
|
34
|
+
declare function executeTgBotMethod<M extends keyof Api>(params: {
|
|
35
|
+
config: Required<TgClientConfig>;
|
|
36
|
+
method: M;
|
|
37
|
+
input: Parameters<Api[M]>[0];
|
|
38
|
+
}): Promise<ReturnType<Api[M]>>;
|
|
39
|
+
declare const makePayload: (body: object) => FormData | undefined;
|
|
41
40
|
|
|
42
41
|
type ErrorReason = {
|
|
43
42
|
_tag: "NotOkResponse";
|
|
@@ -95,4 +94,4 @@ declare const isMessageEffect: (input: unknown) => input is MessageEffect;
|
|
|
95
94
|
|
|
96
95
|
declare const snakeToCamel: (str: string) => string;
|
|
97
96
|
|
|
98
|
-
export { type
|
|
97
|
+
export { type ExecuteMethod, type FileContent, MESSAGE_EFFECTS, type MessageEffect, TG_BOT_API_URL, type TgBotApiResponseSchema, type TgBotClient, TgBotClientError, type TgClientConfig, type TgFile, executeTgBotMethod, getFile, isFileContent, isMessageEffect, isTgBotApiResponse, makePayload, makeTgBotClient, messageEffectIdCodes, snakeToCamel };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
import { Api } from '@effect-ak/tg-bot-api';
|
|
2
2
|
|
|
3
|
-
interface
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
interface TgFile {
|
|
4
|
+
readonly content: ArrayBuffer;
|
|
5
|
+
readonly file_name: string;
|
|
6
|
+
readonly base64String: () => string;
|
|
7
|
+
readonly file: () => File;
|
|
6
8
|
}
|
|
7
|
-
declare const
|
|
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 {
|
|
9
|
+
declare const getFile: (params: {
|
|
17
10
|
fileId: string;
|
|
11
|
+
config: {
|
|
12
|
+
bot_token: string;
|
|
13
|
+
base_url: string;
|
|
14
|
+
};
|
|
18
15
|
type?: string;
|
|
19
|
-
|
|
20
|
-
|
|
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>;
|
|
16
|
+
execute: ExecuteMethod;
|
|
17
|
+
}) => Promise<TgFile>;
|
|
31
18
|
|
|
32
19
|
interface TgBotClient {
|
|
33
|
-
readonly
|
|
34
|
-
readonly
|
|
20
|
+
readonly config: Required<TgClientConfig>;
|
|
21
|
+
readonly execute: ExecuteMethod;
|
|
22
|
+
readonly getFile: (input: {
|
|
23
|
+
fileId: string;
|
|
24
|
+
type?: string;
|
|
25
|
+
}) => Promise<TgFile>;
|
|
35
26
|
}
|
|
36
|
-
interface
|
|
27
|
+
interface TgClientConfig {
|
|
37
28
|
bot_token: string;
|
|
38
29
|
base_url?: string;
|
|
39
30
|
}
|
|
40
|
-
declare function makeTgBotClient(config:
|
|
31
|
+
declare function makeTgBotClient(config: TgClientConfig): TgBotClient;
|
|
32
|
+
|
|
33
|
+
type ExecuteMethod = <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<ReturnType<Api[M]>>;
|
|
34
|
+
declare function executeTgBotMethod<M extends keyof Api>(params: {
|
|
35
|
+
config: Required<TgClientConfig>;
|
|
36
|
+
method: M;
|
|
37
|
+
input: Parameters<Api[M]>[0];
|
|
38
|
+
}): Promise<ReturnType<Api[M]>>;
|
|
39
|
+
declare const makePayload: (body: object) => FormData | undefined;
|
|
41
40
|
|
|
42
41
|
type ErrorReason = {
|
|
43
42
|
_tag: "NotOkResponse";
|
|
@@ -95,4 +94,4 @@ declare const isMessageEffect: (input: unknown) => input is MessageEffect;
|
|
|
95
94
|
|
|
96
95
|
declare const snakeToCamel: (str: string) => string;
|
|
97
96
|
|
|
98
|
-
export { type
|
|
97
|
+
export { type ExecuteMethod, type FileContent, MESSAGE_EFFECTS, type MessageEffect, TG_BOT_API_URL, type TgBotApiResponseSchema, type TgBotClient, TgBotClientError, type TgClientConfig, type TgFile, executeTgBotMethod, getFile, isFileContent, isMessageEffect, isTgBotApiResponse, makePayload, makeTgBotClient, messageEffectIdCodes, snakeToCamel };
|
package/dist/index.js
CHANGED
|
@@ -13,28 +13,6 @@ var TgBotClientError = class extends Error {
|
|
|
13
13
|
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";
|
|
14
14
|
var isTgBotApiResponse = (input) => typeof input == "object" && input != null && "ok" in input && typeof input.ok == "boolean";
|
|
15
15
|
|
|
16
|
-
// src/const.ts
|
|
17
|
-
var TG_BOT_API_URL = "https://api.telegram.org";
|
|
18
|
-
var MESSAGE_EFFECTS = {
|
|
19
|
-
"\u{1F525}": "5104841245755180586",
|
|
20
|
-
"\u{1F44D}": "5107584321108051014",
|
|
21
|
-
"\u{1F44E}": "5104858069142078462",
|
|
22
|
-
"\u2764\uFE0F": "5159385139981059251",
|
|
23
|
-
"\u{1F389}": "5046509860389126442",
|
|
24
|
-
"\u{1F4A9}": "5046589136895476101"
|
|
25
|
-
};
|
|
26
|
-
var messageEffectIdCodes = Object.keys(
|
|
27
|
-
MESSAGE_EFFECTS
|
|
28
|
-
);
|
|
29
|
-
var isMessageEffect = (input) => {
|
|
30
|
-
return typeof input === "string" && input in MESSAGE_EFFECTS;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// src/config.ts
|
|
34
|
-
var getBaseUrl = (config) => {
|
|
35
|
-
return config?.baseUrl ?? TG_BOT_API_URL;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
16
|
// src/utils.ts
|
|
39
17
|
var snakeToCamel = (str) => {
|
|
40
18
|
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
@@ -43,12 +21,10 @@ var snakeToCamel = (str) => {
|
|
|
43
21
|
// src/execute.ts
|
|
44
22
|
async function executeTgBotMethod(params) {
|
|
45
23
|
const { config, method, input } = params;
|
|
46
|
-
const baseUrl = getBaseUrl(config);
|
|
47
|
-
const botToken = config.botToken;
|
|
48
24
|
let httpResponse;
|
|
49
25
|
try {
|
|
50
26
|
httpResponse = await fetch(
|
|
51
|
-
`${
|
|
27
|
+
`${config.base_url}/bot${config.bot_token}/${snakeToCamel(method)}`,
|
|
52
28
|
{
|
|
53
29
|
body: makePayload(input) ?? null,
|
|
54
30
|
method: "POST"
|
|
@@ -101,8 +77,8 @@ var makePayload = (body) => {
|
|
|
101
77
|
};
|
|
102
78
|
|
|
103
79
|
// src/client-file.ts
|
|
104
|
-
var
|
|
105
|
-
const { config, execute } =
|
|
80
|
+
var getFile = async (params) => {
|
|
81
|
+
const { fileId, config, execute } = params;
|
|
106
82
|
const response = await execute("get_file", { file_id: fileId });
|
|
107
83
|
const file_path = response.file_path;
|
|
108
84
|
if (!file_path || file_path.length === 0) {
|
|
@@ -114,9 +90,7 @@ var getFileBytes = async (fileId, context) => {
|
|
|
114
90
|
});
|
|
115
91
|
}
|
|
116
92
|
const file_name = file_path.replaceAll("/", "-");
|
|
117
|
-
const
|
|
118
|
-
const botToken = config.botToken;
|
|
119
|
-
const url = `${baseUrl}/file/bot${botToken}/${file_path}`;
|
|
93
|
+
const url = `${config.base_url}/file/bot${config.bot_token}/${file_path}`;
|
|
120
94
|
let content;
|
|
121
95
|
try {
|
|
122
96
|
content = await fetch(url).then((_) => _.arrayBuffer());
|
|
@@ -126,29 +100,49 @@ var getFileBytes = async (fileId, context) => {
|
|
|
126
100
|
});
|
|
127
101
|
}
|
|
128
102
|
const base64String = () => Buffer.from(content).toString("base64");
|
|
103
|
+
const file = () => new File([content], file_name, {
|
|
104
|
+
...params.type ? { type: params.type } : {}
|
|
105
|
+
});
|
|
129
106
|
return {
|
|
130
107
|
content,
|
|
131
108
|
file_name,
|
|
132
|
-
base64String
|
|
109
|
+
base64String,
|
|
110
|
+
file
|
|
133
111
|
};
|
|
134
112
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
113
|
+
|
|
114
|
+
// src/const.ts
|
|
115
|
+
var TG_BOT_API_URL = "https://api.telegram.org";
|
|
116
|
+
var MESSAGE_EFFECTS = {
|
|
117
|
+
"\u{1F525}": "5104841245755180586",
|
|
118
|
+
"\u{1F44D}": "5107584321108051014",
|
|
119
|
+
"\u{1F44E}": "5104858069142078462",
|
|
120
|
+
"\u2764\uFE0F": "5159385139981059251",
|
|
121
|
+
"\u{1F389}": "5046509860389126442",
|
|
122
|
+
"\u{1F4A9}": "5046589136895476101"
|
|
123
|
+
};
|
|
124
|
+
var messageEffectIdCodes = Object.keys(
|
|
125
|
+
MESSAGE_EFFECTS
|
|
126
|
+
);
|
|
127
|
+
var isMessageEffect = (input) => {
|
|
128
|
+
return typeof input === "string" && input in MESSAGE_EFFECTS;
|
|
140
129
|
};
|
|
141
130
|
|
|
142
131
|
// src/client.ts
|
|
143
132
|
function makeTgBotClient(config) {
|
|
144
133
|
const tgConfig = {
|
|
145
|
-
|
|
146
|
-
|
|
134
|
+
bot_token: config.bot_token,
|
|
135
|
+
base_url: config.base_url ?? TG_BOT_API_URL
|
|
147
136
|
};
|
|
148
|
-
const execute = (method, input) => executeTgBotMethod({
|
|
137
|
+
const execute = (method, input) => executeTgBotMethod({
|
|
138
|
+
config: tgConfig,
|
|
139
|
+
method,
|
|
140
|
+
input
|
|
141
|
+
});
|
|
149
142
|
return {
|
|
143
|
+
config: tgConfig,
|
|
150
144
|
execute,
|
|
151
|
-
getFile: (input) => getFile(input,
|
|
145
|
+
getFile: (input) => getFile({ ...input, config: tgConfig, execute })
|
|
152
146
|
};
|
|
153
147
|
}
|
|
154
148
|
export {
|
|
@@ -156,9 +150,7 @@ export {
|
|
|
156
150
|
TG_BOT_API_URL,
|
|
157
151
|
TgBotClientError,
|
|
158
152
|
executeTgBotMethod,
|
|
159
|
-
getBaseUrl,
|
|
160
153
|
getFile,
|
|
161
|
-
getFileBytes,
|
|
162
154
|
isFileContent,
|
|
163
155
|
isMessageEffect,
|
|
164
156
|
isTgBotApiResponse,
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@effect-ak/tg-bot-client",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Type-safe HTTP client for Telegram Bot API",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.3.1",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Aleksandr Kondaurov",
|
|
@@ -30,9 +30,10 @@
|
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@effect-ak/tg-bot-api": "0.
|
|
33
|
+
"@effect-ak/tg-bot-api": "^1.0.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
|
-
"build": "tsup"
|
|
36
|
+
"build": "tsup",
|
|
37
|
+
"typecheck": "tsc"
|
|
37
38
|
}
|
|
38
39
|
}
|
package/src/client-file.ts
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
|
-
import type { Api } from "@effect-ak/tg-bot-api"
|
|
2
1
|
import { TgBotClientError } from "./errors"
|
|
3
|
-
import type {
|
|
4
|
-
import { getBaseUrl } from "./config"
|
|
2
|
+
import type { ExecuteMethod } from "./execute"
|
|
5
3
|
|
|
6
|
-
export interface
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export interface FileBytes {
|
|
12
|
-
content: ArrayBuffer
|
|
13
|
-
file_name: string
|
|
14
|
-
base64String: () => string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface FileContext {
|
|
18
|
-
config: TgBotConfig
|
|
19
|
-
execute: <M extends keyof Api>(
|
|
20
|
-
method: M,
|
|
21
|
-
input: Parameters<Api[M]>[0]
|
|
22
|
-
) => Promise<ReturnType<Api[M]>>
|
|
4
|
+
export interface TgFile {
|
|
5
|
+
readonly content: ArrayBuffer
|
|
6
|
+
readonly file_name: string
|
|
7
|
+
readonly base64String: () => string
|
|
8
|
+
readonly file: () => File
|
|
23
9
|
}
|
|
24
10
|
|
|
25
|
-
export const
|
|
26
|
-
fileId: string
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
11
|
+
export const getFile = async (params: {
|
|
12
|
+
fileId: string
|
|
13
|
+
config: {
|
|
14
|
+
bot_token: string
|
|
15
|
+
base_url: string
|
|
16
|
+
}
|
|
17
|
+
type?: string
|
|
18
|
+
execute: ExecuteMethod
|
|
19
|
+
}): Promise<TgFile> => {
|
|
20
|
+
const { fileId, config, execute } = params
|
|
30
21
|
const response = await execute("get_file", { file_id: fileId })
|
|
31
22
|
const file_path = response.file_path
|
|
32
23
|
|
|
@@ -40,9 +31,7 @@ export const getFileBytes = async (
|
|
|
40
31
|
}
|
|
41
32
|
|
|
42
33
|
const file_name = file_path.replaceAll("/", "-")
|
|
43
|
-
const
|
|
44
|
-
const botToken = config.botToken
|
|
45
|
-
const url = `${baseUrl}/file/bot${botToken}/${file_path}`
|
|
34
|
+
const url = `${config.base_url}/file/bot${config.bot_token}/${file_path}`
|
|
46
35
|
|
|
47
36
|
let content: ArrayBuffer
|
|
48
37
|
try {
|
|
@@ -54,20 +43,15 @@ export const getFileBytes = async (
|
|
|
54
43
|
}
|
|
55
44
|
|
|
56
45
|
const base64String = () => Buffer.from(content).toString("base64")
|
|
46
|
+
const file = () =>
|
|
47
|
+
new File([content], file_name, {
|
|
48
|
+
...(params.type ? { type: params.type } : {})
|
|
49
|
+
})
|
|
57
50
|
|
|
58
51
|
return {
|
|
59
52
|
content,
|
|
60
53
|
file_name,
|
|
61
|
-
base64String
|
|
54
|
+
base64String,
|
|
55
|
+
file
|
|
62
56
|
}
|
|
63
57
|
}
|
|
64
|
-
|
|
65
|
-
export const getFile = async (
|
|
66
|
-
input: GetFile,
|
|
67
|
-
context: FileContext
|
|
68
|
-
): Promise<File> => {
|
|
69
|
-
const { content, file_name } = await getFileBytes(input.fileId, context)
|
|
70
|
-
return new File([content], file_name, {
|
|
71
|
-
...(input.type ? { type: input.type } : {})
|
|
72
|
-
})
|
|
73
|
-
}
|
package/src/client.ts
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import type { Api } from "@effect-ak/tg-bot-api"
|
|
2
|
-
import { executeTgBotMethod } from "./execute"
|
|
3
|
-
import type
|
|
4
|
-
import {
|
|
2
|
+
import { executeTgBotMethod, type ExecuteMethod } from "./execute"
|
|
3
|
+
import { getFile as getFileImpl, type TgFile } from "./client-file"
|
|
4
|
+
import { TG_BOT_API_URL } from "./const"
|
|
5
5
|
|
|
6
6
|
export interface TgBotClient {
|
|
7
|
-
readonly
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
) => Promise<ReturnType<Api[M]>>
|
|
11
|
-
readonly getFile: (input: GetFile) => Promise<File>
|
|
7
|
+
readonly config: Required<TgClientConfig>
|
|
8
|
+
readonly execute: ExecuteMethod
|
|
9
|
+
readonly getFile: (input: { fileId: string; type?: string }) => Promise<TgFile>
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
export interface
|
|
12
|
+
export interface TgClientConfig {
|
|
15
13
|
bot_token: string
|
|
16
14
|
base_url?: string
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
export function makeTgBotClient(config:
|
|
20
|
-
const tgConfig
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
export function makeTgBotClient(config: TgClientConfig): TgBotClient {
|
|
18
|
+
const tgConfig = {
|
|
19
|
+
bot_token: config.bot_token,
|
|
20
|
+
base_url: config.base_url ?? TG_BOT_API_URL
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
const execute = <M extends keyof Api>(
|
|
26
24
|
method: M,
|
|
27
25
|
input: Parameters<Api[M]>[0]
|
|
28
|
-
) => executeTgBotMethod({
|
|
26
|
+
) => executeTgBotMethod({
|
|
27
|
+
config: tgConfig, method, input
|
|
28
|
+
})
|
|
29
29
|
|
|
30
30
|
return {
|
|
31
|
+
config: tgConfig,
|
|
31
32
|
execute,
|
|
32
|
-
getFile: (input
|
|
33
|
+
getFile: (input) => getFileImpl({ ...input, config: tgConfig, execute })
|
|
33
34
|
}
|
|
34
35
|
}
|
package/src/execute.ts
CHANGED
|
@@ -2,23 +2,27 @@ import type { Api } from "@effect-ak/tg-bot-api"
|
|
|
2
2
|
|
|
3
3
|
import { TgBotClientError } from "./errors"
|
|
4
4
|
import { isFileContent, isTgBotApiResponse } from "./guards"
|
|
5
|
-
import type { TgBotConfig } from "./config"
|
|
6
|
-
import { getBaseUrl } from "./config"
|
|
7
5
|
import { snakeToCamel } from "./utils"
|
|
6
|
+
import type { TgClientConfig } from "./client"
|
|
8
7
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
method: M
|
|
8
|
+
export type ExecuteMethod = <M extends keyof Api>(
|
|
9
|
+
method: M,
|
|
12
10
|
input: Parameters<Api[M]>[0]
|
|
13
|
-
|
|
11
|
+
) => Promise<ReturnType<Api[M]>>
|
|
12
|
+
|
|
13
|
+
export async function executeTgBotMethod<M extends keyof Api>(
|
|
14
|
+
params: {
|
|
15
|
+
config: Required<TgClientConfig>
|
|
16
|
+
method: M
|
|
17
|
+
input: Parameters<Api[M]>[0]
|
|
18
|
+
}
|
|
19
|
+
): Promise<ReturnType<Api[M]>> {
|
|
14
20
|
const { config, method, input } = params
|
|
15
|
-
const baseUrl = getBaseUrl(config)
|
|
16
|
-
const botToken = config.botToken
|
|
17
21
|
|
|
18
22
|
let httpResponse: Response
|
|
19
23
|
try {
|
|
20
24
|
httpResponse = await fetch(
|
|
21
|
-
`${
|
|
25
|
+
`${config.base_url}/bot${config.bot_token}/${snakeToCamel(method)}`,
|
|
22
26
|
{
|
|
23
27
|
body: makePayload(input) ?? null,
|
|
24
28
|
method: "POST"
|
package/src/index.ts
CHANGED
package/test/execute.test.ts
CHANGED
|
@@ -1,32 +1,27 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, vi } from "vitest"
|
|
2
2
|
|
|
3
3
|
import { fixture } from "./fixture"
|
|
4
|
-
import { MESSAGE_EFFECTS } from "
|
|
5
|
-
import {
|
|
6
|
-
import { executeTgBotMethod } from "../src/execute"
|
|
4
|
+
import { MESSAGE_EFFECTS } from "~/const"
|
|
5
|
+
import { executeTgBotMethod } from "~/execute"
|
|
7
6
|
|
|
8
7
|
const fetchSpy = vi.spyOn(global, "fetch")
|
|
9
8
|
|
|
10
9
|
describe("telegram bot client, execute method", () => {
|
|
11
|
-
fixture("send dice", async ({ chat_id,
|
|
10
|
+
fixture("send dice", async ({ chat_id, client }) => {
|
|
12
11
|
// skip();
|
|
13
12
|
|
|
14
|
-
const response = await
|
|
13
|
+
const response = await client.execute("send_dice", {
|
|
15
14
|
chat_id,
|
|
16
15
|
emoji: "🎲",
|
|
17
16
|
message_effect_id: MESSAGE_EFFECTS["🔥"]
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
assert(response._tag == "Success")
|
|
17
|
+
})
|
|
21
18
|
|
|
22
19
|
const url = fetchSpy.mock.calls[0][0] as string
|
|
23
20
|
const lastPath = url.split("/").pop()
|
|
24
21
|
|
|
25
22
|
expect(lastPath).toEqual("sendDice")
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(response.value.chat.id).toBeDefined()
|
|
24
|
+
expect(response.chat.id).toBeDefined()
|
|
30
25
|
})
|
|
31
26
|
|
|
32
27
|
fixture("send message", async ({ chat_id, client, skip }) => {
|
package/test/fixture.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { test } from "vitest"
|
|
2
|
-
import { Context } from "effect"
|
|
3
2
|
|
|
4
|
-
import { makeTgBotClient, TgBotClient } from "
|
|
5
|
-
import { TgBotApiToken } from "../src/config"
|
|
3
|
+
import { makeTgBotClient, TgBotClient, TgClientConfig } from "~/client"
|
|
6
4
|
|
|
7
5
|
interface Fixture {
|
|
8
6
|
readonly token: string
|
|
9
7
|
readonly client: TgBotClient
|
|
10
8
|
readonly chat_id: string
|
|
11
|
-
readonly
|
|
9
|
+
readonly config: Required<TgClientConfig>
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export const fixture = test.extend<Fixture>({
|
|
15
|
-
token: async (
|
|
13
|
+
token: async ({}, use) => {
|
|
16
14
|
const token = process.env["bot_token"]
|
|
17
15
|
if (!token) throw Error("bot_token not defined in config.json")
|
|
18
16
|
use(token)
|
|
@@ -24,12 +22,12 @@ export const fixture = test.extend<Fixture>({
|
|
|
24
22
|
})
|
|
25
23
|
use(client)
|
|
26
24
|
},
|
|
27
|
-
chat_id: async (
|
|
25
|
+
chat_id: async ({}, use) => {
|
|
28
26
|
const chatId = process.env["chat_id"]
|
|
29
27
|
if (!chatId) throw Error("chat_id not defined in config.json")
|
|
30
28
|
use(chatId)
|
|
31
29
|
},
|
|
32
|
-
|
|
33
|
-
use(
|
|
30
|
+
config: async ({ client }, use) => {
|
|
31
|
+
use(client.config)
|
|
34
32
|
}
|
|
35
33
|
})
|
package/vitest.config.ts
ADDED
package/src/config.ts
DELETED
/package/{README.md → readme.md}
RENAMED
|
File without changes
|