chore: enabled isolatedDeclarations
This commit is contained in:
parent
a0ed9c2426
commit
b76463ccc0
126 changed files with 676 additions and 490 deletions
|
@ -28,12 +28,10 @@ describe('@mtcute/tl', () => {
|
|||
|
||||
it('readers map works with TlBinaryReader', () => {
|
||||
const buf = p.hexDecode('4ca5e8dd7b00000000000000c801000000000000')
|
||||
// eslint-disable-next-line
|
||||
const obj = TlBinaryReader.deserializeObject<any>(__tlReaderMap, buf)
|
||||
|
||||
expect(obj._).equal('inputPeerUser')
|
||||
expect(obj.userId).equal(123)
|
||||
// eslint-disable-next-line
|
||||
expect(obj.accessHash.toString()).equal('456')
|
||||
})
|
||||
|
||||
|
|
|
@ -44,6 +44,12 @@ export default antfu({
|
|||
SwitchCase: 1,
|
||||
VariableDeclarator: 1,
|
||||
}],
|
||||
'style/max-len': ['error', {
|
||||
code: 120,
|
||||
ignoreComments: true,
|
||||
ignoreStrings: true,
|
||||
ignoreTemplateLiterals: true,
|
||||
}],
|
||||
'curly': ['error', 'multi-line'],
|
||||
'style/brace-style': ['error', '1tbs', { allowSingleLine: true }],
|
||||
'node/prefer-global/process': ['error', 'always'],
|
||||
|
@ -60,7 +66,7 @@ export default antfu({
|
|||
'ts/no-redeclare': 'off',
|
||||
'eslint-comments/no-unlimited-disable': 'off',
|
||||
'no-cond-assign': 'off',
|
||||
'ts/explicit-function-return-type': 'off', // todo: enable once we move to isolatedDeclarations
|
||||
'ts/explicit-function-return-type': 'off',
|
||||
'no-labels': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
'unicorn/no-new-array': 'off',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { Interface as RlInterface } from 'node:readline'
|
||||
import { createInterface } from 'node:readline'
|
||||
import type { Readable } from 'node:stream'
|
||||
|
||||
import type { FileDownloadLocation, FileDownloadParameters, ITelegramStorageProvider, PartialOnly, User } from '@mtcute/core'
|
||||
import type {
|
||||
|
@ -145,7 +146,7 @@ export class TelegramClient extends TelegramClientBase {
|
|||
return downloadToFile(this, filename, location, params)
|
||||
}
|
||||
|
||||
downloadAsNodeStream(location: FileDownloadLocation, params?: FileDownloadParameters | undefined) {
|
||||
downloadAsNodeStream(location: FileDownloadLocation, params?: FileDownloadParameters | undefined): Readable {
|
||||
return downloadAsNodeStream(this, location, params)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface SqliteStorageDriverOptions {
|
|||
export class SqliteStorageDriver extends BaseSqliteStorageDriver {
|
||||
constructor(
|
||||
readonly filename = ':memory:',
|
||||
readonly params?: SqliteStorageDriverOptions,
|
||||
readonly params?: SqliteStorageDriverOptions | undefined,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export { SqliteStorageDriver } from './driver.js'
|
|||
export class SqliteStorage extends BaseSqliteStorage {
|
||||
constructor(
|
||||
readonly filename = ':memory:',
|
||||
readonly params?: SqliteStorageDriverOptions,
|
||||
readonly params?: SqliteStorageDriverOptions | undefined,
|
||||
) {
|
||||
super(new SqliteStorageDriver(filename, params))
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ export class BunCryptoProvider extends BaseCryptoProvider implements ICryptoProv
|
|||
return gunzip(data)
|
||||
}
|
||||
|
||||
randomFill(buf: Uint8Array) {
|
||||
randomFill(buf: Uint8Array): void {
|
||||
crypto.getRandomValues(buf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,11 @@ function isBunFile(file: unknown): file is BunFile {
|
|||
return file instanceof Blob && 'name' in file && file.name.length > 0
|
||||
}
|
||||
|
||||
export async function normalizeFile(file: UploadFileLike) {
|
||||
export async function normalizeFile(file: UploadFileLike): Promise<{
|
||||
file: UploadFileLike
|
||||
fileName?: string | undefined
|
||||
fileSize?: number
|
||||
} | null> {
|
||||
if (typeof file === 'string') {
|
||||
file = Bun.file(file)
|
||||
}
|
||||
|
|
|
@ -149,5 +149,5 @@ export abstract class BaseTcpTransport extends EventEmitter implements ITelegram
|
|||
}
|
||||
|
||||
export class TcpTransport extends BaseTcpTransport {
|
||||
_packetCodec = new IntermediatePacketCodec()
|
||||
_packetCodec: IntermediatePacketCodec = new IntermediatePacketCodec()
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ export function parseIpFromBytes(data: Uint8Array): string {
|
|||
throw new MtArgumentError('Invalid IP address length')
|
||||
}
|
||||
|
||||
export function serializeIpv4ToBytes(ip: string, buf: Uint8Array) {
|
||||
export function serializeIpv4ToBytes(ip: string, buf: Uint8Array): void {
|
||||
const parts = ip.split('.')
|
||||
|
||||
if (parts.length !== 4) {
|
||||
|
@ -33,7 +33,7 @@ export function serializeIpv4ToBytes(ip: string, buf: Uint8Array) {
|
|||
buf[3] = Number(parts[3])
|
||||
}
|
||||
|
||||
export function serializeIpv6ToBytes(ip: string, buf: Uint8Array) {
|
||||
export function serializeIpv6ToBytes(ip: string, buf: Uint8Array): void {
|
||||
const parts = ip.split(':')
|
||||
|
||||
if (parts.length !== 8) {
|
||||
|
|
|
@ -94,7 +94,7 @@ export class BaseTelegramClient implements ITelegramClient {
|
|||
})
|
||||
}
|
||||
|
||||
readonly appConfig = new AppConfigManager(this)
|
||||
readonly appConfig: AppConfigManager = new AppConfigManager(this)
|
||||
|
||||
private _prepare = asyncResettable(async () => {
|
||||
await this.mt.prepare()
|
||||
|
@ -115,7 +115,7 @@ export class BaseTelegramClient implements ITelegramClient {
|
|||
*
|
||||
* Call {@link connect} to actually connect.
|
||||
*/
|
||||
prepare() {
|
||||
prepare(): Promise<void> {
|
||||
return this._prepare.run()
|
||||
}
|
||||
|
||||
|
@ -327,7 +327,10 @@ export class BaseTelegramClient implements ITelegramClient {
|
|||
this._connectionStateHandler = handler
|
||||
}
|
||||
|
||||
async getApiCrenetials() {
|
||||
async getApiCrenetials(): Promise<{
|
||||
id: number
|
||||
hash: string
|
||||
}> {
|
||||
return {
|
||||
id: this.params.apiId,
|
||||
hash: this.params.apiHash,
|
||||
|
|
|
@ -519,7 +519,6 @@ export interface TelegramClient extends ITelegramClient {
|
|||
*/
|
||||
on(name: 'delete_business_message', handler: ((upd: DeleteBusinessMessageUpdate) => void)): this
|
||||
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
on(name: string, handler: (...args: any[]) => void): this
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,10 +9,11 @@ import {
|
|||
toInputChannel,
|
||||
toInputUser,
|
||||
} from '../../utils/peer-utils.js'
|
||||
import type { BatchedQuery } from '../../utils/query-batcher.js'
|
||||
import { batchedQuery } from '../../utils/query-batcher.js'
|
||||
|
||||
/** @internal */
|
||||
export const _getUsersBatched = batchedQuery<tl.TypeInputUser, tl.TypeUser, number>({
|
||||
export const _getUsersBatched: BatchedQuery<tl.TypeInputUser, tl.TypeUser> = batchedQuery({
|
||||
fetch: (client, items) =>
|
||||
client
|
||||
.call({
|
||||
|
@ -63,7 +64,7 @@ export const _getUsersBatched = batchedQuery<tl.TypeInputUser, tl.TypeUser, numb
|
|||
})
|
||||
|
||||
/** @internal */
|
||||
export const _getChatsBatched = batchedQuery<number, tl.RawChat, number>({
|
||||
export const _getChatsBatched: BatchedQuery<number, tl.RawChat> = batchedQuery({
|
||||
fetch: (client, items) =>
|
||||
client
|
||||
.call({
|
||||
|
@ -78,7 +79,10 @@ export const _getChatsBatched = batchedQuery<number, tl.RawChat, number>({
|
|||
})
|
||||
|
||||
/** @internal */
|
||||
export const _getChannelsBatched = batchedQuery<tl.TypeInputChannel, tl.RawChannel | tl.RawChannelForbidden, number>({
|
||||
export const _getChannelsBatched: BatchedQuery<
|
||||
tl.TypeInputChannel,
|
||||
tl.RawChannel | tl.RawChannelForbidden
|
||||
> = batchedQuery({
|
||||
fetch: (client, items) =>
|
||||
client
|
||||
.call({
|
||||
|
|
|
@ -156,7 +156,13 @@ export async function _processCommonSendParameters(
|
|||
client: ITelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
params: CommonSendParams,
|
||||
) {
|
||||
): Promise<{
|
||||
peer: tl.TypeInputPeer
|
||||
replyTo: tl.TypeInputReplyTo | undefined
|
||||
scheduleDate: number | undefined
|
||||
quickReplyShortcut: tl.TypeInputQuickReplyShortcut | undefined
|
||||
chainId: string
|
||||
}> {
|
||||
let peer = await resolvePeer(client, chatId)
|
||||
|
||||
let replyTo = normalizeMessageId(params.replyTo)
|
||||
|
|
|
@ -62,7 +62,7 @@ export class PeersService extends BaseService {
|
|||
this._cache = new LruMap(options.cacheSize ?? 100)
|
||||
}
|
||||
|
||||
async updatePeersFrom(obj: tl.TlObject | tl.TlObject[]) {
|
||||
async updatePeersFrom(obj: tl.TlObject | tl.TlObject[]): Promise<boolean> {
|
||||
let count = 0
|
||||
|
||||
for (const peer of getAllPeersFrom(obj)) {
|
||||
|
|
|
@ -23,9 +23,9 @@ export interface TelegramStorageManagerExtraOptions {
|
|||
export class TelegramStorageManager {
|
||||
private provider
|
||||
|
||||
readonly updates
|
||||
readonly updates: UpdatesStateService
|
||||
readonly self: PublicPart<CurrentUserService>
|
||||
readonly refMsgs
|
||||
readonly refMsgs: RefMessagesService
|
||||
readonly peers: PublicPart<PeersService>
|
||||
|
||||
constructor(
|
||||
|
@ -56,7 +56,7 @@ export class TelegramStorageManager {
|
|||
)
|
||||
}
|
||||
|
||||
async clear(withAuthKeys = false) {
|
||||
async clear(withAuthKeys = false): Promise<void> {
|
||||
await this.provider.peers.deleteAll()
|
||||
await this.provider.refMessages.deleteAll()
|
||||
await this.mt.clear(withAuthKeys)
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Voice } from './voice.js'
|
|||
export type ParsedDocument = Sticker | Voice | Audio | Video | Document
|
||||
|
||||
/** @internal */
|
||||
export function parseSticker(doc: tl.RawDocument) {
|
||||
export function parseSticker(doc: tl.RawDocument): Sticker | undefined {
|
||||
const stickerAttr = doc.attributes.find(
|
||||
a => a._ === 'documentAttributeSticker' || a._ === 'documentAttributeCustomEmoji',
|
||||
)
|
||||
|
|
|
@ -24,7 +24,7 @@ export class Invoice {
|
|||
|
||||
constructor(
|
||||
readonly raw: tl.RawMessageMediaInvoice,
|
||||
private readonly _extendedMedia?: MessageMedia,
|
||||
private readonly _extendedMedia?: MessageMedia | undefined,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,7 +23,7 @@ export class Photo extends FileLocation {
|
|||
|
||||
constructor(
|
||||
readonly raw: tl.RawPhoto,
|
||||
readonly media?: tl.RawMessageMediaPhoto,
|
||||
readonly media?: tl.RawMessageMediaPhoto | undefined,
|
||||
) {
|
||||
const location = {
|
||||
_: 'inputPhotoFileLocation',
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { PeersIndex } from '../peers/peers-index.js'
|
|||
export class PollAnswer {
|
||||
constructor(
|
||||
readonly raw: tl.TypePollAnswer,
|
||||
readonly result?: tl.TypePollAnswerVoters,
|
||||
readonly result?: tl.RawPollAnswerVoters | undefined,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +71,7 @@ export class Poll {
|
|||
constructor(
|
||||
readonly raw: tl.TypePoll,
|
||||
readonly _peers: PeersIndex,
|
||||
readonly results?: tl.TypePollResults,
|
||||
readonly results?: tl.RawPollResults | undefined,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -72,7 +72,7 @@ export class Sticker extends RawDocument {
|
|||
constructor(
|
||||
doc: tl.RawDocument,
|
||||
readonly attr: tl.RawDocumentAttributeSticker | tl.RawDocumentAttributeCustomEmoji,
|
||||
readonly attr2?: tl.RawDocumentAttributeImageSize | tl.RawDocumentAttributeVideo,
|
||||
readonly attr2?: tl.RawDocumentAttributeImageSize | tl.RawDocumentAttributeVideo | undefined,
|
||||
) {
|
||||
super(doc)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ export class Video extends RawDocument {
|
|||
constructor(
|
||||
doc: tl.RawDocument,
|
||||
readonly attr: tl.RawDocumentAttributeVideo | tl.RawDocumentAttributeImageSize,
|
||||
readonly media?: tl.RawMessageMediaDocument,
|
||||
readonly media?: tl.RawMessageMediaDocument | undefined,
|
||||
) {
|
||||
super(doc)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ export type InputMessageId = { chatId: InputPeerLike, message: number } | { mess
|
|||
export type OmitInputMessageId<T> = Omit<T, 'chatId' | 'message'>
|
||||
|
||||
/** @internal */
|
||||
export function normalizeInputMessageId(id: InputMessageId) {
|
||||
export function normalizeInputMessageId(id: InputMessageId): {
|
||||
chatId: InputPeerLike
|
||||
message: number
|
||||
} {
|
||||
if ('chatId' in id) return id
|
||||
|
||||
return { chatId: id.message.chat.inputPeer, message: id.message.id }
|
||||
|
|
|
@ -67,7 +67,7 @@ export class MessageEntity {
|
|||
*
|
||||
* Since JS strings are UTF-16, you can use this as-is
|
||||
*/
|
||||
get offset() {
|
||||
get offset(): number {
|
||||
return this.raw.offset
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ export class MessageEntity {
|
|||
*
|
||||
* Since JS strings are UTF-16, you can use this as-is
|
||||
*/
|
||||
get length() {
|
||||
get length(): number {
|
||||
return this.raw.length
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { makeInspectable } from '../../utils/inspectable.js'
|
|||
export class ChatColors {
|
||||
constructor(
|
||||
private readonly _peerId: number,
|
||||
readonly raw?: tl.RawPeerColor,
|
||||
readonly raw?: tl.RawPeerColor | undefined,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@ export class ChatInviteLink {
|
|||
|
||||
constructor(
|
||||
raw: tl.TypeExportedChatInvite,
|
||||
readonly _peers?: PeersIndex,
|
||||
readonly _peers?: PeersIndex | undefined,
|
||||
) {
|
||||
assertTypeIsNot('ChatInviteLink', raw, 'chatInvitePublicJoinRequests')
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export class ForumTopic {
|
|||
constructor(
|
||||
readonly raw: tl.RawForumTopic,
|
||||
readonly _peers: PeersIndex,
|
||||
readonly _messages?: Map<number, tl.TypeMessage>,
|
||||
readonly _messages?: Map<number, tl.TypeMessage> | undefined,
|
||||
) {}
|
||||
|
||||
static parseTlForumTopics(topics: tl.messages.TypeForumTopics): ForumTopic[] {
|
||||
|
|
|
@ -14,7 +14,7 @@ import { StoriesStealthMode } from './stealth-mode.js'
|
|||
*/
|
||||
export class AllStories {
|
||||
/** Peers index */
|
||||
readonly _peers
|
||||
readonly _peers: PeersIndex
|
||||
constructor(
|
||||
/** Raw TL object */
|
||||
readonly raw: tl.stories.RawAllStories,
|
||||
|
|
|
@ -18,7 +18,7 @@ import { normalizeInputReaction } from '../../reactions/index.js'
|
|||
export class StoryElement {
|
||||
private constructor(private _position: tl.RawMediaAreaCoordinates) {}
|
||||
|
||||
static at(params: { x: number, y: number, width: number, height: number, rotation?: number }) {
|
||||
static at(params: { x: number, y: number, width: number, height: number, rotation?: number }): StoryElement {
|
||||
return new StoryElement({
|
||||
_: 'mediaAreaCoordinates',
|
||||
x: params.x,
|
||||
|
|
|
@ -3,6 +3,9 @@ import { tl } from '@mtcute/tl'
|
|||
import { MtArgumentError } from '../../types/errors.js'
|
||||
import type { MaybePromise } from '../../types/utils.js'
|
||||
import { assertNever } from '../../types/utils.js'
|
||||
import type {
|
||||
Logger,
|
||||
} from '../../utils/index.js'
|
||||
import {
|
||||
AsyncLock,
|
||||
ConditionVariable,
|
||||
|
@ -89,26 +92,32 @@ const UPDATES_TOO_LONG = { _: 'updatesTooLong' } as const
|
|||
// todo: fix docs
|
||||
export class UpdatesManager {
|
||||
updatesLoopActive = false
|
||||
updatesLoopCv = new ConditionVariable()
|
||||
updatesLoopCv: ConditionVariable = new ConditionVariable()
|
||||
|
||||
postponedTimer = new EarlyTimer()
|
||||
postponedTimer: EarlyTimer = new EarlyTimer()
|
||||
hasTimedoutPostponed = false
|
||||
|
||||
pendingUpdateContainers = new SortedLinkedList<PendingUpdateContainer>((a, b) => a.seqStart - b.seqStart)
|
||||
pendingPtsUpdates = new SortedLinkedList<PendingUpdate>((a, b) => a.ptsBefore! - b.ptsBefore!)
|
||||
pendingPtsUpdatesPostponed = new SortedLinkedList<PendingUpdate>((a, b) => a.ptsBefore! - b.ptsBefore!)
|
||||
pendingQtsUpdates = new SortedLinkedList<PendingUpdate>((a, b) => a.qtsBefore! - b.qtsBefore!)
|
||||
pendingQtsUpdatesPostponed = new SortedLinkedList<PendingUpdate>((a, b) => a.qtsBefore! - b.qtsBefore!)
|
||||
pendingUnorderedUpdates = new Deque<PendingUpdate>()
|
||||
pendingUpdateContainers: SortedLinkedList<PendingUpdateContainer>
|
||||
= new SortedLinkedList((a, b) => a.seqStart - b.seqStart)
|
||||
|
||||
noDispatchEnabled
|
||||
pendingPtsUpdates: SortedLinkedList<PendingUpdate> = new SortedLinkedList((a, b) => a.ptsBefore! - b.ptsBefore!)
|
||||
pendingPtsUpdatesPostponed: SortedLinkedList<PendingUpdate>
|
||||
= new SortedLinkedList((a, b) => a.ptsBefore! - b.ptsBefore!)
|
||||
|
||||
pendingQtsUpdates: SortedLinkedList<PendingUpdate> = new SortedLinkedList((a, b) => a.qtsBefore! - b.qtsBefore!)
|
||||
pendingQtsUpdatesPostponed: SortedLinkedList<PendingUpdate>
|
||||
= new SortedLinkedList((a, b) => a.qtsBefore! - b.qtsBefore!)
|
||||
|
||||
pendingUnorderedUpdates: Deque<PendingUpdate> = new Deque()
|
||||
|
||||
noDispatchEnabled: boolean
|
||||
// channel id or 0 => msg id
|
||||
noDispatchMsg = new Map<number, Set<number>>()
|
||||
noDispatchMsg: Map<number, Set<number>> = new Map()
|
||||
// channel id or 0 => pts
|
||||
noDispatchPts = new Map<number, Set<number>>()
|
||||
noDispatchQts = new Set<number>()
|
||||
noDispatchPts: Map<number, Set<number>> = new Map()
|
||||
noDispatchQts: Set<number> = new Set()
|
||||
|
||||
lock = new AsyncLock()
|
||||
lock: AsyncLock = new AsyncLock()
|
||||
// rpsIncoming?: RpsMeter
|
||||
// rpsProcessing?: RpsMeter
|
||||
|
||||
|
@ -129,14 +138,14 @@ export class UpdatesManager {
|
|||
|
||||
// whether to catch up channels from the locally stored pts
|
||||
catchingUp = false
|
||||
catchUpOnStart
|
||||
catchUpOnStart: boolean
|
||||
|
||||
cpts = new Map<number, number>()
|
||||
cptsMod = new Map<number, number>()
|
||||
channelDiffTimeouts = new Map<number, NodeJS.Timeout>()
|
||||
channelsOpened = new Map<number, number>()
|
||||
cpts: Map<number, number> = new Map()
|
||||
cptsMod: Map<number, number> = new Map()
|
||||
channelDiffTimeouts: Map<number, NodeJS.Timeout> = new Map()
|
||||
channelsOpened: Map<number, number> = new Map()
|
||||
|
||||
log
|
||||
log: Logger
|
||||
private _handler: RawUpdateHandler = () => {}
|
||||
|
||||
private _onCatchingUp: (catchingUp: boolean) => void = () => {}
|
||||
|
@ -189,7 +198,7 @@ export class UpdatesManager {
|
|||
this._onCatchingUp = handler
|
||||
}
|
||||
|
||||
destroy() {
|
||||
destroy(): void {
|
||||
this.stopLoop()
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ export function encodeInlineMessageId(id: tl.TypeInputBotInlineMessageID): strin
|
|||
return getPlatform().base64Encode(writer.result(), true)
|
||||
}
|
||||
|
||||
export function normalizeInlineId(id: string | tl.TypeInputBotInlineMessageID) {
|
||||
export function normalizeInlineId(id: string | tl.TypeInputBotInlineMessageID): tl.TypeInputBotInlineMessageID {
|
||||
if (typeof id === 'string') {
|
||||
return parseInlineMessageId(id)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { assertNever } from '../../types/utils.js'
|
|||
import { MtInvalidPeerTypeError } from '../types/errors.js'
|
||||
import type { InputPeerLike } from '../types/peers/index.js'
|
||||
|
||||
export const INVITE_LINK_REGEX
|
||||
export const INVITE_LINK_REGEX: RegExp
|
||||
= /^(?:https?:\/\/)?(?:www\.)?t(?:elegram)?\.(?:org|me|dog)\/(?:joinchat\/|\+)([\w-]+)$/i
|
||||
|
||||
// helpers to convert result of `resolvePeer` function
|
||||
|
@ -145,7 +145,7 @@ export function inputPeerToPeer(inp: tl.TypeInputPeer): tl.TypePeer {
|
|||
}
|
||||
}
|
||||
|
||||
export function extractUsernames(obj: tl.RawUser | tl.RawChannel) {
|
||||
export function extractUsernames(obj: tl.RawUser | tl.RawChannel): string[] {
|
||||
if (obj.usernames?.length) return obj.usernames.map(x => x.username.toLowerCase())
|
||||
if (obj.username) return [obj.username.toLowerCase()]
|
||||
|
||||
|
|
|
@ -4,14 +4,15 @@ import type { ITelegramClient } from '../client.types.js'
|
|||
type Resolve<T> = (value: T | PromiseLike<T>) => void
|
||||
type Reject = (err?: unknown) => void
|
||||
|
||||
type WaitersMap<K, U, T> = Map<K, [T, Resolve<U | null>, Reject][]>
|
||||
interface InternalState<K, U, T> {
|
||||
waiters: WaitersMap<K, U, T>
|
||||
fetchingKeys: Set<K>
|
||||
type WaitersMap<U, T> = Map<string | number, [T, Resolve<U | null>, Reject][]>
|
||||
interface InternalState<U, T> {
|
||||
waiters: WaitersMap<U, T>
|
||||
fetchingKeys: Set<string | number>
|
||||
retryQueue: Deque<T>
|
||||
numRunning: number
|
||||
}
|
||||
|
||||
export type BatchedQuery<T, U> = (client: ITelegramClient, item: T) => Promise<U | null>
|
||||
// todo: should it be MtClient?
|
||||
|
||||
/**
|
||||
|
@ -23,7 +24,7 @@ interface InternalState<K, U, T> {
|
|||
* - "key" - unique identifier of the item, which should be deriveable from both input and output.
|
||||
* used for matching input and output items and deduplicating them.
|
||||
*/
|
||||
export function batchedQuery<T, U, K extends string | number>(params: {
|
||||
export function batchedQuery<T, U>(params: {
|
||||
/**
|
||||
* Fetcher function, taking an array of input items and returning an array of output items.
|
||||
*
|
||||
|
@ -33,9 +34,9 @@ export function batchedQuery<T, U, K extends string | number>(params: {
|
|||
fetch: (client: ITelegramClient, items: T[]) => Promise<U[]>
|
||||
|
||||
/** Key derivation function for input items */
|
||||
inputKey: (item: T, client: ITelegramClient) => K
|
||||
inputKey: (item: T, client: ITelegramClient) => string | number
|
||||
/** Key derivation function for output items */
|
||||
outputKey: (item: U, client: ITelegramClient) => K
|
||||
outputKey: (item: U, client: ITelegramClient) => string | number
|
||||
|
||||
/**
|
||||
* Maximum number of items to be passed to the `fetcher` function at once.
|
||||
|
@ -64,13 +65,13 @@ export function batchedQuery<T, U, K extends string | number>(params: {
|
|||
* or an array of items for which the query should be retried (waiters for other items will throw `err`).
|
||||
*/
|
||||
retrySingleOnError?: (items: T[], err: unknown) => boolean | T[]
|
||||
}): (client: ITelegramClient, item: T) => Promise<U | null> {
|
||||
}): BatchedQuery<T, U> {
|
||||
const { inputKey, outputKey, fetch, maxBatchSize = Infinity, maxConcurrent = 1, retrySingleOnError } = params
|
||||
|
||||
const symbol = Symbol('batchedQueryState')
|
||||
|
||||
function getState(client_: ITelegramClient) {
|
||||
const client = client_ as { [symbol]?: InternalState<K, U, T> }
|
||||
const client = client_ as { [symbol]?: InternalState<U, T> }
|
||||
|
||||
if (!client[symbol]) {
|
||||
client[symbol] = {
|
||||
|
@ -84,7 +85,7 @@ export function batchedQuery<T, U, K extends string | number>(params: {
|
|||
return client[symbol]
|
||||
}
|
||||
|
||||
function addWaiter(client: ITelegramClient, waiters: WaitersMap<K, U, T>, item: T) {
|
||||
function addWaiter(client: ITelegramClient, waiters: WaitersMap<U, T>, item: T) {
|
||||
const key = inputKey(item, client)
|
||||
|
||||
let arr = waiters.get(key)
|
||||
|
@ -99,7 +100,7 @@ export function batchedQuery<T, U, K extends string | number>(params: {
|
|||
})
|
||||
}
|
||||
|
||||
function popWaiters(waiters: WaitersMap<K, U, T>, key: K) {
|
||||
function popWaiters(waiters: WaitersMap<U, T>, key: string | number) {
|
||||
const arr = waiters.get(key)
|
||||
if (!arr) return []
|
||||
|
||||
|
@ -108,19 +109,19 @@ export function batchedQuery<T, U, K extends string | number>(params: {
|
|||
return arr
|
||||
}
|
||||
|
||||
function startLoops(client: ITelegramClient, state: InternalState<K, U, T>) {
|
||||
function startLoops(client: ITelegramClient, state: InternalState<U, T>) {
|
||||
for (let i = state.numRunning; i <= maxConcurrent; i++) {
|
||||
processPending(client, state)
|
||||
}
|
||||
}
|
||||
|
||||
function processPending(client: ITelegramClient, state: InternalState<K, U, T>) {
|
||||
function processPending(client: ITelegramClient, state: InternalState<U, T>) {
|
||||
const { waiters, fetchingKeys, retryQueue } = state
|
||||
|
||||
if (state.numRunning >= maxConcurrent) return
|
||||
|
||||
const request: T[] = []
|
||||
const requestKeys: K[] = []
|
||||
const requestKeys: (string | number)[] = []
|
||||
let isRetryRequest = false
|
||||
|
||||
if (retryQueue.length > 0) {
|
||||
|
@ -152,7 +153,7 @@ export function batchedQuery<T, U, K extends string | number>(params: {
|
|||
// eslint-disable-next-line ts/no-floating-promises
|
||||
fetch(client, request)
|
||||
.then((res) => {
|
||||
const receivedKeys = new Set<K>()
|
||||
const receivedKeys = new Set()
|
||||
|
||||
for (const it of res) {
|
||||
const key = outputKey(it, client)
|
||||
|
|
|
@ -24,7 +24,10 @@ export async function streamToBuffer(stream: ReadableStream<Uint8Array>): Promis
|
|||
return concatBuffers(chunks)
|
||||
}
|
||||
|
||||
export function createChunkedReader(stream: ReadableStream<Uint8Array>, chunkSize: number) {
|
||||
export function createChunkedReader(stream: ReadableStream<Uint8Array>, chunkSize: number): {
|
||||
ended: () => boolean
|
||||
read: () => Promise<Uint8Array | null>
|
||||
} {
|
||||
const reader = stream.getReader()
|
||||
const lock = new AsyncLock()
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import type { WorkerInvoker } from './invoker.js'
|
|||
|
||||
export class AppConfigManagerProxy implements PublicPart<AppConfigManager> {
|
||||
readonly get: AppConfigManager['get']
|
||||
readonly getField
|
||||
readonly getField: AppConfigManager['getField']
|
||||
|
||||
constructor(readonly invoker: WorkerInvoker) {
|
||||
const bind = invoker.makeBinder<AppConfigManager>('app-config')
|
||||
|
|
|
@ -57,7 +57,7 @@ export class WorkerInvoker {
|
|||
return this._invoke(target, method, args, false, abortSignal) as Promise<unknown>
|
||||
}
|
||||
|
||||
handleResult(msg: Extract<WorkerOutboundMessage, { type: 'result' }>) {
|
||||
handleResult(msg: Extract<WorkerOutboundMessage, { type: 'result' }>): void {
|
||||
const promise = this._pending.get(msg.id)
|
||||
if (!promise) return
|
||||
|
||||
|
|
|
@ -18,36 +18,36 @@ export interface TelegramWorkerPortOptions {
|
|||
}
|
||||
|
||||
export abstract class TelegramWorkerPort<Custom extends WorkerCustomMethods> implements ITelegramClient {
|
||||
readonly log
|
||||
readonly log: LogManager
|
||||
|
||||
private _connection
|
||||
private _invoker
|
||||
|
||||
readonly storage
|
||||
readonly appConfig
|
||||
readonly storage: TelegramStorageProxy
|
||||
readonly appConfig: AppConfigManagerProxy
|
||||
|
||||
// bound methods
|
||||
readonly prepare
|
||||
readonly prepare: ITelegramClient['prepare']
|
||||
private _connect
|
||||
readonly close
|
||||
readonly notifyLoggedIn
|
||||
readonly notifyLoggedOut
|
||||
readonly notifyChannelOpened
|
||||
readonly notifyChannelClosed
|
||||
readonly importSession
|
||||
readonly exportSession
|
||||
readonly handleClientUpdate
|
||||
readonly getApiCrenetials
|
||||
readonly getPoolSize
|
||||
readonly getPrimaryDcId
|
||||
readonly changePrimaryDc
|
||||
readonly computeSrpParams
|
||||
readonly computeNewPasswordHash
|
||||
readonly startUpdatesLoop
|
||||
readonly stopUpdatesLoop
|
||||
readonly close: ITelegramClient['close']
|
||||
readonly notifyLoggedIn: ITelegramClient['notifyLoggedIn']
|
||||
readonly notifyLoggedOut: ITelegramClient['notifyLoggedOut']
|
||||
readonly notifyChannelOpened: ITelegramClient['notifyChannelOpened']
|
||||
readonly notifyChannelClosed: ITelegramClient['notifyChannelClosed']
|
||||
readonly importSession: ITelegramClient['importSession']
|
||||
readonly exportSession: ITelegramClient['exportSession']
|
||||
readonly handleClientUpdate: ITelegramClient['handleClientUpdate']
|
||||
readonly getApiCrenetials: ITelegramClient['getApiCrenetials']
|
||||
readonly getPoolSize: ITelegramClient['getPoolSize']
|
||||
readonly getPrimaryDcId: ITelegramClient['getPrimaryDcId']
|
||||
readonly changePrimaryDc: ITelegramClient['changePrimaryDc']
|
||||
readonly computeSrpParams: ITelegramClient['computeSrpParams']
|
||||
readonly computeNewPasswordHash: ITelegramClient['computeNewPasswordHash']
|
||||
readonly startUpdatesLoop: ITelegramClient['startUpdatesLoop']
|
||||
readonly stopUpdatesLoop: ITelegramClient['stopUpdatesLoop']
|
||||
|
||||
private _abortController = new AbortController()
|
||||
readonly stopSignal = this._abortController.signal
|
||||
readonly stopSignal: AbortSignal = this._abortController.signal
|
||||
|
||||
constructor(readonly options: TelegramWorkerPortOptions) {
|
||||
this.log = new LogManager('worker')
|
||||
|
|
|
@ -60,12 +60,12 @@ class CurrentUserServiceProxy implements PublicPart<CurrentUserService> {
|
|||
}
|
||||
|
||||
class PeersServiceProxy implements PublicPart<PeersService> {
|
||||
readonly updatePeersFrom
|
||||
readonly store
|
||||
readonly getById
|
||||
readonly getByPhone
|
||||
readonly getByUsername
|
||||
readonly getCompleteById
|
||||
readonly updatePeersFrom: PeersService['updatePeersFrom']
|
||||
readonly store: PeersService['store']
|
||||
readonly getById: PeersService['getById']
|
||||
readonly getByPhone: PeersService['getByPhone']
|
||||
readonly getByUsername: PeersService['getByUsername']
|
||||
readonly getCompleteById: PeersService['getCompleteById']
|
||||
|
||||
constructor(private _invoker: WorkerInvoker) {
|
||||
const bind = this._invoker.makeBinder<PeersService>('storage-peers')
|
||||
|
@ -80,10 +80,10 @@ class PeersServiceProxy implements PublicPart<PeersService> {
|
|||
}
|
||||
|
||||
export class TelegramStorageProxy implements PublicPart<TelegramStorageManager> {
|
||||
readonly self
|
||||
readonly peers
|
||||
readonly self: CurrentUserServiceProxy
|
||||
readonly peers: PeersServiceProxy
|
||||
|
||||
readonly clear
|
||||
readonly clear: TelegramStorageManager['clear']
|
||||
|
||||
constructor(private _invoker: WorkerInvoker) {
|
||||
const bind = this._invoker.makeBinder<TelegramStorageManager>('storage')
|
||||
|
|
|
@ -24,7 +24,7 @@ export abstract class TelegramWorker<T extends WorkerCustomMethods> {
|
|||
|
||||
abstract registerWorker(handler: WorkerMessageHandler): RespondFn
|
||||
|
||||
readonly pendingAborts = new Map<number, AbortController>()
|
||||
readonly pendingAborts: Map<number, AbortController> = new Map()
|
||||
|
||||
constructor(readonly params: TelegramWorkerOptions<T>) {
|
||||
this.broadcast = this.registerWorker((message, respond) => {
|
||||
|
|
|
@ -20,9 +20,8 @@ import type { SessionConnection } from './session-connection.js'
|
|||
// see https://core.telegram.org/mtproto/security_guidelines
|
||||
// const DH_SAFETY_RANGE = bigInt[2].pow(2048 - 64)
|
||||
const DH_SAFETY_RANGE = 2n ** (2048n - 64n)
|
||||
const KNOWN_DH_PRIME
|
||||
|
||||
= 0xC71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5Bn
|
||||
// eslint-disable-next-line style/max-len
|
||||
const KNOWN_DH_PRIME = 0xC71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5Bn
|
||||
const TWO_POW_2047 = 2n ** 2047n
|
||||
const TWO_POW_2048 = 2n ** 2048n
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ export class MtClient extends EventEmitter {
|
|||
/** TL writers map used by the client */
|
||||
readonly _writerMap: TlWriterMap
|
||||
|
||||
readonly _config = new ConfigManager(async () => {
|
||||
readonly _config: ConfigManager = new ConfigManager(async () => {
|
||||
const res = await this.call({ _: 'help.getConfig' })
|
||||
|
||||
if (isTlRpcError(res)) throw new Error(`Failed to get config: ${res.errorMessage}`)
|
||||
|
@ -313,7 +313,7 @@ export class MtClient extends EventEmitter {
|
|||
*
|
||||
* Call {@link connect} to actually connect.
|
||||
*/
|
||||
prepare() {
|
||||
prepare(): Promise<void> {
|
||||
return this._prepare.run()
|
||||
}
|
||||
|
||||
|
|
|
@ -92,40 +92,40 @@ export type PendingMessage =
|
|||
* all the relevant state
|
||||
*/
|
||||
export class MtprotoSession {
|
||||
_sessionId = randomLong()
|
||||
_sessionId: Long = randomLong()
|
||||
|
||||
_authKey: AuthKey
|
||||
_authKeyTemp: AuthKey
|
||||
_authKeyTempSecondary: AuthKey
|
||||
|
||||
_timeOffset = 0
|
||||
_lastMessageId = Long.ZERO
|
||||
_lastMessageId: Long = Long.ZERO
|
||||
_seqNo = 0
|
||||
|
||||
/// state ///
|
||||
// recent msg ids
|
||||
recentOutgoingMsgIds = new LruSet<Long>(1000, true)
|
||||
recentIncomingMsgIds = new LruSet<Long>(1000, true)
|
||||
recentOutgoingMsgIds: LruSet<Long> = new LruSet(1000, true)
|
||||
recentIncomingMsgIds: LruSet<Long> = new LruSet(1000, true)
|
||||
|
||||
// queues
|
||||
queuedRpc = new Deque<PendingRpc>()
|
||||
queuedRpc: Deque<PendingRpc> = new Deque()
|
||||
queuedAcks: Long[] = []
|
||||
queuedStateReq: Long[] = []
|
||||
queuedResendReq: Long[] = []
|
||||
queuedCancelReq: Long[] = []
|
||||
getStateSchedule = new SortedArray<PendingRpc>([], (a, b) => a.getState! - b.getState!)
|
||||
getStateSchedule: SortedArray<PendingRpc> = new SortedArray<PendingRpc>([], (a, b) => a.getState! - b.getState!)
|
||||
|
||||
chains = new Map<string | number, Long>()
|
||||
chainsPendingFails = new Map<string | number, SortedArray<PendingRpc>>()
|
||||
chains: Map<string | number, Long> = new Map()
|
||||
chainsPendingFails: Map<string | number, SortedArray<PendingRpc>> = new Map()
|
||||
|
||||
// requests info
|
||||
pendingMessages = new LongMap<PendingMessage>()
|
||||
destroySessionIdToMsgId = new LongMap<Long>()
|
||||
pendingMessages: LongMap<PendingMessage> = new LongMap()
|
||||
destroySessionIdToMsgId: LongMap<Long> = new LongMap()
|
||||
|
||||
lastPingRtt = Number.NaN
|
||||
lastPingRtt: number = Number.NaN
|
||||
lastPingTime = 0
|
||||
lastPingMsgId = Long.ZERO
|
||||
lastSessionCreatedUid = Long.ZERO
|
||||
lastPingMsgId: Long = Long.ZERO
|
||||
lastSessionCreatedUid: Long = Long.ZERO
|
||||
|
||||
initConnectionCalled = false
|
||||
authorizationPending = false
|
||||
|
@ -176,7 +176,7 @@ export class MtprotoSession {
|
|||
this._authKeyTempSecondary.reset()
|
||||
}
|
||||
|
||||
updateTimeOffset(offset: number) {
|
||||
updateTimeOffset(offset: number): void {
|
||||
this.log.debug('time offset updated: %d', offset)
|
||||
this._timeOffset = offset
|
||||
// lastMessageId was generated with (potentially) wrong time
|
||||
|
@ -330,7 +330,7 @@ export class MtprotoSession {
|
|||
return messageId
|
||||
}
|
||||
|
||||
onTransportFlood(callback: () => void) {
|
||||
onTransportFlood(callback: () => void): number | undefined {
|
||||
if (this.current429Timeout) return // already waiting
|
||||
|
||||
// all active queries must be resent after a timeout
|
||||
|
|
|
@ -32,7 +32,7 @@ export class MultiSessionConnection extends EventEmitter {
|
|||
|
||||
protected _connections: SessionConnection[] = []
|
||||
|
||||
setCount(count: number, connect = this.params.isMainConnection): void {
|
||||
setCount(count: number, connect: boolean = this.params.isMainConnection): void {
|
||||
this._count = count
|
||||
|
||||
this._updateConnections(connect)
|
||||
|
|
|
@ -456,7 +456,7 @@ export class DcConnectionManager {
|
|||
this.main.setCount(count)
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
async destroy(): Promise<void> {
|
||||
await this.main.destroy()
|
||||
await this.upload.destroy()
|
||||
await this.download.destroy()
|
||||
|
@ -469,15 +469,15 @@ export class DcConnectionManager {
|
|||
* Class that manages all connections to Telegram servers.
|
||||
*/
|
||||
export class NetworkManager {
|
||||
readonly _log
|
||||
readonly _storage
|
||||
readonly _log: Logger
|
||||
readonly _storage: StorageManager
|
||||
|
||||
readonly _initConnectionParams: tl.RawInitConnectionRequest
|
||||
readonly _transportFactory: TransportFactory
|
||||
readonly _reconnectionStrategy: ReconnectionStrategy<PersistentConnectionParams>
|
||||
readonly _connectionCount: ConnectionCountDelegate
|
||||
|
||||
protected readonly _dcConnections = new Map<number, DcConnectionManager>()
|
||||
protected readonly _dcConnections: Map<number, DcConnectionManager> = new Map()
|
||||
protected _primaryDc?: DcConnectionManager
|
||||
|
||||
private _updateHandler: (upd: tl.TypeUpdates, fromClient: boolean) => void
|
||||
|
@ -866,7 +866,7 @@ export class NetworkManager {
|
|||
}
|
||||
}
|
||||
|
||||
getPoolSize(kind: ConnectionKind, dcId?: number) {
|
||||
getPoolSize(kind: ConnectionKind, dcId?: number): number {
|
||||
const dc = dcId ? this._dcConnections.get(dcId) : this._primaryDc
|
||||
|
||||
if (!dc) {
|
||||
|
@ -882,7 +882,7 @@ export class NetworkManager {
|
|||
return dc[kind].getPoolSize()
|
||||
}
|
||||
|
||||
getPrimaryDcId() {
|
||||
getPrimaryDcId(): number {
|
||||
if (!this._primaryDc) throw new MtcuteError('Not connected to any DC')
|
||||
|
||||
return this._primaryDc.dcId
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { mtp } from '@mtcute/tl'
|
|||
export class ServerSaltManager {
|
||||
private _futureSalts: mtp.RawMt_future_salt[] = []
|
||||
|
||||
currentSalt = Long.ZERO
|
||||
currentSalt: Long = Long.ZERO
|
||||
|
||||
isFetching = false
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
this.emit('error', error)
|
||||
}
|
||||
|
||||
protected onConnectionUsable() {
|
||||
protected onConnectionUsable(): void {
|
||||
super.onConnectionUsable()
|
||||
|
||||
if (this.params.withUpdates) {
|
||||
|
@ -1499,7 +1499,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
}
|
||||
}
|
||||
|
||||
protected _onInactivityTimeout() {
|
||||
protected _onInactivityTimeout(): void {
|
||||
// we should send all pending acks and other service messages
|
||||
// before dropping the connection
|
||||
// additionally, if we are still waiting for some rpc results,
|
||||
|
|
|
@ -62,7 +62,7 @@ export class PaddedIntermediatePacketCodec extends IntermediatePacketCodec {
|
|||
}
|
||||
|
||||
private _crypto!: ICryptoProvider
|
||||
setup?(crypto: ICryptoProvider) {
|
||||
setup?(crypto: ICryptoProvider): void {
|
||||
this._crypto = crypto
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { concatBuffers } from '../../utils/index.js'
|
|||
* multiple transport packets.
|
||||
*/
|
||||
export abstract class StreamedCodec extends EventEmitter {
|
||||
protected _stream = new Uint8Array(0)
|
||||
protected _stream: Uint8Array = new Uint8Array(0)
|
||||
|
||||
/**
|
||||
* Should return whether a full packet is available
|
||||
|
|
|
@ -11,5 +11,5 @@ export class MemoryStorageDriver implements IStorageDriver {
|
|||
return this.states.get(repo) as T
|
||||
}
|
||||
|
||||
load() {}
|
||||
load(): void {}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ export { MemoryStorageDriver } from './driver.js'
|
|||
* or if you know exactly what you're doing.
|
||||
*/
|
||||
export class MemoryStorage implements IMtStorageProvider, ITelegramStorageProvider {
|
||||
readonly driver = new MemoryStorageDriver()
|
||||
readonly kv = new MemoryKeyValueRepository(this.driver)
|
||||
readonly authKeys = new MemoryAuthKeysRepository(this.driver)
|
||||
readonly peers = new MemoryPeersRepository(this.driver)
|
||||
readonly refMessages = new MemoryRefMessagesRepository(this.driver)
|
||||
readonly driver: MemoryStorageDriver = new MemoryStorageDriver()
|
||||
readonly kv: MemoryKeyValueRepository = new MemoryKeyValueRepository(this.driver)
|
||||
readonly authKeys: MemoryAuthKeysRepository = new MemoryAuthKeysRepository(this.driver)
|
||||
readonly peers: MemoryPeersRepository = new MemoryPeersRepository(this.driver)
|
||||
readonly refMessages: MemoryRefMessagesRepository = new MemoryRefMessagesRepository(this.driver)
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ interface AuthKeysState {
|
|||
}
|
||||
|
||||
export class MemoryAuthKeysRepository implements IAuthKeysRepository {
|
||||
readonly state
|
||||
readonly state: AuthKeysState
|
||||
constructor(readonly _driver: MemoryStorageDriver) {
|
||||
this.state = this._driver.getState<AuthKeysState>('authKeys', () => ({
|
||||
this.state = this._driver.getState('authKeys', () => ({
|
||||
authKeys: new Map(),
|
||||
authKeysTemp: new Map(),
|
||||
authKeysTempExpiry: new Map(),
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { IKeyValueRepository } from '../../repository/key-value.js'
|
|||
import type { MemoryStorageDriver } from '../driver.js'
|
||||
|
||||
export class MemoryKeyValueRepository implements IKeyValueRepository {
|
||||
readonly state
|
||||
readonly state: Map<string, Uint8Array>
|
||||
constructor(readonly _driver: MemoryStorageDriver) {
|
||||
this.state = this._driver.getState<Map<string, Uint8Array>>('kv', () => new Map())
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ interface PeersState {
|
|||
}
|
||||
|
||||
export class MemoryPeersRepository implements IPeersRepository {
|
||||
readonly state
|
||||
readonly state: PeersState
|
||||
constructor(readonly _driver: MemoryStorageDriver) {
|
||||
this.state = this._driver.getState<PeersState>('peers', () => ({
|
||||
this.state = this._driver.getState('peers', () => ({
|
||||
entities: new Map(),
|
||||
usernameIndex: new Map(),
|
||||
phoneIndex: new Map(),
|
||||
|
|
|
@ -6,9 +6,9 @@ interface RefMessagesState {
|
|||
}
|
||||
|
||||
export class MemoryRefMessagesRepository implements IReferenceMessagesRepository {
|
||||
readonly state
|
||||
readonly state: RefMessagesState
|
||||
constructor(readonly _driver: MemoryStorageDriver) {
|
||||
this.state = this._driver.getState<RefMessagesState>('refMessages', () => ({
|
||||
this.state = this._driver.getState('refMessages', () => ({
|
||||
refs: new Map(),
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ export { BaseSqliteStorageDriver }
|
|||
export * from './types.js'
|
||||
|
||||
export class BaseSqliteStorage implements IMtStorageProvider, ITelegramStorageProvider {
|
||||
readonly authKeys
|
||||
readonly kv
|
||||
readonly refMessages
|
||||
readonly peers
|
||||
readonly authKeys: SqliteAuthKeysRepository
|
||||
readonly kv: SqliteKeyValueRepository
|
||||
readonly refMessages: SqliteRefMessagesRepository
|
||||
readonly peers: SqlitePeersRepository
|
||||
|
||||
constructor(readonly driver: BaseSqliteStorageDriver) {
|
||||
this.authKeys = new SqliteAuthKeysRepository(this.driver)
|
||||
|
|
|
@ -9,6 +9,7 @@ import { AuthKeysService } from './service/auth-keys.js'
|
|||
import type { ServiceOptions } from './service/base.js'
|
||||
import { DefaultDcsService } from './service/default-dcs.js'
|
||||
import { FutureSaltsService } from './service/future-salts.js'
|
||||
import type { IStorageDriver } from './driver.js'
|
||||
|
||||
interface StorageManagerOptions {
|
||||
provider: IMtStorageProvider
|
||||
|
@ -41,12 +42,12 @@ export interface StorageManagerExtraOptions {
|
|||
}
|
||||
|
||||
export class StorageManager {
|
||||
readonly provider
|
||||
readonly driver
|
||||
readonly log
|
||||
readonly dcs
|
||||
readonly salts
|
||||
readonly keys
|
||||
readonly provider: IMtStorageProvider
|
||||
readonly driver: IStorageDriver
|
||||
readonly log: Logger
|
||||
readonly dcs: DefaultDcsService
|
||||
readonly salts: FutureSaltsService
|
||||
readonly keys: AuthKeysService
|
||||
|
||||
constructor(readonly options: StorageManagerOptions & StorageManagerExtraOptions) {
|
||||
this.provider = this.options.provider
|
||||
|
@ -87,7 +88,7 @@ export class StorageManager {
|
|||
await this.driver.save?.()
|
||||
}
|
||||
|
||||
async clear(withAuthKeys = false) {
|
||||
async clear(withAuthKeys = false): Promise<void> {
|
||||
if (withAuthKeys) {
|
||||
await this.provider.authKeys.deleteAll()
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { ICryptoProvider } from './crypto/abstract.js'
|
|||
/**
|
||||
* Get the minimum number of bits required to represent a number
|
||||
*/
|
||||
export function bigIntBitLength(n: bigint) {
|
||||
export function bigIntBitLength(n: bigint): number {
|
||||
// not the fastest way, but at least not .toString(2) and not too complex
|
||||
// taken from: https://stackoverflow.com/a/76616288/22656950
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export function buffersEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|||
* @param start Start offset
|
||||
* @param end End offset
|
||||
*/
|
||||
export function cloneBuffer(buf: Uint8Array, start = 0, end = buf.length): Uint8Array {
|
||||
export function cloneBuffer(buf: Uint8Array, start = 0, end: number = buf.length): Uint8Array {
|
||||
const ret = new Uint8Array(end - start)
|
||||
ret.set(buf.subarray(start, end))
|
||||
|
||||
|
@ -67,7 +67,7 @@ export function dataViewFromBuffer(buf: Uint8Array): DataView {
|
|||
/**
|
||||
* Reverse a buffer (or a part of it) into a new buffer
|
||||
*/
|
||||
export function bufferToReversed(buf: Uint8Array, start = 0, end = buf.length): Uint8Array {
|
||||
export function bufferToReversed(buf: Uint8Array, start = 0, end: number = buf.length): Uint8Array {
|
||||
const len = end - start
|
||||
const ret = new Uint8Array(len)
|
||||
|
||||
|
|
|
@ -45,11 +45,11 @@ export interface ICryptoProvider {
|
|||
export abstract class BaseCryptoProvider {
|
||||
abstract randomFill(buf: Uint8Array): void
|
||||
|
||||
factorizePQ(pq: Uint8Array) {
|
||||
factorizePQ(pq: Uint8Array): [Uint8Array, Uint8Array] {
|
||||
return factorizePQSync(this as unknown as ICryptoProvider, pq)
|
||||
}
|
||||
|
||||
randomBytes(size: number) {
|
||||
randomBytes(size: number): Uint8Array {
|
||||
const buf = new Uint8Array(size)
|
||||
this.randomFill(buf)
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ export class Deque<T> {
|
|||
protected _capacity: number
|
||||
|
||||
constructor(
|
||||
readonly maxLength = Infinity,
|
||||
minCapacity = maxLength === Infinity ? MIN_INITIAL_CAPACITY : maxLength,
|
||||
readonly maxLength: number = Infinity,
|
||||
minCapacity: number = maxLength === Infinity ? MIN_INITIAL_CAPACITY : maxLength,
|
||||
) {
|
||||
let capacity = minCapacity
|
||||
|
||||
|
@ -51,7 +51,7 @@ export class Deque<T> {
|
|||
this._capacity = capacity
|
||||
}
|
||||
|
||||
protected _resize() {
|
||||
protected _resize(): void {
|
||||
const p = this._head
|
||||
const n = this._capacity
|
||||
const r = n - p // number of elements to the right of the head
|
||||
|
|
|
@ -39,7 +39,12 @@ export function throttle(func: () => void, delay: number): ThrottledFunction {
|
|||
return res
|
||||
}
|
||||
|
||||
export function asyncResettable<T extends(...args: any[]) => Promise<any>>(func: T) {
|
||||
export function asyncResettable<T extends(...args: any[]) => Promise<any>>(func: T): {
|
||||
run: T
|
||||
finished: () => boolean
|
||||
wait: () => Promise<any> | null
|
||||
reset: () => void
|
||||
} {
|
||||
let runningPromise: Promise<any> | null = null
|
||||
let finished = false
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import type { tl } from '@mtcute/tl'
|
|||
import { isPresent } from '../type-assertions.js'
|
||||
import { assertNever } from '../../types/utils.js'
|
||||
|
||||
import type { Deeplink } from './common.js'
|
||||
import { deeplinkBuilder } from './common.js'
|
||||
|
||||
/**
|
||||
|
@ -10,12 +11,12 @@ import { deeplinkBuilder } from './common.js'
|
|||
*
|
||||
* Used to link to bots with a start parameter
|
||||
*/
|
||||
export const botStart = deeplinkBuilder<{
|
||||
export const botStart: Deeplink<{
|
||||
/** Bot username */
|
||||
username: string
|
||||
/** Start parameter */
|
||||
parameter: string
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ username, parameter }) => ['resolve', { domain: username, start: parameter }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'resolve') return null
|
||||
|
@ -137,14 +138,14 @@ function parseBotAdmin(rights: string | null): BotAdminRight[] | undefined {
|
|||
* Note that the user is still free to choose which rights to grant, and
|
||||
* whether to grant them at all.
|
||||
*/
|
||||
export const botAddToGroup = deeplinkBuilder<{
|
||||
export const botAddToGroup: Deeplink<{
|
||||
/** Bot username */
|
||||
bot: string
|
||||
/** If specified, the client will call `/start parameter` on the bot once the bot has been added */
|
||||
parameter?: string
|
||||
/** Admin rights to request */
|
||||
admin?: BotAdminRight[]
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ bot, parameter, admin }) => [
|
||||
'resolve',
|
||||
{ domain: bot, startgroup: parameter ?? true, admin: normalizeBotAdmin(admin) },
|
||||
|
@ -193,12 +194,12 @@ export const botAddToGroup = deeplinkBuilder<{
|
|||
* Note that the user is still free to choose which rights to grant, and
|
||||
* whether to grant them at all.
|
||||
*/
|
||||
export const botAddToChannel = deeplinkBuilder<{
|
||||
export const botAddToChannel: Deeplink<{
|
||||
/** Bot username */
|
||||
bot: string
|
||||
/** Admin rights to request */
|
||||
admin?: BotAdminRight[]
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ bot, admin }) => [
|
||||
'resolve',
|
||||
{ domain: bot, startchannel: true, admin: normalizeBotAdmin(admin) },
|
||||
|
@ -240,12 +241,12 @@ export const botAddToChannel = deeplinkBuilder<{
|
|||
*
|
||||
* Used to share games.
|
||||
*/
|
||||
export const botGame = deeplinkBuilder<{
|
||||
export const botGame: Deeplink<{
|
||||
/** Bot username */
|
||||
bot: string
|
||||
/** Game short name */
|
||||
game: string
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ bot, game }) => ['resolve', { domain: bot, game }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'resolve') return null
|
||||
|
@ -280,14 +281,14 @@ export const botGame = deeplinkBuilder<{
|
|||
* and a single bot can offer multiple named web apps, distinguished by
|
||||
* their `short_name`.
|
||||
*/
|
||||
export const botWebApp = deeplinkBuilder<{
|
||||
export const botWebApp: Deeplink<{
|
||||
/** Bot username */
|
||||
bot: string
|
||||
/** App short name */
|
||||
app: string
|
||||
/** Parameter to be passed by the client to messages.requestAppWebView as `start_param` */
|
||||
parameter?: string
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ bot, app, parameter }) => ['resolve', { domain: bot, appname: app, startapp: parameter }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'resolve') return null
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { Deeplink } from './common.js'
|
||||
import { deeplinkBuilder } from './common.js'
|
||||
|
||||
/**
|
||||
|
@ -6,7 +7,7 @@ import { deeplinkBuilder } from './common.js'
|
|||
* Used to join video/voice chats in groups, and livestreams in channels.
|
||||
* Such links are generated using phone.exportGroupCallInvite.
|
||||
*/
|
||||
export const videoChat = deeplinkBuilder<{
|
||||
export const videoChat: Deeplink<{
|
||||
username: string
|
||||
/**
|
||||
* Invite hash exported if the `can_self_unmute` flag is set when calling `phone.exportGroupCallInvite`:
|
||||
|
@ -15,7 +16,7 @@ export const videoChat = deeplinkBuilder<{
|
|||
*/
|
||||
inviteHash?: string
|
||||
isLivestream?: boolean
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ username, inviteHash, isLivestream }) => [
|
||||
'resolve',
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { Deeplink } from './common.js'
|
||||
import { deeplinkBuilder } from './common.js'
|
||||
|
||||
/**
|
||||
|
@ -5,7 +6,7 @@ import { deeplinkBuilder } from './common.js'
|
|||
*
|
||||
* Used to invite users to private groups and channels
|
||||
*/
|
||||
export const chatInvite = deeplinkBuilder<{ hash: string }>({
|
||||
export const chatInvite: Deeplink<{ hash: string }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ hash }) => ['join', { invite: hash }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'join') return null
|
||||
|
@ -32,7 +33,7 @@ export const chatInvite = deeplinkBuilder<{ hash: string }>({
|
|||
/**
|
||||
* Chat folder links
|
||||
*/
|
||||
export const chatFolder = deeplinkBuilder<{ slug: string }>({
|
||||
export const chatFolder: Deeplink<{ slug: string }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ slug }) => ['addlist', { slug }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'addlist') return null
|
||||
|
@ -76,8 +77,7 @@ function parseMediaTimestamp(timestamp: string) {
|
|||
*
|
||||
* Note: `channelId` is a non-marked channel ID
|
||||
*/
|
||||
export const message = deeplinkBuilder<
|
||||
({ username: string } | { channelId: number }) & {
|
||||
export const message: Deeplink<({ username: string } | { channelId: number }) & {
|
||||
/** Message ID */
|
||||
id: number
|
||||
/** Thread ID */
|
||||
|
@ -101,7 +101,7 @@ export const message = deeplinkBuilder<
|
|||
*/
|
||||
single?: boolean
|
||||
}
|
||||
>({
|
||||
> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: (params) => {
|
||||
const common = {
|
||||
post: params.id,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { Deeplink } from './common.js'
|
||||
import { deeplinkBuilder } from './common.js'
|
||||
|
||||
/**
|
||||
|
@ -5,7 +6,7 @@ import { deeplinkBuilder } from './common.js'
|
|||
*
|
||||
* Used to share a prepared message and URL into a chosen chat's text field.
|
||||
*/
|
||||
export const share = deeplinkBuilder<{ url: string, text?: string }>({
|
||||
export const share: Deeplink<{ url: string, text?: string }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ url, text }) => ['msg_url', { url, text }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'msg_url') return null
|
||||
|
@ -35,7 +36,7 @@ export const share = deeplinkBuilder<{ url: string, text?: string }>({
|
|||
*
|
||||
* Used by users to boost channels, granting them the ability to post stories.
|
||||
*/
|
||||
export const boost = deeplinkBuilder<{ username: string } | { channelId: number }>({
|
||||
export const boost: Deeplink<{ username: string } | { channelId: number }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: (params) => {
|
||||
if ('username' in params) {
|
||||
return ['boost', { domain: params.username }]
|
||||
|
@ -86,7 +87,7 @@ export const boost = deeplinkBuilder<{ username: string } | { channelId: number
|
|||
/**
|
||||
* Link to a shared folder (chat list)
|
||||
*/
|
||||
export const folder = deeplinkBuilder<{ slug: string }>({
|
||||
export const folder: Deeplink<{ slug: string }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
// tg://addlist?slug=XXX
|
||||
internalBuild: ({ slug }) => ['addlist', { slug }],
|
||||
internalParse: (path, query) => {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import type { Deeplink } from './common.js'
|
||||
import { deeplinkBuilder } from './common.js'
|
||||
|
||||
/**
|
||||
* MTProxy links
|
||||
*/
|
||||
export const mtproxy = deeplinkBuilder<{
|
||||
export const mtproxy: Deeplink<{
|
||||
server: string
|
||||
port: number
|
||||
secret: string
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: params => ['proxy', params],
|
||||
externalBuild: params => ['proxy', params],
|
||||
internalParse: (path, query) => {
|
||||
|
@ -37,12 +38,12 @@ export const mtproxy = deeplinkBuilder<{
|
|||
/**
|
||||
* Socks5 proxy links
|
||||
*/
|
||||
export const socks5 = deeplinkBuilder<{
|
||||
export const socks5: Deeplink<{
|
||||
server: string
|
||||
port: number
|
||||
user?: string
|
||||
pass?: string
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: params => ['socks', params],
|
||||
externalBuild: params => ['socks', params],
|
||||
internalParse: (path, query) => {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { Deeplink } from './common.js'
|
||||
import { deeplinkBuilder } from './common.js'
|
||||
|
||||
/**
|
||||
|
@ -5,10 +6,10 @@ import { deeplinkBuilder } from './common.js'
|
|||
*
|
||||
* Used to import stickersets or custom emoji stickersets
|
||||
*/
|
||||
export const stickerset = deeplinkBuilder<{
|
||||
export const stickerset: Deeplink<{
|
||||
slug: string
|
||||
emoji?: boolean
|
||||
}>({
|
||||
}> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ slug, emoji }) => [emoji ? 'addemoji' : 'addstickers', { set: slug }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'addstickers' && path !== 'addemoji') return null
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { Deeplink } from './common.js'
|
||||
import { deeplinkBuilder } from './common.js'
|
||||
|
||||
/**
|
||||
|
@ -5,7 +6,7 @@ import { deeplinkBuilder } from './common.js'
|
|||
*
|
||||
* Used to link to public users, groups and channels
|
||||
*/
|
||||
export const publicUsername = deeplinkBuilder<{ username: string }>({
|
||||
export const publicUsername: Deeplink<{ username: string }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ username }) => ['resolve', { domain: username }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'resolve') return null
|
||||
|
@ -36,7 +37,7 @@ export const publicUsername = deeplinkBuilder<{ username: string }>({
|
|||
* and they have an expiration date, specified by the expires field of the exportedContactToken
|
||||
* constructor returned by contacts.exportContactToken.
|
||||
*/
|
||||
export const temporaryProfile = deeplinkBuilder<{ token: string }>({
|
||||
export const temporaryProfile: Deeplink<{ token: string }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ token }) => ['contact', { token }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'contact') return null
|
||||
|
@ -60,7 +61,7 @@ export const temporaryProfile = deeplinkBuilder<{ token: string }>({
|
|||
*
|
||||
* Used to link to public and private users by their phone number.
|
||||
*/
|
||||
export const phoneNumber = deeplinkBuilder<{ phone: string }>({
|
||||
export const phoneNumber: Deeplink<{ phone: string }> = /* #__PURE__ */ deeplinkBuilder({
|
||||
internalBuild: ({ phone }) => ['resolve', { phone }],
|
||||
internalParse: (path, query) => {
|
||||
if (path !== 'resolve') return null
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { tl } from '@mtcute/tl'
|
||||
|
||||
import type { ICorePlatform } from '../platform.js'
|
||||
import { getPlatform } from '../platform.js'
|
||||
|
||||
import { isTlRpcError } from './type-assertions.js'
|
||||
|
@ -127,11 +128,11 @@ export class Logger {
|
|||
this.mgr.handler(this.color, level, this.tag, this.getPrefix() + fmt, args)
|
||||
}
|
||||
|
||||
readonly error = this.log.bind(this, LogManager.ERROR)
|
||||
readonly warn = this.log.bind(this, LogManager.WARN)
|
||||
readonly info = this.log.bind(this, LogManager.INFO)
|
||||
readonly debug = this.log.bind(this, LogManager.DEBUG)
|
||||
readonly verbose = this.log.bind(this, LogManager.VERBOSE)
|
||||
readonly error: (fmt: string, ...args: unknown[]) => void = this.log.bind(this, LogManager.ERROR)
|
||||
readonly warn: (fmt: string, ...args: unknown[]) => void = this.log.bind(this, LogManager.WARN)
|
||||
readonly info: (fmt: string, ...args: unknown[]) => void = this.log.bind(this, LogManager.INFO)
|
||||
readonly debug: (fmt: string, ...args: unknown[]) => void = this.log.bind(this, LogManager.DEBUG)
|
||||
readonly verbose: (fmt: string, ...args: unknown[]) => void = this.log.bind(this, LogManager.VERBOSE)
|
||||
|
||||
/**
|
||||
* Create a {@link Logger} with the given tag
|
||||
|
@ -158,9 +159,9 @@ export class LogManager extends Logger {
|
|||
static DEBUG = 4
|
||||
static VERBOSE = 5
|
||||
|
||||
readonly platform
|
||||
readonly platform: ICorePlatform
|
||||
level: number
|
||||
handler
|
||||
handler: (color: number, level: number, tag: string, fmt: string, args: unknown[]) => void
|
||||
|
||||
constructor(tag = 'base') {
|
||||
// workaround because we cant pass this to super
|
||||
|
|
|
@ -159,23 +159,23 @@ export class LongSet {
|
|||
return this._set.size
|
||||
}
|
||||
|
||||
add(val: Long) {
|
||||
add(val: Long): void {
|
||||
this._set.add(longToFastString(val))
|
||||
}
|
||||
|
||||
delete(val: Long) {
|
||||
delete(val: Long): void {
|
||||
this._set.delete(longToFastString(val))
|
||||
}
|
||||
|
||||
has(val: Long) {
|
||||
has(val: Long): boolean {
|
||||
return this._set.has(longToFastString(val))
|
||||
}
|
||||
|
||||
clear() {
|
||||
clear(): void {
|
||||
this._set.clear()
|
||||
}
|
||||
|
||||
toArray() {
|
||||
toArray(): Long[] {
|
||||
const arr: Long[] = []
|
||||
|
||||
for (const v of this._set) {
|
||||
|
|
|
@ -33,12 +33,12 @@ export class LruSet<T extends string | number | Long> {
|
|||
this._set = forLong ? new LongSet() : new Set()
|
||||
}
|
||||
|
||||
clear() {
|
||||
clear(): void {
|
||||
this._first = this._last = undefined
|
||||
this._set.clear()
|
||||
}
|
||||
|
||||
add(val: T) {
|
||||
add(val: T): void {
|
||||
if (this._set.has(val as any)) return
|
||||
|
||||
if (!this._first) this._first = { v: val }
|
||||
|
@ -59,7 +59,7 @@ export class LruSet<T extends string | number | Long> {
|
|||
}
|
||||
}
|
||||
|
||||
has(val: T) {
|
||||
has(val: T): boolean {
|
||||
return this._set.has(val as any)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export interface UserConfigPersisted {
|
|||
apiHash: string
|
||||
}
|
||||
|
||||
export function getConfigFilePath() {
|
||||
export function getConfigFilePath(): string {
|
||||
switch (process.platform) {
|
||||
case 'linux':
|
||||
return path.join(homedir(), '.local', 'share', 'mtcute-create.json')
|
||||
|
@ -35,7 +35,7 @@ export async function readConfig(): Promise<UserConfigPersisted | null> {
|
|||
}
|
||||
}
|
||||
|
||||
export async function writeConfig(config: UserConfigPersisted) {
|
||||
export async function writeConfig(config: UserConfigPersisted): Promise<void> {
|
||||
const filePath = getConfigFilePath()
|
||||
|
||||
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
||||
|
|
|
@ -11,7 +11,7 @@ export interface DependenciesList {
|
|||
devDepdenencies: string[]
|
||||
}
|
||||
|
||||
export function buildDependenciesList(config: UserConfig) {
|
||||
export function buildDependenciesList(config: UserConfig): DependenciesList {
|
||||
const dependencies = []
|
||||
const devDepdenencies = []
|
||||
|
||||
|
@ -57,7 +57,7 @@ export function buildDependenciesList(config: UserConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function installDependencies(cwd: string, config: UserConfig) {
|
||||
export async function installDependencies(cwd: string, config: UserConfig): Promise<void> {
|
||||
const { dependencies, devDepdenencies } = buildDependenciesList(config)
|
||||
|
||||
if (config.packageManager === PackageManager.Deno) {
|
||||
|
|
|
@ -85,7 +85,7 @@ export function getInstallCommand(params: { mgr: PackageManager, packages: strin
|
|||
return exec
|
||||
}
|
||||
|
||||
export function getExecCommand(mgr: PackageManager, ...cmd: string[]) {
|
||||
export function getExecCommand(mgr: PackageManager, ...cmd: string[]): string[] {
|
||||
switch (mgr) {
|
||||
case PackageManager.Npm:
|
||||
return ['npx', ...cmd]
|
||||
|
@ -100,7 +100,7 @@ export function getExecCommand(mgr: PackageManager, ...cmd: string[]) {
|
|||
}
|
||||
}
|
||||
|
||||
export function packageManagerToRuntime(mgr: PackageManager) {
|
||||
export function packageManagerToRuntime(mgr: PackageManager): 'node' | 'bun' | 'deno' {
|
||||
switch (mgr) {
|
||||
case PackageManager.Npm:
|
||||
case PackageManager.Yarn:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as colors from 'colorette'
|
||||
import { spawn } from 'cross-spawn'
|
||||
|
||||
export function exec(cwd: string, ...cmd: string[]) {
|
||||
export function exec(cwd: string, ...cmd: string[]): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
console.log(`${colors.blue('$')} ${cmd.map(it => (it.includes(' ') ? JSON.stringify(it) : it)).join(' ')}`)
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ class WrappedDatabase implements ISqliteDatabase {
|
|||
export class SqliteStorageDriver extends BaseSqliteStorageDriver {
|
||||
constructor(
|
||||
readonly filename = ':memory:',
|
||||
readonly params?: SqliteStorageDriverOptions,
|
||||
readonly params?: SqliteStorageDriverOptions | undefined,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export { SqliteStorageDriver } from './driver.js'
|
|||
export class SqliteStorage extends BaseSqliteStorage {
|
||||
constructor(
|
||||
readonly filename = ':memory:',
|
||||
readonly params?: SqliteStorageDriverOptions,
|
||||
readonly params?: SqliteStorageDriverOptions | undefined,
|
||||
) {
|
||||
super(new SqliteStorageDriver(filename, params))
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ export class DenoCryptoProvider extends BaseCryptoProvider implements ICryptoPro
|
|||
return toUint8Array(gunzipSync(data))
|
||||
}
|
||||
|
||||
randomFill(buf: Uint8Array) {
|
||||
randomFill(buf: Uint8Array): void {
|
||||
crypto.getRandomValues(buf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,11 @@ import { Readable as NodeReadable } from 'node:stream'
|
|||
import type { UploadFileLike } from '@mtcute/core'
|
||||
import { extractFileName } from '@mtcute/core/utils.js'
|
||||
|
||||
export async function normalizeFile(file: UploadFileLike) {
|
||||
export async function normalizeFile(file: UploadFileLike): Promise<{
|
||||
file: UploadFileLike
|
||||
fileName?: string | undefined
|
||||
fileSize?: number
|
||||
} | null> {
|
||||
if (typeof file === 'string') {
|
||||
const fd = await Deno.open(file, { read: true })
|
||||
|
||||
|
|
|
@ -134,5 +134,5 @@ export abstract class BaseTcpTransport extends EventEmitter implements ITelegram
|
|||
}
|
||||
|
||||
export class TcpTransport extends BaseTcpTransport {
|
||||
_packetCodec = new IntermediatePacketCodec()
|
||||
_packetCodec: IntermediatePacketCodec = new IntermediatePacketCodec()
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { OmitInputMessageId, ParametersSkip1 } from '@mtcute/core'
|
||||
import type { Message, OmitInputMessageId, ParametersSkip1, Sticker } from '@mtcute/core'
|
||||
import { BusinessMessage } from '@mtcute/core'
|
||||
import type { TelegramClient } from '@mtcute/core/client.js'
|
||||
import type {
|
||||
|
@ -45,12 +45,12 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Get all custom emojis contained in this message (message group), if any */
|
||||
getCustomEmojis() {
|
||||
getCustomEmojis(): Promise<Sticker[]> {
|
||||
return this.client.getCustomEmojisFromMessages(this.messages)
|
||||
}
|
||||
|
||||
/** Send a text message to the same chat (and topic, if applicable) as a given message */
|
||||
answerText(...params: ParametersSkip1<TelegramClient['answerText']>) {
|
||||
answerText(...params: ParametersSkip1<TelegramClient['answerText']>): Promise<Message> {
|
||||
const [send, params_ = {}] = params
|
||||
params_.businessConnectionId = this.update.connectionId
|
||||
|
||||
|
@ -58,7 +58,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Send a media to the same chat (and topic, if applicable) as a given message */
|
||||
answerMedia(...params: ParametersSkip1<TelegramClient['answerMedia']>) {
|
||||
answerMedia(...params: ParametersSkip1<TelegramClient['answerMedia']>): Promise<Message> {
|
||||
const [send, params_ = {}] = params
|
||||
params_.businessConnectionId = this.update.connectionId
|
||||
|
||||
|
@ -66,7 +66,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Send a media group to the same chat (and topic, if applicable) as a given message */
|
||||
answerMediaGroup(...params: ParametersSkip1<TelegramClient['answerMediaGroup']>) {
|
||||
answerMediaGroup(...params: ParametersSkip1<TelegramClient['answerMediaGroup']>): Promise<Message[]> {
|
||||
const [send, params_ = {}] = params
|
||||
params_.businessConnectionId = this.update.connectionId
|
||||
|
||||
|
@ -74,7 +74,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Send a text message in reply to this message */
|
||||
replyText(...params: ParametersSkip1<TelegramClient['replyText']>) {
|
||||
replyText(...params: ParametersSkip1<TelegramClient['replyText']>): Promise<Message> {
|
||||
const [send, params_ = {}] = params
|
||||
params_.businessConnectionId = this.update.connectionId
|
||||
|
||||
|
@ -82,7 +82,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Send a media in reply to this message */
|
||||
replyMedia(...params: ParametersSkip1<TelegramClient['replyMedia']>) {
|
||||
replyMedia(...params: ParametersSkip1<TelegramClient['replyMedia']>): Promise<Message> {
|
||||
const [send, params_ = {}] = params
|
||||
params_.businessConnectionId = this.update.connectionId
|
||||
|
||||
|
@ -90,7 +90,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Send a media group in reply to this message */
|
||||
replyMediaGroup(...params: ParametersSkip1<TelegramClient['replyMediaGroup']>) {
|
||||
replyMediaGroup(...params: ParametersSkip1<TelegramClient['replyMediaGroup']>): Promise<Message[]> {
|
||||
const [send, params_ = {}] = params
|
||||
params_.businessConnectionId = this.update.connectionId
|
||||
|
||||
|
@ -98,28 +98,28 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Send a text message in reply to this message */
|
||||
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]) {
|
||||
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]): Promise<Message> {
|
||||
params.businessConnectionId = this.update.connectionId
|
||||
|
||||
return this.client.quoteWithText(this, params)
|
||||
}
|
||||
|
||||
/** Send a media in reply to this message */
|
||||
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]) {
|
||||
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]): Promise<Message> {
|
||||
params.businessConnectionId = this.update.connectionId
|
||||
|
||||
return this.client.quoteWithMedia(this, params)
|
||||
}
|
||||
|
||||
/** Send a media group in reply to this message */
|
||||
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]) {
|
||||
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]): Promise<Message[]> {
|
||||
params.businessConnectionId = this.update.connectionId
|
||||
|
||||
return this.client.quoteWithMediaGroup(this, params)
|
||||
}
|
||||
|
||||
/** Delete this message (message group) */
|
||||
delete(params?: DeleteMessagesParams) {
|
||||
delete(params?: DeleteMessagesParams): Promise<void> {
|
||||
return this.client.deleteMessagesById(
|
||||
this.chat.inputPeer,
|
||||
this.messages.map(it => it.id),
|
||||
|
@ -128,7 +128,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Pin this message */
|
||||
pin(params?: OmitInputMessageId<Parameters<TelegramClient['pinMessage']>[0]>) {
|
||||
pin(params?: OmitInputMessageId<Parameters<TelegramClient['pinMessage']>[0]>): Promise<Message | null> {
|
||||
return this.client.pinMessage({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
@ -137,7 +137,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Unpin this message */
|
||||
unpin() {
|
||||
unpin(): Promise<void> {
|
||||
return this.client.unpinMessage({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
@ -145,7 +145,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Edit this message */
|
||||
edit(params: OmitInputMessageId<Parameters<TelegramClient['editMessage']>[0]>) {
|
||||
edit(params: OmitInputMessageId<Parameters<TelegramClient['editMessage']>[0]>): Promise<Message> {
|
||||
return this.client.editMessage({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
@ -154,7 +154,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Forward this message (message group) */
|
||||
forwardTo(params: ForwardMessageOptions) {
|
||||
forwardTo(params: ForwardMessageOptions): Promise<Message[]> {
|
||||
return this.client.forwardMessagesById({
|
||||
fromChatId: this.chat.inputPeer,
|
||||
messages: this.messages.map(it => it.id),
|
||||
|
@ -163,7 +163,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** Send a copy of this message (message group) */
|
||||
copy(params: SendCopyParams & SendCopyGroupParams) {
|
||||
copy(params: SendCopyParams & SendCopyGroupParams): Promise<Message | Message[]> {
|
||||
if (this.isMessageGroup) {
|
||||
return this.client.sendCopyGroup({
|
||||
messages: this.messages,
|
||||
|
@ -178,7 +178,7 @@ export class BusinessMessageContext extends BusinessMessage implements UpdateCon
|
|||
}
|
||||
|
||||
/** React to this message */
|
||||
react(params: OmitInputMessageId<Parameters<TelegramClient['sendReaction']>[0]>) {
|
||||
react(params: OmitInputMessageId<Parameters<TelegramClient['sendReaction']>[0]>): Promise<Message | null> {
|
||||
return this.client.sendReaction({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
|
|
@ -20,7 +20,7 @@ export class CallbackQueryContext extends CallbackQuery implements UpdateContext
|
|||
}
|
||||
|
||||
/** Answer to this callback query */
|
||||
answer(params: Parameters<TelegramClient['answerCallbackQuery']>[1]) {
|
||||
answer(params: Parameters<TelegramClient['answerCallbackQuery']>[1]): Promise<void> {
|
||||
return this.client.answerCallbackQuery(this.id, params)
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ export class CallbackQueryContext extends CallbackQuery implements UpdateContext
|
|||
/**
|
||||
* Edit the message that contained the callback button that was clicked.
|
||||
*/
|
||||
async editMessage(params: Omit<Parameters<TelegramClient['editInlineMessage']>[0], 'messageId'>) {
|
||||
async editMessage(params: Omit<Parameters<TelegramClient['editInlineMessage']>[0], 'messageId'>): Promise<Message> {
|
||||
return this.client.editMessage({
|
||||
chatId: this.raw.peer,
|
||||
message: this.raw.msgId,
|
||||
|
@ -48,7 +48,9 @@ export class CallbackQueryContext extends CallbackQuery implements UpdateContext
|
|||
/**
|
||||
* Shortcut for getting the message and editing it.
|
||||
*/
|
||||
async editMessageWith(handler: (msg: Message) => MaybePromise<Parameters<CallbackQueryContext['editMessage']>[0]>) {
|
||||
async editMessageWith(
|
||||
handler: (msg: Message) => MaybePromise<Parameters<CallbackQueryContext['editMessage']>[0]>,
|
||||
): Promise<Message | undefined> {
|
||||
const msg = await this.getMessage()
|
||||
if (!msg) return
|
||||
|
||||
|
@ -75,14 +77,14 @@ export class InlineCallbackQueryContext extends InlineCallbackQuery implements U
|
|||
}
|
||||
|
||||
/** Answer to this callback query */
|
||||
answer(params: Parameters<TelegramClient['answerCallbackQuery']>[1]) {
|
||||
answer(params: Parameters<TelegramClient['answerCallbackQuery']>[1]): Promise<void> {
|
||||
return this.client.answerCallbackQuery(this.id, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the message that contained the callback button that was clicked.
|
||||
*/
|
||||
async editMessage(params: Omit<Parameters<TelegramClient['editInlineMessage']>[0], 'messageId'>) {
|
||||
async editMessage(params: Omit<Parameters<TelegramClient['editInlineMessage']>[0], 'messageId'>): Promise<void> {
|
||||
return this.client.editInlineMessage({
|
||||
messageId: this.raw.msgId,
|
||||
...params,
|
||||
|
@ -108,14 +110,14 @@ export class BusinessCallbackQueryContext
|
|||
}
|
||||
|
||||
/** Answer to this callback query */
|
||||
answer(params: Parameters<TelegramClient['answerCallbackQuery']>[1]) {
|
||||
answer(params: Parameters<TelegramClient['answerCallbackQuery']>[1]): Promise<void> {
|
||||
return this.client.answerCallbackQuery(this.id, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the message that contained the callback button that was clicked.
|
||||
*/
|
||||
async editMessage(params: Omit<Parameters<TelegramClient['editInlineMessage']>[0], 'messageId'>) {
|
||||
async editMessage(params: Omit<Parameters<TelegramClient['editInlineMessage']>[0], 'messageId'>): Promise<Message> {
|
||||
return this.client.editMessage({
|
||||
message: this.message,
|
||||
businessConnectionId: this.connectionId,
|
||||
|
|
|
@ -20,7 +20,7 @@ export class InlineQueryContext extends InlineQuery implements UpdateContext<Inl
|
|||
}
|
||||
|
||||
/** Answer to this inline query */
|
||||
answer(...params: ParametersSkip1<TelegramClient['answerInlineQuery']>) {
|
||||
answer(...params: ParametersSkip1<TelegramClient['answerInlineQuery']>): Promise<void> {
|
||||
return this.client.answerInlineQuery(this.id, ...params)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import type { OmitInputMessageId, ParametersSkip1, Peer } from '@mtcute/core'
|
||||
import type { OmitInputMessageId, ParametersSkip1, Peer, Sticker } from '@mtcute/core'
|
||||
import { Message, MtPeerNotFoundError } from '@mtcute/core'
|
||||
import type { TelegramClient } from '@mtcute/core/client.js'
|
||||
import type { DeleteMessagesParams, ForwardMessageOptions, SendCopyGroupParams, SendCopyParams } from '@mtcute/core/methods.js'
|
||||
import type {
|
||||
DeleteMessagesParams,
|
||||
ForwardMessageOptions,
|
||||
SendCopyGroupParams,
|
||||
SendCopyParams,
|
||||
} from '@mtcute/core/methods.js'
|
||||
|
||||
import type { UpdateContext } from './base.js'
|
||||
|
||||
|
@ -63,82 +68,82 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
|||
}
|
||||
|
||||
/** Get a message that this message is a reply to */
|
||||
getReplyTo() {
|
||||
getReplyTo(): Promise<Message | null> {
|
||||
return this.client.getReplyTo(this)
|
||||
}
|
||||
|
||||
/** If this is a channel post, get its automatic forward in the discussion group */
|
||||
getDiscussionMessage() {
|
||||
getDiscussionMessage(): Promise<Message | null> {
|
||||
return this.client.getDiscussionMessage({ chatId: this.chat.inputPeer, message: this.id })
|
||||
}
|
||||
|
||||
/** Get all custom emojis contained in this message (message group), if any */
|
||||
getCustomEmojis() {
|
||||
getCustomEmojis(): Promise<Sticker[]> {
|
||||
return this.client.getCustomEmojisFromMessages(this.messages)
|
||||
}
|
||||
|
||||
/** Send a text message to the same chat (and topic, if applicable) as a given message */
|
||||
answerText(...params: ParametersSkip1<TelegramClient['answerText']>) {
|
||||
answerText(...params: ParametersSkip1<TelegramClient['answerText']>): Promise<Message> {
|
||||
return this.client.answerText(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a media to the same chat (and topic, if applicable) as a given message */
|
||||
answerMedia(...params: ParametersSkip1<TelegramClient['answerMedia']>) {
|
||||
answerMedia(...params: ParametersSkip1<TelegramClient['answerMedia']>): Promise<Message> {
|
||||
return this.client.answerMedia(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a media group to the same chat (and topic, if applicable) as a given message */
|
||||
answerMediaGroup(...params: ParametersSkip1<TelegramClient['answerMediaGroup']>) {
|
||||
answerMediaGroup(...params: ParametersSkip1<TelegramClient['answerMediaGroup']>): Promise<Message[]> {
|
||||
return this.client.answerMediaGroup(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a text message in reply to this message */
|
||||
replyText(...params: ParametersSkip1<TelegramClient['replyText']>) {
|
||||
replyText(...params: ParametersSkip1<TelegramClient['replyText']>): Promise<Message> {
|
||||
return this.client.replyText(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a media in reply to this message */
|
||||
replyMedia(...params: ParametersSkip1<TelegramClient['replyMedia']>) {
|
||||
replyMedia(...params: ParametersSkip1<TelegramClient['replyMedia']>): Promise<Message> {
|
||||
return this.client.replyMedia(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a media group in reply to this message */
|
||||
replyMediaGroup(...params: ParametersSkip1<TelegramClient['replyMediaGroup']>) {
|
||||
replyMediaGroup(...params: ParametersSkip1<TelegramClient['replyMediaGroup']>): Promise<Message[]> {
|
||||
return this.client.replyMediaGroup(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a text message in reply to this message */
|
||||
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]) {
|
||||
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]): Promise<Message> {
|
||||
return this.client.quoteWithText(this, params)
|
||||
}
|
||||
|
||||
/** Send a media in reply to this message */
|
||||
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]) {
|
||||
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]): Promise<Message> {
|
||||
return this.client.quoteWithMedia(this, params)
|
||||
}
|
||||
|
||||
/** Send a media group in reply to this message */
|
||||
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]) {
|
||||
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]): Promise<Message[]> {
|
||||
return this.client.quoteWithMediaGroup(this, params)
|
||||
}
|
||||
|
||||
/** Send a text as a comment to this message */
|
||||
commentText(...params: ParametersSkip1<TelegramClient['commentText']>) {
|
||||
commentText(...params: ParametersSkip1<TelegramClient['commentText']>): Promise<Message> {
|
||||
return this.client.commentText(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a media as a comment to this message */
|
||||
commentMedia(...params: ParametersSkip1<TelegramClient['commentMedia']>) {
|
||||
commentMedia(...params: ParametersSkip1<TelegramClient['commentMedia']>): Promise<Message> {
|
||||
return this.client.commentMedia(this, ...params)
|
||||
}
|
||||
|
||||
/** Send a media group as a comment to this message */
|
||||
commentMediaGroup(...params: ParametersSkip1<TelegramClient['commentMediaGroup']>) {
|
||||
commentMediaGroup(...params: ParametersSkip1<TelegramClient['commentMediaGroup']>): Promise<Message[]> {
|
||||
return this.client.commentMediaGroup(this, ...params)
|
||||
}
|
||||
|
||||
/** Delete this message (message group) */
|
||||
delete(params?: DeleteMessagesParams) {
|
||||
delete(params?: DeleteMessagesParams): Promise<void> {
|
||||
return this.client.deleteMessagesById(
|
||||
this.chat.inputPeer,
|
||||
this.messages.map(it => it.id),
|
||||
|
@ -147,7 +152,7 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
|||
}
|
||||
|
||||
/** Pin this message */
|
||||
pin(params?: OmitInputMessageId<Parameters<TelegramClient['pinMessage']>[0]>) {
|
||||
pin(params?: OmitInputMessageId<Parameters<TelegramClient['pinMessage']>[0]>): Promise<Message | null> {
|
||||
return this.client.pinMessage({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
@ -156,7 +161,7 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
|||
}
|
||||
|
||||
/** Unpin this message */
|
||||
unpin() {
|
||||
unpin(): Promise<void> {
|
||||
return this.client.unpinMessage({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
@ -164,7 +169,7 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
|||
}
|
||||
|
||||
/** Edit this message */
|
||||
edit(params: OmitInputMessageId<Parameters<TelegramClient['editMessage']>[0]>) {
|
||||
edit(params: OmitInputMessageId<Parameters<TelegramClient['editMessage']>[0]>): Promise<Message> {
|
||||
return this.client.editMessage({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
@ -173,7 +178,7 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
|||
}
|
||||
|
||||
/** Forward this message (message group) */
|
||||
forwardTo(params: ForwardMessageOptions) {
|
||||
forwardTo(params: ForwardMessageOptions): Promise<Message[]> {
|
||||
return this.client.forwardMessagesById({
|
||||
fromChatId: this.chat.inputPeer,
|
||||
messages: this.messages.map(it => it.id),
|
||||
|
@ -182,7 +187,7 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
|||
}
|
||||
|
||||
/** Send a copy of this message (message group) */
|
||||
copy(params: SendCopyParams & SendCopyGroupParams) {
|
||||
copy(params: SendCopyParams & SendCopyGroupParams): Promise<Message> | Promise<Message[]> {
|
||||
if (this.isMessageGroup) {
|
||||
return this.client.sendCopyGroup({
|
||||
messages: this.messages,
|
||||
|
@ -197,7 +202,9 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
|||
}
|
||||
|
||||
/** React to this message */
|
||||
react(params: OmitInputMessageId<Parameters<TelegramClient['sendReaction']>[0]>) {
|
||||
react(
|
||||
params: OmitInputMessageId<Parameters<TelegramClient['sendReaction']>[0]>,
|
||||
): Promise<Message | null> {
|
||||
return this.client.sendReaction({
|
||||
chatId: this.chat.inputPeer,
|
||||
message: this.id,
|
||||
|
|
|
@ -1,4 +1,21 @@
|
|||
import type { ParsedUpdate } from '@mtcute/core'
|
||||
import type {
|
||||
BotReactionCountUpdate,
|
||||
BotReactionUpdate,
|
||||
BotStoppedUpdate,
|
||||
BusinessConnection,
|
||||
ChatJoinRequestUpdate,
|
||||
ChatMemberUpdate,
|
||||
DeleteBusinessMessageUpdate,
|
||||
DeleteMessageUpdate,
|
||||
DeleteStoryUpdate,
|
||||
HistoryReadUpdate,
|
||||
ParsedUpdate,
|
||||
PollUpdate,
|
||||
PollVoteUpdate,
|
||||
StoryUpdate,
|
||||
UserStatusUpdate,
|
||||
UserTypingUpdate,
|
||||
} from '@mtcute/core'
|
||||
import type { TelegramClient } from '@mtcute/core/client.js'
|
||||
|
||||
import type { UpdateContextDistributed } from './base.js'
|
||||
|
@ -10,8 +27,36 @@ import { InlineQueryContext } from './inline-query.js'
|
|||
import { MessageContext } from './message.js'
|
||||
import { PreCheckoutQueryContext } from './pre-checkout-query.js'
|
||||
|
||||
export type UpdateContextType =
|
||||
| MessageContext
|
||||
| InlineQueryContext
|
||||
| ChosenInlineResultContext
|
||||
| CallbackQueryContext
|
||||
| InlineCallbackQueryContext
|
||||
| BusinessCallbackQueryContext
|
||||
| ChatJoinRequestUpdateContext
|
||||
| PreCheckoutQueryContext
|
||||
| BusinessMessageContext
|
||||
| UpdateContextDistributed<
|
||||
| DeleteMessageUpdate
|
||||
| ChatMemberUpdate
|
||||
| PollUpdate
|
||||
| PollVoteUpdate
|
||||
| UserStatusUpdate
|
||||
| UserTypingUpdate
|
||||
| HistoryReadUpdate
|
||||
| BotStoppedUpdate
|
||||
| ChatJoinRequestUpdate
|
||||
| StoryUpdate
|
||||
| DeleteStoryUpdate
|
||||
| BotReactionUpdate
|
||||
| BotReactionCountUpdate
|
||||
| BusinessConnection
|
||||
| DeleteBusinessMessageUpdate
|
||||
>
|
||||
|
||||
/** @internal */
|
||||
export function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpdate) {
|
||||
export function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpdate): UpdateContextType {
|
||||
switch (update.name) {
|
||||
case 'new_message':
|
||||
case 'edit_message':
|
||||
|
@ -43,5 +88,3 @@ export function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpd
|
|||
|
||||
return _update
|
||||
}
|
||||
|
||||
export type UpdateContextType = ReturnType<typeof _parsedUpdateToContext>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import type { MaybeArray, MaybePromise, Message } from '@mtcute/core'
|
||||
import type { Chat, MaybeArray, MaybePromise, Message } from '@mtcute/core'
|
||||
|
||||
import type { BusinessMessageContext } from '../context/business-message.js'
|
||||
import type { MessageContext } from '../context/message.js'
|
||||
|
||||
import { chat } from './chat.js'
|
||||
import { and, or } from './logic.js'
|
||||
import type { UpdateFilter } from './types.js'
|
||||
import type { Modify, UpdateFilter } from './types.js'
|
||||
|
||||
/**
|
||||
* Filter messages that call the given command(s)..
|
||||
|
@ -97,13 +97,30 @@ export function command(commands: MaybeArray<string | RegExp>, {
|
|||
* Shorthand filter that matches /start commands sent to bot's
|
||||
* private messages.
|
||||
*/
|
||||
export const start = and(chat('private'), command('start'))
|
||||
export const start: UpdateFilter<
|
||||
MessageContext | BusinessMessageContext,
|
||||
{
|
||||
chat: Modify<Chat, {
|
||||
chatType: 'private'
|
||||
}>
|
||||
command: string[]
|
||||
}
|
||||
> = and(chat('private'), command('start'))
|
||||
|
||||
/**
|
||||
* Shorthand filter that matches /start commands
|
||||
* sent in groups (i.e. using `?startgroup` parameter).
|
||||
*/
|
||||
export const startGroup = and(or(chat('supergroup'), chat('group')), command('start'))
|
||||
export const startGroup: UpdateFilter<
|
||||
MessageContext | BusinessMessageContext,
|
||||
{
|
||||
chat: Modify<Chat, {
|
||||
chatType: 'group' | 'supergroup'
|
||||
}>
|
||||
command: string[]
|
||||
},
|
||||
never
|
||||
> = and(or(chat('supergroup'), chat('group')), command('start'))
|
||||
|
||||
function deeplinkBase(base: UpdateFilter<MessageContext | BusinessMessageContext, { command: string[] }>) {
|
||||
return (
|
||||
|
@ -156,7 +173,10 @@ function deeplinkBase(base: UpdateFilter<MessageContext | BusinessMessageContext
|
|||
* If the parameter is a regex, groups are added to `msg.command`,
|
||||
* meaning that the first group is available in `msg.command[2]`.
|
||||
*/
|
||||
export const deeplink = deeplinkBase(start)
|
||||
export const deeplink: (params: MaybeArray<string | RegExp>) => UpdateFilter<
|
||||
MessageContext | BusinessMessageContext,
|
||||
{ command: string[] }
|
||||
> = deeplinkBase(start)
|
||||
|
||||
/**
|
||||
* Filter for group deep links (i.e. `/start <deeplink_parameter>`).
|
||||
|
@ -164,4 +184,7 @@ export const deeplink = deeplinkBase(start)
|
|||
* If the parameter is a regex, groups are added to `msg.command`,
|
||||
* meaning that the first group is available in `msg.command[2]`.
|
||||
*/
|
||||
export const deeplinkGroup = deeplinkBase(startGroup)
|
||||
export const deeplinkGroup: (params: MaybeArray<string | RegExp>) => UpdateFilter<
|
||||
MessageContext | BusinessMessageContext,
|
||||
{ command: string[] }
|
||||
> = deeplinkBase(startGroup)
|
||||
|
|
|
@ -1,16 +1,29 @@
|
|||
import type {
|
||||
Audio,
|
||||
Contact,
|
||||
Dice,
|
||||
Document,
|
||||
Game,
|
||||
Invoice,
|
||||
LiveLocation,
|
||||
Location,
|
||||
MaybeArray,
|
||||
Message,
|
||||
MessageAction,
|
||||
MessageMediaType,
|
||||
Peer,
|
||||
Photo,
|
||||
Poll,
|
||||
RepliedMessageInfo,
|
||||
RepliedMessageOrigin,
|
||||
Sticker,
|
||||
StickerSourceType,
|
||||
StickerType,
|
||||
User,
|
||||
Venue,
|
||||
Video,
|
||||
Voice,
|
||||
WebPage,
|
||||
_RepliedMessageAssertionsByOrigin,
|
||||
} from '@mtcute/core'
|
||||
import {
|
||||
|
@ -68,41 +81,44 @@ export const media: UpdateFilter<Message, { media: Exclude<Message['media'], nul
|
|||
/**
|
||||
* Filter messages containing media of given type
|
||||
*/
|
||||
export function mediaOf<T extends MessageMediaType>(type: T): UpdateFilter<Message, { media: Extract<Message['media'], { type: T }> }> {
|
||||
export function mediaOf<T extends MessageMediaType>(type: T): UpdateFilter<
|
||||
Message,
|
||||
{ media: Extract<Message['media'], { type: T }> }
|
||||
> {
|
||||
return msg =>
|
||||
msg.media?.type === type
|
||||
}
|
||||
|
||||
/** Filter messages containing a photo */
|
||||
export const photo = mediaOf('photo')
|
||||
export const photo: UpdateFilter<Message, { media: Photo }> = mediaOf('photo')
|
||||
/** Filter messages containing a dice */
|
||||
export const dice = mediaOf('dice')
|
||||
export const dice: UpdateFilter<Message, { media: Dice }> = mediaOf('dice')
|
||||
/** Filter messages containing a contact */
|
||||
export const contact = mediaOf('contact')
|
||||
export const contact: UpdateFilter<Message, { media: Contact }> = mediaOf('contact')
|
||||
/** Filter messages containing an audio file */
|
||||
export const audio = mediaOf('audio')
|
||||
export const audio: UpdateFilter<Message, { media: Audio }> = mediaOf('audio')
|
||||
/** Filter messages containing a voice message (audio-only) */
|
||||
export const voice = mediaOf('voice')
|
||||
export const voice: UpdateFilter<Message, { media: Voice }> = mediaOf('voice')
|
||||
/** Filter messages containing a sticker */
|
||||
export const sticker = mediaOf('sticker')
|
||||
export const sticker: UpdateFilter<Message, { media: Sticker }> = mediaOf('sticker')
|
||||
/** Filter messages containing a document (a file) */
|
||||
export const document = mediaOf('document')
|
||||
export const document: UpdateFilter<Message, { media: Document }> = mediaOf('document')
|
||||
/** Filter messages containing any video (videos, round messages and animations) */
|
||||
export const anyVideo = mediaOf('video')
|
||||
export const anyVideo: UpdateFilter<Message, { media: Video }> = mediaOf('video')
|
||||
/** Filter messages containing a static location */
|
||||
export const location = mediaOf('location')
|
||||
export const location: UpdateFilter<Message, { media: Location }> = mediaOf('location')
|
||||
/** Filter messages containing a live location */
|
||||
export const liveLocation = mediaOf('live_location')
|
||||
export const liveLocation: UpdateFilter<Message, { media: LiveLocation }> = mediaOf('live_location')
|
||||
/** Filter messages containing a game */
|
||||
export const game = mediaOf('game')
|
||||
export const game: UpdateFilter<Message, { media: Game }> = mediaOf('game')
|
||||
/** Filter messages containing a web page */
|
||||
export const webpage = mediaOf('webpage')
|
||||
export const webpage: UpdateFilter<Message, { media: WebPage }> = mediaOf('webpage')
|
||||
/** Filter messages containing a venue */
|
||||
export const venue = mediaOf('venue')
|
||||
export const venue: UpdateFilter<Message, { media: Venue }> = mediaOf('venue')
|
||||
/** Filter messages containing a poll */
|
||||
export const poll = mediaOf('poll')
|
||||
export const poll: UpdateFilter<Message, { media: Poll }> = mediaOf('poll')
|
||||
/** Filter messages containing an invoice */
|
||||
export const invoice = mediaOf('invoice')
|
||||
export const invoice: UpdateFilter<Message, { media: Invoice }> = mediaOf('invoice')
|
||||
|
||||
/**
|
||||
* Filter messages containing any location (live or static).
|
||||
|
@ -224,7 +240,10 @@ export function action<T extends Exclude<MessageAction, null>['type']>(type: May
|
|||
return msg => msg.action?.type === type
|
||||
}
|
||||
|
||||
export function sender<T extends Message['sender']['type']>(type: T): UpdateFilter<Message, { sender: Extract<Message['sender'], { type: T }> }> {
|
||||
export function sender<T extends Message['sender']['type']>(type: T): UpdateFilter<
|
||||
Message,
|
||||
{ sender: Extract<Message['sender'], { type: T }> }
|
||||
> {
|
||||
return msg =>
|
||||
msg.sender.type === type
|
||||
}
|
||||
|
@ -235,7 +254,13 @@ export function sender<T extends Message['sender']['type']>(type: T): UpdateFilt
|
|||
*
|
||||
* Optionally, you can pass a filter that will be applied to the replied message.
|
||||
*/
|
||||
export function replyTo<Mod, State extends object>(filter?: UpdateFilter<Message, Mod, State>): UpdateFilter<MessageContext | BusinessMessageContext, { getReplyTo: () => Promise<Message & Mod> }, State> {
|
||||
export function replyTo<Mod, State extends object>(
|
||||
filter?: UpdateFilter<Message, Mod, State>,
|
||||
): UpdateFilter<
|
||||
MessageContext | BusinessMessageContext,
|
||||
{ getReplyTo: () => Promise<Message & Mod> },
|
||||
State
|
||||
> {
|
||||
return async (msg, state) => {
|
||||
if (!msg.replyToMessage?.id) return false
|
||||
|
||||
|
@ -256,7 +281,9 @@ export function replyTo<Mod, State extends object>(filter?: UpdateFilter<Message
|
|||
* Middleware-like filter that will fetch the sender of the message
|
||||
* and make it available to further filters, as well as the handler itself.
|
||||
*/
|
||||
export function withCompleteSender<Mod, State extends object>(filter?: UpdateFilter<MessageContext, Mod, State>): UpdateFilter<MessageContext, Mod, State> {
|
||||
export function withCompleteSender<Mod, State extends object>(
|
||||
filter?: UpdateFilter<MessageContext, Mod, State>,
|
||||
): UpdateFilter<MessageContext, Mod, State> {
|
||||
return async (msg, state) => {
|
||||
try {
|
||||
await msg.getCompleteSender()
|
||||
|
|
|
@ -15,8 +15,8 @@ interface RateLimitDto {
|
|||
}
|
||||
|
||||
class MemoryStateRepository implements IStateRepository {
|
||||
readonly state
|
||||
readonly rl
|
||||
readonly state: Map<string, StateDto>
|
||||
readonly rl: Map<string, RateLimitDto>
|
||||
constructor(readonly _driver: MemoryStorageDriver) {
|
||||
this.state = this._driver.getState<Map<string, StateDto>>('dispatcher_fsm', () => new Map())
|
||||
this.rl = this._driver.getState<Map<string, RateLimitDto>>('rl', () => new Map())
|
||||
|
@ -99,7 +99,7 @@ class MemoryStateRepository implements IStateRepository {
|
|||
}
|
||||
|
||||
export class MemoryStateStorage implements IStateStorageProvider {
|
||||
readonly state
|
||||
readonly state: MemoryStateRepository
|
||||
|
||||
constructor(readonly driver: MemoryStorageDriver = new MemoryStorageDriver()) {
|
||||
this.state = new MemoryStateRepository(this.driver)
|
||||
|
|
|
@ -116,12 +116,12 @@ class SqliteStateRepository implements IStateRepository {
|
|||
}
|
||||
|
||||
export class SqliteStateStorage implements IStateStorageProvider {
|
||||
readonly state
|
||||
readonly state: SqliteStateRepository
|
||||
constructor(readonly driver: BaseSqliteStorageDriver) {
|
||||
this.state = new SqliteStateRepository(driver)
|
||||
}
|
||||
|
||||
static from(provider: BaseSqliteStorage) {
|
||||
static from(provider: BaseSqliteStorage): SqliteStateStorage {
|
||||
return new SqliteStateStorage(provider.driver)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { LruMap, asyncResettable } from '@mtcute/core/utils.js'
|
||||
import type { MaybePromise } from '@mtcute/core'
|
||||
|
||||
import type { IStateStorageProvider } from './provider.js'
|
||||
|
||||
|
@ -16,14 +17,14 @@ export class StateService {
|
|||
this._loaded = true
|
||||
})
|
||||
|
||||
async load() {
|
||||
async load(): Promise<void> {
|
||||
await this._load.run()
|
||||
this._vacuumTimer = setInterval(() => {
|
||||
Promise.resolve(this.provider.state.vacuum(Date.now())).catch(() => {})
|
||||
}, 300_000)
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
async destroy(): Promise<void> {
|
||||
await this.provider.driver.save?.()
|
||||
await this.provider.driver.destroy?.()
|
||||
clearInterval(this._vacuumTimer)
|
||||
|
@ -68,11 +69,11 @@ export class StateService {
|
|||
return this.deleteState(makeCurrentSceneKey(key))
|
||||
}
|
||||
|
||||
getRateLimit(key: string, limit: number, window: number) {
|
||||
getRateLimit(key: string, limit: number, window: number): MaybePromise<[number, number]> {
|
||||
return this.provider.state.getRateLimit(key, Date.now(), limit, window)
|
||||
}
|
||||
|
||||
resetRateLimit(key: string) {
|
||||
resetRateLimit(key: string): MaybePromise<void> {
|
||||
return this.provider.state.resetRateLimit(key)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import type { MaybePromise } from '@mtcute/core'
|
|||
import type { MessageContext } from './context/message.js'
|
||||
import type { DispatcherParams } from './dispatcher.js'
|
||||
import { Dispatcher } from './dispatcher.js'
|
||||
import type { UpdateFilter } from './filters/index.js'
|
||||
import { filters } from './filters/index.js'
|
||||
import type { UpdateState } from './state/update-state.js'
|
||||
|
||||
|
@ -61,7 +62,7 @@ export class WizardScene<State extends object> extends Dispatcher<State & Wizard
|
|||
/**
|
||||
* Go to the Nth step
|
||||
*/
|
||||
async goToStep(state: UpdateState<WizardInternalState>, step: number) {
|
||||
async goToStep(state: UpdateState<WizardInternalState>, step: number): Promise<void> {
|
||||
if (step >= this._steps) {
|
||||
await state.exit()
|
||||
} else {
|
||||
|
@ -72,7 +73,7 @@ export class WizardScene<State extends object> extends Dispatcher<State & Wizard
|
|||
/**
|
||||
* Skip N steps
|
||||
*/
|
||||
async skip(state: UpdateState<WizardInternalState>, count = 1) {
|
||||
async skip(state: UpdateState<WizardInternalState>, count = 1): Promise<void> {
|
||||
const { $step } = (await state.get()) || {}
|
||||
if ($step === undefined) throw new Error('Wizard state is not initialized')
|
||||
|
||||
|
@ -82,7 +83,8 @@ export class WizardScene<State extends object> extends Dispatcher<State & Wizard
|
|||
/**
|
||||
* Filter that will only pass if the current step is `step`
|
||||
*/
|
||||
static onNthStep(step: number) {
|
||||
// eslint-disable-next-line ts/no-empty-object-type
|
||||
static onNthStep(step: number): UpdateFilter<any, {}, WizardInternalState> {
|
||||
const filter = filters.state<WizardInternalState>(it => it.$step === step)
|
||||
|
||||
if (step === 0) return filters.or(filters.stateEmpty, filter)
|
||||
|
@ -93,7 +95,8 @@ export class WizardScene<State extends object> extends Dispatcher<State & Wizard
|
|||
/**
|
||||
* Filter that will only pass if the current step is the one after last one added
|
||||
*/
|
||||
onCurrentStep() {
|
||||
// eslint-disable-next-line ts/no-empty-object-type
|
||||
onCurrentStep(): UpdateFilter<any, {}, WizardInternalState> {
|
||||
return WizardScene.onNthStep(this._steps)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ import type Long from 'long'
|
|||
export const PERSISTENT_ID_VERSION_OLD = 2
|
||||
export const PERSISTENT_ID_VERSION = 4
|
||||
|
||||
export const WEB_LOCATION_FLAG = 1 << 24
|
||||
export const FILE_REFERENCE_FLAG = 1 << 25
|
||||
export const WEB_LOCATION_FLAG: number = 1 << 24
|
||||
export const FILE_REFERENCE_FLAG: number = 1 << 25
|
||||
|
||||
export const CURRENT_VERSION = 48
|
||||
|
||||
|
|
|
@ -160,5 +160,5 @@ export abstract class BaseHttpProxyTcpTransport extends BaseTcpTransport {
|
|||
* (unless you want to use a custom codec).
|
||||
*/
|
||||
export class HttpProxyTcpTransport extends BaseHttpProxyTcpTransport {
|
||||
_packetCodec = new IntermediatePacketCodec()
|
||||
_packetCodec: IntermediatePacketCodec = new IntermediatePacketCodec()
|
||||
}
|
||||
|
|
|
@ -277,7 +277,7 @@ export async function generateFakeTlsHeader(domain: string, secret: Buffer, cryp
|
|||
* @internal
|
||||
*/
|
||||
export class FakeTlsPacketCodec extends WrappedCodec implements IPacketCodec {
|
||||
protected _stream = Buffer.alloc(0)
|
||||
protected _stream: Buffer = Buffer.alloc(0)
|
||||
|
||||
private _header!: Buffer
|
||||
private _isFirstTls = true
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { Interface as RlInterface } from 'node:readline'
|
||||
import { createInterface } from 'node:readline'
|
||||
import type { Readable } from 'node:stream'
|
||||
|
||||
import type { FileDownloadLocation, FileDownloadParameters, ITelegramStorageProvider, PartialOnly, User } from '@mtcute/core'
|
||||
import type {
|
||||
|
@ -157,7 +158,7 @@ export class TelegramClient extends TelegramClientBase {
|
|||
return downloadToFile(this, filename, location, params)
|
||||
}
|
||||
|
||||
downloadAsNodeStream(location: FileDownloadLocation, params?: FileDownloadParameters | undefined) {
|
||||
downloadAsNodeStream(location: FileDownloadLocation, params?: FileDownloadParameters | undefined): Readable {
|
||||
return downloadAsNodeStream(this, location, params)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,13 @@ const LEVEL_NAMES = isTty
|
|||
const TAG_COLORS = [6, 2, 3, 4, 5, 1].map(i => `\x1B[3${i};1m`)
|
||||
|
||||
/** @internal */
|
||||
export const defaultLoggingHandler = isTty
|
||||
export const defaultLoggingHandler: (
|
||||
color: number,
|
||||
level: number,
|
||||
tag: string,
|
||||
fmt: string,
|
||||
args: unknown[]
|
||||
) => void = isTty
|
||||
? (color: number, level: number, tag: string, fmt: string, args: unknown[]): void => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(BASE_FORMAT + fmt, new Date().toISOString(), LEVEL_NAMES[level], TAG_COLORS[color], tag, ...args)
|
||||
|
|
|
@ -25,7 +25,7 @@ export interface SqliteStorageDriverOptions {
|
|||
export class SqliteStorageDriver extends BaseSqliteStorageDriver {
|
||||
constructor(
|
||||
readonly filename = ':memory:',
|
||||
readonly params?: SqliteStorageDriverOptions,
|
||||
readonly params?: SqliteStorageDriverOptions | undefined,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export { SqliteStorageDriver } from './driver.js'
|
|||
export class SqliteStorage extends BaseSqliteStorage {
|
||||
constructor(
|
||||
readonly filename = ':memory:',
|
||||
readonly params?: SqliteStorageDriverOptions,
|
||||
readonly params?: SqliteStorageDriverOptions | undefined,
|
||||
) {
|
||||
super(new SqliteStorageDriver(filename, params))
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ export abstract class BaseNodeCryptoProvider extends BaseCryptoProvider {
|
|||
return gunzipSync(data)
|
||||
}
|
||||
|
||||
randomFill(buf: Uint8Array) {
|
||||
randomFill(buf: Uint8Array): void {
|
||||
randomFillSync(buf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,11 @@ import type { UploadFileLike } from '@mtcute/core'
|
|||
|
||||
import { nodeStreamToWeb } from './stream-utils.js'
|
||||
|
||||
export async function normalizeFile(file: UploadFileLike) {
|
||||
export async function normalizeFile(file: UploadFileLike): Promise<{
|
||||
file: UploadFileLike
|
||||
fileName?: string | undefined
|
||||
fileSize?: number
|
||||
} | null> {
|
||||
if (typeof file === 'string') {
|
||||
file = createReadStream(file)
|
||||
}
|
||||
|
|
|
@ -136,5 +136,5 @@ export abstract class BaseTcpTransport extends EventEmitter implements ITelegram
|
|||
}
|
||||
|
||||
export class TcpTransport extends BaseTcpTransport {
|
||||
_packetCodec = new IntermediatePacketCodec()
|
||||
_packetCodec: IntermediatePacketCodec = new IntermediatePacketCodec()
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue