@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/src/client.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import * as Micro from "effect/Micro"
|
|
2
|
-
import * as Context from "effect/Context"
|
|
3
|
-
|
|
4
1
|
import type { Api } from "@effect-ak/tg-bot-api"
|
|
5
2
|
import { executeTgBotMethod } from "./execute"
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import type { TgBotConfig } from "./config"
|
|
4
|
+
import { getFile as getFileImpl, type GetFile } from "./client-file"
|
|
8
5
|
|
|
9
6
|
export interface TgBotClient {
|
|
10
7
|
readonly execute: <M extends keyof Api>(
|
|
@@ -14,33 +11,24 @@ export interface TgBotClient {
|
|
|
14
11
|
readonly getFile: (input: GetFile) => Promise<File>
|
|
15
12
|
}
|
|
16
13
|
|
|
17
|
-
interface MakeTgClient {
|
|
14
|
+
export interface MakeTgClient {
|
|
18
15
|
bot_token: string
|
|
16
|
+
base_url?: string
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
export function makeTgBotClient(config: MakeTgClient): TgBotClient {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Micro.gen(function* () {
|
|
27
|
-
const file = yield* Micro.service(ClientFileService)
|
|
28
|
-
const context = Context.make(TgBotApiToken, bot_token)
|
|
29
|
-
|
|
30
|
-
const execute = <M extends keyof Api>(
|
|
31
|
-
method: M,
|
|
32
|
-
input: Parameters<Api[M]>[0]
|
|
33
|
-
) =>
|
|
34
|
-
executeTgBotMethod(method, input).pipe(
|
|
35
|
-
Micro.provideContext(context),
|
|
36
|
-
Micro.runPromise
|
|
37
|
-
)
|
|
20
|
+
const tgConfig: TgBotConfig = {
|
|
21
|
+
botToken: config.bot_token,
|
|
22
|
+
...(config.base_url ? { baseUrl: config.base_url } : {})
|
|
23
|
+
}
|
|
38
24
|
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
const execute = <M extends keyof Api>(
|
|
26
|
+
method: M,
|
|
27
|
+
input: Parameters<Api[M]>[0]
|
|
28
|
+
) => executeTgBotMethod({ config: tgConfig, method, input })
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
30
|
+
return {
|
|
31
|
+
execute,
|
|
32
|
+
getFile: (input: GetFile) => getFileImpl(input, { config: tgConfig, execute })
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import * as Context from "effect/Context"
|
|
2
|
-
|
|
3
1
|
import { TG_BOT_API_URL } from "./const"
|
|
4
2
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
export interface TgBotConfig {
|
|
4
|
+
botToken: string
|
|
5
|
+
baseUrl?: string
|
|
6
|
+
}
|
|
9
7
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
>() {}
|
|
8
|
+
export const getBaseUrl = (config?: Pick<TgBotConfig, "baseUrl">): string => {
|
|
9
|
+
return config?.baseUrl ?? TG_BOT_API_URL
|
|
10
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
type ErrorReason =
|
|
2
|
+
| { _tag: "NotOkResponse"; errorCode?: number; details?: string }
|
|
3
|
+
| { _tag: "UnexpectedResponse"; response: unknown }
|
|
4
|
+
| { _tag: "ClientInternalError"; cause: unknown }
|
|
5
|
+
| { _tag: "UnableToGetFile"; cause: unknown }
|
|
6
|
+
| { _tag: "BotHandlerError"; cause: unknown }
|
|
7
|
+
| { _tag: "NotJsonResponse"; response: unknown }
|
|
2
8
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
ClientInternalError: { cause: unknown }
|
|
7
|
-
UnableToGetFile: { cause: unknown }
|
|
8
|
-
BotHandlerError: { cause: unknown }
|
|
9
|
-
NotJsonResponse: { response: unknown }
|
|
10
|
-
}>
|
|
9
|
+
export class TgBotClientError extends Error {
|
|
10
|
+
readonly _tag = "TgBotClientError"
|
|
11
|
+
readonly cause: ErrorReason
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
constructor(options: { cause: ErrorReason }) {
|
|
14
|
+
super(`TgBotClientError: ${options.cause._tag}`)
|
|
15
|
+
this.cause = options.cause
|
|
16
|
+
this.name = "TgBotClientError"
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/execute.ts
CHANGED
|
@@ -1,65 +1,62 @@
|
|
|
1
|
-
import * as String from "effect/String"
|
|
2
|
-
import * as Micro from "effect/Micro"
|
|
3
1
|
import type { Api } from "@effect-ak/tg-bot-api"
|
|
4
2
|
|
|
5
3
|
import { TgBotClientError } from "./errors"
|
|
6
4
|
import { isFileContent, isTgBotApiResponse } from "./guards"
|
|
7
|
-
import {
|
|
5
|
+
import type { TgBotConfig } from "./config"
|
|
6
|
+
import { getBaseUrl } from "./config"
|
|
7
|
+
import { snakeToCamel } from "./utils"
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
|
|
9
|
+
export async function executeTgBotMethod<M extends keyof Api>(params: {
|
|
10
|
+
config: TgBotConfig
|
|
11
|
+
method: M
|
|
11
12
|
input: Parameters<Api[M]>[0]
|
|
12
|
-
):
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
}): Promise<ReturnType<Api[M]>> {
|
|
14
|
+
const { config, method, input } = params
|
|
15
|
+
const baseUrl = getBaseUrl(config)
|
|
16
|
+
const botToken = config.botToken
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
let httpResponse: Response
|
|
19
|
+
try {
|
|
20
|
+
httpResponse = await fetch(
|
|
21
|
+
`${baseUrl}/bot${botToken}/${snakeToCamel(method)}`,
|
|
22
|
+
{
|
|
23
|
+
body: makePayload(input) ?? null,
|
|
24
|
+
method: "POST"
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
} catch (cause) {
|
|
28
|
+
throw new TgBotClientError({
|
|
29
|
+
cause: { _tag: "ClientInternalError", cause }
|
|
27
30
|
})
|
|
31
|
+
}
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
let response: unknown
|
|
34
|
+
try {
|
|
35
|
+
response = await httpResponse.json()
|
|
36
|
+
} catch {
|
|
37
|
+
throw new TgBotClientError({
|
|
38
|
+
cause: { _tag: "NotJsonResponse", response: httpResponse }
|
|
35
39
|
})
|
|
40
|
+
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
}
|
|
42
|
+
if (!isTgBotApiResponse(response)) {
|
|
43
|
+
throw new TgBotClientError({
|
|
44
|
+
cause: { _tag: "UnexpectedResponse", response }
|
|
45
|
+
})
|
|
46
|
+
}
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
? { details: response.description }
|
|
55
|
-
: undefined)
|
|
56
|
-
}
|
|
57
|
-
})
|
|
58
|
-
)
|
|
59
|
-
}
|
|
48
|
+
if (!httpResponse.ok) {
|
|
49
|
+
throw new TgBotClientError({
|
|
50
|
+
cause: {
|
|
51
|
+
_tag: "NotOkResponse",
|
|
52
|
+
...(response.error_code ? { errorCode: response.error_code } : {}),
|
|
53
|
+
...(response.description ? { details: response.description } : {})
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
return response.result as ReturnType<Api[M]>
|
|
59
|
+
}
|
|
63
60
|
|
|
64
61
|
export const makePayload = (body: object): FormData | undefined => {
|
|
65
62
|
const entries = Object.entries(body)
|
package/src/index.ts
CHANGED
package/src/utils.ts
ADDED