Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/BotApiError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import * as Dialog from './Dialog.ts'
import * as internal from './internal/botApiError.ts'

export const TypeId = '@grom.js/effect-tg/BotApiError'
export const TypeId: unique symbol = Symbol.for('@grom.js/effect-tg/BotApiError')

export type TypeId = typeof TypeId

Expand All @@ -25,14 +25,14 @@
/**
* Error caused by the transport when accessing Bot API.
*/
export class TransportError extends Data.TaggedError('TransportError')<{

Check failure on line 28 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Extends clause can't contain an expression with --isolatedDeclarations.
cause:
| HttpClientError.HttpClientError
| HttpBody.HttpBodyError
}> {
readonly [TypeId]: TypeId = TypeId

Check failure on line 33 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.

override get message() {
override get message(): string {
return Match.value(this.cause).pipe(
Match.tagsExhaustive({
RequestError: e => e.message,
Expand All @@ -48,33 +48,33 @@
}
}

export class MethodFailed extends Data.TaggedError('MethodFailed')<{

Check failure on line 51 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Extends clause can't contain an expression with --isolatedDeclarations.
response: FailureResponse
possibleReason: MethodFailureReason
}> {
readonly [TypeId]: TypeId = TypeId

Check failure on line 55 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.

override get message() {
return `(${this.response.error_code}) ${this.response.description}`
}
}

export class GroupUpgraded extends Data.TaggedError('GroupUpgraded')<{

Check failure on line 62 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Extends clause can't contain an expression with --isolatedDeclarations.
response: FailureResponse
supergroup: Dialog.Supergroup
}> {
readonly [TypeId]: TypeId = TypeId

Check failure on line 66 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.

override get message() {
return `Group has been upgraded to a supergroup with ID ${this.supergroup.id}.`
}
}

export class RateLimited extends Data.TaggedError('RateLimited')<{

Check failure on line 73 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Extends clause can't contain an expression with --isolatedDeclarations.
response: FailureResponse
retryAfter: Duration.Duration
}> {
readonly [TypeId]: TypeId = TypeId

Check failure on line 77 in src/BotApiError.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.

override get message() {
return `Flood limit exceeded. Should wait for ${Duration.format(this.retryAfter)} before retrying.`
Expand Down
2 changes: 1 addition & 1 deletion src/Content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export const text = (
options?: {
linkPreview?: LinkPreview.LinkPreview
},
) => new Text({
): Text => new Text({
text,
linkPreview: Option.fromNullable(options?.linkPreview),
})
Expand Down
10 changes: 5 additions & 5 deletions src/Dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,19 @@ export class Supergroup extends Data.TaggedClass('Supergroup')<{
* @see {@link https://core.telegram.org/api/bots/ids Telegram API • Bot API dialog IDs}
*/
export type DialogId = number & Brand.Brand<'@grom.js/effect-tg/DialogId'>
export const DialogId = Brand.refined<DialogId>(
export const DialogId: Brand.Brand.Constructor<DialogId> = Brand.refined<DialogId>(
n => Option.isSome(internal.decodeDialogId(n)),
n => Brand.error(`Invalid dialog ID: ${n}`),
)

export type UserId = number & Brand.Brand<'@grom.js/effect-tg/UserId'>
export const UserId = Brand.refined<UserId>(
export const UserId: Brand.Brand.Constructor<UserId> = Brand.refined<UserId>(
n => Option.isSome(internal.encodePeerId('user', n)),
n => Brand.error(`Invalid user ID: ${n}`),
)

export type GroupId = number & Brand.Brand<'@grom.js/effect-tg/GroupId'>
export const GroupId = Brand.refined<GroupId>(
export const GroupId: Brand.Brand.Constructor<GroupId> = Brand.refined<GroupId>(
n => Option.isSome(internal.encodePeerId('group', n)),
n => Brand.error(`Invalid group ID: ${n}`),
)
Expand All @@ -116,7 +116,7 @@ export const GroupId = Brand.refined<GroupId>(
* @see {@link https://core.telegram.org/api/bots/ids Telegram API • Bot API dialog IDs}
*/
export type ChannelId = number & Brand.Brand<'@grom.js/effect-tg/ChannelId'>
export const ChannelId = Brand.refined<ChannelId>(
export const ChannelId: Brand.Brand.Constructor<ChannelId> = Brand.refined<ChannelId>(
n => Option.isSome(internal.encodePeerId('channel', n)),
n => Brand.error(`Invalid channel or supergroup ID: ${n}`),
)
Expand All @@ -125,7 +125,7 @@ export const ChannelId = Brand.refined<ChannelId>(
export type SupergroupId = ChannelId

/** @alias ChannelId */
export const SupergroupId = ChannelId
export const SupergroupId: Brand.Brand.Constructor<ChannelId> = ChannelId

// =============================================================================
// Dialog ID <-> Peer ID
Expand Down
4 changes: 2 additions & 2 deletions src/File.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import * as Data from 'effect/Data'
import * as internal from './internal/file.ts'

export type FileId = string & Brand.Brand<'FileId'>
export const FileId = Brand.nominal<FileId>()
export const FileId: Brand.Brand.Constructor<FileId> = Brand.nominal<FileId>()

export type External = URL & Brand.Brand<'External'>
export const External = Brand.nominal<External>()
export const External: Brand.Brand.Constructor<External> = Brand.nominal<External>()

export class InputFile extends Data.TaggedClass('InputFile')<{
stream: Stream.Stream<Uint8Array>
Expand Down
6 changes: 5 additions & 1 deletion src/Runner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type * as Effect from 'effect/Effect'
import type * as Bot from './Bot.ts'
import type * as BotApi from './BotApi.ts'
import type * as BotApiError from './BotApiError.ts'
import * as internal from './internal/runner.ts'

/**
Expand All @@ -19,4 +21,6 @@ export interface Runner<E = never, R = never> {
* Creates a simple runner that fetches updates by calling `BotApi.getUpdates`
* method and handles them one by one.
*/
export const makeSimple = internal.makeSimple
export const makeSimple: (options?: {
allowedUpdates?: string[]
}) => Runner<BotApiError.BotApiError, BotApi.BotApi> = internal.makeSimple
13 changes: 10 additions & 3 deletions src/internal/file.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import type { FileId } from '../File.ts'
import type * as HttpClientError from '@effect/platform/HttpClientError'
import type * as HttpClientResponse from '@effect/platform/HttpClientResponse'
import type * as BotApiError from '../BotApiError.ts'
import type * as File from '../File.ts'
import * as HttpClient from '@effect/platform/HttpClient'
import * as Effect from 'effect/Effect'
import * as BotApi from '../BotApi.ts'
import * as BotApiUrl from '../BotApiUrl.ts'

export const download = Effect.fnUntraced(
function* (fileId: FileId) {
export const download: (fileId: File.FileId) => Effect.Effect<
HttpClientResponse.HttpClientResponse,
BotApiError.BotApiError | HttpClientError.HttpClientError,
BotApi.BotApi | BotApiUrl.BotApiUrl | HttpClient.HttpClient
> = Effect.fnUntraced(
function* (fileId) {
const file = yield* BotApi.callMethod('getFile', { file_id: fileId })
if (file.file_path == null) {
return yield* Effect.die(new Error(`Bot API returned no file path for file "${fileId}".`))
Expand Down
37 changes: 23 additions & 14 deletions src/internal/send.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type * as Effect from 'effect/Effect'
import type * as BotApiError from '../BotApiError.ts'
import type * as Content from '../Content.ts'
import type * as Dialog from '../Dialog.ts'
import type * as Markup from '../Markup.ts'
Expand All @@ -7,7 +9,6 @@ import type * as Text from '../Text.ts'
import type { Types } from './botApi.gen.ts'
import * as Tgx from '@grom.js/tgx'
import * as Duration from 'effect/Duration'
import * as Effect from 'effect/Effect'
import * as Match from 'effect/Match'
import * as Option from 'effect/Option'
import * as BotApi from '../BotApi.ts'
Expand Down Expand Up @@ -491,21 +492,29 @@ const paramsOptions = (options: Send.Options): ParamsOptions => {
// Send Methods
// =============================================================================

export const sendMessage = Effect.fnUntraced(function* (params: {
export const sendMessage: (params: {
content: Content.Content
dialog: Dialog.Dialog | Dialog.DialogId
markup?: Markup.Markup
reply?: Reply.Reply
options?: Send.Options
}) {
return yield* BotApi.callMethod(
methodByContent[params.content._tag],
{
...paramsContent(params.content),
...paramsDialog(params.dialog),
...(params.markup ? paramsMarkup(params.markup) : {}),
...(params.reply ? paramsReply(params.reply) : {}),
...(params.options ? paramsOptions(params.options) : {}),
},
)
})
}) => Effect.Effect<
Types.Message,
BotApiError.BotApiError,
BotApi.BotApi
> = ({
content,
dialog,
markup,
reply,
options,
}) => BotApi.callMethod(
methodByContent[content._tag],
{
...paramsContent(content),
...paramsDialog(dialog),
...(markup ? paramsMarkup(markup) : {}),
...(reply ? paramsReply(reply) : {}),
...(options ? paramsOptions(options) : {}),
},
)
1 change: 1 addition & 0 deletions tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"outDir": "dist",
"sourceMap": true,
"forceConsistentCasingInFileNames": true,
"isolatedDeclarations": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
Expand Down
Loading