@grom.js/effect-tg 0.12.0 → 0.14.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 (88) hide show
  1. package/README.md +13 -14
  2. package/dist/Bot.d.ts +2 -3
  3. package/dist/Bot.d.ts.map +1 -1
  4. package/dist/Bot.js +1 -2
  5. package/dist/Bot.js.map +1 -1
  6. package/dist/BotApi.d.ts +6 -6
  7. package/dist/BotApi.d.ts.map +1 -1
  8. package/dist/BotApi.js +1 -2
  9. package/dist/BotApi.js.map +1 -1
  10. package/dist/BotApiError.d.ts +15 -19
  11. package/dist/BotApiError.d.ts.map +1 -1
  12. package/dist/BotApiError.js +10 -12
  13. package/dist/BotApiError.js.map +1 -1
  14. package/dist/BotApiTransport.d.ts +5 -8
  15. package/dist/BotApiTransport.d.ts.map +1 -1
  16. package/dist/BotApiTransport.js +1 -2
  17. package/dist/BotApiTransport.js.map +1 -1
  18. package/dist/BotApiUrl.d.ts +6 -9
  19. package/dist/BotApiUrl.d.ts.map +1 -1
  20. package/dist/BotApiUrl.js +1 -2
  21. package/dist/BotApiUrl.js.map +1 -1
  22. package/dist/Content.d.ts +89 -155
  23. package/dist/Content.d.ts.map +1 -1
  24. package/dist/Content.js +26 -119
  25. package/dist/Content.js.map +1 -1
  26. package/dist/Dialog.d.ts +28 -58
  27. package/dist/Dialog.d.ts.map +1 -1
  28. package/dist/Dialog.js +29 -48
  29. package/dist/Dialog.js.map +1 -1
  30. package/dist/File.d.ts +11 -6
  31. package/dist/File.d.ts.map +1 -1
  32. package/dist/File.js +19 -3
  33. package/dist/File.js.map +1 -1
  34. package/dist/Markup.d.ts +8 -21
  35. package/dist/Markup.d.ts.map +1 -1
  36. package/dist/Markup.js +12 -13
  37. package/dist/Markup.js.map +1 -1
  38. package/dist/Runner.d.ts +3 -1
  39. package/dist/Runner.d.ts.map +1 -1
  40. package/dist/Runner.js.map +1 -1
  41. package/dist/Send.d.ts +14 -14
  42. package/dist/Send.d.ts.map +1 -1
  43. package/dist/Send.js +6 -13
  44. package/dist/Send.js.map +1 -1
  45. package/dist/Text.d.ts +13 -26
  46. package/dist/Text.d.ts.map +1 -1
  47. package/dist/Text.js +4 -13
  48. package/dist/Text.js.map +1 -1
  49. package/dist/internal/botApi.d.ts +3 -3
  50. package/dist/internal/botApi.d.ts.map +1 -1
  51. package/dist/internal/botApi.gen.d.ts +39 -8
  52. package/dist/internal/botApi.gen.d.ts.map +1 -1
  53. package/dist/internal/botApi.js +2 -1
  54. package/dist/internal/botApi.js.map +1 -1
  55. package/dist/internal/botApiTransport.d.ts +2 -2
  56. package/dist/internal/botApiTransport.d.ts.map +1 -1
  57. package/dist/internal/botApiTransport.js +3 -4
  58. package/dist/internal/botApiTransport.js.map +1 -1
  59. package/dist/internal/dialog.d.ts.map +1 -1
  60. package/dist/internal/dialog.js +8 -16
  61. package/dist/internal/dialog.js.map +1 -1
  62. package/dist/internal/file.d.ts +5 -2
  63. package/dist/internal/file.d.ts.map +1 -1
  64. package/dist/internal/file.js +3 -0
  65. package/dist/internal/file.js.map +1 -1
  66. package/dist/internal/send.d.ts +6 -4
  67. package/dist/internal/send.d.ts.map +1 -1
  68. package/dist/internal/send.js +18 -17
  69. package/dist/internal/send.js.map +1 -1
  70. package/package.json +11 -11
  71. package/src/Bot.ts +3 -4
  72. package/src/BotApi.ts +7 -8
  73. package/src/BotApiError.ts +19 -25
  74. package/src/BotApiTransport.ts +6 -9
  75. package/src/BotApiUrl.ts +7 -10
  76. package/src/Content.ts +128 -130
  77. package/src/Dialog.ts +79 -73
  78. package/src/File.ts +36 -5
  79. package/src/Markup.ts +37 -27
  80. package/src/Runner.ts +5 -1
  81. package/src/Send.ts +27 -26
  82. package/src/Text.ts +21 -18
  83. package/src/internal/botApi.gen.ts +39 -8
  84. package/src/internal/botApi.ts +5 -6
  85. package/src/internal/botApiTransport.ts +5 -6
  86. package/src/internal/dialog.ts +8 -16
  87. package/src/internal/file.ts +5 -2
  88. package/src/internal/send.ts +23 -23
