@grom.js/effect-tg 0.7.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.
Files changed (99) hide show
  1. package/README.md +162 -5
  2. package/dist/BotApi.d.ts +10 -12
  3. package/dist/BotApi.d.ts.map +1 -1
  4. package/dist/BotApi.js +2 -2
  5. package/dist/BotApi.js.map +1 -1
  6. package/dist/BotApiError.d.ts +46 -71
  7. package/dist/BotApiError.d.ts.map +1 -1
  8. package/dist/BotApiError.js +59 -41
  9. package/dist/BotApiError.js.map +1 -1
  10. package/dist/BotApiTransport.d.ts +10 -17
  11. package/dist/BotApiTransport.d.ts.map +1 -1
  12. package/dist/BotApiTransport.js +2 -7
  13. package/dist/BotApiTransport.js.map +1 -1
  14. package/dist/BotApiUrl.d.ts +6 -8
  15. package/dist/BotApiUrl.d.ts.map +1 -1
  16. package/dist/BotApiUrl.js.map +1 -1
  17. package/dist/Content.d.ts.map +1 -1
  18. package/dist/Dialog.d.ts +96 -41
  19. package/dist/Dialog.d.ts.map +1 -1
  20. package/dist/Dialog.js +60 -25
  21. package/dist/Dialog.js.map +1 -1
  22. package/dist/File.d.ts +1 -2
  23. package/dist/File.d.ts.map +1 -1
  24. package/dist/File.js +1 -1
  25. package/dist/File.js.map +1 -1
  26. package/dist/Markup.d.ts.map +1 -1
  27. package/dist/Runner.d.ts +1 -1
  28. package/dist/Runner.d.ts.map +1 -1
  29. package/dist/Send.d.ts +57 -130
  30. package/dist/Send.d.ts.map +1 -1
  31. package/dist/Send.js +65 -128
  32. package/dist/Send.js.map +1 -1
  33. package/dist/Text.d.ts.map +1 -1
  34. package/dist/internal/botApi.d.ts +3 -1
  35. package/dist/internal/botApi.d.ts.map +1 -1
  36. package/dist/internal/botApi.gen.d.ts +6501 -0
  37. package/dist/internal/botApi.gen.d.ts.map +1 -0
  38. package/dist/internal/botApi.gen.js +2 -0
  39. package/dist/internal/botApi.gen.js.map +1 -0
  40. package/dist/internal/botApi.js +2 -6
  41. package/dist/internal/botApi.js.map +1 -1
  42. package/dist/internal/botApiError.d.ts +5 -2
  43. package/dist/internal/botApiError.d.ts.map +1 -1
  44. package/dist/internal/botApiError.js +8 -18
  45. package/dist/internal/botApiError.js.map +1 -1
  46. package/dist/internal/botApiTransport.d.ts +5 -2
  47. package/dist/internal/botApiTransport.d.ts.map +1 -1
  48. package/dist/internal/botApiTransport.js +14 -10
  49. package/dist/internal/botApiTransport.js.map +1 -1
  50. package/dist/internal/dialog.d.ts +27 -10
  51. package/dist/internal/dialog.d.ts.map +1 -1
  52. package/dist/internal/dialog.js +88 -14
  53. package/dist/internal/dialog.js.map +1 -1
  54. package/dist/internal/file.d.ts +1 -1
  55. package/dist/internal/file.d.ts.map +1 -1
  56. package/dist/internal/file.js +1 -1
  57. package/dist/internal/file.js.map +1 -1
  58. package/dist/internal/runner.d.ts +4 -5
  59. package/dist/internal/runner.d.ts.map +1 -1
  60. package/dist/internal/runner.js +14 -19
  61. package/dist/internal/runner.js.map +1 -1
  62. package/dist/internal/send.d.ts +4 -4
  63. package/dist/internal/send.d.ts.map +1 -1
  64. package/dist/internal/send.js +62 -51
  65. package/dist/internal/send.js.map +1 -1
  66. package/package.json +12 -10
  67. package/src/BotApi.ts +38 -31
  68. package/src/BotApiError.ts +109 -63
  69. package/src/BotApiTransport.ts +18 -20
  70. package/src/BotApiUrl.ts +6 -8
  71. package/src/Content.ts +14 -14
  72. package/src/Dialog.ts +164 -42
  73. package/src/File.ts +3 -4
  74. package/src/Markup.ts +5 -5
  75. package/src/Send.ts +114 -202
  76. package/src/Text.ts +5 -5
  77. package/src/internal/botApi.gen.ts +6783 -0
  78. package/src/internal/botApi.ts +7 -11
  79. package/src/internal/botApiError.ts +15 -20
  80. package/src/internal/botApiTransport.ts +25 -17
  81. package/src/internal/dialog.ts +109 -26
  82. package/src/internal/file.ts +1 -1
  83. package/src/internal/runner.ts +34 -38
  84. package/src/internal/send.ts +161 -132
  85. package/dist/internal/botApiMethods.gen.d.ts +0 -2026
  86. package/dist/internal/botApiMethods.gen.d.ts.map +0 -1
  87. package/dist/internal/botApiMethods.gen.js +0 -2
  88. package/dist/internal/botApiMethods.gen.js.map +0 -1
  89. package/dist/internal/botApiShape.gen.d.ts +0 -398
  90. package/dist/internal/botApiShape.gen.d.ts.map +0 -1
  91. package/dist/internal/botApiShape.gen.js +0 -2
  92. package/dist/internal/botApiShape.gen.js.map +0 -1
  93. package/dist/internal/botApiTypes.gen.d.ts +0 -3903
  94. package/dist/internal/botApiTypes.gen.d.ts.map +0 -1
  95. package/dist/internal/botApiTypes.gen.js +0 -2
  96. package/dist/internal/botApiTypes.gen.js.map +0 -1
  97. package/src/internal/botApiMethods.gen.ts +0 -2027
  98. package/src/internal/botApiShape.gen.ts +0 -398
  99. package/src/internal/botApiTypes.gen.ts +0 -4178
