@grom.js/effect-tg 0.8.0 → 0.9.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 +162 -5
- package/dist/BotApi.d.ts +10 -12
- package/dist/BotApi.d.ts.map +1 -1
- package/dist/BotApi.js +2 -2
- package/dist/BotApi.js.map +1 -1
- package/dist/BotApiError.d.ts +46 -71
- package/dist/BotApiError.d.ts.map +1 -1
- package/dist/BotApiError.js +59 -41
- package/dist/BotApiError.js.map +1 -1
- package/dist/BotApiTransport.d.ts +10 -17
- package/dist/BotApiTransport.d.ts.map +1 -1
- package/dist/BotApiTransport.js +2 -7
- package/dist/BotApiTransport.js.map +1 -1
- package/dist/BotApiUrl.d.ts +6 -8
- package/dist/BotApiUrl.d.ts.map +1 -1
- package/dist/BotApiUrl.js.map +1 -1
- package/dist/Content.d.ts.map +1 -1
- package/dist/Dialog.d.ts +96 -41
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Dialog.js +60 -25
- package/dist/Dialog.js.map +1 -1
- package/dist/File.d.ts +1 -2
- package/dist/File.d.ts.map +1 -1
- package/dist/File.js +1 -1
- package/dist/File.js.map +1 -1
- package/dist/Markup.d.ts.map +1 -1
- package/dist/Runner.d.ts +1 -1
- package/dist/Runner.d.ts.map +1 -1
- package/dist/Send.d.ts +57 -130
- package/dist/Send.d.ts.map +1 -1
- package/dist/Send.js +65 -128
- package/dist/Send.js.map +1 -1
- package/dist/Text.d.ts.map +1 -1
- package/dist/internal/botApi.d.ts +3 -1
- package/dist/internal/botApi.d.ts.map +1 -1
- package/dist/internal/botApi.gen.d.ts +6501 -0
- package/dist/internal/botApi.gen.d.ts.map +1 -0
- package/dist/internal/botApi.gen.js +2 -0
- package/dist/internal/botApi.gen.js.map +1 -0
- package/dist/internal/botApi.js +2 -6
- package/dist/internal/botApi.js.map +1 -1
- package/dist/internal/botApiError.d.ts +5 -2
- package/dist/internal/botApiError.d.ts.map +1 -1
- package/dist/internal/botApiError.js +8 -18
- package/dist/internal/botApiError.js.map +1 -1
- package/dist/internal/botApiTransport.d.ts +5 -2
- package/dist/internal/botApiTransport.d.ts.map +1 -1
- package/dist/internal/botApiTransport.js +14 -10
- package/dist/internal/botApiTransport.js.map +1 -1
- package/dist/internal/dialog.d.ts +27 -10
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +88 -14
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/file.d.ts +1 -1
- package/dist/internal/file.d.ts.map +1 -1
- package/dist/internal/file.js +1 -1
- package/dist/internal/file.js.map +1 -1
- package/dist/internal/runner.d.ts +4 -5
- package/dist/internal/runner.d.ts.map +1 -1
- package/dist/internal/runner.js +14 -19
- package/dist/internal/runner.js.map +1 -1
- package/dist/internal/send.d.ts +4 -4
- package/dist/internal/send.d.ts.map +1 -1
- package/dist/internal/send.js +62 -51
- package/dist/internal/send.js.map +1 -1
- package/package.json +11 -9
- package/src/BotApi.ts +38 -31
- package/src/BotApiError.ts +109 -63
- package/src/BotApiTransport.ts +18 -20
- package/src/BotApiUrl.ts +6 -8
- package/src/Content.ts +14 -14
- package/src/Dialog.ts +164 -42
- package/src/File.ts +3 -4
- package/src/Markup.ts +5 -5
- package/src/Send.ts +114 -202
- package/src/Text.ts +5 -5
- package/src/internal/botApi.gen.ts +6783 -0
- package/src/internal/botApi.ts +7 -11
- package/src/internal/botApiError.ts +15 -20
- package/src/internal/botApiTransport.ts +25 -17
- package/src/internal/dialog.ts +109 -26
- package/src/internal/file.ts +1 -1
- package/src/internal/runner.ts +34 -38
- package/src/internal/send.ts +161 -132
- package/dist/internal/botApiMethods.gen.d.ts +0 -2110
- package/dist/internal/botApiMethods.gen.d.ts.map +0 -1
- package/dist/internal/botApiMethods.gen.js +0 -2
- package/dist/internal/botApiMethods.gen.js.map +0 -1
- package/dist/internal/botApiShape.gen.d.ts +0 -406
- package/dist/internal/botApiShape.gen.d.ts.map +0 -1
- package/dist/internal/botApiShape.gen.js +0 -2
- package/dist/internal/botApiShape.gen.js.map +0 -1
- package/dist/internal/botApiTypes.gen.d.ts +0 -3986
- package/dist/internal/botApiTypes.gen.d.ts.map +0 -1
- package/dist/internal/botApiTypes.gen.js +0 -2
- package/dist/internal/botApiTypes.gen.js.map +0 -1
- package/src/internal/botApiMethods.gen.ts +0 -2111
- package/src/internal/botApiShape.gen.ts +0 -406
- package/src/internal/botApiTypes.gen.ts +0 -4264
package/src/BotApiError.ts
CHANGED
|
@@ -1,81 +1,127 @@
|
|
|
1
|
-
import type * as
|
|
2
|
-
import type * as
|
|
1
|
+
import type * as HttpBody from '@effect/platform/HttpBody'
|
|
2
|
+
import type * as HttpClientError from '@effect/platform/HttpClientError'
|
|
3
|
+
import type * as BotApiTransport from './BotApiTransport.ts'
|
|
3
4
|
import * as Data from 'effect/Data'
|
|
5
|
+
import * as Duration from 'effect/Duration'
|
|
6
|
+
import * as Match from 'effect/Match'
|
|
7
|
+
import * as Option from 'effect/Option'
|
|
8
|
+
import * as Predicate from 'effect/Predicate'
|
|
9
|
+
import * as Dialog from './Dialog.ts'
|
|
4
10
|
import * as internal from './internal/botApiError.ts'
|
|
5
11
|
|
|
12
|
+
export const TypeId = '@grom.js/effect-tg/BotApiError'
|
|
13
|
+
|
|
14
|
+
export type TypeId = typeof TypeId
|
|
15
|
+
|
|
16
|
+
export const isBotApiError = (u: unknown): u is BotApiError => Predicate.hasProperty(u, TypeId)
|
|
17
|
+
|
|
18
|
+
export type BotApiError =
|
|
19
|
+
| TransportError
|
|
20
|
+
| MethodFailed
|
|
21
|
+
| GroupUpgraded
|
|
22
|
+
| RateLimited
|
|
23
|
+
| InternalServerError
|
|
24
|
+
|
|
6
25
|
/**
|
|
7
|
-
* Error
|
|
26
|
+
* Error caused by the transport when accessing Bot API.
|
|
8
27
|
*/
|
|
9
|
-
export class
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
28
|
+
export class TransportError extends Data.TaggedError('TransportError')<{
|
|
29
|
+
cause:
|
|
30
|
+
| HttpClientError.HttpClientError
|
|
31
|
+
| HttpBody.HttpBodyError
|
|
13
32
|
}> {
|
|
33
|
+
readonly [TypeId]: TypeId = TypeId
|
|
34
|
+
|
|
14
35
|
override get message() {
|
|
15
|
-
return
|
|
36
|
+
return Match.value(this.cause).pipe(
|
|
37
|
+
Match.tagsExhaustive({
|
|
38
|
+
RequestError: e => e.message,
|
|
39
|
+
ResponseError: e => e.message,
|
|
40
|
+
HttpBodyError: e => Match.value(e.reason).pipe(
|
|
41
|
+
Match.tagsExhaustive({
|
|
42
|
+
SchemaError: e => e.error.message,
|
|
43
|
+
JsonError: e => `JsonError: ${e.error}`,
|
|
44
|
+
}),
|
|
45
|
+
),
|
|
46
|
+
}),
|
|
47
|
+
)
|
|
16
48
|
}
|
|
17
49
|
}
|
|
18
50
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export const narrow: (error: BotApiError) => KnownError | BotApiError = internal.narrow
|
|
51
|
+
export class MethodFailed extends Data.TaggedError('MethodFailed')<{
|
|
52
|
+
response: FailureResponse
|
|
53
|
+
possibleReason: MethodFailureReason
|
|
54
|
+
}> {
|
|
55
|
+
readonly [TypeId]: TypeId = TypeId
|
|
56
|
+
|
|
57
|
+
override get message() {
|
|
58
|
+
return `(${this.response.error_code}) ${this.response.description}`
|
|
59
|
+
}
|
|
60
|
+
}
|
|
30
61
|
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
| QueryIdInvalid
|
|
37
|
-
| MediaGroupedInvalid
|
|
62
|
+
export class GroupUpgraded extends Data.TaggedError('GroupUpgraded')<{
|
|
63
|
+
response: FailureResponse
|
|
64
|
+
supergroup: Dialog.Supergroup
|
|
65
|
+
}> {
|
|
66
|
+
readonly [TypeId]: TypeId = TypeId
|
|
38
67
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
68
|
+
override get message() {
|
|
69
|
+
return `Group has been upgraded to a supergroup with ID ${this.supergroup.id}.`
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class RateLimited extends Data.TaggedError('RateLimited')<{
|
|
74
|
+
response: FailureResponse
|
|
44
75
|
retryAfter: Duration.Duration
|
|
45
|
-
}> {
|
|
76
|
+
}> {
|
|
77
|
+
readonly [TypeId]: TypeId = TypeId
|
|
46
78
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
cause: BotApiError
|
|
52
|
-
}> {}
|
|
79
|
+
override get message() {
|
|
80
|
+
return `Flood limit exceeded. Should wait for ${Duration.format(this.retryAfter)} before retrying.`
|
|
81
|
+
}
|
|
82
|
+
}
|
|
53
83
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
cause: BotApiError
|
|
60
|
-
}> {}
|
|
84
|
+
export class InternalServerError extends Data.TaggedError('InternalServerError')<{
|
|
85
|
+
response: FailureResponse
|
|
86
|
+
}> {
|
|
87
|
+
readonly [TypeId]: TypeId = TypeId
|
|
88
|
+
}
|
|
61
89
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
90
|
+
export const fromResponse = (response: FailureResponse): BotApiError => {
|
|
91
|
+
if (response.error_code === 429 && response.parameters?.retry_after != null) {
|
|
92
|
+
return new RateLimited({
|
|
93
|
+
response,
|
|
94
|
+
retryAfter: Duration.seconds(response.parameters.retry_after),
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
if (response.error_code === 400 && response.parameters?.migrate_to_chat_id != null) {
|
|
98
|
+
return new GroupUpgraded({
|
|
99
|
+
response,
|
|
100
|
+
supergroup: Dialog.supergroup(
|
|
101
|
+
Option.getOrThrow(
|
|
102
|
+
Dialog.decodePeerId('supergroup', response.parameters.migrate_to_chat_id),
|
|
103
|
+
),
|
|
104
|
+
),
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
if (response.error_code >= 500) {
|
|
108
|
+
return new InternalServerError({ response })
|
|
109
|
+
}
|
|
110
|
+
return new MethodFailed({
|
|
111
|
+
response,
|
|
112
|
+
possibleReason: internal.guessReason({
|
|
113
|
+
code: response.error_code,
|
|
114
|
+
description: response.description,
|
|
115
|
+
}),
|
|
116
|
+
})
|
|
117
|
+
}
|
|
68
118
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
119
|
+
export type MethodFailureReason =
|
|
120
|
+
| 'Unknown'
|
|
121
|
+
| 'BotBlockedByUser'
|
|
122
|
+
| 'MessageNotModified'
|
|
123
|
+
| 'ReplyMarkupTooLong'
|
|
124
|
+
| 'QueryIdInvalid'
|
|
125
|
+
| 'MediaGroupedInvalid'
|
|
75
126
|
|
|
76
|
-
|
|
77
|
-
* Invalid combination of media types in the media group.
|
|
78
|
-
*/
|
|
79
|
-
export class MediaGroupedInvalid extends Data.TaggedError('@grom.js/effect-tg/BotApiError/MediaGroupedInvalid')<{
|
|
80
|
-
cause: BotApiError
|
|
81
|
-
}> {}
|
|
127
|
+
type FailureResponse = Extract<BotApiTransport.BotApiResponse, { ok: false }>
|
package/src/BotApiTransport.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type * as
|
|
1
|
+
import type * as BotApi from './BotApi.ts'
|
|
2
|
+
import type * as BotApiError from './BotApiError.ts'
|
|
2
3
|
import * as HttpClient from '@effect/platform/HttpClient'
|
|
3
4
|
import * as Context from 'effect/Context'
|
|
4
|
-
import * as Data from 'effect/Data'
|
|
5
5
|
import * as Effect from 'effect/Effect'
|
|
6
6
|
import * as Layer from 'effect/Layer'
|
|
7
7
|
import * as BotApiUrl from './BotApiUrl.ts'
|
|
@@ -9,23 +9,21 @@ import * as internal from './internal/botApiTransport.ts'
|
|
|
9
9
|
|
|
10
10
|
export class BotApiTransport extends Context.Tag('@grom.js/effect-tg/BotApiTransport')<
|
|
11
11
|
BotApiTransport,
|
|
12
|
-
|
|
12
|
+
Service
|
|
13
13
|
>() {}
|
|
14
14
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
) => Effect.Effect<BotApiResponse, BotApiTransportError>
|
|
21
|
-
}
|
|
15
|
+
export interface Service {
|
|
16
|
+
sendRequest: (
|
|
17
|
+
method: string,
|
|
18
|
+
params: unknown,
|
|
19
|
+
) => Effect.Effect<BotApiResponse, BotApiError.TransportError>
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
/**
|
|
25
23
|
* @see https://core.telegram.org/bots/api#making-requests
|
|
26
24
|
*/
|
|
27
|
-
export type BotApiResponse
|
|
28
|
-
|
|
25
|
+
export type BotApiResponse =
|
|
26
|
+
| {
|
|
29
27
|
ok: true
|
|
30
28
|
result: unknown
|
|
31
29
|
description?: string
|
|
@@ -33,15 +31,13 @@ export type BotApiResponse
|
|
|
33
31
|
ok: false
|
|
34
32
|
error_code: number
|
|
35
33
|
description: string
|
|
36
|
-
parameters?: Types.ResponseParameters
|
|
34
|
+
parameters?: BotApi.Types.ResponseParameters
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
cause: unknown
|
|
44
|
-
}> {}
|
|
37
|
+
export const make: (options: {
|
|
38
|
+
httpClient: HttpClient.HttpClient
|
|
39
|
+
botApiUrl: BotApiUrl.Service
|
|
40
|
+
}) => Service = internal.make
|
|
45
41
|
|
|
46
42
|
export const layer: Layer.Layer<
|
|
47
43
|
BotApiTransport,
|
|
@@ -50,6 +46,8 @@ export const layer: Layer.Layer<
|
|
|
50
46
|
> = Layer.effect(
|
|
51
47
|
BotApiTransport,
|
|
52
48
|
Effect.all([HttpClient.HttpClient, BotApiUrl.BotApiUrl]).pipe(
|
|
53
|
-
Effect.andThen(
|
|
49
|
+
Effect.andThen(([httpClient, botApiUrl]) => (
|
|
50
|
+
internal.make({ httpClient, botApiUrl })),
|
|
51
|
+
),
|
|
54
52
|
),
|
|
55
53
|
)
|
package/src/BotApiUrl.ts
CHANGED
|
@@ -2,24 +2,22 @@ import * as Context from 'effect/Context'
|
|
|
2
2
|
|
|
3
3
|
export class BotApiUrl extends Context.Tag('@grom.js/effect-tg/BotApiUrl')<
|
|
4
4
|
BotApiUrl,
|
|
5
|
-
|
|
5
|
+
Service
|
|
6
6
|
>() {}
|
|
7
7
|
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
toFile: (filePath: string) => URL
|
|
12
|
-
}
|
|
8
|
+
export interface Service {
|
|
9
|
+
toMethod: (method: string) => URL
|
|
10
|
+
toFile: (filePath: string) => URL
|
|
13
11
|
}
|
|
14
12
|
|
|
15
|
-
export const makeProd = (token: string):
|
|
13
|
+
export const makeProd = (token: string): Service => (
|
|
16
14
|
{
|
|
17
15
|
toMethod: (method: string) => new URL(`https://api.telegram.org/bot${token}/${method}`),
|
|
18
16
|
toFile: (filePath: string) => new URL(`https://api.telegram.org/file/bot${token}/${filePath}`),
|
|
19
17
|
}
|
|
20
18
|
)
|
|
21
19
|
|
|
22
|
-
export const makeTest = (token: string):
|
|
20
|
+
export const makeTest = (token: string): Service => (
|
|
23
21
|
{
|
|
24
22
|
toMethod: (method: string) => new URL(`https://api.telegram.org/bot${token}/test/${method}`),
|
|
25
23
|
// TODO: make sure this works in test environment
|
package/src/Content.ts
CHANGED
|
@@ -12,20 +12,20 @@ import * as Option from 'effect/Option'
|
|
|
12
12
|
* @todo Invoices (fiat & stars)
|
|
13
13
|
* @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_input_message_content.html TDLib • td_api.InputMessageContent}
|
|
14
14
|
*/
|
|
15
|
-
export type Content
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
export type Content =
|
|
16
|
+
| Text
|
|
17
|
+
| Photo
|
|
18
|
+
| Audio
|
|
19
|
+
| Document
|
|
20
|
+
| Video
|
|
21
|
+
| Animation
|
|
22
|
+
| Voice
|
|
23
|
+
| VideoNote
|
|
24
|
+
| Location
|
|
25
|
+
| Venue
|
|
26
|
+
| Contact
|
|
27
|
+
| Dice
|
|
28
|
+
| Sticker
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Content of a text message.
|
package/src/Dialog.ts
CHANGED
|
@@ -1,54 +1,176 @@
|
|
|
1
|
+
import type * as BotApi from './BotApi.ts'
|
|
2
|
+
import * as Brand from 'effect/Brand'
|
|
1
3
|
import * as Data from 'effect/Data'
|
|
4
|
+
import * as Option from 'effect/Option'
|
|
2
5
|
import * as internal from './internal/dialog.ts'
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export class UserId extends internal.PeerId({
|
|
15
|
-
tag: 'UserId',
|
|
16
|
-
isValid: id => (id >= 1 && id <= 0xFFFFFFFFFF),
|
|
17
|
-
toDialogId: id => id,
|
|
18
|
-
}) {}
|
|
19
|
-
|
|
20
|
-
export class GroupId extends internal.PeerId({
|
|
21
|
-
tag: 'GroupId',
|
|
22
|
-
isValid: id => (id >= 1 && id <= 999999999999),
|
|
23
|
-
toDialogId: id => -id,
|
|
24
|
-
}) {}
|
|
25
|
-
|
|
26
|
-
export class ChannelId extends internal.PeerId({
|
|
27
|
-
tag: 'ChannelId',
|
|
28
|
-
isValid: id => (id >= 1 && id <= 997852516352),
|
|
29
|
-
toDialogId: id => -(1000000000000 + id),
|
|
30
|
-
}) {}
|
|
31
|
-
|
|
32
|
-
export class SupergroupId extends internal.PeerId({
|
|
33
|
-
tag: 'SupergroupId',
|
|
34
|
-
isValid: id => (id >= 1 && id <= 997852516352),
|
|
35
|
-
toDialogId: id => -(1000000000000 + id),
|
|
36
|
-
}) {}
|
|
37
|
-
|
|
38
|
-
export class PublicChannel extends Data.TaggedClass('PublicChannel')<{
|
|
39
|
-
username: string
|
|
40
|
-
}> {}
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// Dialog
|
|
9
|
+
// =============================================================================
|
|
10
|
+
|
|
11
|
+
export type Dialog =
|
|
12
|
+
| Peer
|
|
13
|
+
| PrivateTopic
|
|
14
|
+
| ForumTopic
|
|
15
|
+
| ChannelDm
|
|
41
16
|
|
|
42
|
-
export class
|
|
43
|
-
|
|
17
|
+
export class PrivateTopic extends Data.TaggedClass('PrivateTopic')<{
|
|
18
|
+
user: User
|
|
19
|
+
topicId: number
|
|
44
20
|
}> {}
|
|
45
21
|
|
|
46
22
|
export class ForumTopic extends Data.TaggedClass('ForumTopic')<{
|
|
47
|
-
|
|
23
|
+
supergroup: Supergroup
|
|
48
24
|
topicId: number
|
|
49
25
|
}> {}
|
|
50
26
|
|
|
51
27
|
export class ChannelDm extends Data.TaggedClass('ChannelDm')<{
|
|
52
|
-
channel:
|
|
53
|
-
|
|
28
|
+
channel: Channel
|
|
29
|
+
topicId: number
|
|
54
30
|
}> {}
|
|
31
|
+
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// Peer
|
|
34
|
+
// =============================================================================
|
|
35
|
+
|
|
36
|
+
export type Peer =
|
|
37
|
+
| User
|
|
38
|
+
| Group
|
|
39
|
+
| Supergroup
|
|
40
|
+
| Channel
|
|
41
|
+
|
|
42
|
+
export class User extends Data.TaggedClass('User')<{
|
|
43
|
+
id: UserId
|
|
44
|
+
}> {
|
|
45
|
+
public dialogId(): DialogId {
|
|
46
|
+
return Option.getOrThrow(internal.encodePeerId('user', this.id))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public topic(topicId: number): PrivateTopic {
|
|
50
|
+
return new PrivateTopic({ user: this, topicId })
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class Group extends Data.TaggedClass('Group')<{
|
|
55
|
+
id: GroupId
|
|
56
|
+
}> {
|
|
57
|
+
public dialogId(): DialogId {
|
|
58
|
+
return Option.getOrThrow(internal.encodePeerId('group', this.id))
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class Supergroup extends Data.TaggedClass('Supergroup')<{
|
|
63
|
+
id: SupergroupId
|
|
64
|
+
}> {
|
|
65
|
+
public dialogId(): DialogId {
|
|
66
|
+
return Option.getOrThrow(internal.encodePeerId('supergroup', this.id))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public topic(topicId: number): ForumTopic {
|
|
70
|
+
return new ForumTopic({ supergroup: this, topicId })
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class Channel extends Data.TaggedClass('Channel')<{
|
|
75
|
+
id: ChannelId
|
|
76
|
+
}> {
|
|
77
|
+
public dialogId(): DialogId {
|
|
78
|
+
return Option.getOrThrow(internal.encodePeerId('supergroup', this.id))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public directMessages(topicId: number): ChannelDm {
|
|
82
|
+
return new ChannelDm({ channel: this, topicId })
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// =============================================================================
|
|
87
|
+
// Brands
|
|
88
|
+
// =============================================================================
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Dialog ID is a single integer encoding peer type and its ID.
|
|
92
|
+
*
|
|
93
|
+
* @see {@link https://core.telegram.org/api/bots/ids Telegram API • Bot API dialog IDs}
|
|
94
|
+
*/
|
|
95
|
+
export type DialogId = number & Brand.Brand<'@grom.js/effect-tg/DialogId'>
|
|
96
|
+
export const DialogId = Brand.refined<DialogId>(
|
|
97
|
+
n => Option.isSome(internal.decodeDialogId(n)),
|
|
98
|
+
n => Brand.error(`Invalid dialog ID: ${n}`),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
export type UserId = number & Brand.Brand<'@grom.js/effect-tg/UserId'>
|
|
102
|
+
export const UserId = Brand.refined<UserId>(
|
|
103
|
+
n => Option.isSome(internal.encodePeerId('user', n)),
|
|
104
|
+
n => Brand.error(`Invalid user ID: ${n}`),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
export type GroupId = number & Brand.Brand<'@grom.js/effect-tg/GroupId'>
|
|
108
|
+
export const GroupId = Brand.refined<GroupId>(
|
|
109
|
+
n => Option.isSome(internal.encodePeerId('group', n)),
|
|
110
|
+
n => Brand.error(`Invalid group ID: ${n}`),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
export type SupergroupId = number & Brand.Brand<'@grom.js/effect-tg/SupergroupId'>
|
|
114
|
+
export const SupergroupId = Brand.refined<SupergroupId>(
|
|
115
|
+
n => Option.isSome(internal.encodePeerId('supergroup', n)),
|
|
116
|
+
n => Brand.error(`Invalid supergroup or channel ID: ${n}`),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @alias SupergroupId
|
|
121
|
+
*/
|
|
122
|
+
export type ChannelId = SupergroupId
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @alias SupergroupId
|
|
126
|
+
*/
|
|
127
|
+
export const ChannelId = SupergroupId
|
|
128
|
+
|
|
129
|
+
// =============================================================================
|
|
130
|
+
// Dialog ID <-> Peer ID
|
|
131
|
+
// =============================================================================
|
|
132
|
+
|
|
133
|
+
export const decodeDialogId: (dialogId: number) => Option.Option<
|
|
134
|
+
| { peer: 'user', id: UserId }
|
|
135
|
+
| { peer: 'group', id: GroupId }
|
|
136
|
+
| { peer: 'supergroup', id: SupergroupId }
|
|
137
|
+
| { peer: 'monoforum', id: number }
|
|
138
|
+
| { peer: 'secret-chat', id: number }
|
|
139
|
+
> = internal.decodeDialogId
|
|
140
|
+
|
|
141
|
+
export const decodePeerId: {
|
|
142
|
+
(peer: 'user', dialogId: number): Option.Option<UserId>
|
|
143
|
+
(peer: 'group', dialogId: number): Option.Option<GroupId>
|
|
144
|
+
(peer: 'supergroup', dialogId: number): Option.Option<SupergroupId>
|
|
145
|
+
(peer: 'monoforum', dialogId: number): Option.Option<number>
|
|
146
|
+
(peer: 'secret-chat', dialogId: number): Option.Option<number>
|
|
147
|
+
} = internal.decodePeerId
|
|
148
|
+
|
|
149
|
+
export const encodePeerId: (
|
|
150
|
+
peer: 'user' | 'group' | 'supergroup' | 'monoforum' | 'secret-chat',
|
|
151
|
+
id: number,
|
|
152
|
+
) => Option.Option<DialogId> = internal.encodePeerId
|
|
153
|
+
|
|
154
|
+
// =============================================================================
|
|
155
|
+
// Constructors
|
|
156
|
+
// =============================================================================
|
|
157
|
+
|
|
158
|
+
export const user: (id: number) => User = (id) => {
|
|
159
|
+
return new User({ id: UserId(id) })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const group: (id: number) => Group = (id) => {
|
|
163
|
+
return new Group({ id: GroupId(id) })
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export const supergroup: (id: number) => Supergroup = (id) => {
|
|
167
|
+
return new Supergroup({ id: SupergroupId(id) })
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export const channel: (id: number) => Channel = (id) => {
|
|
171
|
+
return new Channel({ id: SupergroupId(id) })
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export const ofMessage: (
|
|
175
|
+
message: BotApi.Types.Message,
|
|
176
|
+
) => Dialog = internal.ofMessage
|
package/src/File.ts
CHANGED
|
@@ -5,7 +5,6 @@ import type * as Effect from 'effect/Effect'
|
|
|
5
5
|
import type * as Stream from 'effect/Stream'
|
|
6
6
|
import type * as BotApi from './BotApi.ts'
|
|
7
7
|
import type * as BotApiError from './BotApiError.ts'
|
|
8
|
-
import type * as BotApiTransport from './BotApiTransport.ts'
|
|
9
8
|
import type * as BotApiUrl from './BotApiUrl.ts'
|
|
10
9
|
import * as Brand from 'effect/Brand'
|
|
11
10
|
import * as Data from 'effect/Data'
|
|
@@ -28,8 +27,8 @@ export class InputFile extends Data.TaggedClass('InputFile')<{
|
|
|
28
27
|
*
|
|
29
28
|
* @see {@link https://core.telegram.org/bots/api#getfile Bot API • getFile}
|
|
30
29
|
*/
|
|
31
|
-
export const
|
|
30
|
+
export const download: (fileId: FileId) => Effect.Effect<
|
|
32
31
|
HttpClientResponse.HttpClientResponse,
|
|
33
|
-
BotApiError.BotApiError |
|
|
32
|
+
BotApiError.BotApiError | HttpClientError.HttpClientError,
|
|
34
33
|
BotApi.BotApi | BotApiUrl.BotApiUrl | HttpClient.HttpClient
|
|
35
|
-
> = internal.
|
|
34
|
+
> = internal.download
|
package/src/Markup.ts
CHANGED
|
@@ -4,11 +4,11 @@ import * as Data from 'effect/Data'
|
|
|
4
4
|
/**
|
|
5
5
|
* Reply markup for the message.
|
|
6
6
|
*/
|
|
7
|
-
export type Markup
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
export type Markup =
|
|
8
|
+
| InlineKeyboard
|
|
9
|
+
| ReplyKeyboard
|
|
10
|
+
| ReplyKeyboardRemove
|
|
11
|
+
| ForceReply
|
|
12
12
|
|
|
13
13
|
export class InlineKeyboard extends Data.TaggedClass('InlineKeyboard')<{
|
|
14
14
|
rows: [] // TODO
|