package/src/BotApiUrl.ts CHANGED
@@ -1,23 +1,20 @@
1
1
  import * as Context from 'effect/Context'
2
2
 
3
- export class BotApiUrl extends Context.Tag('@grom.js/effect-tg/BotApiUrl')<
4
- BotApiUrl,
5
- Service
6
- >() {}
7
-
8
- export interface Service {
9
- toMethod: (method: string) => URL
10
- toFile: (filePath: string) => URL
3
+ export interface BotApiUrl {
4
+ readonly toMethod: (method: string) => URL
5
+ readonly toFile: (filePath: string) => URL
11
6
  }
12
7
 
13
- export const makeProd = (token: string): Service => (
8
+ export const BotApiUrl: Context.Tag<BotApiUrl, BotApiUrl> = Context.GenericTag<BotApiUrl>('@grom.js/effect-tg/BotApiUrl')
9
+
10
+ export const makeProd = (token: string): BotApiUrl => (
14
11
  {
15
12
  toMethod: (method: string) => new URL(`https://api.telegram.org/bot${token}/${method}`),
16
13
  toFile: (filePath: string) => new URL(`https://api.telegram.org/file/bot${token}/${filePath}`),
17
14
  }
18
15
  )
19
16
 
20
- export const makeTest = (token: string): Service => (
17
+ export const makeTest = (token: string): BotApiUrl => (
21
18
  {
22
19
  toMethod: (method: string) => new URL(`https://api.telegram.org/bot${token}/test/${method}`),
23
20
  // TODO: make sure this works in test environment
package/src/Content.ts CHANGED
@@ -2,7 +2,6 @@ import type * as Duration from 'effect/Duration'
2
2
  import type * as File from './File.ts'
3
3
  import type * as LinkPreview from './LinkPreview.ts'
4
4
  import type * as Text_ from './Text.ts'
5
- import * as Data from 'effect/Data'
6
5
  import * as Option from 'effect/Option'
7
6
 
8
7
  /**
@@ -28,184 +27,171 @@ export type Content =
28
27
  | Sticker
29
28
 
30
29
  /**
31
- * Content of a text message.
32
- *
33
30
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_text.html TDLib • td_api.inputMessageText}
34
31
  * @see {@link https://core.telegram.org/bots/api#sendmessage Bot API • sendMessage}
35
32
  */
36
- export class Text extends Data.TaggedClass('Text')<{
37
- text: Text_.Text
38
- linkPreview: Option.Option<LinkPreview.LinkPreview>
39
- }> {}
33
+ export interface Text {
34
+ readonly _tag: 'Text'
35
+ readonly text: Text_.Text
36
+ readonly linkPreview: Option.Option<LinkPreview.LinkPreview>
37
+ }
40
38
 
41
39
  /**
42
- * Content of a photo message.
43
- *
44
40
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_photo.html TDLib • td_api.inputMessagePhoto}
45
41
  * @see {@link https://core.telegram.org/bots/api#sendphoto Bot API • sendPhoto}
46
42
  */
47
- export class Photo extends Data.TaggedClass('Photo')<{
48
- file: File.FileId | File.External | File.InputFile
49
- caption: Option.Option<Text_.Text>
50
- layout: 'caption-above' | 'caption-below'
51
- spoiler: boolean
52
- }> {}
43
+ export interface Photo {
44
+ readonly _tag: 'Photo'
45
+ readonly file: File.FileId | File.External | File.InputFile
46
+ readonly caption: Option.Option<Text_.Text>
47
+ readonly layout: 'caption-above' | 'caption-below'
48
+ readonly spoiler: boolean
49
+ }
53
50
 
54
51
  /**
55
- * Content of an audio message.
56
- *
57
52
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_audio.html TDLib • td_api.inputMessageAudio}
58
53
  * @see {@link https://core.telegram.org/bots/api#sendaudio Bot API • sendAudio}
59
54
  */
60
- export class Audio extends Data.TaggedClass('Audio')<{
61
- file: File.FileId | File.External | File.InputFile
62
- caption: Option.Option<Text_.Text>
63
- duration: Option.Option<Duration.Duration>
64
- performer: Option.Option<string>
65
- title: Option.Option<string>
66
- thumbnail: Option.Option<File.InputFile>
67
- }> {}
55
+ export interface Audio {
56
+ readonly _tag: 'Audio'
57
+ readonly file: File.FileId | File.External | File.InputFile
58
+ readonly caption: Option.Option<Text_.Text>
59
+ readonly duration: Option.Option<Duration.Duration>
60
+ readonly performer: Option.Option<string>
61
+ readonly title: Option.Option<string>
62
+ readonly thumbnail: Option.Option<File.InputFile>
63
+ }
68
64
 
69
65
  /**
70
- * Content of a document message.
71
- *
72
66
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_document.html TDLib • td_api.inputMessageDocument}
73
67
  * @see {@link https://core.telegram.org/bots/api#senddocument Bot API • sendDocument}
74
68
  */
75
- export class Document extends Data.TaggedClass('Document')<{
76
- file: File.FileId | File.External | File.InputFile
77
- caption: Option.Option<Text_.Text>
78
- thumbnail: Option.Option<File.InputFile>
79
- contentTypeDetection: boolean
80
- }> {}
69
+ export interface Document {
70
+ readonly _tag: 'Document'
71
+ readonly file: File.FileId | File.External | File.InputFile
72
+ readonly caption: Option.Option<Text_.Text>
73
+ readonly thumbnail: Option.Option<File.InputFile>
74
+ readonly contentTypeDetection: boolean
75
+ }
81
76
 
82
77
  /**
83
- * Content of a video message.
84
- *
85
78
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_video.html TDLib • td_api.inputMessageVideo}
86
79
  * @see {@link https://core.telegram.org/bots/api#sendvideo Bot API • sendVideo}
87
80
  */
88
- export class Video extends Data.TaggedClass('Video')<{
89
- file: File.FileId | File.External | File.InputFile
90
- caption: Option.Option<Text_.Text>
91
- layout: 'caption-above' | 'caption-below'
92
- spoiler: boolean
93
- duration: Option.Option<Duration.Duration>
94
- width: Option.Option<number>
95
- height: Option.Option<number>
96
- thumbnail: Option.Option<File.InputFile>
97
- cover: Option.Option<File.FileId | File.External | File.InputFile>
98
- startAt: Option.Option<Duration.Duration>
99
- supportsStreaming: boolean
100
- }> {}
81
+ export interface Video {
82
+ readonly _tag: 'Video'
83
+ readonly file: File.FileId | File.External | File.InputFile
84
+ readonly caption: Option.Option<Text_.Text>
85
+ readonly layout: 'caption-above' | 'caption-below'
86
+ readonly spoiler: boolean
87
+ readonly duration: Option.Option<Duration.Duration>
88
+ readonly width: Option.Option<number>
89
+ readonly height: Option.Option<number>
90
+ readonly thumbnail: Option.Option<File.InputFile>
91
+ readonly cover: Option.Option<File.FileId | File.External | File.InputFile>
92
+ readonly startAt: Option.Option<Duration.Duration>
93
+ readonly supportsStreaming: boolean
94
+ }
101
95
 
102
96
  /**
103
- * Content of an animation message (GIF or video without sound).
104
- *
105
97
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_animation.html TDLib • td_api.inputMessageAnimation}
106
98
  * @see {@link https://core.telegram.org/bots/api#sendanimation Bot API • sendAnimation}
107
99
  */
108
- export class Animation extends Data.TaggedClass('Animation')<{
109
- file: File.FileId | File.External | File.InputFile
110
- caption: Option.Option<Text_.Text>
111
- layout: 'caption-above' | 'caption-below'
112
- spoiler: boolean
113
- duration: Option.Option<Duration.Duration>
114
- width: Option.Option<number>
115
- height: Option.Option<number>
116
- thumbnail: Option.Option<File.InputFile>
117
- }> {}
100
+ export interface Animation {
101
+ readonly _tag: 'Animation'
102
+ readonly file: File.FileId | File.External | File.InputFile
103
+ readonly caption: Option.Option<Text_.Text>
104
+ readonly layout: 'caption-above' | 'caption-below'
105
+ readonly spoiler: boolean
106
+ readonly duration: Option.Option<Duration.Duration>
107
+ readonly width: Option.Option<number>
108
+ readonly height: Option.Option<number>
109
+ readonly thumbnail: Option.Option<File.InputFile>
110
+ }
118
111
 
119
112
  /**
120
- * Content of a voice note message.
121
- *
122
113
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_voice_note.html TDLib • td_api.inputMessageVoiceNote}
123
114
  * @see {@link https://core.telegram.org/bots/api#sendvoice Bot API • sendVoice}
124
115
  */
125
- export class Voice extends Data.TaggedClass('Voice')<{
126
- file: File.FileId | File.External | File.InputFile
127
- caption: Option.Option<Text_.Text>
128
- duration: Option.Option<Duration.Duration>
129
- }> {}
116
+ export interface Voice {
117
+ readonly _tag: 'Voice'
118
+ readonly file: File.FileId | File.External | File.InputFile
119
+ readonly caption: Option.Option<Text_.Text>
120
+ readonly duration: Option.Option<Duration.Duration>
121
+ }
130
122
 
131
123
  /**
132
- * Content of a video note message (round video).
133
- *
134
124
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_video_note.html TDLib • td_api.inputMessageVideoNote}
135
125
  * @see {@link https://core.telegram.org/bots/api#sendvideonote Bot API • sendVideoNote}
136
126
  */
137
- export class VideoNote extends Data.TaggedClass('VideoNote')<{
138
- file: File.FileId | File.InputFile
139
- duration: Option.Option<Duration.Duration>
140
- diameter: Option.Option<number>
141
- thumbnail: Option.Option<File.InputFile>
142
- }> {}
127
+ export interface VideoNote {
128
+ readonly _tag: 'VideoNote'
129
+ readonly file: File.FileId | File.InputFile
130
+ readonly duration: Option.Option<Duration.Duration>
131
+ readonly diameter: Option.Option<number>
132
+ readonly thumbnail: Option.Option<File.InputFile>
133
+ }
143
134
 
144
135
  /**
145
- * Content of a location message.
146
- *
147
136
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_location.html TDLib • td_api.inputMessageLocation}
148
137
  * @see {@link https://core.telegram.org/bots/api#sendlocation Bot API • sendLocation}
149
138
  */
150
- export class Location extends Data.TaggedClass('Location')<{
151
- latitude: number
152
- longitude: number
153
- uncertaintyRadius: Option.Option<number>
154
- livePeriod: Option.Option<Duration.Duration>
155
- heading: Option.Option<number>
156
- proximityAlertRadius: Option.Option<number>
157
- }> {}
139
+ export interface Location {
140
+ readonly _tag: 'Location'
141
+ readonly latitude: number
142
+ readonly longitude: number
143
+ readonly uncertaintyRadius: Option.Option<number>
144
+ readonly livePeriod: Option.Option<Duration.Duration>
145
+ readonly heading: Option.Option<number>
146
+ readonly proximityAlertRadius: Option.Option<number>
147
+ }
158
148
 
159
149
  /**
160
- * Content of a venue message.
161
- *
162
150
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_venue.html TDLib • td_api.inputMessageVenue}
163
151
  * @see {@link https://core.telegram.org/bots/api#sendvenue Bot API • sendVenue}
164
152
  */
165
- export class Venue extends Data.TaggedClass('Venue')<{
166
- latitude: number
167
- longitude: number
168
- title: string
169
- address: string
170
- foursquareId: Option.Option<string>
171
- foursquareType: Option.Option<string>
172
- googlePlaceId: Option.Option<string>
173
- googlePlaceType: Option.Option<string>
174
- }> {}
153
+ export interface Venue {
154
+ readonly _tag: 'Venue'
155
+ readonly latitude: number
156
+ readonly longitude: number
157
+ readonly title: string
158
+ readonly address: string
159
+ readonly foursquareId: Option.Option<string>
160
+ readonly foursquareType: Option.Option<string>
161
+ readonly googlePlaceId: Option.Option<string>
162
+ readonly googlePlaceType: Option.Option<string>
163
+ }
175
164
 
176
165
  /**
177
- * Content of a contact message.
178
- *
179
166
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_contact.html TDLib • td_api.inputMessageContact}
180
167
  * @see {@link https://core.telegram.org/bots/api#sendcontact Bot API • sendContact}
181
168
  */
182
- export class Contact extends Data.TaggedClass('Contact')<{
183
- phoneNumber: string
184
- firstName: string
185
- lastName: Option.Option<string>
186
- vcard: Option.Option<string>
187
- }> {}
169
+ export interface Contact {
170
+ readonly _tag: 'Contact'
171
+ readonly phoneNumber: string
172
+ readonly firstName: string
173
+ readonly lastName: Option.Option<string>
174
+ readonly vcard: Option.Option<string>
175
+ }
188
176
 
189
177
  /**
190
- * Content of a dice message.
191
- *
192
178
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_dice.html TDLib • td_api.inputMessageDice}
193
179
  * @see {@link https://core.telegram.org/bots/api#senddice Bot API • sendDice}
194
180
  */
195
- export class Dice extends Data.TaggedClass('Dice')<{
196
- emoji: '🎲' | '🎯' | '🏀' | '⚽' | '🎳' | '🎰'
197
- }> {}
181
+ export interface Dice {
182
+ readonly _tag: 'Dice'
183
+ readonly emoji: '🎲' | '🎯' | '🏀' | '⚽' | '🎳' | '🎰'
184
+ }
198
185
 
199
186
  /**
200
- * Content of a sticker message.
201
- *
202
187
  * @see {@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1input_message_sticker.html TDLib • td_api.inputMessageSticker}
203
188
  * @see {@link https://core.telegram.org/bots/api#sendsticker Bot API • sendSticker}
204
189
  */
205
- export class Sticker extends Data.TaggedClass('Sticker')<{
206
- file: File.FileId | File.External | File.InputFile
207
- emoji: Option.Option<string>
208
- }> {}
190
+ export interface Sticker {
191
+ readonly _tag: 'Sticker'
192
+ readonly file: File.FileId | File.External | File.InputFile
193
+ readonly emoji: Option.Option<string>
194
+ }
209
195
 
210
196
  // ——— Constructors ——————————————————————————————————————————————————————————
211
197
 
@@ -214,7 +200,8 @@ export const text = (
214
200
  options?: {
215
201
  linkPreview?: LinkPreview.LinkPreview
216
202
  },
217
- ) => new Text({
203
+ ): Text => ({
204
+ _tag: 'Text',
218
205
  text,
219
206
  linkPreview: Option.fromNullable(options?.linkPreview),
220
207
  })
@@ -226,7 +213,8 @@ export const photo = (
226
213
  layout?: 'caption-above' | 'caption-below'
227
214
  spoiler?: boolean
228
215
  },
229
- ): Photo => new Photo({
216
+ ): Photo => ({
217
+ _tag: 'Photo',
230
218
  file,
231
219
  caption: Option.fromNullable(options.caption),
232
220
  layout: options.layout ?? 'caption-below',
@@ -242,7 +230,8 @@ export const audio = (
242
230
  title?: string
243
231
  thumbnail?: File.InputFile
244
232
  },
245
- ): Audio => new Audio({
233
+ ): Audio => ({
234
+ _tag: 'Audio',
246
235
  file,
247
236
  caption: Option.fromNullable(options.caption),
248
237
  duration: Option.fromNullable(options.duration),
@@ -258,7 +247,8 @@ export const document = (
258
247
  thumbnail?: File.InputFile
259
248
  contentTypeDetection?: boolean
260
249
  },
261
- ): Document => new Document({
250
+ ): Document => ({
251
+ _tag: 'Document',
262
252
  file,
263
253
  caption: Option.fromNullable(options.caption),
264
254
  thumbnail: Option.fromNullable(options.thumbnail),
@@ -279,7 +269,8 @@ export const video = (
279
269
  startAt?: Duration.Duration
280
270
  supportsStreaming?: boolean
281
271
  },
282
- ): Video => new Video({
272
+ ): Video => ({
273
+ _tag: 'Video',
283
274
  file,
284
275
  caption: Option.fromNullable(options.caption),
285
276
  layout: options.layout ?? 'caption-below',
@@ -304,7 +295,8 @@ export const animation = (
304
295
  height?: number
305
296
  thumbnail?: File.InputFile
306
297
  },
307
- ): Animation => new Animation({
298
+ ): Animation => ({
299
+ _tag: 'Animation',
308
300
  file,
309
301
  caption: Option.fromNullable(options.caption),
310
302
  layout: options.layout ?? 'caption-below',
@@ -321,7 +313,8 @@ export const voice = (
321
313
  caption?: Text_.Text
322
314
  duration?: Duration.Duration
323
315
  },
324
- ): Voice => new Voice({
316
+ ): Voice => ({
317
+ _tag: 'Voice',
325
318
  file,
326
319
  caption: Option.fromNullable(options.caption),
327
320
  duration: Option.fromNullable(options.duration),
@@ -334,7 +327,8 @@ export const videoNote = (
334
327
  diameter?: number
335
328
  thumbnail?: File.InputFile
336
329
  },
337
- ): VideoNote => new VideoNote({
330
+ ): VideoNote => ({
331
+ _tag: 'VideoNote',
338
332
  file,
339
333
  duration: Option.fromNullable(options.duration),
340
334
  diameter: Option.fromNullable(options.diameter),
@@ -345,7 +339,8 @@ export const location = (options: {
345
339
  latitude: number
346
340
  longitude: number
347
341
  uncertaintyRadius?: number
348
- }): Location => new Location({
342
+ }): Location => ({
343
+ _tag: 'Location',
349
344
  latitude: options.latitude,
350
345
  longitude: options.longitude,
351
346
  uncertaintyRadius: Option.fromNullable(options.uncertaintyRadius),
@@ -361,7 +356,8 @@ export const liveLocation = (options: {
361
356
  livePeriod: Duration.Duration
362
357
  heading?: number
363
358
  proximityAlertRadius?: number
364
- }): Location => new Location({
359
+ }): Location => ({
360
+ _tag: 'Location',
365
361
  latitude: options.latitude,
366
362
  longitude: options.longitude,
367
363
  uncertaintyRadius: Option.fromNullable(options.uncertaintyRadius),
@@ -379,7 +375,8 @@ export const venue = (options: {
379
375
  foursquareType?: string
380
376
  googlePlaceId?: string
381
377
  googlePlaceType?: string
382
- }): Venue => new Venue({
378
+ }): Venue => ({
379
+ _tag: 'Venue',
383
380
  latitude: options.latitude,
384
381
  longitude: options.longitude,
385
382
  title: options.title,
@@ -395,16 +392,17 @@ export const contact = (options: {
395
392
  firstName: string
396
393
  lastName?: string
397
394
  vcard?: string
398
- }): Contact => new Contact({
395
+ }): Contact => ({
396
+ _tag: 'Contact',
399
397
  phoneNumber: options.phoneNumber,
400
398
  firstName: options.firstName,
401
399
  lastName: Option.fromNullable(options.lastName),
402
400
  vcard: Option.fromNullable(options.vcard),
403
401
  })
404
402
 
405
- export const dice = (emoji: Dice['emoji']): Dice => new Dice({ emoji })
403
+ export const dice = (emoji: Dice['emoji']): Dice => ({ _tag: 'Dice', emoji })
406
404
 
407
405
  export const sticker = (
408
406
  file: File.FileId | File.External | File.InputFile,
409
407
  emoji?: string,
410
- ): Sticker => new Sticker({ file, emoji: Option.fromNullable(emoji) })
408
+ ): Sticker => ({ _tag: 'Sticker', file, emoji: Option.fromNullable(emoji) })
package/src/Dialog.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type * as BotApi from './BotApi.ts'
2
2
  import * as Brand from 'effect/Brand'
3
- import * as Data from 'effect/Data'
3
+ import * as Match from 'effect/Match'
4
4
  import * as Option from 'effect/Option'
5
5
  import * as internal from './internal/dialog.ts'
6
6
 
@@ -14,20 +14,23 @@ export type Dialog =
14
14
  | ForumTopic
15
15
  | ChannelDm
16
16
 
17
- export class PrivateTopic extends Data.TaggedClass('PrivateTopic')<{
18
- user: User
19
- topicId: number
20
- }> {}
17
+ export interface PrivateTopic {
18
+ readonly _tag: 'PrivateTopic'
19
+ readonly user: User
20
+ readonly topicId: number
21
+ }
21
22
 
22
- export class ForumTopic extends Data.TaggedClass('ForumTopic')<{
23
- supergroup: Supergroup
24
- topicId: number
25
- }> {}
23
+ export interface ForumTopic {
24
+ readonly _tag: 'ForumTopic'
25
+ readonly supergroup: Supergroup
26
+ readonly topicId: number
27
+ }
26
28
 
27
- export class ChannelDm extends Data.TaggedClass('ChannelDm')<{
28
- channel: Channel
29
- topicId: number
30
- }> {}
29
+ export interface ChannelDm {
30
+ readonly _tag: 'ChannelDm'
31
+ readonly channel: Channel
32
+ readonly topicId: number
33
+ }
31
34
 
32
35
  // =============================================================================
33
36
  // Peer
@@ -39,49 +42,38 @@ export type Peer =
39
42
  | Channel
40
43
  | Supergroup
41
44
 
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
- }
45
+ export interface User {
46
+ readonly _tag: 'User'
47
+ readonly id: UserId
52
48
  }
53
49
 
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
- }
50
+ export interface Group {
51
+ readonly _tag: 'Group'
52
+ readonly id: GroupId
60
53
  }
61
54
 
62
- export class Channel extends Data.TaggedClass('Channel')<{
63
- id: ChannelId
64
- }> {
65
- public dialogId(): DialogId {
66
- return Option.getOrThrow(internal.encodePeerId('channel', this.id))
67
- }
55
+ export interface Channel {
56
+ readonly _tag: 'Channel'
57
+ readonly id: ChannelId
58
+ }
68
59
 
69
- public directMessages(topicId: number): ChannelDm {
70
- return new ChannelDm({ channel: this, topicId })
71
- }
60
+ export interface Supergroup {
61
+ readonly _tag: 'Supergroup'
62
+ readonly id: SupergroupId
72
63
  }
73
64
 
74
- export class Supergroup extends Data.TaggedClass('Supergroup')<{
75
- id: SupergroupId
76
- }> {
77
- public dialogId(): DialogId {
78
- return Option.getOrThrow(internal.encodePeerId('channel', this.id))
79
- }
65
+ // =============================================================================
66
+ // Peer Functions
67
+ // =============================================================================
80
68
 
81
- public topic(topicId: number): ForumTopic {
82
- return new ForumTopic({ supergroup: this, topicId })
83
- }
84
- }
69
+ export const dialogId: (peer: Peer) => DialogId = Match.type<Peer>().pipe(
70
+ Match.tagsExhaustive({
71
+ User: u => Option.getOrThrow(internal.encodePeerId('user', u.id)),
72
+ Group: g => Option.getOrThrow(internal.encodePeerId('group', g.id)),
73
+ Channel: c => Option.getOrThrow(internal.encodePeerId('channel', c.id)),
74
+ Supergroup: s => Option.getOrThrow(internal.encodePeerId('channel', s.id)),
75
+ }),
76
+ )
85
77
 
86
78
  // =============================================================================
87
79
  // Brands
@@ -93,30 +85,25 @@ export class Supergroup extends Data.TaggedClass('Supergroup')<{
93
85
  * @see {@link https://core.telegram.org/api/bots/ids Telegram API • Bot API dialog IDs}
94
86
  */
95
87
  export type DialogId = number & Brand.Brand<'@grom.js/effect-tg/DialogId'>
96
- export const DialogId = Brand.refined<DialogId>(
88
+ export const DialogId: Brand.Brand.Constructor<DialogId> = Brand.refined<DialogId>(
97
89
  n => Option.isSome(internal.decodeDialogId(n)),
98
90
  n => Brand.error(`Invalid dialog ID: ${n}`),
99
91
  )
100
92
 
101
93
  export type UserId = number & Brand.Brand<'@grom.js/effect-tg/UserId'>
102
- export const UserId = Brand.refined<UserId>(
94
+ export const UserId: Brand.Brand.Constructor<UserId> = Brand.refined<UserId>(
103
95
  n => Option.isSome(internal.encodePeerId('user', n)),
104
96
  n => Brand.error(`Invalid user ID: ${n}`),
105
97
  )
106
98
 
107
99
  export type GroupId = number & Brand.Brand<'@grom.js/effect-tg/GroupId'>
108
- export const GroupId = Brand.refined<GroupId>(
100
+ export const GroupId: Brand.Brand.Constructor<GroupId> = Brand.refined<GroupId>(
109
101
  n => Option.isSome(internal.encodePeerId('group', n)),
110
102
  n => Brand.error(`Invalid group ID: ${n}`),
111
103
  )
112
104
 
113
- /**
114
- * ID for channels (including supergroups).
115
- *
116
- * @see {@link https://core.telegram.org/api/bots/ids Telegram API • Bot API dialog IDs}
117
- */
118
105
  export type ChannelId = number & Brand.Brand<'@grom.js/effect-tg/ChannelId'>
119
- export const ChannelId = Brand.refined<ChannelId>(
106
+ export const ChannelId: Brand.Brand.Constructor<ChannelId> = Brand.refined<ChannelId>(
120
107
  n => Option.isSome(internal.encodePeerId('channel', n)),
121
108
  n => Brand.error(`Invalid channel or supergroup ID: ${n}`),
122
109
  )
@@ -125,7 +112,7 @@ export const ChannelId = Brand.refined<ChannelId>(
125
112
  export type SupergroupId = ChannelId
126
113
 
127
114
  /** @alias ChannelId */
128
- export const SupergroupId = ChannelId
115
+ export const SupergroupId: Brand.Brand.Constructor<ChannelId> = ChannelId
129
116
 
130
117
  // =============================================================================
131
118
  // Dialog ID <-> Peer ID
@@ -156,21 +143,40 @@ export const encodePeerId: (
156
143
  // Constructors
157
144
  // =============================================================================
158
145
 
159
- export const user: (id: number) => User = (id) => {
160
- return new User({ id: UserId(id) })
161
- }
162
-
163
- export const group: (id: number) => Group = (id) => {
164
- return new Group({ id: GroupId(id) })
165
- }
166
-
167
- export const channel: (id: number) => Channel = (id) => {
168
- return new Channel({ id: ChannelId(id) })
169
- }
170
-
171
- export const supergroup: (id: number) => Supergroup = (id) => {
172
- return new Supergroup({ id: ChannelId(id) })
173
- }
146
+ export const user: (id: number) => User = id => ({ _tag: 'User', id: UserId(id) })
147
+
148
+ export const group: (id: number) => Group = id => ({ _tag: 'Group', id: GroupId(id) })
149
+
150
+ export const channel: (id: number) => Channel = id => ({ _tag: 'Channel', id: ChannelId(id) })
151
+
152
+ export const supergroup: (id: number) => Supergroup = id => ({ _tag: 'Supergroup', id: ChannelId(id) })
153
+
154
+ export const privateTopic: (
155
+ user: User,
156
+ topicId: number,
157
+ ) => PrivateTopic = (user, topicId) => ({
158
+ _tag: 'PrivateTopic',
159
+ user,
160
+ topicId,
161
+ })
162
+
163
+ export const forumTopic: (
164
+ supergroup: Supergroup,
165
+ topicId: number,
166
+ ) => ForumTopic = (supergroup, topicId) => ({
167
+ _tag: 'ForumTopic',
168
+ supergroup,
169
+ topicId,
170
+ })
171
+
172
+ export const channelDm: (
173
+ channel: Channel,
174
+ topicId: number,
175
+ ) => ChannelDm = (channel, topicId) => ({
176
+ _tag: 'ChannelDm',
177
+ channel,
178
+ topicId,
179
+ })
174
180
 
175
181
  export const ofMessage: (
176
182
  message: BotApi.Types.Message,