diff --git a/src/BotApiError.ts b/src/BotApiError.ts index d5757ea..b0a0561 100644 --- a/src/BotApiError.ts +++ b/src/BotApiError.ts @@ -9,7 +9,7 @@ import * as Predicate from 'effect/Predicate' 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 @@ -32,7 +32,7 @@ export class TransportError extends Data.TaggedError('TransportError')<{ }> { readonly [TypeId]: TypeId = TypeId - override get message() { + override get message(): string { return Match.value(this.cause).pipe( Match.tagsExhaustive({ RequestError: e => e.message, diff --git a/src/Content.ts b/src/Content.ts index 5c941ef..8e5bc7d 100644 --- a/src/Content.ts +++ b/src/Content.ts @@ -214,7 +214,7 @@ export const text = ( options?: { linkPreview?: LinkPreview.LinkPreview }, -) => new Text({ +): Text => new Text({ text, linkPreview: Option.fromNullable(options?.linkPreview), }) diff --git a/src/Dialog.ts b/src/Dialog.ts index 0ab4846..48b3d52 100644 --- a/src/Dialog.ts +++ b/src/Dialog.ts @@ -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( +export const DialogId: Brand.Brand.Constructor = Brand.refined( 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( +export const UserId: Brand.Brand.Constructor = Brand.refined( 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( +export const GroupId: Brand.Brand.Constructor = Brand.refined( n => Option.isSome(internal.encodePeerId('group', n)), n => Brand.error(`Invalid group ID: ${n}`), ) @@ -116,7 +116,7 @@ export const GroupId = Brand.refined( * @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( +export const ChannelId: Brand.Brand.Constructor = Brand.refined( n => Option.isSome(internal.encodePeerId('channel', n)), n => Brand.error(`Invalid channel or supergroup ID: ${n}`), ) @@ -125,7 +125,7 @@ export const ChannelId = Brand.refined( export type SupergroupId = ChannelId /** @alias ChannelId */ -export const SupergroupId = ChannelId +export const SupergroupId: Brand.Brand.Constructor = ChannelId // ============================================================================= // Dialog ID <-> Peer ID diff --git a/src/File.ts b/src/File.ts index 8cf39d6..1332757 100644 --- a/src/File.ts +++ b/src/File.ts @@ -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() +export const FileId: Brand.Brand.Constructor = Brand.nominal() export type External = URL & Brand.Brand<'External'> -export const External = Brand.nominal() +export const External: Brand.Brand.Constructor = Brand.nominal() export class InputFile extends Data.TaggedClass('InputFile')<{ stream: Stream.Stream diff --git a/src/Runner.ts b/src/Runner.ts index 7d1b84e..0399f1b 100644 --- a/src/Runner.ts +++ b/src/Runner.ts @@ -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' /** @@ -19,4 +21,6 @@ export interface Runner { * 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 = internal.makeSimple diff --git a/src/internal/file.ts b/src/internal/file.ts index 96f6b8b..aaefa8c 100644 --- a/src/internal/file.ts +++ b/src/internal/file.ts @@ -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}".`)) diff --git a/src/internal/send.ts b/src/internal/send.ts index e1986a3..7d613b5 100644 --- a/src/internal/send.ts +++ b/src/internal/send.ts @@ -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' @@ -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' @@ -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) : {}), + }, +) diff --git a/tsconfig.lib.json b/tsconfig.lib.json index 6608030..1a34992 100644 --- a/tsconfig.lib.json +++ b/tsconfig.lib.json @@ -50,6 +50,7 @@ "outDir": "dist", "sourceMap": true, "forceConsistentCasingInFileNames": true, + "isolatedDeclarations": true, "verbatimModuleSyntax": true, "skipLibCheck": true },