fix: tests
This commit is contained in:
parent
4e78b643df
commit
6768b15514
44 changed files with 146 additions and 127 deletions
|
@ -8,7 +8,7 @@
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "pnpm run -w build-package mtcute",
|
"build": "pnpm run -w build-package core",
|
||||||
"gen-client": "node ./scripts/generate-client.cjs",
|
"gen-client": "node ./scripts/generate-client.cjs",
|
||||||
"gen-updates": "node ./scripts/generate-updates.cjs"
|
"gen-updates": "node ./scripts/generate-updates.cjs"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/require-await */
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
import { MtClient, MtClientOptions } from '../network/client.js'
|
import { MtClient, MtClientOptions } from '../network/client.js'
|
||||||
|
@ -5,7 +6,14 @@ import { ConnectionKind, RpcCallOptions } from '../network/network-manager.js'
|
||||||
import { StorageManagerExtraOptions } from '../storage/storage.js'
|
import { StorageManagerExtraOptions } from '../storage/storage.js'
|
||||||
import { MtArgumentError } from '../types/errors.js'
|
import { MtArgumentError } from '../types/errors.js'
|
||||||
import { MustEqual } from '../types/utils.js'
|
import { MustEqual } from '../types/utils.js'
|
||||||
import { asyncResettable, computeNewPasswordHash, computeSrpParams, readStringSession, StringSessionData, writeStringSession } from '../utils/index.js'
|
import {
|
||||||
|
asyncResettable,
|
||||||
|
computeNewPasswordHash,
|
||||||
|
computeSrpParams,
|
||||||
|
readStringSession,
|
||||||
|
StringSessionData,
|
||||||
|
writeStringSession,
|
||||||
|
} from '../utils/index.js'
|
||||||
import { LogManager } from '../utils/logger.js'
|
import { LogManager } from '../utils/logger.js'
|
||||||
import { ITelegramClient } from './client.types.js'
|
import { ITelegramClient } from './client.types.js'
|
||||||
import { ITelegramStorageProvider } from './storage/provider.js'
|
import { ITelegramStorageProvider } from './storage/provider.js'
|
||||||
|
@ -29,7 +37,7 @@ export class BaseTelegramClient implements ITelegramClient {
|
||||||
this._serverUpdatesHandler = this.updates.handleUpdate.bind(this.updates)
|
this._serverUpdatesHandler = this.updates.handleUpdate.bind(this.updates)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mt.on('update', (update) => {
|
this.mt.on('update', (update: tl.TypeUpdates) => {
|
||||||
this._serverUpdatesHandler(update)
|
this._serverUpdatesHandler(update)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -272,16 +280,10 @@ export class BaseTelegramClient implements ITelegramClient {
|
||||||
return this.mt.network.getPrimaryDcId()
|
return this.mt.network.getPrimaryDcId()
|
||||||
}
|
}
|
||||||
|
|
||||||
computeSrpParams(
|
computeSrpParams(request: tl.account.RawPassword, password: string): Promise<tl.RawInputCheckPasswordSRP> {
|
||||||
request: tl.account.RawPassword,
|
|
||||||
password: string,
|
|
||||||
): Promise<tl.RawInputCheckPasswordSRP> {
|
|
||||||
return computeSrpParams(this.crypto, request, password)
|
return computeSrpParams(this.crypto, request, password)
|
||||||
}
|
}
|
||||||
computeNewPasswordHash(
|
computeNewPasswordHash(algo: tl.TypePasswordKdfAlgo, password: string): Promise<Uint8Array> {
|
||||||
algo: tl.TypePasswordKdfAlgo,
|
|
||||||
password: string,
|
|
||||||
): Promise<Uint8Array> {
|
|
||||||
return computeNewPasswordHash(this.crypto, algo, password)
|
return computeNewPasswordHash(this.crypto, algo, password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4917,7 +4917,7 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* **Available**: ✅ both users and bots
|
* **Available**: ✅ both users and bots
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
getMyUsername(): string | null
|
getMyUsername(): Promise<string | null>
|
||||||
/**
|
/**
|
||||||
* Get a single profile picture of a user by its ID
|
* Get a single profile picture of a user by its ID
|
||||||
*
|
*
|
||||||
|
|
|
@ -103,7 +103,7 @@ describe('sendText', () => {
|
||||||
it('should correctly handle updateShortSentMessage with cached peer', async () => {
|
it('should correctly handle updateShortSentMessage with cached peer', async () => {
|
||||||
const client = new StubTelegramClient()
|
const client = new StubTelegramClient()
|
||||||
|
|
||||||
client.storage.self.store({
|
await client.storage.self.store({
|
||||||
userId: stubUser.id,
|
userId: stubUser.id,
|
||||||
isBot: false,
|
isBot: false,
|
||||||
isPremium: false,
|
isPremium: false,
|
||||||
|
@ -132,7 +132,7 @@ describe('sendText', () => {
|
||||||
it('should correctly handle updateShortSentMessage without cached peer', async () => {
|
it('should correctly handle updateShortSentMessage without cached peer', async () => {
|
||||||
const client = new StubTelegramClient()
|
const client = new StubTelegramClient()
|
||||||
|
|
||||||
client.storage.self.store({
|
await client.storage.self.store({
|
||||||
userId: stubUser.id,
|
userId: stubUser.id,
|
||||||
isBot: false,
|
isBot: false,
|
||||||
isPremium: false,
|
isPremium: false,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { ITelegramClient } from '../../client.types.js'
|
||||||
* This method uses locally available information and
|
* This method uses locally available information and
|
||||||
* does not call any API methods.
|
* does not call any API methods.
|
||||||
*/
|
*/
|
||||||
export function getMyUsername(client: ITelegramClient): string | null {
|
export async function getMyUsername(client: ITelegramClient): Promise<string | null> {
|
||||||
throw new Error('Not implemented')
|
return client.storage.self.fetch().then((self) => self?.usernames[0] ?? null)
|
||||||
// return getAuthState(client).selfUsername
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ export async function setMyUsername(client: ITelegramClient, username: string |
|
||||||
username,
|
username,
|
||||||
})
|
})
|
||||||
|
|
||||||
client.storage.self.update({ username })
|
await client.storage.self.update({ username })
|
||||||
|
|
||||||
return new User(res)
|
return new User(res)
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ function parse(data: Uint8Array): CurrentUserInfo | null {
|
||||||
|
|
||||||
if (flags & 2) {
|
if (flags & 2) {
|
||||||
const len = reader.int()
|
const len = reader.int()
|
||||||
usernames = new Array(len)
|
usernames = new Array<string>(len)
|
||||||
|
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
usernames[i] = reader.string()
|
usernames[i] = reader.string()
|
||||||
|
@ -143,11 +143,7 @@ export class CurrentUserService extends BaseService {
|
||||||
return this._cached
|
return this._cached
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(params: {
|
async update(params: { username?: string; usernames?: string[]; isPremium?: boolean }): Promise<void> {
|
||||||
username?: string
|
|
||||||
usernames?: string[]
|
|
||||||
isPremium?: boolean
|
|
||||||
}): Promise<void> {
|
|
||||||
const info = await this.fetch()
|
const info = await this.fetch()
|
||||||
if (!info) return
|
if (!info) return
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ export function deserializeError(error: SerializedError): Error {
|
||||||
for (const key in custom) {
|
for (const key in custom) {
|
||||||
if (key === 'code' || key === 'text') continue
|
if (key === 'code' || key === 'text') continue
|
||||||
// @ts-expect-error lol
|
// @ts-expect-error lol
|
||||||
err2[key] = custom[key]
|
err2[key] = custom[key] // eslint-disable-line
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,9 @@ export class WorkerInvoker {
|
||||||
constructor(private send: SendFn) {}
|
constructor(private send: SendFn) {}
|
||||||
|
|
||||||
private _nextId = 0
|
private _nextId = 0
|
||||||
private _pending = new Map<number, ControllablePromise<unknown>>()
|
private _pending = new Map<number, ControllablePromise>()
|
||||||
|
|
||||||
private _invoke(
|
private _invoke(target: InvokeTarget, method: string, args: unknown[], isVoid: boolean) {
|
||||||
target: InvokeTarget,
|
|
||||||
method: string,
|
|
||||||
args: unknown[],
|
|
||||||
isVoid: boolean,
|
|
||||||
) {
|
|
||||||
const id = this._nextId++
|
const id = this._nextId++
|
||||||
|
|
||||||
this.send({
|
this.send({
|
||||||
|
@ -36,15 +31,12 @@ export class WorkerInvoker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
invoke(
|
invoke(target: InvokeTarget, method: string, args: unknown[]): Promise<unknown> {
|
||||||
target: InvokeTarget,
|
|
||||||
method: string,
|
|
||||||
args: unknown[],
|
|
||||||
): Promise<unknown> {
|
|
||||||
return this._invoke(target, method, args, false) as Promise<unknown>
|
return this._invoke(target, method, args, false) as Promise<unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeVoid(target: InvokeTarget, method: string, args: unknown[]): void {
|
invokeVoid(target: InvokeTarget, method: string, args: unknown[]): void {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this._invoke(target, method, args, true)
|
this._invoke(target, method, args, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ export function connectToWorker(worker: SomeWorker, handler: ClientMessageHandle
|
||||||
const send: SendFn = worker.postMessage.bind(worker)
|
const send: SendFn = worker.postMessage.bind(worker)
|
||||||
|
|
||||||
const messageHandler = (ev: MessageEvent) => {
|
const messageHandler = (ev: MessageEvent) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
handler(ev.data)
|
handler(ev.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ export function connectToWorker(worker: SomeWorker, handler: ClientMessageHandle
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
handler(ev.data)
|
handler(ev.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
|
||||||
|
|
||||||
const respond: RespondFn = port.postMessage.bind(port)
|
const respond: RespondFn = port.postMessage.bind(port)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
parentPort.on('message', (message) => handler(message, respond))
|
parentPort.on('message', (message) => handler(message, respond))
|
||||||
|
|
||||||
return respond
|
return respond
|
||||||
|
|
|
@ -10,6 +10,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
|
||||||
if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
|
if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
|
||||||
const respond: RespondFn = self.postMessage.bind(self)
|
const respond: RespondFn = self.postMessage.bind(self)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
self.addEventListener('message', (message) => handler(message.data, respond))
|
self.addEventListener('message', (message) => handler(message.data, respond))
|
||||||
|
|
||||||
return respond
|
return respond
|
||||||
|
@ -53,7 +54,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
|
||||||
// so even if the browser has suspended the timers, we should still get a ping within a minute
|
// so even if the browser has suspended the timers, we should still get a ping within a minute
|
||||||
let timeout = setTimeout(onTimeout, 60000)
|
let timeout = setTimeout(onTimeout, 60000)
|
||||||
|
|
||||||
port.addEventListener('message', async (message) => {
|
port.addEventListener('message', (message) => {
|
||||||
if (message.data.__type__ === 'close') {
|
if (message.data.__type__ === 'close') {
|
||||||
onClose()
|
onClose()
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
handler(message.data, respond)
|
handler(message.data, respond)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,14 +72,11 @@ export class TelegramWorkerPort<Custom extends WorkerCustomMethods> implements I
|
||||||
this._destroyed = true
|
this._destroyed = true
|
||||||
|
|
||||||
if (terminate && 'terminate' in this.options.worker) {
|
if (terminate && 'terminate' in this.options.worker) {
|
||||||
this.options.worker.terminate()
|
Promise.resolve(this.options.worker.terminate()).catch(() => {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeCustom<T extends keyof Custom>(
|
invokeCustom<T extends keyof Custom>(method: T, ...args: Parameters<Custom[T]>): Promise<ReturnType<Custom[T]>> {
|
||||||
method: T,
|
|
||||||
...args: Parameters<Custom[T]>
|
|
||||||
): Promise<ReturnType<Custom[T]>> {
|
|
||||||
return this._invoker.invoke('custom', method as string, args) as Promise<ReturnType<Custom[T]>>
|
return this._invoker.invoke('custom', method as string, args) as Promise<ReturnType<Custom[T]>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ export function makeTelegramWorker<T extends WorkerCustomMethods>(params: Telegr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const method = target[msg.method]
|
const method = target[msg.method]
|
||||||
|
|
||||||
if (!method) {
|
if (!method) {
|
||||||
|
@ -57,6 +58,7 @@ export function makeTelegramWorker<T extends WorkerCustomMethods>(params: Telegr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||||
Promise.resolve(method.apply(target, msg.args))
|
Promise.resolve(method.apply(target, msg.args))
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (msg.void) return
|
if (msg.void) return
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { afterAll, beforeAll, describe } from 'vitest'
|
import { afterAll, beforeAll, describe } from 'vitest'
|
||||||
|
|
||||||
import { testPeersRepository } from '../../../highlevel/storage/repository/peers.test-utils.js'
|
import {
|
||||||
import { testRefMessagesRepository } from '../../../highlevel/storage/repository/ref-messages.test-utils.js'
|
testAuthKeysRepository,
|
||||||
import { testAuthKeysRepository } from '../../repository/auth-keys.test-utils.js'
|
testKeyValueRepository,
|
||||||
import { testKeyValueRepository } from '../../repository/key-value.test-utils.js'
|
testPeersRepository,
|
||||||
|
testRefMessagesRepository,
|
||||||
|
} from '@mtcute/test'
|
||||||
|
|
||||||
import { IdbStorage } from './index.js'
|
import { IdbStorage } from './index.js'
|
||||||
|
|
||||||
if (import.meta.env.TEST_ENV === 'browser') {
|
if (import.meta.env.TEST_ENV === 'browser') {
|
||||||
|
@ -20,7 +23,7 @@ if (import.meta.env.TEST_ENV === 'browser') {
|
||||||
testRefMessagesRepository(storage.refMessages, storage.driver)
|
testRefMessagesRepository(storage.refMessages, storage.driver)
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
storage.driver.destroy()
|
await storage.driver.destroy()
|
||||||
|
|
||||||
const req = indexedDB.deleteDatabase(idbName)
|
const req = indexedDB.deleteDatabase(idbName)
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
|
|
@ -39,7 +39,7 @@ export class IdbAuthKeysRepository implements IAuthKeysRepository {
|
||||||
async get(dc: number): Promise<Uint8Array | null> {
|
async get(dc: number): Promise<Uint8Array | null> {
|
||||||
const os = this.os()
|
const os = this.os()
|
||||||
|
|
||||||
const it = await reqToPromise<AuthKeyDto>(os.get(dc))
|
const it = await reqToPromise<AuthKeyDto>(os.get(dc) as IDBRequest<AuthKeyDto>)
|
||||||
if (it === undefined) return null
|
if (it === undefined) return null
|
||||||
|
|
||||||
return it.key
|
return it.key
|
||||||
|
@ -61,7 +61,7 @@ export class IdbAuthKeysRepository implements IAuthKeysRepository {
|
||||||
|
|
||||||
async getTemp(dc: number, idx: number, now: number): Promise<Uint8Array | null> {
|
async getTemp(dc: number, idx: number, now: number): Promise<Uint8Array | null> {
|
||||||
const os = this.osTemp()
|
const os = this.osTemp()
|
||||||
const row = await reqToPromise<TempAuthKeyDto>(os.get([dc, idx]))
|
const row = await reqToPromise<TempAuthKeyDto>(os.get([dc, idx]) as IDBRequest<TempAuthKeyDto>)
|
||||||
|
|
||||||
if (row === undefined || row.expiresAt! < now) return null
|
if (row === undefined || row.expiresAt! < now) return null
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ export class IdbKvRepository implements IKeyValueRepository {
|
||||||
|
|
||||||
async get(key: string): Promise<Uint8Array | null> {
|
async get(key: string): Promise<Uint8Array | null> {
|
||||||
const os = this.os()
|
const os = this.os()
|
||||||
const res = await reqToPromise<KeyValueDto>(os.get(key))
|
const res = await reqToPromise<KeyValueDto>(os.get(key) as IDBRequest<KeyValueDto>)
|
||||||
if (res === undefined) return null
|
if (res === undefined) return null
|
||||||
|
|
||||||
return res.value
|
return res.value
|
||||||
|
|
|
@ -22,19 +22,21 @@ export class IdbPeersRepository implements IPeersRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getById(id: number): Promise<IPeersRepository.PeerInfo | null> {
|
async getById(id: number): Promise<IPeersRepository.PeerInfo | null> {
|
||||||
const it = await reqToPromise(this.os().get(id))
|
const it = await reqToPromise(this.os().get(id) as IDBRequest<IPeersRepository.PeerInfo>)
|
||||||
|
|
||||||
return it ?? null
|
return it ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
async getByUsername(username: string): Promise<IPeersRepository.PeerInfo | null> {
|
async getByUsername(username: string): Promise<IPeersRepository.PeerInfo | null> {
|
||||||
const it = await reqToPromise(this.os().index('by_username').get(username))
|
const it = await reqToPromise(
|
||||||
|
this.os().index('by_username').get(username) as IDBRequest<IPeersRepository.PeerInfo>,
|
||||||
|
)
|
||||||
|
|
||||||
return it ?? null
|
return it ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
async getByPhone(phone: string): Promise<IPeersRepository.PeerInfo | null> {
|
async getByPhone(phone: string): Promise<IPeersRepository.PeerInfo | null> {
|
||||||
const it = await reqToPromise(this.os().index('by_phone').get(phone))
|
const it = await reqToPromise(this.os().index('by_phone').get(phone) as IDBRequest<IPeersRepository.PeerInfo>)
|
||||||
|
|
||||||
return it ?? null
|
return it ?? null
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ export class IdbRefMsgRepository implements IReferenceMessagesRepository {
|
||||||
const os = this.os()
|
const os = this.os()
|
||||||
const index = os.index('by_peer')
|
const index = os.index('by_peer')
|
||||||
|
|
||||||
const it = await reqToPromise<MessageRefDto>(index.get(peerId))
|
const it = await reqToPromise<MessageRefDto>(index.get(peerId) as IDBRequest<MessageRefDto>)
|
||||||
if (!it) return null
|
if (!it) return null
|
||||||
|
|
||||||
return [it.chatId, it.msgId]
|
return [it.chatId, it.msgId]
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { describe } from 'vitest'
|
import { describe } from 'vitest'
|
||||||
|
|
||||||
import { testPeersRepository } from '../../../highlevel/storage/repository/peers.test-utils.js'
|
import {
|
||||||
import { testRefMessagesRepository } from '../../../highlevel/storage/repository/ref-messages.test-utils.js'
|
testAuthKeysRepository,
|
||||||
import { testAuthKeysRepository } from '../../repository/auth-keys.test-utils.js'
|
testKeyValueRepository,
|
||||||
import { testKeyValueRepository } from '../../repository/key-value.test-utils.js'
|
testPeersRepository,
|
||||||
|
testRefMessagesRepository,
|
||||||
|
} from '@mtcute/test'
|
||||||
|
|
||||||
import { MemoryStorage } from './index.js'
|
import { MemoryStorage } from './index.js'
|
||||||
|
|
||||||
describe('memory storage', () => {
|
describe('memory storage', () => {
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
export * from '../../highlevel/storage/repository/peers.js'
|
|
||||||
export * from '../../highlevel/storage/repository/ref-messages.js'
|
|
||||||
export * from './auth-keys.js'
|
export * from './auth-keys.js'
|
||||||
export * from './key-value.js'
|
export * from './key-value.js'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { fakeAuthKeysRepository } from '../repository/auth-keys.test-utils.js'
|
import { fakeAuthKeysRepository, fakeKeyValueRepository } from '@mtcute/test'
|
||||||
import { fakeKeyValueRepository } from '../repository/key-value.test-utils.js'
|
|
||||||
import { AuthKeysService } from './auth-keys.js'
|
import { AuthKeysService } from './auth-keys.js'
|
||||||
import { FutureSaltsService } from './future-salts.js'
|
import { FutureSaltsService } from './future-salts.js'
|
||||||
import { testServiceOptions } from './utils.test-utils.js'
|
import { testServiceOptions } from './utils.test-utils.js'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { fakeKeyValueRepository } from '../repository/key-value.test-utils.js'
|
import { fakeKeyValueRepository } from '@mtcute/test'
|
||||||
|
|
||||||
import { UpdatesStateService } from '../../highlevel/storage/service/updates.js'
|
import { UpdatesStateService } from '../../highlevel/storage/service/updates.js'
|
||||||
import { testServiceOptions } from './utils.test-utils.js'
|
import { testServiceOptions } from './utils.test-utils.js'
|
||||||
|
|
||||||
|
@ -73,10 +74,7 @@ describe('updates state service', () => {
|
||||||
it('should write to updates_channel:xxx key', async () => {
|
it('should write to updates_channel:xxx key', async () => {
|
||||||
await service.setChannelPts(123, 0x04030201)
|
await service.setChannelPts(123, 0x04030201)
|
||||||
|
|
||||||
expect(kv.set).toHaveBeenCalledWith(
|
expect(kv.set).toHaveBeenCalledWith('updates_channel:123', new Uint8Array([1, 2, 3, 4]))
|
||||||
'updates_channel:123',
|
|
||||||
new Uint8Array([1, 2, 3, 4]),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -62,7 +62,9 @@ export class StorageManager {
|
||||||
this.driver.setup?.(this.log)
|
this.driver.setup?.(this.log)
|
||||||
|
|
||||||
if (this.options.cleanup ?? true) {
|
if (this.options.cleanup ?? true) {
|
||||||
this._cleanupRestore = beforeExit(() => this._destroy().catch((err) => this.log.error(err)))
|
this._cleanupRestore = beforeExit(() => {
|
||||||
|
this._destroy().catch((err) => this.log.error('cleanup error: %s', err))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.driver.load?.()
|
await this.driver.load?.()
|
||||||
|
|
|
@ -51,8 +51,9 @@ export function asyncResettable<T extends(...args: any[]) => Promise<any>>(func:
|
||||||
return runningPromise
|
return runningPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
runningPromise = func(...args)
|
runningPromise = func(...args)
|
||||||
runningPromise.then(() => {
|
void runningPromise.then(() => {
|
||||||
runningPromise = null
|
runningPromise = null
|
||||||
finished = true
|
finished = true
|
||||||
})
|
})
|
||||||
|
|
|
@ -125,7 +125,12 @@ describe('readStringSession', () => {
|
||||||
testMode: false,
|
testMode: false,
|
||||||
primaryDcs: stubDcs,
|
primaryDcs: stubDcs,
|
||||||
authKey: stubAuthKey,
|
authKey: stubAuthKey,
|
||||||
self: { userId: 12345, isBot: false },
|
self: {
|
||||||
|
userId: 12345,
|
||||||
|
isBot: false,
|
||||||
|
isPremium: false,
|
||||||
|
usernames: [],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -140,7 +145,12 @@ describe('readStringSession', () => {
|
||||||
testMode: true,
|
testMode: true,
|
||||||
primaryDcs: stubDcs,
|
primaryDcs: stubDcs,
|
||||||
authKey: stubAuthKey,
|
authKey: stubAuthKey,
|
||||||
self: { userId: 12345, isBot: false },
|
self: {
|
||||||
|
userId: 12345,
|
||||||
|
isBot: false,
|
||||||
|
isPremium: false,
|
||||||
|
usernames: [],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -158,7 +168,12 @@ describe('readStringSession', () => {
|
||||||
// v1 didn't have separate media dc
|
// v1 didn't have separate media dc
|
||||||
primaryDcs: stubDcsSameMedia,
|
primaryDcs: stubDcsSameMedia,
|
||||||
authKey: stubAuthKey,
|
authKey: stubAuthKey,
|
||||||
self: { userId: 12345, isBot: false },
|
self: {
|
||||||
|
userId: 12345,
|
||||||
|
isBot: false,
|
||||||
|
isPremium: false,
|
||||||
|
usernames: [],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
import { CallbackQuery, MtArgumentError, PeersIndex } from '@mtcute/client'
|
import { CallbackQuery, MtArgumentError, PeersIndex } from '@mtcute/core'
|
||||||
import { utf8EncodeToBuffer } from '@mtcute/client/utils.js'
|
import { utf8EncodeToBuffer } from '@mtcute/core/utils.js'
|
||||||
import { createStub } from '@mtcute/test'
|
import { createStub } from '@mtcute/test'
|
||||||
|
|
||||||
import { CallbackDataBuilder } from './callback-data-builder.js'
|
import { CallbackDataBuilder } from './callback-data-builder.js'
|
||||||
|
|
|
@ -20,12 +20,12 @@ describe('filters.command', () => {
|
||||||
const ctx = createMessageContext({
|
const ctx = createMessageContext({
|
||||||
message: text,
|
message: text,
|
||||||
})
|
})
|
||||||
// todo
|
void ctx.client.storage.self.store({
|
||||||
// ctx.client.getAuthState = () => ({
|
isBot: true,
|
||||||
// isBot: true,
|
isPremium: false,
|
||||||
// userId: 0,
|
userId: 0,
|
||||||
// selfUsername: 'testbot',
|
usernames: ['testbot'],
|
||||||
// })
|
})
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
if (command(...params)(ctx)) return (ctx as any).command
|
if (command(...params)(ctx)) return (ctx as any).command
|
||||||
|
@ -39,11 +39,10 @@ describe('filters.command', () => {
|
||||||
expect(getParsedCommand('/start', ['start', 'stop'])).toEqual(['start'])
|
expect(getParsedCommand('/start', ['start', 'stop'])).toEqual(['start'])
|
||||||
})
|
})
|
||||||
|
|
||||||
// todo
|
it('should only parse commands to the current bot', () => {
|
||||||
// it('should only parse commands to the current bot', () => {
|
expect(getParsedCommand('/start@testbot', 'start')).toEqual(['start'])
|
||||||
// expect(getParsedCommand('/start@testbot', 'start')).toEqual(['start'])
|
expect(getParsedCommand('/start@otherbot', 'start')).toEqual(null)
|
||||||
// expect(getParsedCommand('/start@otherbot', 'start')).toEqual(null)
|
})
|
||||||
// })
|
|
||||||
|
|
||||||
it('should parse command arguments', () => {
|
it('should parse command arguments', () => {
|
||||||
expect(getParsedCommand('/start foo bar baz', 'start')).toEqual(['start', 'foo', 'bar', 'baz'])
|
expect(getParsedCommand('/start foo bar baz', 'start')).toEqual(['start', 'foo', 'bar', 'baz'])
|
||||||
|
|
|
@ -18,15 +18,14 @@ export class StateService {
|
||||||
async load() {
|
async load() {
|
||||||
await this._load.run()
|
await this._load.run()
|
||||||
this._vacuumTimer = setInterval(() => {
|
this._vacuumTimer = setInterval(() => {
|
||||||
Promise.resolve(this.provider.state.vacuum(Date.now()))
|
Promise.resolve(this.provider.state.vacuum(Date.now())).catch(() => {})
|
||||||
.catch(() => {})
|
|
||||||
}, 300_000)
|
}, 300_000)
|
||||||
}
|
}
|
||||||
|
|
||||||
async destroy() {
|
async destroy() {
|
||||||
await this.provider.driver.save?.()
|
await this.provider.driver.save?.()
|
||||||
await this.provider.driver.destroy?.()
|
await this.provider.driver.destroy?.()
|
||||||
clearInterval(this._vacuumTimer!)
|
clearInterval(this._vacuumTimer)
|
||||||
this._loaded = false
|
this._loaded = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
import { PeersIndex, TelegramClient } from '@mtcute/client'
|
import { PeersIndex, TelegramClient } from '@mtcute/core'
|
||||||
|
|
||||||
import { Dispatcher, PropagationAction } from '../src/index.js'
|
import { Dispatcher, PropagationAction } from '../src/index.js'
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Long from 'long'
|
import Long from 'long'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
import { MessageEntity, TextWithEntities, tl } from '@mtcute/client'
|
import { MessageEntity, TextWithEntities, tl } from '@mtcute/core'
|
||||||
|
|
||||||
// prettier has "html" special-cased which breaks the formatting
|
// prettier has "html" special-cased which breaks the formatting
|
||||||
// this is not an issue when using normally, since we properly handle newlines/spaces,
|
// this is not an issue when using normally, since we properly handle newlines/spaces,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
import { Message, PeersIndex } from '@mtcute/client'
|
import { Message, PeersIndex } from '@mtcute/core'
|
||||||
import { MessageContext } from '@mtcute/dispatcher'
|
import { MessageContext } from '@mtcute/dispatcher'
|
||||||
|
|
||||||
import { createMtcuteI18n, OtherLanguageWrap } from '../src/index.js'
|
import { createMtcuteI18n, OtherLanguageWrap } from '../src/index.js'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Long from 'long'
|
import Long from 'long'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
import { MessageEntity, TextWithEntities, tl } from '@mtcute/client'
|
import { MessageEntity, TextWithEntities, tl } from '@mtcute/core'
|
||||||
|
|
||||||
// md is special cased in prettier, we don't want that here
|
// md is special cased in prettier, we don't want that here
|
||||||
import { md as md_ } from './index.js'
|
import { md as md_ } from './index.js'
|
||||||
|
|
|
@ -18,7 +18,7 @@ function mapPeerDto(dto: PeerDto): IPeersRepository.PeerInfo {
|
||||||
return {
|
return {
|
||||||
id: dto.id,
|
id: dto.id,
|
||||||
accessHash: dto.hash,
|
accessHash: dto.hash,
|
||||||
usernames: JSON.parse(dto.usernames),
|
usernames: JSON.parse(dto.usernames) as string[],
|
||||||
updated: dto.updated,
|
updated: dto.updated,
|
||||||
phone: dto.phone || undefined,
|
phone: dto.phone || undefined,
|
||||||
complete: dto.complete,
|
complete: dto.complete,
|
||||||
|
@ -47,7 +47,9 @@ export class SqlitePeersRepository implements IPeersRepository {
|
||||||
)
|
)
|
||||||
|
|
||||||
this._getById = db.prepare('select * from peers where id = ?')
|
this._getById = db.prepare('select * from peers where id = ?')
|
||||||
this._getByUsername = db.prepare('select * from peers where exists (select 1 from json_each(usernames) where value = ?)')
|
this._getByUsername = db.prepare(
|
||||||
|
'select * from peers where exists (select 1 from json_each(usernames) where value = ?)',
|
||||||
|
)
|
||||||
this._getByPhone = db.prepare('select * from peers where phone = ?')
|
this._getByPhone = db.prepare('select * from peers where phone = ?')
|
||||||
|
|
||||||
this._delAll = db.prepare('delete from peers')
|
this._delAll = db.prepare('delete from peers')
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { afterAll, beforeAll, describe } from 'vitest'
|
import { afterAll, beforeAll, describe } from 'vitest'
|
||||||
|
|
||||||
import { testAuthKeysRepository } from '@mtcute/core/src/storage/repository/auth-keys.test-utils.js'
|
|
||||||
import { testKeyValueRepository } from '@mtcute/core/src/storage/repository/key-value.test-utils.js'
|
|
||||||
import { testPeersRepository } from '@mtcute/core/src/storage/repository/peers.test-utils.js'
|
|
||||||
import { testRefMessagesRepository } from '@mtcute/core/src/storage/repository/ref-messages.test-utils.js'
|
|
||||||
import { LogManager } from '@mtcute/core/utils.js'
|
import { LogManager } from '@mtcute/core/utils.js'
|
||||||
|
import {
|
||||||
|
testAuthKeysRepository,
|
||||||
|
testKeyValueRepository,
|
||||||
|
testPeersRepository,
|
||||||
|
testRefMessagesRepository,
|
||||||
|
} from '@mtcute/test'
|
||||||
|
|
||||||
import { SqliteStorage } from '../src/index.js'
|
import { SqliteStorage } from '../src/index.js'
|
||||||
|
|
||||||
|
@ -12,9 +14,9 @@ if (import.meta.env.TEST_ENV === 'node') {
|
||||||
describe('SqliteStorage', () => {
|
describe('SqliteStorage', () => {
|
||||||
const storage = new SqliteStorage(':memory:')
|
const storage = new SqliteStorage(':memory:')
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(async () => {
|
||||||
storage.driver.setup(new LogManager())
|
storage.driver.setup(new LogManager())
|
||||||
storage.driver.load()
|
await storage.driver.load()
|
||||||
})
|
})
|
||||||
|
|
||||||
testAuthKeysRepository(storage.authKeys)
|
testAuthKeysRepository(storage.authKeys)
|
||||||
|
|
|
@ -24,6 +24,7 @@ export class StubTelegramClient extends BaseTelegramClient {
|
||||||
apiHash: '',
|
apiHash: '',
|
||||||
logLevel: 0,
|
logLevel: 0,
|
||||||
storage,
|
storage,
|
||||||
|
disableUpdates: true,
|
||||||
transport: () => {
|
transport: () => {
|
||||||
const transport = new StubTelegramTransport({
|
const transport = new StubTelegramTransport({
|
||||||
onMessage: (data) => {
|
onMessage: (data) => {
|
||||||
|
@ -279,15 +280,8 @@ export class StubTelegramClient extends BaseTelegramClient {
|
||||||
|
|
||||||
// helpers //
|
// helpers //
|
||||||
|
|
||||||
async connectAndWait() {
|
|
||||||
await this.connect()
|
|
||||||
await new Promise((resolve): void => {
|
|
||||||
this.mt.once('usable', resolve)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async with(fn: () => MaybeAsync<void>): Promise<void> {
|
async with(fn: () => MaybeAsync<void>): Promise<void> {
|
||||||
await this.connectAndWait()
|
await this.connect()
|
||||||
|
|
||||||
let error: unknown
|
let error: unknown
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export * from './client.js'
|
export * from './client.js'
|
||||||
export * from './crypto.js'
|
export * from './crypto.js'
|
||||||
export * from './storage.js'
|
export * from './storage.js'
|
||||||
// export * from './storage-test.js' // todo
|
export * from './storage/index.js'
|
||||||
export * from './stub.js'
|
export * from './stub.js'
|
||||||
export * from './transport.js'
|
export * from './transport.js'
|
||||||
export * from './types.js'
|
export * from './types.js'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { IAuthKeysRepository } from './auth-keys.js'
|
import { IAuthKeysRepository } from '@mtcute/core'
|
||||||
|
|
||||||
export function fakeAuthKeysRepository(): IAuthKeysRepository {
|
export function fakeAuthKeysRepository(): IAuthKeysRepository {
|
||||||
return {
|
return {
|
4
packages/test/src/storage/index.ts
Normal file
4
packages/test/src/storage/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export * from './auth-keys.js'
|
||||||
|
export * from './key-value.js'
|
||||||
|
export * from './peers.js'
|
||||||
|
export * from './ref-messages.js'
|
|
@ -1,7 +1,6 @@
|
||||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { IStorageDriver } from '../driver.js'
|
import { IKeyValueRepository, IStorageDriver } from '@mtcute/core'
|
||||||
import { IKeyValueRepository } from './key-value.js'
|
|
||||||
|
|
||||||
export function fakeKeyValueRepository(): IKeyValueRepository {
|
export function fakeKeyValueRepository(): IKeyValueRepository {
|
||||||
return {
|
return {
|
|
@ -1,11 +1,10 @@
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { createStub } from '@mtcute/test'
|
import { IPeersRepository, IStorageDriver } from '@mtcute/core'
|
||||||
|
import { TlBinaryWriter } from '@mtcute/core/utils.js'
|
||||||
import { __tlWriterMap } from '@mtcute/tl/binary/writer.js'
|
import { __tlWriterMap } from '@mtcute/tl/binary/writer.js'
|
||||||
import { TlBinaryWriter } from '@mtcute/tl-runtime'
|
|
||||||
|
|
||||||
import { IStorageDriver } from '../../../storage/driver.js'
|
import { createStub } from '../stub.js'
|
||||||
import { IPeersRepository } from './peers.js'
|
|
||||||
|
|
||||||
export function fakePeersRepository(): IPeersRepository {
|
export function fakePeersRepository(): IPeersRepository {
|
||||||
return {
|
return {
|
||||||
|
@ -56,8 +55,8 @@ export function testPeersRepository(repo: IPeersRepository, driver: IStorageDriv
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should store and retrieve peers', async () => {
|
it('should store and retrieve peers', async () => {
|
||||||
repo.store(stubPeerUser)
|
await repo.store(stubPeerUser)
|
||||||
repo.store(stubPeerChannel)
|
await repo.store(stubPeerChannel)
|
||||||
await driver.save?.()
|
await driver.save?.()
|
||||||
|
|
||||||
expect(fixPeerInfo(await repo.getById(123123))).toEqual(stubPeerUser)
|
expect(fixPeerInfo(await repo.getById(123123))).toEqual(stubPeerUser)
|
||||||
|
@ -69,11 +68,11 @@ export function testPeersRepository(repo: IPeersRepository, driver: IStorageDriv
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should update peers usernames', async () => {
|
it('should update peers usernames', async () => {
|
||||||
repo.store(stubPeerUser)
|
await repo.store(stubPeerUser)
|
||||||
await driver.save?.()
|
await driver.save?.()
|
||||||
|
|
||||||
const modUser = { ...stubPeerUser, usernames: ['some_user2'] }
|
const modUser = { ...stubPeerUser, usernames: ['some_user2'] }
|
||||||
repo.store(modUser)
|
await repo.store(modUser)
|
||||||
await driver.save?.()
|
await driver.save?.()
|
||||||
|
|
||||||
expect(fixPeerInfo(await repo.getById(123123))).toEqual(modUser)
|
expect(fixPeerInfo(await repo.getById(123123))).toEqual(modUser)
|
|
@ -1,7 +1,6 @@
|
||||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { IStorageDriver } from '../../../storage/driver.js'
|
import { IReferenceMessagesRepository, IStorageDriver } from '@mtcute/core'
|
||||||
import { IReferenceMessagesRepository } from './ref-messages.js'
|
|
||||||
|
|
||||||
export function fakeRefMessagesRepository(): IReferenceMessagesRepository {
|
export function fakeRefMessagesRepository(): IReferenceMessagesRepository {
|
||||||
return {
|
return {
|
||||||
|
@ -27,7 +26,10 @@ export function testRefMessagesRepository(repo: IReferenceMessagesRepository, dr
|
||||||
await repo.store(2, 6, 7)
|
await repo.store(2, 6, 7)
|
||||||
await driver.save?.()
|
await driver.save?.()
|
||||||
|
|
||||||
expect(await repo.getByPeer(1)).deep.oneOf([[2, 3], [4, 5]])
|
expect(await repo.getByPeer(1)).deep.oneOf([
|
||||||
|
[2, 3],
|
||||||
|
[4, 5],
|
||||||
|
])
|
||||||
expect(await repo.getByPeer(2)).toEqual([6, 7])
|
expect(await repo.getByPeer(2)).toEqual([6, 7])
|
||||||
expect(await repo.getByPeer(3)).toEqual(null)
|
expect(await repo.getByPeer(3)).toEqual(null)
|
||||||
expect(await repo.getByPeer(4)).toEqual(null)
|
expect(await repo.getByPeer(4)).toEqual(null)
|
||||||
|
@ -64,7 +66,11 @@ export function testRefMessagesRepository(repo: IReferenceMessagesRepository, dr
|
||||||
await repo.deleteByPeer(1)
|
await repo.deleteByPeer(1)
|
||||||
await driver.save?.()
|
await driver.save?.()
|
||||||
expect(await repo.getByPeer(1)).toEqual(null)
|
expect(await repo.getByPeer(1)).toEqual(null)
|
||||||
expect(await repo.getByPeer(2)).deep.oneOf([[20, 30], [40, 50], [60, 70]])
|
expect(await repo.getByPeer(2)).deep.oneOf([
|
||||||
|
[20, 30],
|
||||||
|
[40, 50],
|
||||||
|
[60, 70],
|
||||||
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import EventEmitter from 'events'
|
import EventEmitter from 'events'
|
||||||
|
|
||||||
import { tl } from '@mtcute/tl'
|
|
||||||
import { ITelegramTransport, TransportState } from '@mtcute/core'
|
import { ITelegramTransport, TransportState } from '@mtcute/core'
|
||||||
import { ICryptoProvider, Logger } from '@mtcute/core/utils.js'
|
import { ICryptoProvider, Logger } from '@mtcute/core/utils.js'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
export class StubTelegramTransport extends EventEmitter implements ITelegramTransport {
|
export class StubTelegramTransport extends EventEmitter implements ITelegramTransport {
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { readFile, writeFile } from 'fs/promises'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import * as readline from 'readline'
|
import * as readline from 'readline'
|
||||||
|
|
||||||
|
import { hasPresentKey, isPresent } from '@mtcute/core/utils.js'
|
||||||
import {
|
import {
|
||||||
generateTlSchemasDifference,
|
generateTlSchemasDifference,
|
||||||
mergeTlEntries,
|
mergeTlEntries,
|
||||||
|
@ -19,7 +20,6 @@ import {
|
||||||
TlFullSchema,
|
TlFullSchema,
|
||||||
writeTlEntryToString,
|
writeTlEntryToString,
|
||||||
} from '@mtcute/tl-utils'
|
} from '@mtcute/tl-utils'
|
||||||
import { hasPresentKey, isPresent } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
__dirname,
|
__dirname,
|
||||||
|
|
Loading…
Reference in a new issue