@@ -1,81 +1,127 @@
1
- import type * as Duration from 'effect/Duration'
2
- import type * as BotApi from './BotApi.ts'
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 returned from the Bot API server in case of unsuccessful method call.
26
+ * Error caused by the transport when accessing Bot API.
8
27
  */
9
- export class BotApiError extends Data.TaggedError('@grom.js/effect-tg/BotApiError')<{
10
- code: number
11
- description: string
12
- parameters?: BotApi.Types.ResponseParameters
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 `(${this.code}) ${this.description}`
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
- * Attempts to narrow a {@link BotApiError} to a more specific {@link KnownError}.
21
- *
22
- * **Warning!** Error types are detected based on the error code and message
23
- * returned from the Bot API, which are not guaranteed to be the same in
24
- * the future. If they change, this function may not determine error type
25
- * correctly.
26
- *
27
- * @see {@link https://github.com/tdlib/telegram-bot-api telegram-bot-api source code}
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 type KnownError
32
- = | TooManyRequests
33
- | BotBlockedByUser
34
- | MessageNotModified
35
- | ReplyMarkupTooLong
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
- * Flood limit exceeded. Need to wait `retryAfter` before retrying.
41
- */
42
- export class TooManyRequests extends Data.TaggedError('@grom.js/effect-tg/BotApiError/TooManyRequests')<{
43
- cause: BotApiError
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
- * Bot was blocked by the user.
49
- */
50
- export class BotBlockedByUser extends Data.TaggedError('@grom.js/effect-tg/BotApiError/BotBlockedByUser')<{
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
- * Message was not modified as its content and reply markup
56
- * are exactly the same as the current one.
57
- */
58
- export class MessageNotModified extends Data.TaggedError('@grom.js/effect-tg/BotApiError/MessageNotModified')<{
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
- * Message reply markup is too long.
64
- */
65
- export class ReplyMarkupTooLong extends Data.TaggedError('@grom.js/effect-tg/BotApiError/ReplyMarkupTooLong')<{
66
- cause: BotApiError
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
- * Query has expired, or ID is invalid.
71
- */
72
- export class QueryIdInvalid extends Data.TaggedError('@grom.js/effect-tg/BotApiError/QueryIdInvalid')<{
73
- cause: BotApiError
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 }>
@@ -1,7 +1,7 @@
1
- import type * as Types from './internal/botApiTypes.gen.ts'
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
- BotApiTransport.Service
12
+ Service
13
13
  >() {}
14
14
 
15
- export declare namespace BotApiTransport {
16
- export interface Service {
17
- sendRequest: (
18
- method: string,
19
- params: unknown,
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
- * Error caused by the transport when accessing Bot API.
41
- */
42
- export class BotApiTransportError extends Data.TaggedError('@grom.js/effect-tg/BotApiTransport/BotApiTransportError')<{
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(reqs => internal.make(...reqs)),
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
- BotApiUrl.Service
5
+ Service
6
6
  >() {}
7
7
 
8
- export declare namespace BotApiUrl {
9
- export interface Service {
10
- toMethod: (method: string) => URL
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): BotApiUrl.Service => (
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): BotApiUrl.Service => (
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
- = | 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
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
- export type Dialog
5
- = | UserId
6
- | GroupId
7
- | ChannelId
8
- | SupergroupId
9
- | PublicChannel
10
- | PublicSupergroup
11
- | ForumTopic
12
- | ChannelDm
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 PublicSupergroup extends Data.TaggedClass('PublicSupergroup')<{
43
- username: string
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
- forum: SupergroupId | PublicSupergroup
23
+ supergroup: Supergroup
48
24
  topicId: number
49
25
  }> {}
50
26
 
51
27
  export class ChannelDm extends Data.TaggedClass('ChannelDm')<{
52
- channel: ChannelId | PublicChannel
53
- userId: number
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 get: (fileId: FileId) => Effect.Effect<
30
+ export const download: (fileId: FileId) => Effect.Effect<
32
31
  HttpClientResponse.HttpClientResponse,
33
- BotApiError.BotApiError | BotApiTransport.BotApiTransportError | HttpClientError.HttpClientError,
32
+ BotApiError.BotApiError | HttpClientError.HttpClientError,
34
33
  BotApi.BotApi | BotApiUrl.BotApiUrl | HttpClient.HttpClient
35
- > = internal.get
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
- = | InlineKeyboard
9
- | ReplyKeyboard
10
- | ReplyKeyboardRemove
11
- | ForceReply
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