@effect-ak/tg-bot-client 1.0.0 → 1.2.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 +95 -116
- package/dist/index.d.cts +53 -50
- package/dist/index.d.ts +53 -50
- package/dist/index.js +90 -101
- package/package.json +1 -4
- package/src/client-file.ts +58 -55
- package/src/client.ts +17 -29
- package/src/config.ts +7 -10
- package/src/errors.ts +16 -12
- package/src/execute.ts +46 -49
- package/src/index.ts +1 -0
- package/src/utils.ts +3 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,60 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Api, Update } from '@effect-ak/tg-bot-api';
|
|
3
|
-
import * as effect_Cause from 'effect/Cause';
|
|
4
|
-
import * as effect_Types from 'effect/Types';
|
|
5
|
-
import * as Data from 'effect/Data';
|
|
6
|
-
import * as Context from 'effect/Context';
|
|
1
|
+
import { Api } from '@effect-ak/tg-bot-api';
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
details?: string;
|
|
12
|
-
};
|
|
13
|
-
UnexpectedResponse: {
|
|
14
|
-
response: unknown;
|
|
15
|
-
};
|
|
16
|
-
ClientInternalError: {
|
|
17
|
-
cause: unknown;
|
|
18
|
-
};
|
|
19
|
-
UnableToGetFile: {
|
|
20
|
-
cause: unknown;
|
|
21
|
-
};
|
|
22
|
-
BotHandlerError: {
|
|
23
|
-
cause: unknown;
|
|
24
|
-
};
|
|
25
|
-
NotJsonResponse: {
|
|
26
|
-
response: unknown;
|
|
27
|
-
};
|
|
28
|
-
}>;
|
|
29
|
-
declare const TgBotClientError_base: new <A extends Record<string, any> = {}>(args: effect_Types.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => effect_Cause.YieldableError & {
|
|
30
|
-
readonly _tag: "TgBotClientError";
|
|
31
|
-
} & Readonly<A>;
|
|
32
|
-
declare class TgBotClientError extends TgBotClientError_base<{
|
|
33
|
-
cause: ErrorReason;
|
|
34
|
-
}> {
|
|
3
|
+
interface TgBotConfig {
|
|
4
|
+
botToken: string;
|
|
5
|
+
baseUrl?: string;
|
|
35
6
|
}
|
|
7
|
+
declare const getBaseUrl: (config?: Pick<TgBotConfig, "baseUrl">) => string;
|
|
36
8
|
|
|
37
|
-
declare
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
declare const executeTgBotMethod: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Micro.Micro<ReturnType<Api[M]>, TgBotClientError, TgBotApiToken>;
|
|
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]>>;
|
|
45
14
|
declare const makePayload: (body: object) => FormData | undefined;
|
|
46
15
|
|
|
47
|
-
declare const ClientFileService_base: Context.TagClass<ClientFileService, "ClientFileService", {
|
|
48
|
-
getFile: (input: GetFile) => ReturnType<typeof getFile>;
|
|
49
|
-
}>;
|
|
50
|
-
declare class ClientFileService extends ClientFileService_base {
|
|
51
|
-
static live: () => Context.Context<ClientFileService>;
|
|
52
|
-
}
|
|
53
16
|
interface GetFile {
|
|
54
17
|
fileId: string;
|
|
55
18
|
type?: string;
|
|
56
19
|
}
|
|
57
|
-
|
|
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>;
|
|
58
31
|
|
|
59
32
|
interface TgBotClient {
|
|
60
33
|
readonly execute: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<ReturnType<Api[M]>>;
|
|
@@ -62,9 +35,38 @@ interface TgBotClient {
|
|
|
62
35
|
}
|
|
63
36
|
interface MakeTgClient {
|
|
64
37
|
bot_token: string;
|
|
38
|
+
base_url?: string;
|
|
65
39
|
}
|
|
66
40
|
declare function makeTgBotClient(config: MakeTgClient): TgBotClient;
|
|
67
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
|
+
|
|
68
70
|
interface FileContent {
|
|
69
71
|
file_content: Uint8Array<ArrayBuffer>;
|
|
70
72
|
file_name: string;
|
|
@@ -77,7 +79,6 @@ interface TgBotApiResponseSchema {
|
|
|
77
79
|
result?: unknown;
|
|
78
80
|
}
|
|
79
81
|
declare const isTgBotApiResponse: (input: unknown) => input is TgBotApiResponseSchema;
|
|
80
|
-
declare const isTgBotApiUpdate: (input: unknown) => input is Update;
|
|
81
82
|
|
|
82
83
|
declare const TG_BOT_API_URL = "https://api.telegram.org";
|
|
83
84
|
declare const MESSAGE_EFFECTS: {
|
|
@@ -92,4 +93,6 @@ type MessageEffect = keyof typeof MESSAGE_EFFECTS;
|
|
|
92
93
|
declare const messageEffectIdCodes: MessageEffect[];
|
|
93
94
|
declare const isMessageEffect: (input: unknown) => input is MessageEffect;
|
|
94
95
|
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,60 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Api, Update } from '@effect-ak/tg-bot-api';
|
|
3
|
-
import * as effect_Cause from 'effect/Cause';
|
|
4
|
-
import * as effect_Types from 'effect/Types';
|
|
5
|
-
import * as Data from 'effect/Data';
|
|
6
|
-
import * as Context from 'effect/Context';
|
|
1
|
+
import { Api } from '@effect-ak/tg-bot-api';
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
details?: string;
|
|
12
|
-
};
|
|
13
|
-
UnexpectedResponse: {
|
|
14
|
-
response: unknown;
|
|
15
|
-
};
|
|
16
|
-
ClientInternalError: {
|
|
17
|
-
cause: unknown;
|
|
18
|
-
};
|
|
19
|
-
UnableToGetFile: {
|
|
20
|
-
cause: unknown;
|
|
21
|
-
};
|
|
22
|
-
BotHandlerError: {
|
|
23
|
-
cause: unknown;
|
|
24
|
-
};
|
|
25
|
-
NotJsonResponse: {
|
|
26
|
-
response: unknown;
|
|
27
|
-
};
|
|
28
|
-
}>;
|
|
29
|
-
declare const TgBotClientError_base: new <A extends Record<string, any> = {}>(args: effect_Types.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => effect_Cause.YieldableError & {
|
|
30
|
-
readonly _tag: "TgBotClientError";
|
|
31
|
-
} & Readonly<A>;
|
|
32
|
-
declare class TgBotClientError extends TgBotClientError_base<{
|
|
33
|
-
cause: ErrorReason;
|
|
34
|
-
}> {
|
|
3
|
+
interface TgBotConfig {
|
|
4
|
+
botToken: string;
|
|
5
|
+
baseUrl?: string;
|
|
35
6
|
}
|
|
7
|
+
declare const getBaseUrl: (config?: Pick<TgBotConfig, "baseUrl">) => string;
|
|
36
8
|
|
|
37
|
-
declare
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
declare const executeTgBotMethod: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Micro.Micro<ReturnType<Api[M]>, TgBotClientError, TgBotApiToken>;
|
|
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]>>;
|
|
45
14
|
declare const makePayload: (body: object) => FormData | undefined;
|
|
46
15
|
|
|
47
|
-
declare const ClientFileService_base: Context.TagClass<ClientFileService, "ClientFileService", {
|
|
48
|
-
getFile: (input: GetFile) => ReturnType<typeof getFile>;
|
|
49
|
-
}>;
|
|
50
|
-
declare class ClientFileService extends ClientFileService_base {
|
|
51
|
-
static live: () => Context.Context<ClientFileService>;
|
|
52
|
-
}
|
|
53
16
|
interface GetFile {
|
|
54
17
|
fileId: string;
|
|
55
18
|
type?: string;
|
|
56
19
|
}
|
|
57
|
-
|
|
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>;
|
|
58
31
|
|
|
59
32
|
interface TgBotClient {
|
|
60
33
|
readonly execute: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<ReturnType<Api[M]>>;
|
|
@@ -62,9 +35,38 @@ interface TgBotClient {
|
|
|
62
35
|
}
|
|
63
36
|
interface MakeTgClient {
|
|
64
37
|
bot_token: string;
|
|
38
|
+
base_url?: string;
|
|
65
39
|
}
|
|
66
40
|
declare function makeTgBotClient(config: MakeTgClient): TgBotClient;
|
|
67
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
|
+
|
|
68
70
|
interface FileContent {
|
|
69
71
|
file_content: Uint8Array<ArrayBuffer>;
|
|
70
72
|
file_name: string;
|
|
@@ -77,7 +79,6 @@ interface TgBotApiResponseSchema {
|
|
|
77
79
|
result?: unknown;
|
|
78
80
|
}
|
|
79
81
|
declare const isTgBotApiResponse: (input: unknown) => input is TgBotApiResponseSchema;
|
|
80
|
-
declare const isTgBotApiUpdate: (input: unknown) => input is Update;
|
|
81
82
|
|
|
82
83
|
declare const TG_BOT_API_URL = "https://api.telegram.org";
|
|
83
84
|
declare const MESSAGE_EFFECTS: {
|
|
@@ -92,4 +93,6 @@ type MessageEffect = keyof typeof MESSAGE_EFFECTS;
|
|
|
92
93
|
declare const messageEffectIdCodes: MessageEffect[];
|
|
93
94
|
declare const isMessageEffect: (input: unknown) => input is MessageEffect;
|
|
94
95
|
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
// src/execute.ts
|
|
2
|
-
import * as String from "effect/String";
|
|
3
|
-
import * as Micro from "effect/Micro";
|
|
4
|
-
|
|
5
1
|
// src/errors.ts
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
var TgBotClientError = class extends Error {
|
|
3
|
+
_tag = "TgBotClientError";
|
|
4
|
+
cause;
|
|
5
|
+
constructor(options) {
|
|
6
|
+
super(`TgBotClientError: ${options.cause._tag}`);
|
|
7
|
+
this.cause = options.cause;
|
|
8
|
+
this.name = "TgBotClientError";
|
|
9
|
+
}
|
|
8
10
|
};
|
|
9
11
|
|
|
10
12
|
// src/guards.ts
|
|
11
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";
|
|
12
14
|
var isTgBotApiResponse = (input) => typeof input == "object" && input != null && "ok" in input && typeof input.ok == "boolean";
|
|
13
|
-
var isTgBotApiUpdate = (input) => typeof input == "object" && input != null && "update_id" in input && typeof input.update_id == "number";
|
|
14
|
-
|
|
15
|
-
// src/config.ts
|
|
16
|
-
import * as Context from "effect/Context";
|
|
17
15
|
|
|
18
16
|
// src/const.ts
|
|
19
17
|
var TG_BOT_API_URL = "https://api.telegram.org";
|
|
@@ -33,53 +31,58 @@ var isMessageEffect = (input) => {
|
|
|
33
31
|
};
|
|
34
32
|
|
|
35
33
|
// src/config.ts
|
|
36
|
-
var
|
|
37
|
-
|
|
38
|
-
{ defaultValue: () => TG_BOT_API_URL }
|
|
39
|
-
) {
|
|
34
|
+
var getBaseUrl = (config) => {
|
|
35
|
+
return config?.baseUrl ?? TG_BOT_API_URL;
|
|
40
36
|
};
|
|
41
|
-
|
|
37
|
+
|
|
38
|
+
// src/utils.ts
|
|
39
|
+
var snakeToCamel = (str) => {
|
|
40
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
42
41
|
};
|
|
43
42
|
|
|
44
43
|
// src/execute.ts
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const baseUrl =
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
async function executeTgBotMethod(params) {
|
|
45
|
+
const { config, method, input } = params;
|
|
46
|
+
const baseUrl = getBaseUrl(config);
|
|
47
|
+
const botToken = config.botToken;
|
|
48
|
+
let httpResponse;
|
|
49
|
+
try {
|
|
50
|
+
httpResponse = await fetch(
|
|
51
|
+
`${baseUrl}/bot${botToken}/${snakeToCamel(method)}`,
|
|
52
|
+
{
|
|
53
|
+
body: makePayload(input) ?? null,
|
|
54
|
+
method: "POST"
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
} catch (cause) {
|
|
58
|
+
throw new TgBotClientError({
|
|
54
59
|
cause: { _tag: "ClientInternalError", cause }
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
let response;
|
|
63
|
+
try {
|
|
64
|
+
response = await httpResponse.json();
|
|
65
|
+
} catch {
|
|
66
|
+
throw new TgBotClientError({
|
|
60
67
|
cause: { _tag: "NotJsonResponse", response: httpResponse }
|
|
61
|
-
})
|
|
62
|
-
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
63
70
|
if (!isTgBotApiResponse(response)) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
})
|
|
68
|
-
);
|
|
71
|
+
throw new TgBotClientError({
|
|
72
|
+
cause: { _tag: "UnexpectedResponse", response }
|
|
73
|
+
});
|
|
69
74
|
}
|
|
70
75
|
if (!httpResponse.ok) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
})
|
|
79
|
-
);
|
|
76
|
+
throw new TgBotClientError({
|
|
77
|
+
cause: {
|
|
78
|
+
_tag: "NotOkResponse",
|
|
79
|
+
...response.error_code ? { errorCode: response.error_code } : {},
|
|
80
|
+
...response.description ? { details: response.description } : {}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
80
83
|
}
|
|
81
84
|
return response.result;
|
|
82
|
-
}
|
|
85
|
+
}
|
|
83
86
|
var makePayload = (body) => {
|
|
84
87
|
const entries = Object.entries(body);
|
|
85
88
|
if (entries.length == 0) return void 0;
|
|
@@ -98,83 +101,69 @@ var makePayload = (body) => {
|
|
|
98
101
|
};
|
|
99
102
|
|
|
100
103
|
// src/client-file.ts
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
static live = () => {
|
|
105
|
-
return _ClientFileService.context({
|
|
106
|
-
getFile
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
var getFile = ({ fileId, type }) => getFileBytes(fileId).pipe(
|
|
111
|
-
Micro2.andThen(
|
|
112
|
-
({ content, file_name }) => new File([content], file_name, {
|
|
113
|
-
...type ? { type } : void 0
|
|
114
|
-
})
|
|
115
|
-
)
|
|
116
|
-
);
|
|
117
|
-
var getFileBytes = (fileId) => Micro2.gen(function* () {
|
|
118
|
-
const response = yield* executeTgBotMethod("get_file", { file_id: fileId });
|
|
104
|
+
var getFileBytes = async (fileId, context) => {
|
|
105
|
+
const { config, execute } = context;
|
|
106
|
+
const response = await execute("get_file", { file_id: fileId });
|
|
119
107
|
const file_path = response.file_path;
|
|
120
|
-
if (!file_path || file_path.length
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
})
|
|
128
|
-
);
|
|
108
|
+
if (!file_path || file_path.length === 0) {
|
|
109
|
+
throw new TgBotClientError({
|
|
110
|
+
cause: {
|
|
111
|
+
_tag: "UnableToGetFile",
|
|
112
|
+
cause: "File path not defined"
|
|
113
|
+
}
|
|
114
|
+
});
|
|
129
115
|
}
|
|
130
116
|
const file_name = file_path.replaceAll("/", "-");
|
|
131
|
-
const baseUrl =
|
|
132
|
-
const botToken =
|
|
117
|
+
const baseUrl = getBaseUrl(config);
|
|
118
|
+
const botToken = config.botToken;
|
|
133
119
|
const url = `${baseUrl}/file/bot${botToken}/${file_path}`;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
120
|
+
let content;
|
|
121
|
+
try {
|
|
122
|
+
content = await fetch(url).then((_) => _.arrayBuffer());
|
|
123
|
+
} catch (cause) {
|
|
124
|
+
throw new TgBotClientError({
|
|
137
125
|
cause: { _tag: "UnableToGetFile", cause }
|
|
138
|
-
})
|
|
139
|
-
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const base64String = () => Buffer.from(content).toString("base64");
|
|
140
129
|
return {
|
|
141
130
|
content,
|
|
142
|
-
file_name
|
|
131
|
+
file_name,
|
|
132
|
+
base64String
|
|
143
133
|
};
|
|
144
|
-
}
|
|
134
|
+
};
|
|
135
|
+
var getFile = async (input, context) => {
|
|
136
|
+
const { content, file_name } = await getFileBytes(input.fileId, context);
|
|
137
|
+
return new File([content], file_name, {
|
|
138
|
+
...input.type ? { type: input.type } : {}
|
|
139
|
+
});
|
|
140
|
+
};
|
|
145
141
|
|
|
146
142
|
// src/client.ts
|
|
147
|
-
import * as Micro3 from "effect/Micro";
|
|
148
|
-
import * as Context3 from "effect/Context";
|
|
149
143
|
function makeTgBotClient(config) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
const execute = (method, input) => executeTgBotMethod(method, input).pipe(
|
|
156
|
-
Micro3.provideContext(context),
|
|
157
|
-
Micro3.runPromise
|
|
158
|
-
);
|
|
159
|
-
const getFile2 = (input) => file.getFile(input).pipe(Micro3.provideContext(context), Micro3.runPromise);
|
|
144
|
+
const tgConfig = {
|
|
145
|
+
botToken: config.bot_token,
|
|
146
|
+
...config.base_url ? { baseUrl: config.base_url } : {}
|
|
147
|
+
};
|
|
148
|
+
const execute = (method, input) => executeTgBotMethod({ config: tgConfig, method, input });
|
|
160
149
|
return {
|
|
161
150
|
execute,
|
|
162
|
-
getFile:
|
|
151
|
+
getFile: (input) => getFile(input, { config: tgConfig, execute })
|
|
163
152
|
};
|
|
164
|
-
}
|
|
153
|
+
}
|
|
165
154
|
export {
|
|
166
|
-
ClientFileService,
|
|
167
155
|
MESSAGE_EFFECTS,
|
|
168
156
|
TG_BOT_API_URL,
|
|
169
|
-
TgBotApiBaseUrl,
|
|
170
|
-
TgBotApiToken,
|
|
171
157
|
TgBotClientError,
|
|
172
158
|
executeTgBotMethod,
|
|
159
|
+
getBaseUrl,
|
|
160
|
+
getFile,
|
|
161
|
+
getFileBytes,
|
|
173
162
|
isFileContent,
|
|
174
163
|
isMessageEffect,
|
|
175
164
|
isTgBotApiResponse,
|
|
176
|
-
isTgBotApiUpdate,
|
|
177
165
|
makePayload,
|
|
178
166
|
makeTgBotClient,
|
|
179
|
-
messageEffectIdCodes
|
|
167
|
+
messageEffectIdCodes,
|
|
168
|
+
snakeToCamel
|
|
180
169
|
};
|
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.2.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Aleksandr Kondaurov",
|
|
@@ -32,9 +32,6 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@effect-ak/tg-bot-api": "0.9.2"
|
|
34
34
|
},
|
|
35
|
-
"peerDependencies": {
|
|
36
|
-
"effect": "^3.12.0"
|
|
37
|
-
},
|
|
38
35
|
"scripts": {
|
|
39
36
|
"build": "tsup"
|
|
40
37
|
}
|
package/src/client-file.ts
CHANGED
|
@@ -1,70 +1,73 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as Context from "effect/Context"
|
|
3
|
-
|
|
1
|
+
import type { Api } from "@effect-ak/tg-bot-api"
|
|
4
2
|
import { TgBotClientError } from "./errors"
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export class ClientFileService extends Context.Tag("ClientFileService")<
|
|
9
|
-
ClientFileService,
|
|
10
|
-
{
|
|
11
|
-
getFile: (input: GetFile) => ReturnType<typeof getFile>
|
|
12
|
-
}
|
|
13
|
-
>() {
|
|
14
|
-
static live = () => {
|
|
15
|
-
return ClientFileService.context({
|
|
16
|
-
getFile
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
}
|
|
3
|
+
import type { TgBotConfig } from "./config"
|
|
4
|
+
import { getBaseUrl } from "./config"
|
|
20
5
|
|
|
21
6
|
export interface GetFile {
|
|
22
7
|
fileId: string
|
|
23
8
|
type?: string
|
|
24
9
|
}
|
|
25
10
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
...(type ? { type } : undefined)
|
|
32
|
-
})
|
|
33
|
-
)
|
|
34
|
-
)
|
|
11
|
+
export interface FileBytes {
|
|
12
|
+
content: ArrayBuffer
|
|
13
|
+
file_name: string
|
|
14
|
+
base64String: () => string
|
|
15
|
+
}
|
|
35
16
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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]>>
|
|
23
|
+
}
|
|
40
24
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
})
|
|
49
|
-
)
|
|
50
|
-
}
|
|
25
|
+
export const getFileBytes = async (
|
|
26
|
+
fileId: string,
|
|
27
|
+
context: FileContext
|
|
28
|
+
): Promise<FileBytes> => {
|
|
29
|
+
const { config, execute } = context
|
|
30
|
+
const response = await execute("get_file", { file_id: fileId })
|
|
31
|
+
const file_path = response.file_path
|
|
51
32
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
33
|
+
if (!file_path || file_path.length === 0) {
|
|
34
|
+
throw new TgBotClientError({
|
|
35
|
+
cause: {
|
|
36
|
+
_tag: "UnableToGetFile",
|
|
37
|
+
cause: "File path not defined"
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
55
41
|
|
|
56
|
-
|
|
42
|
+
const file_name = file_path.replaceAll("/", "-")
|
|
43
|
+
const baseUrl = getBaseUrl(config)
|
|
44
|
+
const botToken = config.botToken
|
|
45
|
+
const url = `${baseUrl}/file/bot${botToken}/${file_path}`
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
47
|
+
let content: ArrayBuffer
|
|
48
|
+
try {
|
|
49
|
+
content = await fetch(url).then((_) => _.arrayBuffer())
|
|
50
|
+
} catch (cause) {
|
|
51
|
+
throw new TgBotClientError({
|
|
52
|
+
cause: { _tag: "UnableToGetFile", cause }
|
|
64
53
|
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const base64String = () => Buffer.from(content).toString("base64")
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
return {
|
|
59
|
+
content,
|
|
60
|
+
file_name,
|
|
61
|
+
base64String
|
|
62
|
+
}
|
|
63
|
+
}
|
|
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 } : {})
|
|
70
72
|
})
|
|
73
|
+
}
|