fix: fixed upload and download for new networking
This commit is contained in:
parent
85c43d804d
commit
4a0d6fbc88
30 changed files with 1014 additions and 821 deletions
|
@ -181,6 +181,10 @@ module.exports = {
|
||||||
],
|
],
|
||||||
globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly' },
|
globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly' },
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
project: true,
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
},
|
||||||
plugins: ['@typescript-eslint'],
|
plugins: ['@typescript-eslint'],
|
||||||
rules: {
|
rules: {
|
||||||
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules
|
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules
|
||||||
|
|
10
package.json
10
package.json
|
@ -27,15 +27,15 @@
|
||||||
"@types/node": "18.16.0",
|
"@types/node": "18.16.0",
|
||||||
"@types/node-forge": "1.3.2",
|
"@types/node-forge": "1.3.2",
|
||||||
"@types/ws": "8.5.4",
|
"@types/ws": "8.5.4",
|
||||||
"@typescript-eslint/eslint-plugin": "5.59.8",
|
"@typescript-eslint/eslint-plugin": "6.4.0",
|
||||||
"@typescript-eslint/parser": "5.59.8",
|
"@typescript-eslint/parser": "6.4.0",
|
||||||
"chai": "4.3.7",
|
"chai": "4.3.7",
|
||||||
"dotenv-flow": "3.2.0",
|
"dotenv-flow": "3.2.0",
|
||||||
"eslint": "8.42.0",
|
"eslint": "8.47.0",
|
||||||
"eslint-config-prettier": "8.8.0",
|
"eslint-config-prettier": "8.8.0",
|
||||||
"eslint-import-resolver-typescript": "3.5.5",
|
"eslint-import-resolver-typescript": "3.6.0",
|
||||||
"eslint-plugin-ascii": "1.0.0",
|
"eslint-plugin-ascii": "1.0.0",
|
||||||
"eslint-plugin-import": "2.27.5",
|
"eslint-plugin-import": "2.28.0",
|
||||||
"eslint-plugin-simple-import-sort": "10.0.0",
|
"eslint-plugin-simple-import-sort": "10.0.0",
|
||||||
"glob": "10.2.6",
|
"glob": "10.2.6",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
|
|
|
@ -64,8 +64,11 @@ async function addSingleMethod(state, fileName) {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!stmt.importClause.namedBindings ||
|
!stmt.importClause.namedBindings ||
|
||||||
stmt.importClause.namedBindings.kind !== ts.SyntaxKind.NamedImports
|
stmt.importClause.namedBindings.kind !==
|
||||||
) { throwError(stmt, fileName, 'Only named imports are supported!') }
|
ts.SyntaxKind.NamedImports
|
||||||
|
) {
|
||||||
|
throwError(stmt, fileName, 'Only named imports are supported!')
|
||||||
|
}
|
||||||
|
|
||||||
let module = stmt.moduleSpecifier.text
|
let module = stmt.moduleSpecifier.text
|
||||||
|
|
||||||
|
@ -131,11 +134,7 @@ async function addSingleMethod(state, fileName) {
|
||||||
})()
|
})()
|
||||||
|
|
||||||
if (!isExported && !isPrivate) {
|
if (!isExported && !isPrivate) {
|
||||||
throwError(
|
throwError(stmt, fileName, 'Public methods MUST be exported.')
|
||||||
stmt,
|
|
||||||
fileName,
|
|
||||||
'Public methods MUST be exported.',
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isExported && !checkForFlag(stmt, '@internal')) {
|
if (isExported && !checkForFlag(stmt, '@internal')) {
|
||||||
|
@ -182,8 +181,12 @@ async function addSingleMethod(state, fileName) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnsExported = (stmt.body ?
|
const returnsExported = (
|
||||||
ts.getLeadingCommentRanges(fileFullText, stmt.body.pos + 2) ||
|
stmt.body ?
|
||||||
|
ts.getLeadingCommentRanges(
|
||||||
|
fileFullText,
|
||||||
|
stmt.body.pos + 2,
|
||||||
|
) ||
|
||||||
(stmt.statements &&
|
(stmt.statements &&
|
||||||
stmt.statements.length &&
|
stmt.statements.length &&
|
||||||
ts.getLeadingCommentRanges(
|
ts.getLeadingCommentRanges(
|
||||||
|
@ -275,7 +278,9 @@ async function addSingleMethod(state, fileName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const output = fs.createWriteStream(path.join(__dirname, '../src/client.ts'))
|
const output = fs.createWriteStream(
|
||||||
|
path.join(__dirname, '../src/client.ts'),
|
||||||
|
)
|
||||||
const state = {
|
const state = {
|
||||||
imports: {},
|
imports: {},
|
||||||
fields: [],
|
fields: [],
|
||||||
|
@ -295,6 +300,7 @@ async function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
output.write(
|
output.write(
|
||||||
|
'/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging, @typescript-eslint/unified-signatures */\n' +
|
||||||
'/* THIS FILE WAS AUTO-GENERATED */\n' +
|
'/* THIS FILE WAS AUTO-GENERATED */\n' +
|
||||||
"import { BaseTelegramClient, BaseTelegramClientOptions } from '@mtcute/core'\n" +
|
"import { BaseTelegramClient, BaseTelegramClientOptions } from '@mtcute/core'\n" +
|
||||||
"import { tl } from '@mtcute/tl'\n",
|
"import { tl } from '@mtcute/tl'\n",
|
||||||
|
@ -336,7 +342,9 @@ async function main() {
|
||||||
* @param name Event name
|
* @param name Event name
|
||||||
* @param handler ${updates.toSentence(type, 'full')}
|
* @param handler ${updates.toSentence(type, 'full')}
|
||||||
*/
|
*/
|
||||||
on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this\n`)
|
on(name: '${type.typeName}', handler: ((upd: ${
|
||||||
|
type.updateType
|
||||||
|
}) => void)): this\n`)
|
||||||
})
|
})
|
||||||
|
|
||||||
const printer = ts.createPrinter()
|
const printer = ts.createPrinter()
|
||||||
|
@ -406,7 +414,9 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
|
||||||
it.initializer = undefined
|
it.initializer = undefined
|
||||||
|
|
||||||
const deleteParents = (obj) => {
|
const deleteParents = (obj) => {
|
||||||
if (Array.isArray(obj)) { return obj.forEach((it) => deleteParents(it)) }
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.forEach((it) => deleteParents(it))
|
||||||
|
}
|
||||||
|
|
||||||
if (obj.parent) delete obj.parent
|
if (obj.parent) delete obj.parent
|
||||||
|
|
||||||
|
@ -465,18 +475,14 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!overload) {
|
if (!overload) {
|
||||||
classContents.push(
|
classContents.push(`${name} = ${origName}`)
|
||||||
`${name} = ${origName}`,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
output.write('}\n')
|
output.write('}\n')
|
||||||
|
|
||||||
output.write(
|
output.write('\nexport class TelegramClient extends BaseTelegramClient {\n')
|
||||||
'\nexport class TelegramClient extends BaseTelegramClient {\n',
|
|
||||||
)
|
|
||||||
|
|
||||||
state.fields.forEach(({ code }) => output.write(`protected ${code}\n`))
|
state.fields.forEach(({ code }) => output.write(`protected ${code}\n`))
|
||||||
|
|
||||||
|
@ -501,10 +507,9 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
|
||||||
await fs.promises.writeFile(targetFile, fullSource)
|
await fs.promises.writeFile(targetFile, fullSource)
|
||||||
|
|
||||||
// fix using eslint
|
// fix using eslint
|
||||||
require('child_process').execSync(
|
require('child_process').execSync(`pnpm exec eslint --fix ${targetFile}`, {
|
||||||
`pnpm exec eslint --fix ${targetFile}`,
|
stdio: 'inherit',
|
||||||
{ stdio: 'inherit' },
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error)
|
main().catch(console.error)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
|
||||||
/* THIS FILE WAS AUTO-GENERATED */
|
/* THIS FILE WAS AUTO-GENERATED */
|
||||||
import { Readable } from 'stream'
|
import { Readable } from 'stream'
|
||||||
|
|
||||||
|
@ -8,7 +9,6 @@ import {
|
||||||
Deque,
|
Deque,
|
||||||
MaybeArray,
|
MaybeArray,
|
||||||
MaybeAsync,
|
MaybeAsync,
|
||||||
SessionConnection,
|
|
||||||
SortedLinkedList,
|
SortedLinkedList,
|
||||||
} from '@mtcute/core'
|
} from '@mtcute/core'
|
||||||
import { ConditionVariable } from '@mtcute/core/src/utils/condition-variable'
|
import { ConditionVariable } from '@mtcute/core/src/utils/condition-variable'
|
||||||
|
@ -1908,14 +1908,15 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total file size. Automatically inferred for Buffer, File and local files.
|
* Total file size. Automatically inferred for Buffer, File and local files.
|
||||||
*
|
|
||||||
* When using with streams, if `fileSize` is not passed, the entire file is
|
|
||||||
* first loaded into memory to determine file size, and used as a Buffer later.
|
|
||||||
* This might be a major performance bottleneck, so be sure to provide file size
|
|
||||||
* when using streams and file size is known (which often is the case).
|
|
||||||
*/
|
*/
|
||||||
fileSize?: number
|
fileSize?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the file size is unknown, you can provide an estimate,
|
||||||
|
* which will be used to determine appropriate part size.
|
||||||
|
*/
|
||||||
|
estimatedSize?: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File MIME type. By default is automatically inferred from magic number
|
* File MIME type. By default is automatically inferred from magic number
|
||||||
* If MIME can't be inferred, it defaults to `application/octet-stream`
|
* If MIME can't be inferred, it defaults to `application/octet-stream`
|
||||||
|
@ -1930,11 +1931,16 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*/
|
*/
|
||||||
partSize?: number
|
partSize?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of parts to be sent in parallel per connection.
|
||||||
|
*/
|
||||||
|
requestsPerConnection?: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that will be called after some part has been uploaded.
|
* Function that will be called after some part has been uploaded.
|
||||||
*
|
*
|
||||||
* @param uploaded Number of bytes already uploaded
|
* @param uploaded Number of bytes already uploaded
|
||||||
* @param total Total file size
|
* @param total Total file size, if known
|
||||||
*/
|
*/
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
}): Promise<UploadedFile>
|
}): Promise<UploadedFile>
|
||||||
|
@ -4019,7 +4025,6 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
protected _selfUsername: string | null
|
protected _selfUsername: string | null
|
||||||
protected _pendingConversations: Record<number, Conversation[]>
|
protected _pendingConversations: Record<number, Conversation[]>
|
||||||
protected _hasConversations: boolean
|
protected _hasConversations: boolean
|
||||||
protected _downloadConnections: Record<number, SessionConnection>
|
|
||||||
protected _parseModes: Record<string, IMessageEntityParser>
|
protected _parseModes: Record<string, IMessageEntityParser>
|
||||||
protected _defaultParseMode: string | null
|
protected _defaultParseMode: string | null
|
||||||
protected _updatesLoopActive: boolean
|
protected _updatesLoopActive: boolean
|
||||||
|
@ -4054,7 +4059,6 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
this.log.prefix = '[USER N/A] '
|
this.log.prefix = '[USER N/A] '
|
||||||
this._pendingConversations = {}
|
this._pendingConversations = {}
|
||||||
this._hasConversations = false
|
this._hasConversations = false
|
||||||
this._downloadConnections = {}
|
|
||||||
this._parseModes = {}
|
this._parseModes = {}
|
||||||
this._defaultParseMode = null
|
this._defaultParseMode = null
|
||||||
this._updatesLoopActive = false
|
this._updatesLoopActive = false
|
||||||
|
|
|
@ -2,12 +2,7 @@
|
||||||
import { Readable } from 'stream'
|
import { Readable } from 'stream'
|
||||||
|
|
||||||
// @copy
|
// @copy
|
||||||
import {
|
import { AsyncLock, MaybeArray, MaybeAsync } from '@mtcute/core'
|
||||||
AsyncLock,
|
|
||||||
MaybeArray,
|
|
||||||
MaybeAsync,
|
|
||||||
SessionConnection,
|
|
||||||
} from '@mtcute/core'
|
|
||||||
// @copy
|
// @copy
|
||||||
import { Logger } from '@mtcute/core/src/utils/logger'
|
import { Logger } from '@mtcute/core/src/utils/logger'
|
||||||
// @copy
|
// @copy
|
||||||
|
|
|
@ -155,8 +155,9 @@ export async function start(
|
||||||
me.isBot,
|
me.isBot,
|
||||||
)
|
)
|
||||||
|
|
||||||
// todo where is this._disableUpdates?
|
this.network.setIsPremium(me.isPremium)
|
||||||
if (!false) {
|
|
||||||
|
if (!this.network.params.disableUpdates) {
|
||||||
this._catchUpChannels = Boolean(params.catchUp)
|
this._catchUpChannels = Boolean(params.catchUp)
|
||||||
|
|
||||||
if (!params.catchUp) {
|
if (!params.catchUp) {
|
||||||
|
@ -176,14 +177,18 @@ export async function start(
|
||||||
if (!(e instanceof tl.errors.AuthKeyUnregisteredError)) throw e
|
if (!(e instanceof tl.errors.AuthKeyUnregisteredError)) throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.phone && !params.botToken) { throw new MtArgumentError('Neither phone nor bot token were provided') }
|
if (!params.phone && !params.botToken) {
|
||||||
|
throw new MtArgumentError('Neither phone nor bot token were provided')
|
||||||
|
}
|
||||||
|
|
||||||
let phone = params.phone ? await resolveMaybeDynamic(params.phone) : null
|
let phone = params.phone ? await resolveMaybeDynamic(params.phone) : null
|
||||||
|
|
||||||
if (phone) {
|
if (phone) {
|
||||||
phone = normalizePhoneNumber(phone)
|
phone = normalizePhoneNumber(phone)
|
||||||
|
|
||||||
if (!params.code) { throw new MtArgumentError('You must pass `code` to use `phone`') }
|
if (!params.code) {
|
||||||
|
throw new MtArgumentError('You must pass `code` to use `phone`')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const botToken = params.botToken ?
|
const botToken = params.botToken ?
|
||||||
await resolveMaybeDynamic(params.botToken) :
|
await resolveMaybeDynamic(params.botToken) :
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { SessionConnection } from '@mtcute/core'
|
|
||||||
|
|
||||||
import { TelegramClient } from '../../client'
|
|
||||||
|
|
||||||
// @extension
|
|
||||||
interface FilesExtension {
|
|
||||||
_downloadConnections: Record<number, SessionConnection>
|
|
||||||
}
|
|
||||||
|
|
||||||
// @initialize
|
|
||||||
function _initializeFiles(this: TelegramClient): void {
|
|
||||||
this._downloadConnections = {}
|
|
||||||
}
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ConditionVariable, ConnectionKind } from '@mtcute/core'
|
||||||
import {
|
import {
|
||||||
fileIdToInputFileLocation,
|
fileIdToInputFileLocation,
|
||||||
fileIdToInputWebFileLocation,
|
fileIdToInputWebFileLocation,
|
||||||
|
@ -10,9 +11,16 @@ import {
|
||||||
FileDownloadParameters,
|
FileDownloadParameters,
|
||||||
FileLocation,
|
FileLocation,
|
||||||
MtArgumentError,
|
MtArgumentError,
|
||||||
|
MtUnsupportedError,
|
||||||
} from '../../types'
|
} from '../../types'
|
||||||
import { determinePartSize } from '../../utils/file-utils'
|
import { determinePartSize } from '../../utils/file-utils'
|
||||||
|
|
||||||
|
// small files (less than 128 kb) are downloaded using the "downloadSmall" pool
|
||||||
|
// furthermore, if the file is small and is located on our main DC, it will be downloaded
|
||||||
|
// using the current main connection
|
||||||
|
const SMALL_FILE_MAX_SIZE = 131072
|
||||||
|
const REQUESTS_PER_CONNECTION = 3 // some arbitrary magic value that seems to work best
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a file and return it as an iterable, which yields file contents
|
* Download a file and return it as an iterable, which yields file contents
|
||||||
* in chunks of a given size. Order of the chunks is guaranteed to be
|
* in chunks of a given size. Order of the chunks is guaranteed to be
|
||||||
|
@ -25,16 +33,6 @@ export async function* downloadAsIterable(
|
||||||
this: TelegramClient,
|
this: TelegramClient,
|
||||||
params: FileDownloadParameters,
|
params: FileDownloadParameters,
|
||||||
): AsyncIterableIterator<Buffer> {
|
): AsyncIterableIterator<Buffer> {
|
||||||
const partSizeKb =
|
|
||||||
params.partSize ??
|
|
||||||
(params.fileSize ? determinePartSize(params.fileSize) : 64)
|
|
||||||
|
|
||||||
if (partSizeKb % 4 !== 0) {
|
|
||||||
throw new MtArgumentError(
|
|
||||||
`Invalid part size: ${partSizeKb}. Must be divisible by 4.`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const offset = params.offset ?? 0
|
const offset = params.offset ?? 0
|
||||||
|
|
||||||
if (offset % 4096 !== 0) {
|
if (offset % 4096 !== 0) {
|
||||||
|
@ -77,91 +75,151 @@ export async function* downloadAsIterable(
|
||||||
// we will receive a FileMigrateError in case this is invalid
|
// we will receive a FileMigrateError in case this is invalid
|
||||||
if (!dcId) dcId = this._defaultDc.id
|
if (!dcId) dcId = this._defaultDc.id
|
||||||
|
|
||||||
|
const partSizeKb =
|
||||||
|
params.partSize ?? (fileSize ? determinePartSize(fileSize) : 64)
|
||||||
|
|
||||||
|
if (partSizeKb % 4 !== 0) {
|
||||||
|
throw new MtArgumentError(
|
||||||
|
`Invalid part size: ${partSizeKb}. Must be divisible by 4.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const chunkSize = partSizeKb * 1024
|
const chunkSize = partSizeKb * 1024
|
||||||
|
|
||||||
const limit =
|
let limitBytes = params.limit ?? fileSize ?? Infinity
|
||||||
params.limit ??
|
if (limitBytes === 0) return
|
||||||
// derive limit from chunk size, file size and offset
|
|
||||||
(fileSize ?
|
|
||||||
~~((fileSize + chunkSize - offset - 1) / chunkSize) :
|
|
||||||
// we will receive an error when we have reached the end anyway
|
|
||||||
Infinity)
|
|
||||||
|
|
||||||
// fixme
|
let numChunks =
|
||||||
throw new Error('TODO')
|
limitBytes === Infinity ?
|
||||||
|
Infinity :
|
||||||
|
~~((limitBytes + chunkSize - offset - 1) / chunkSize)
|
||||||
|
|
||||||
// let connection = this._downloadConnections[dcId]
|
let nextChunkIdx = 0
|
||||||
|
let nextWorkerChunkIdx = 0
|
||||||
|
const nextChunkCv = new ConditionVariable()
|
||||||
|
const buffer: Record<number, Buffer> = {}
|
||||||
|
|
||||||
// if (!connection) {
|
const isSmall = fileSize && fileSize <= SMALL_FILE_MAX_SIZE
|
||||||
// connection = await this.createAdditionalConnection(dcId)
|
let connectionKind: ConnectionKind
|
||||||
// this._downloadConnections[dcId] = connection
|
|
||||||
// }
|
if (isSmall) {
|
||||||
//
|
connectionKind =
|
||||||
// const requestCurrent = async (): Promise<Buffer> => {
|
dcId === this.network.getPrimaryDcId() ? 'main' : 'downloadSmall'
|
||||||
// let result:
|
} else {
|
||||||
// | tl.RpcCallReturn['upload.getFile']
|
connectionKind = 'download'
|
||||||
// | tl.RpcCallReturn['upload.getWebFile']
|
}
|
||||||
//
|
const poolSize = this.network.getPoolSize(connectionKind, dcId)
|
||||||
// try {
|
|
||||||
// result = await this.call(
|
this.log.debug(
|
||||||
// {
|
'Downloading file of size %d from dc %d using %s connection pool (pool size: %d)',
|
||||||
// _: isWeb ? 'upload.getWebFile' : 'upload.getFile',
|
limitBytes,
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
dcId,
|
||||||
// location: location as any,
|
connectionKind,
|
||||||
// offset,
|
poolSize,
|
||||||
// limit: chunkSize,
|
)
|
||||||
// },
|
|
||||||
// { connection },
|
const downloadChunk = async (
|
||||||
// )
|
chunk = nextWorkerChunkIdx++,
|
||||||
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
): Promise<void> => {
|
||||||
// } catch (e: any) {
|
let result:
|
||||||
// if (e.constructor === tl.errors.FileMigrateXError) {
|
| tl.RpcCallReturn['upload.getFile']
|
||||||
// connection = this._downloadConnections[e.new_dc]
|
| tl.RpcCallReturn['upload.getWebFile']
|
||||||
//
|
|
||||||
// if (!connection) {
|
try {
|
||||||
// connection = await this.createAdditionalConnection(e.new_dc)
|
result = await this.call(
|
||||||
// this._downloadConnections[e.new_dc] = connection
|
{
|
||||||
// }
|
_: isWeb ? 'upload.getWebFile' : 'upload.getFile',
|
||||||
//
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
// return requestCurrent()
|
location: location as any,
|
||||||
// } else if (e.constructor === tl.errors.FilerefUpgradeNeededError) {
|
offset: chunkSize * chunk,
|
||||||
// // todo: implement someday
|
limit: chunkSize,
|
||||||
// // see: https://github.com/LonamiWebs/Telethon/blob/0e8bd8248cc649637b7c392616887c50986427a0/telethon/client/downloads.py#L99
|
},
|
||||||
// throw new MtUnsupportedError('File ref expired!')
|
{ dcId, kind: connectionKind },
|
||||||
// } else throw e
|
)
|
||||||
// }
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
//
|
} catch (e: any) {
|
||||||
// if (result._ === 'upload.fileCdnRedirect') {
|
if (e.constructor === tl.errors.FileMigrateXError) {
|
||||||
// // we shouldnt receive them since cdnSupported is not set in the getFile request.
|
dcId = e.new_dc
|
||||||
// // also, i couldnt find any media that would be downloaded from cdn, so even if
|
|
||||||
// // i implemented that, i wouldnt be able to test that, so :shrug:
|
return downloadChunk(chunk)
|
||||||
// throw new MtUnsupportedError(
|
} else if (e.constructor === tl.errors.FilerefUpgradeNeededError) {
|
||||||
// 'Received CDN redirect, which is not supported (yet)',
|
// todo: implement someday
|
||||||
// )
|
// see: https://github.com/LonamiWebs/Telethon/blob/0e8bd8248cc649637b7c392616887c50986427a0/telethon/client/downloads.py#L99
|
||||||
// }
|
throw new MtUnsupportedError('File ref expired!')
|
||||||
//
|
} else throw e
|
||||||
// if (
|
}
|
||||||
// result._ === 'upload.webFile' &&
|
|
||||||
// result.size &&
|
if (result._ === 'upload.fileCdnRedirect') {
|
||||||
// limit === Infinity
|
// we shouldnt receive them since cdnSupported is not set in the getFile request.
|
||||||
// ) {
|
// also, i couldnt find any media that would be downloaded from cdn, so even if
|
||||||
// limit = result.size
|
// i implemented that, i wouldnt be able to test that, so :shrug:
|
||||||
// }
|
throw new MtUnsupportedError(
|
||||||
//
|
'Received CDN redirect, which is not supported (yet)',
|
||||||
// return result.bytes
|
)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// for (let i = 0; i < limit; i++) {
|
if (
|
||||||
// const buf = await requestCurrent()
|
result._ === 'upload.webFile' &&
|
||||||
//
|
result.size &&
|
||||||
// if (buf.length === 0) {
|
limitBytes === Infinity
|
||||||
// // we've reached the end
|
) {
|
||||||
// return
|
limitBytes = result.size
|
||||||
// }
|
numChunks = ~~((limitBytes + chunkSize - offset - 1) / chunkSize)
|
||||||
//
|
}
|
||||||
// yield buf
|
|
||||||
// offset += chunkSize
|
buffer[chunk] = result.bytes
|
||||||
//
|
|
||||||
// params.progressCallback?.(offset, limit)
|
if (chunk === nextChunkIdx) {
|
||||||
// }
|
nextChunkCv.notify()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
nextWorkerChunkIdx < numChunks &&
|
||||||
|
result.bytes.length === chunkSize
|
||||||
|
) {
|
||||||
|
return downloadChunk()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let error: unknown = undefined
|
||||||
|
Promise.all(
|
||||||
|
Array.from(
|
||||||
|
{ length: Math.min(poolSize * REQUESTS_PER_CONNECTION, numChunks) },
|
||||||
|
downloadChunk,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.catch((e) => {
|
||||||
|
this.log.debug('download workers errored: %s', e.message)
|
||||||
|
error = e
|
||||||
|
nextChunkCv.notify()
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.log.debug('download workers finished')
|
||||||
|
})
|
||||||
|
|
||||||
|
let position = offset
|
||||||
|
|
||||||
|
while (position < limitBytes) {
|
||||||
|
await nextChunkCv.wait()
|
||||||
|
|
||||||
|
if (error) throw error
|
||||||
|
|
||||||
|
while (nextChunkIdx in buffer) {
|
||||||
|
const buf = buffer[nextChunkIdx]
|
||||||
|
delete buffer[nextChunkIdx]
|
||||||
|
|
||||||
|
position += buf.length
|
||||||
|
|
||||||
|
params.progressCallback?.(position, limitBytes)
|
||||||
|
|
||||||
|
yield buf
|
||||||
|
|
||||||
|
nextChunkIdx++
|
||||||
|
|
||||||
|
if (buf.length < chunkSize) {
|
||||||
|
// we received the last chunk
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { fromBuffer as fileTypeFromBuffer } from 'file-type'
|
||||||
import type { ReadStream } from 'fs'
|
import type { ReadStream } from 'fs'
|
||||||
import { Readable } from 'stream'
|
import { Readable } from 'stream'
|
||||||
|
|
||||||
import { randomLong } from '@mtcute/core'
|
import { AsyncLock, randomLong } from '@mtcute/core'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
|
@ -13,7 +13,6 @@ import {
|
||||||
bufferToStream,
|
bufferToStream,
|
||||||
convertWebStreamToNodeReadable,
|
convertWebStreamToNodeReadable,
|
||||||
readBytesFromStream,
|
readBytesFromStream,
|
||||||
readStreamUntilEnd,
|
|
||||||
} from '../../utils/stream-utils'
|
} from '../../utils/stream-utils'
|
||||||
|
|
||||||
let fs: any = null
|
let fs: any = null
|
||||||
|
@ -29,6 +28,14 @@ const OVERRIDE_MIME: Record<string, string> = {
|
||||||
'audio/opus': 'audio/ogg',
|
'audio/opus': 'audio/ogg',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// small files (less than 128 kb) are uploaded using the current connection and not the "upload" pool
|
||||||
|
const SMALL_FILE_MAX_SIZE = 131072
|
||||||
|
const BIG_FILE_MIN_SIZE = 10485760 // files >10 MB are considered "big"
|
||||||
|
const DEFAULT_FILE_NAME = 'unnamed'
|
||||||
|
const REQUESTS_PER_CONNECTION = 3
|
||||||
|
const MAX_PART_COUNT = 4000 // 512 kb * 4000 = 2000 MiB
|
||||||
|
const MAX_PART_COUNT_PREMIUM = 8000 // 512 kb * 8000 = 4000 MiB
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload a file to Telegram servers, without actually
|
* Upload a file to Telegram servers, without actually
|
||||||
* sending a message anywhere. Useful when an `InputFile` is required.
|
* sending a message anywhere. Useful when an `InputFile` is required.
|
||||||
|
@ -60,14 +67,15 @@ export async function uploadFile(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total file size. Automatically inferred for Buffer, File and local files.
|
* Total file size. Automatically inferred for Buffer, File and local files.
|
||||||
*
|
|
||||||
* When using with streams, if `fileSize` is not passed, the entire file is
|
|
||||||
* first loaded into memory to determine file size, and used as a Buffer later.
|
|
||||||
* This might be a major performance bottleneck, so be sure to provide file size
|
|
||||||
* when using streams and file size is known (which often is the case).
|
|
||||||
*/
|
*/
|
||||||
fileSize?: number
|
fileSize?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the file size is unknown, you can provide an estimate,
|
||||||
|
* which will be used to determine appropriate part size.
|
||||||
|
*/
|
||||||
|
estimatedSize?: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File MIME type. By default is automatically inferred from magic number
|
* File MIME type. By default is automatically inferred from magic number
|
||||||
* If MIME can't be inferred, it defaults to `application/octet-stream`
|
* If MIME can't be inferred, it defaults to `application/octet-stream`
|
||||||
|
@ -82,11 +90,16 @@ export async function uploadFile(
|
||||||
*/
|
*/
|
||||||
partSize?: number
|
partSize?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of parts to be sent in parallel per connection.
|
||||||
|
*/
|
||||||
|
requestsPerConnection?: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that will be called after some part has been uploaded.
|
* Function that will be called after some part has been uploaded.
|
||||||
*
|
*
|
||||||
* @param uploaded Number of bytes already uploaded
|
* @param uploaded Number of bytes already uploaded
|
||||||
* @param total Total file size
|
* @param total Total file size, if known
|
||||||
*/
|
*/
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
},
|
},
|
||||||
|
@ -94,7 +107,7 @@ export async function uploadFile(
|
||||||
// normalize params
|
// normalize params
|
||||||
let file = params.file
|
let file = params.file
|
||||||
let fileSize = -1 // unknown
|
let fileSize = -1 // unknown
|
||||||
let fileName = 'unnamed'
|
let fileName = DEFAULT_FILE_NAME
|
||||||
let fileMime = params.fileMime
|
let fileMime = params.fileMime
|
||||||
|
|
||||||
if (Buffer.isBuffer(file)) {
|
if (Buffer.isBuffer(file)) {
|
||||||
|
@ -162,12 +175,12 @@ export async function uploadFile(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileName === 'unnamed') {
|
if (fileName === DEFAULT_FILE_NAME) {
|
||||||
// try to infer from url
|
// try to infer from url
|
||||||
const url = new URL(file.url)
|
const url = new URL(file.url)
|
||||||
const name = url.pathname.split('/').pop()
|
const name = url.pathname.split('/').pop()
|
||||||
|
|
||||||
if (name && name.indexOf('.') > -1) {
|
if (name && name.includes('.')) {
|
||||||
fileName = name
|
fileName = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,42 +205,88 @@ export async function uploadFile(
|
||||||
// set file size if not automatically inferred
|
// set file size if not automatically inferred
|
||||||
if (fileSize === -1 && params.fileSize) fileSize = params.fileSize
|
if (fileSize === -1 && params.fileSize) fileSize = params.fileSize
|
||||||
|
|
||||||
|
let partSizeKb = params.partSize
|
||||||
|
|
||||||
|
if (!partSizeKb) {
|
||||||
if (fileSize === -1) {
|
if (fileSize === -1) {
|
||||||
// load the entire stream into memory
|
partSizeKb = params.estimatedSize ?
|
||||||
const buffer = await readStreamUntilEnd(file as Readable)
|
determinePartSize(params.estimatedSize) :
|
||||||
fileSize = buffer.length
|
64
|
||||||
file = bufferToStream(buffer)
|
} else {
|
||||||
|
partSizeKb = determinePartSize(fileSize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(file instanceof Readable)) {
|
if (!(file instanceof Readable)) {
|
||||||
throw new MtArgumentError('Could not convert input `file` to stream!')
|
throw new MtArgumentError('Could not convert input `file` to stream!')
|
||||||
}
|
}
|
||||||
|
|
||||||
const partSizeKb = params.partSize ?? determinePartSize(fileSize)
|
|
||||||
|
|
||||||
if (partSizeKb > 512) {
|
if (partSizeKb > 512) {
|
||||||
throw new MtArgumentError(`Invalid part size: ${partSizeKb}KB`)
|
throw new MtArgumentError(`Invalid part size: ${partSizeKb}KB`)
|
||||||
}
|
}
|
||||||
const partSize = partSizeKb * 1024
|
const partSize = partSizeKb * 1024
|
||||||
|
|
||||||
const isBig = fileSize > 10485760 // 10 MB
|
let partCount =
|
||||||
const hash = this._crypto.createMd5()
|
fileSize === -1 ? -1 : ~~((fileSize + partSize - 1) / partSize)
|
||||||
|
const maxPartCount = this.network.params.isPremium ?
|
||||||
|
MAX_PART_COUNT_PREMIUM :
|
||||||
|
MAX_PART_COUNT
|
||||||
|
|
||||||
|
if (partCount > maxPartCount) {
|
||||||
|
throw new MtArgumentError(
|
||||||
|
`File is too large (max ${maxPartCount} parts, got ${partCount})`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBig = fileSize === -1 || fileSize > BIG_FILE_MIN_SIZE
|
||||||
|
const isSmall = fileSize !== -1 && fileSize < SMALL_FILE_MAX_SIZE
|
||||||
|
const connectionKind = isSmall ? 'main' : 'upload'
|
||||||
|
const connectionPoolSize = Math.min(
|
||||||
|
this.network.getPoolSize(connectionKind),
|
||||||
|
partCount,
|
||||||
|
)
|
||||||
|
const requestsPerConnection =
|
||||||
|
params.requestsPerConnection ?? REQUESTS_PER_CONNECTION
|
||||||
|
|
||||||
const partCount = ~~((fileSize + partSize - 1) / partSize)
|
|
||||||
this.log.debug(
|
this.log.debug(
|
||||||
'uploading %d bytes file in %d chunks, each %d bytes',
|
'uploading %d bytes file in %d chunks, each %d bytes in %s connection pool of size %d',
|
||||||
fileSize,
|
fileSize,
|
||||||
partCount,
|
partCount,
|
||||||
partSize,
|
partSize,
|
||||||
|
connectionKind,
|
||||||
|
connectionPoolSize,
|
||||||
)
|
)
|
||||||
|
|
||||||
// why is the file id generated by the client?
|
// why is the file id generated by the client?
|
||||||
// isn't the server supposed to generate it and handle collisions?
|
// isn't the server supposed to generate it and handle collisions?
|
||||||
const fileId = randomLong()
|
const fileId = randomLong()
|
||||||
let pos = 0
|
const stream = file
|
||||||
|
|
||||||
for (let idx = 0; idx < partCount; idx++) {
|
let pos = 0
|
||||||
const part = await readBytesFromStream(file, partSize)
|
let idx = 0
|
||||||
|
const lock = new AsyncLock()
|
||||||
|
|
||||||
|
const uploadNextPart = async (): Promise<void> => {
|
||||||
|
const thisIdx = idx++
|
||||||
|
|
||||||
|
let part
|
||||||
|
|
||||||
|
try {
|
||||||
|
await lock.acquire()
|
||||||
|
part = await readBytesFromStream(stream, partSize)
|
||||||
|
} finally {
|
||||||
|
lock.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileSize === -1 && stream.readableEnded) {
|
||||||
|
fileSize = pos + (part?.length ?? 0)
|
||||||
|
partCount = ~~((fileSize + partSize - 1) / partSize)
|
||||||
|
this.log.debug(
|
||||||
|
'readable ended, file size = %d, part count = %d',
|
||||||
|
fileSize,
|
||||||
|
partCount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (!part) {
|
if (!part) {
|
||||||
throw new MtArgumentError(
|
throw new MtArgumentError(
|
||||||
|
@ -236,15 +295,15 @@ export async function uploadFile(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Buffer.isBuffer(part)) {
|
if (!Buffer.isBuffer(part)) {
|
||||||
throw new MtArgumentError(`Part ${idx} was not a Buffer!`)
|
throw new MtArgumentError(`Part ${thisIdx} was not a Buffer!`)
|
||||||
}
|
}
|
||||||
if (part.length > partSize) {
|
if (part.length > partSize) {
|
||||||
throw new MtArgumentError(
|
throw new MtArgumentError(
|
||||||
`Part ${idx} had invalid size (expected ${partSize}, got ${part.length})`,
|
`Part ${thisIdx} had invalid size (expected ${partSize}, got ${part.length})`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx === 0 && fileMime === undefined) {
|
if (thisIdx === 0 && fileMime === undefined) {
|
||||||
const fileType = await fileTypeFromBuffer(part)
|
const fileType = await fileTypeFromBuffer(part)
|
||||||
fileMime = fileType?.mime
|
fileMime = fileType?.mime
|
||||||
|
|
||||||
|
@ -260,37 +319,43 @@ export async function uploadFile(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isBig) {
|
|
||||||
// why md5 only small files?
|
|
||||||
// big files have more chance of corruption, but whatever
|
|
||||||
// also isn't integrity guaranteed by mtproto?
|
|
||||||
await hash.update(part)
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += part.length
|
|
||||||
|
|
||||||
// why
|
// why
|
||||||
const request = isBig ?
|
const request = isBig ?
|
||||||
({
|
({
|
||||||
_: 'upload.saveBigFilePart',
|
_: 'upload.saveBigFilePart',
|
||||||
fileId,
|
fileId,
|
||||||
filePart: idx,
|
filePart: thisIdx,
|
||||||
fileTotalParts: partCount,
|
fileTotalParts: partCount,
|
||||||
bytes: part,
|
bytes: part,
|
||||||
} as tl.upload.RawSaveBigFilePartRequest) :
|
} satisfies tl.upload.RawSaveBigFilePartRequest) :
|
||||||
({
|
({
|
||||||
_: 'upload.saveFilePart',
|
_: 'upload.saveFilePart',
|
||||||
fileId,
|
fileId,
|
||||||
filePart: idx,
|
filePart: thisIdx,
|
||||||
bytes: part,
|
bytes: part,
|
||||||
} as tl.upload.RawSaveFilePartRequest)
|
} satisfies tl.upload.RawSaveFilePartRequest)
|
||||||
|
|
||||||
const result = await this.call(request)
|
const result = await this.call(request, { kind: connectionKind })
|
||||||
if (!result) throw new Error(`Failed to upload part ${idx}`)
|
if (!result) throw new Error(`Failed to upload part ${idx}`)
|
||||||
|
|
||||||
|
pos += part.length
|
||||||
|
|
||||||
params.progressCallback?.(pos, fileSize)
|
params.progressCallback?.(pos, fileSize)
|
||||||
|
|
||||||
|
if (idx === partCount) return
|
||||||
|
|
||||||
|
return uploadNextPart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
Array.from(
|
||||||
|
{
|
||||||
|
length: connectionPoolSize * requestsPerConnection,
|
||||||
|
},
|
||||||
|
uploadNextPart,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
let inputFile: tl.TypeInputFile
|
let inputFile: tl.TypeInputFile
|
||||||
|
|
||||||
if (isBig) {
|
if (isBig) {
|
||||||
|
@ -306,7 +371,7 @@ export async function uploadFile(
|
||||||
id: fileId,
|
id: fileId,
|
||||||
parts: partCount,
|
parts: partCount,
|
||||||
name: fileName,
|
name: fileName,
|
||||||
md5Checksum: (await hash.digest()).toString('hex'),
|
md5Checksum: '', // tdlib doesn't do this, why should we?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -558,11 +558,15 @@ async function _fetchPeersForShort(
|
||||||
if (
|
if (
|
||||||
msg.replyTo._ === 'messageReplyHeader' &&
|
msg.replyTo._ === 'messageReplyHeader' &&
|
||||||
!(await fetchPeer(msg.replyTo.replyToPeerId))
|
!(await fetchPeer(msg.replyTo.replyToPeerId))
|
||||||
) { return null }
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
msg.replyTo._ === 'messageReplyStoryHeader' &&
|
msg.replyTo._ === 'messageReplyStoryHeader' &&
|
||||||
!(await fetchPeer(msg.replyTo.userId))
|
!(await fetchPeer(msg.replyTo.userId))
|
||||||
) { return null }
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg._ !== 'messageService') {
|
if (msg._ !== 'messageService') {
|
||||||
|
@ -791,7 +795,7 @@ async function _fetchChannelDifference(
|
||||||
if (!_pts) _pts = fallbackPts
|
if (!_pts) _pts = fallbackPts
|
||||||
|
|
||||||
if (!_pts) {
|
if (!_pts) {
|
||||||
this._updsLog.warn(
|
this._updsLog.debug(
|
||||||
'fetchChannelDifference failed for channel %d: base pts not available',
|
'fetchChannelDifference failed for channel %d: base pts not available',
|
||||||
channelId,
|
channelId,
|
||||||
)
|
)
|
||||||
|
|
|
@ -133,8 +133,7 @@ export class Conversation {
|
||||||
|
|
||||||
const pending = this.client['_pendingConversations']
|
const pending = this.client['_pendingConversations']
|
||||||
|
|
||||||
const idx =
|
const idx = pending[this._chatId].indexOf(this)
|
||||||
pending[this._chatId].indexOf(this)
|
|
||||||
|
|
||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
// just in case
|
// just in case
|
||||||
|
@ -143,8 +142,7 @@ export class Conversation {
|
||||||
if (!pending[this._chatId].length) {
|
if (!pending[this._chatId].length) {
|
||||||
delete pending[this._chatId]
|
delete pending[this._chatId]
|
||||||
}
|
}
|
||||||
this.client['_hasConversations'] =
|
this.client['_hasConversations'] = Object.keys(pending).length > 0
|
||||||
Object.keys(pending).length > 0
|
|
||||||
|
|
||||||
// reset pending status
|
// reset pending status
|
||||||
this._queuedNewMessage.clear()
|
this._queuedNewMessage.clear()
|
||||||
|
@ -279,6 +277,7 @@ export class Conversation {
|
||||||
|
|
||||||
if (timeout !== null) {
|
if (timeout !== null) {
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
|
console.log('timed out')
|
||||||
promise.reject(new tl.errors.TimeoutError())
|
promise.reject(new tl.errors.TimeoutError())
|
||||||
this._queuedNewMessage.removeBy((it) => it.promise === promise)
|
this._queuedNewMessage.removeBy((it) => it.promise === promise)
|
||||||
}, timeout)
|
}, timeout)
|
||||||
|
@ -537,7 +536,9 @@ export class Conversation {
|
||||||
it.promise.resolve(msg)
|
it.promise.resolve(msg)
|
||||||
delete this._pendingEditMessage[msg.id]
|
delete this._pendingEditMessage[msg.id]
|
||||||
}
|
}
|
||||||
})().catch((e) => this.client['_emitError'](e))
|
})().catch((e) => {
|
||||||
|
this.client['_emitError'](e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHistoryRead(upd: HistoryReadUpdate) {
|
private _onHistoryRead(upd: HistoryReadUpdate) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
import { makeInspectable } from '../utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
import { FileDownloadParameters } from './utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about file location.
|
* Information about file location.
|
||||||
|
@ -50,48 +51,61 @@ export class FileLocation {
|
||||||
* in chunks of a given size. Order of the chunks is guaranteed to be
|
* in chunks of a given size. Order of the chunks is guaranteed to be
|
||||||
* consecutive.
|
* consecutive.
|
||||||
*
|
*
|
||||||
* Shorthand for `client.downloadAsIterable({ location: this })`
|
* @param params Download parameters
|
||||||
*
|
|
||||||
* @link TelegramClient.downloadAsIterable
|
* @link TelegramClient.downloadAsIterable
|
||||||
*/
|
*/
|
||||||
downloadIterable(): AsyncIterableIterator<Buffer> {
|
downloadIterable(
|
||||||
return this.client.downloadAsIterable({ location: this })
|
params?: Partial<FileDownloadParameters>,
|
||||||
|
): AsyncIterableIterator<Buffer> {
|
||||||
|
return this.client.downloadAsIterable({
|
||||||
|
...params,
|
||||||
|
location: this,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a file and return it as a Node readable stream,
|
* Download a file and return it as a Node readable stream,
|
||||||
* streaming file contents.
|
* streaming file contents.
|
||||||
*
|
*
|
||||||
* Shorthand for `client.downloadAsStream({ location: this })`
|
|
||||||
*
|
|
||||||
* @link TelegramClient.downloadAsStream
|
* @link TelegramClient.downloadAsStream
|
||||||
*/
|
*/
|
||||||
downloadStream(): Readable {
|
downloadStream(params?: Partial<FileDownloadParameters>): Readable {
|
||||||
return this.client.downloadAsStream({ location: this })
|
return this.client.downloadAsStream({
|
||||||
|
...params,
|
||||||
|
location: this,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a file and return its contents as a Buffer.
|
* Download a file and return its contents as a Buffer.
|
||||||
*
|
*
|
||||||
* Shorthand for `client.downloadAsBuffer({ location: this })`
|
* @param params File download parameters
|
||||||
*
|
|
||||||
* @link TelegramClient.downloadAsBuffer
|
* @link TelegramClient.downloadAsBuffer
|
||||||
*/
|
*/
|
||||||
downloadBuffer(): Promise<Buffer> {
|
downloadBuffer(params?: Partial<FileDownloadParameters>): Promise<Buffer> {
|
||||||
return this.client.downloadAsBuffer({ location: this })
|
return this.client.downloadAsBuffer({
|
||||||
|
...params,
|
||||||
|
location: this,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a remote file to a local file (only for NodeJS).
|
* Download a remote file to a local file (only for NodeJS).
|
||||||
* Promise will resolve once the download is complete.
|
* Promise will resolve once the download is complete.
|
||||||
*
|
*
|
||||||
* Shorthand for `client.downloadToFile(filename, { location: this })`
|
|
||||||
*
|
|
||||||
* @param filename Local file name
|
* @param filename Local file name
|
||||||
|
* @param params File download parameters
|
||||||
* @link TelegramClient.downloadToFile
|
* @link TelegramClient.downloadToFile
|
||||||
*/
|
*/
|
||||||
downloadToFile(filename: string): Promise<void> {
|
downloadToFile(
|
||||||
return this.client.downloadToFile(filename, { location: this })
|
filename: string,
|
||||||
|
params?: Partial<FileDownloadParameters>,
|
||||||
|
): Promise<void> {
|
||||||
|
return this.client.downloadToFile(filename, {
|
||||||
|
...params,
|
||||||
|
location: this,
|
||||||
|
fileSize: this.fileSize,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ export interface FileDownloadParameters {
|
||||||
offset?: number
|
offset?: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of chunks (!) of that given size that will be downloaded.
|
* Number of bytes to be downloaded.
|
||||||
* By default, downloads the entire file
|
* By default, downloads the entire file
|
||||||
*/
|
*/
|
||||||
limit?: number
|
limit?: number
|
||||||
|
|
|
@ -5,10 +5,9 @@ import { MtArgumentError } from '../types'
|
||||||
* for upload/download operations.
|
* for upload/download operations.
|
||||||
*/
|
*/
|
||||||
export function determinePartSize(fileSize: number): number {
|
export function determinePartSize(fileSize: number): number {
|
||||||
if (fileSize <= 104857600) return 128 // 100 MB
|
if (fileSize <= 262078465) return 128 // 200 MB
|
||||||
if (fileSize <= 786432000) return 256 // 750 MB
|
if (fileSize <= 786432000) return 256 // 750 MB
|
||||||
if (fileSize <= 2097152000) return 512 // 2000 MB
|
if (fileSize <= 2097152000) return 512 // 2000 MB
|
||||||
if (fileSize <= 4194304000) return 1024 // 4000 MB
|
|
||||||
|
|
||||||
throw new MtArgumentError('File is too large')
|
throw new MtArgumentError('File is too large')
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,9 @@ class NodeReadable extends Readable {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.push(res.value)) {
|
if (this.push(res.value)) {
|
||||||
return doRead()
|
doRead()
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
this._reading = false
|
this._reading = false
|
||||||
this._reader.releaseLock()
|
this._reader.releaseLock()
|
||||||
|
@ -49,7 +51,9 @@ class NodeReadable extends Readable {
|
||||||
const promise = new Promise<void>((resolve) => {
|
const promise = new Promise<void>((resolve) => {
|
||||||
this._doneReading = resolve
|
this._doneReading = resolve
|
||||||
})
|
})
|
||||||
promise.then(() => this._handleDestroy(err, callback))
|
promise.then(() => {
|
||||||
|
this._handleDestroy(err, callback)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
this._handleDestroy(err, callback)
|
this._handleDestroy(err, callback)
|
||||||
}
|
}
|
||||||
|
@ -71,26 +75,6 @@ export function convertWebStreamToNodeReadable(
|
||||||
return new NodeReadable(webStream, opts)
|
return new NodeReadable(webStream, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function readStreamUntilEnd(stream: Readable): Promise<Buffer> {
|
|
||||||
const chunks = []
|
|
||||||
let length = 0
|
|
||||||
|
|
||||||
while (stream.readable) {
|
|
||||||
const c = await stream.read()
|
|
||||||
if (c === null) break
|
|
||||||
|
|
||||||
length += c.length
|
|
||||||
|
|
||||||
if (length > 2097152000) {
|
|
||||||
throw new Error('File is too big')
|
|
||||||
}
|
|
||||||
|
|
||||||
chunks.push(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer.concat(chunks)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bufferToStream(buf: Buffer): Readable {
|
export function bufferToStream(buf: Buffer): Readable {
|
||||||
return new Readable({
|
return new Readable({
|
||||||
read() {
|
read() {
|
||||||
|
@ -109,15 +93,17 @@ export async function readBytesFromStream(
|
||||||
let res = stream.read(size)
|
let res = stream.read(size)
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve, reject) => {
|
||||||
stream.on('readable', function handler() {
|
stream.on('readable', function handler() {
|
||||||
res = stream.read(size)
|
res = stream.read(size)
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
stream.off('readable', handler)
|
stream.off('readable', handler)
|
||||||
|
stream.off('error', reject)
|
||||||
resolve(res)
|
resolve(res)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
stream.on('error', reject)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { expect } from 'chai'
|
|
||||||
import { describe, it } from 'mocha'
|
|
||||||
import { Readable } from 'stream'
|
|
||||||
|
|
||||||
import { readStreamUntilEnd } from '../src/utils/stream-utils'
|
|
||||||
|
|
||||||
describe('readStreamUntilEnd', () => {
|
|
||||||
it('should read stream until end', async () => {
|
|
||||||
const stream = new Readable({
|
|
||||||
read() {
|
|
||||||
this.push(Buffer.from('aaeeff', 'hex'))
|
|
||||||
this.push(Buffer.from('ff33ee', 'hex'))
|
|
||||||
this.push(null)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
expect((await readStreamUntilEnd(stream)).toString('hex')).eq(
|
|
||||||
'aaeeffff33ee',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -245,7 +245,7 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
protected _handleUpdate(update: tl.TypeUpdates): void {}
|
protected _handleUpdate(update: tl.TypeUpdates): void {}
|
||||||
|
|
||||||
readonly log = new LogManager()
|
readonly log = new LogManager('client')
|
||||||
readonly network: NetworkManager
|
readonly network: NetworkManager
|
||||||
|
|
||||||
constructor(opts: BaseTelegramClientOptions) {
|
constructor(opts: BaseTelegramClientOptions) {
|
||||||
|
@ -451,7 +451,6 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
* @param factory New transport factory
|
* @param factory New transport factory
|
||||||
*/
|
*/
|
||||||
changeTransport(factory: TransportFactory): void {
|
changeTransport(factory: TransportFactory): void {
|
||||||
// todo
|
|
||||||
this.network.changeTransport(factory)
|
this.network.changeTransport(factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
export { NetworkManagerExtraParams, RpcCallOptions } from './network-manager'
|
export {
|
||||||
|
ConnectionKind,
|
||||||
|
NetworkManagerExtraParams,
|
||||||
|
RpcCallOptions,
|
||||||
|
} from './network-manager'
|
||||||
export * from './reconnection'
|
export * from './reconnection'
|
||||||
export * from './session-connection'
|
export * from './session-connection'
|
||||||
export * from './transports'
|
export * from './transports'
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
TlWriterMap,
|
TlWriterMap,
|
||||||
} from '@mtcute/tl-runtime'
|
} from '@mtcute/tl-runtime'
|
||||||
|
|
||||||
import { ControllablePromise,
|
import {
|
||||||
|
ControllablePromise,
|
||||||
Deque,
|
Deque,
|
||||||
getRandomInt,
|
getRandomInt,
|
||||||
ICryptoProvider,
|
ICryptoProvider,
|
||||||
|
@ -118,9 +119,18 @@ export class MtprotoSession {
|
||||||
pendingMessages = new LongMap<PendingMessage>()
|
pendingMessages = new LongMap<PendingMessage>()
|
||||||
destroySessionIdToMsgId = new LongMap<Long>()
|
destroySessionIdToMsgId = new LongMap<Long>()
|
||||||
|
|
||||||
|
lastPingRtt = NaN
|
||||||
|
lastPingTime = 0
|
||||||
|
lastPingMsgId = Long.ZERO
|
||||||
|
lastSessionCreatedUid = Long.ZERO
|
||||||
|
|
||||||
initConnectionCalled = false
|
initConnectionCalled = false
|
||||||
authorizationPending = false
|
authorizationPending = false
|
||||||
|
|
||||||
|
next429Timeout = 1000
|
||||||
|
current429Timeout?: NodeJS.Timeout
|
||||||
|
next429ResetTimeout?: NodeJS.Timeout
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly _crypto: ICryptoProvider,
|
readonly _crypto: ICryptoProvider,
|
||||||
readonly log: Logger,
|
readonly log: Logger,
|
||||||
|
@ -130,6 +140,15 @@ export class MtprotoSession {
|
||||||
this.log.prefix = `[SESSION ${this._sessionId.toString(16)}] `
|
this.log.prefix = `[SESSION ${this._sessionId.toString(16)}] `
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasPendingMessages(): boolean {
|
||||||
|
return Boolean(
|
||||||
|
this.queuedRpc.length ||
|
||||||
|
this.queuedAcks.length ||
|
||||||
|
this.queuedStateReq.length ||
|
||||||
|
this.queuedResendReq.length,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset session by resetting auth key(s) and session state
|
* Reset session by resetting auth key(s) and session state
|
||||||
*/
|
*/
|
||||||
|
@ -140,7 +159,9 @@ export class MtprotoSession {
|
||||||
this._authKeyTempSecondary.reset()
|
this._authKeyTempSecondary.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearTimeout(this.current429Timeout)
|
||||||
this.resetState()
|
this.resetState()
|
||||||
|
this.resetLastPing(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,11 +242,11 @@ export class MtprotoSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
getSeqNo(isContentRelated = true): number {
|
getSeqNo(isContentRelated = true): number {
|
||||||
let seqNo = this._seqNo * 2
|
let seqNo = this._seqNo
|
||||||
|
|
||||||
if (isContentRelated) {
|
if (isContentRelated) {
|
||||||
seqNo += 1
|
seqNo += 1
|
||||||
this._seqNo += 1
|
this._seqNo += 2
|
||||||
}
|
}
|
||||||
|
|
||||||
return seqNo
|
return seqNo
|
||||||
|
@ -293,4 +314,43 @@ export class MtprotoSession {
|
||||||
|
|
||||||
return messageId
|
return messageId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onTransportFlood(callback: () => void) {
|
||||||
|
if (this.current429Timeout) return // already waiting
|
||||||
|
|
||||||
|
// all active queries must be resent after a timeout
|
||||||
|
this.resetLastPing(true)
|
||||||
|
|
||||||
|
const timeout = this.next429Timeout
|
||||||
|
|
||||||
|
this.next429Timeout = Math.min(this.next429Timeout * 2, 32000)
|
||||||
|
clearTimeout(this.current429Timeout)
|
||||||
|
clearTimeout(this.next429ResetTimeout)
|
||||||
|
|
||||||
|
this.current429Timeout = setTimeout(() => {
|
||||||
|
this.current429Timeout = undefined
|
||||||
|
callback()
|
||||||
|
}, timeout)
|
||||||
|
this.next429ResetTimeout = setTimeout(() => {
|
||||||
|
this.next429ResetTimeout = undefined
|
||||||
|
this.next429Timeout = 1000
|
||||||
|
}, 60000)
|
||||||
|
|
||||||
|
this.log.debug(
|
||||||
|
'transport flood, waiting for %d ms before proceeding',
|
||||||
|
timeout,
|
||||||
|
)
|
||||||
|
|
||||||
|
return Date.now() + timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
resetLastPing(withTime = false): void {
|
||||||
|
if (withTime) this.lastPingTime = 0
|
||||||
|
|
||||||
|
if (!this.lastPingMsgId.isZero()) {
|
||||||
|
this.pendingMessages.delete(this.lastPingMsgId)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastPingMsgId = Long.ZERO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,43 +32,48 @@ export class MultiSessionConnection extends EventEmitter {
|
||||||
|
|
||||||
protected _connections: SessionConnection[] = []
|
protected _connections: SessionConnection[] = []
|
||||||
|
|
||||||
setCount(count: number, doUpdate = true): void {
|
setCount(count: number, connect = this.params.isMainConnection): void {
|
||||||
this._count = count
|
this._count = count
|
||||||
|
|
||||||
if (doUpdate) this._updateConnections(true)
|
this._updateConnections(connect)
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateSessions(): void {
|
private _updateSessions(): void {
|
||||||
|
// there are two cases
|
||||||
|
// 1. this msc is main, in which case every connection should have its own session
|
||||||
|
// 2. this msc is not main, in which case all connections should share the same session
|
||||||
|
// if (!this.params.isMainConnection) {
|
||||||
|
// // case 2
|
||||||
|
// this._log.debug(
|
||||||
|
// 'updating sessions count: %d -> 1',
|
||||||
|
// this._sessions.length,
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// if (this._sessions.length === 0) {
|
||||||
|
// this._sessions.push(
|
||||||
|
// new MtprotoSession(
|
||||||
|
// this.params.crypto,
|
||||||
|
// this._log.create('session'),
|
||||||
|
// this.params.readerMap,
|
||||||
|
// this.params.writerMap,
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // shouldn't happen, but just in case
|
||||||
|
// while (this._sessions.length > 1) {
|
||||||
|
// this._sessions.pop()!.reset()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
this._log.debug(
|
this._log.debug(
|
||||||
'updating sessions count: %d -> %d',
|
'updating sessions count: %d -> %d',
|
||||||
this._sessions.length,
|
this._sessions.length,
|
||||||
this._count,
|
this._count,
|
||||||
)
|
)
|
||||||
|
|
||||||
// there are two cases
|
|
||||||
// 1. this msc is main, in which case every connection should have its own session
|
|
||||||
// 2. this msc is not main, in which case all connections should share the same session
|
|
||||||
if (!this.params.isMainConnection) {
|
|
||||||
// case 2
|
|
||||||
if (this._sessions.length === 0) {
|
|
||||||
this._sessions.push(
|
|
||||||
new MtprotoSession(
|
|
||||||
this.params.crypto,
|
|
||||||
this._log.create('session'),
|
|
||||||
this.params.readerMap,
|
|
||||||
this.params.writerMap,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shouldn't happen, but just in case
|
|
||||||
while (this._sessions.length > 1) {
|
|
||||||
this._sessions.pop()!.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// case 1
|
// case 1
|
||||||
if (this._sessions.length === this._count) return
|
if (this._sessions.length === this._count) return
|
||||||
|
|
||||||
|
@ -99,7 +104,7 @@ export class MultiSessionConnection extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateConnections(active = false): void {
|
private _updateConnections(connect = false): void {
|
||||||
this._updateSessions()
|
this._updateSessions()
|
||||||
if (this._connections.length === this._count) return
|
if (this._connections.length === this._count) return
|
||||||
|
|
||||||
|
@ -141,9 +146,8 @@ export class MultiSessionConnection extends EventEmitter {
|
||||||
|
|
||||||
// create new connections
|
// create new connections
|
||||||
for (let i = this._connections.length; i < this._count; i++) {
|
for (let i = this._connections.length; i < this._count; i++) {
|
||||||
const session = this.params.isMainConnection ?
|
const session = this._sessions[i] // this.params.isMainConnection ? // :
|
||||||
this._sessions[i] :
|
// this._sessions[0]
|
||||||
this._sessions[0]
|
|
||||||
const conn = new SessionConnection(
|
const conn = new SessionConnection(
|
||||||
{
|
{
|
||||||
...this.params,
|
...this.params,
|
||||||
|
@ -185,9 +189,14 @@ export class MultiSessionConnection extends EventEmitter {
|
||||||
})
|
})
|
||||||
conn.on('usable', () => this.emit('usable', i))
|
conn.on('usable', () => this.emit('usable', i))
|
||||||
conn.on('request-auth', () => this.emit('request-auth', i))
|
conn.on('request-auth', () => this.emit('request-auth', i))
|
||||||
|
conn.on('flood-done', () => {
|
||||||
|
this._log.debug('received flood-done from connection %d', i)
|
||||||
|
|
||||||
|
this._connections.forEach((it) => it.flushWhenIdle())
|
||||||
|
})
|
||||||
|
|
||||||
this._connections.push(conn)
|
this._connections.push(conn)
|
||||||
if (active) conn.connect()
|
if (connect) conn.connect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +216,7 @@ export class MultiSessionConnection extends EventEmitter {
|
||||||
stack?: string,
|
stack?: string,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
): Promise<tl.RpcCallReturn[T['_']]> {
|
): Promise<tl.RpcCallReturn[T['_']]> {
|
||||||
if (this.params.isMainConnection) {
|
// if (this.params.isMainConnection) {
|
||||||
// find the least loaded connection
|
// find the least loaded connection
|
||||||
let min = Infinity
|
let min = Infinity
|
||||||
let minIdx = 0
|
let minIdx = 0
|
||||||
|
@ -225,13 +234,14 @@ export class MultiSessionConnection extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._connections[minIdx].sendRpc(request, stack, timeout)
|
return this._connections[minIdx].sendRpc(request, stack, timeout)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// round-robin connections
|
// round-robin connections
|
||||||
// since they all share the same session, it doesn't matter which one we use
|
// since they all share the same session, it doesn't matter which one we use
|
||||||
return this._connections[
|
// the connection chosen here will only affect the first attempt at sending
|
||||||
this._nextConnection++ % this._connections.length
|
// return this._connections[
|
||||||
].sendRpc(request, stack, timeout)
|
// this._nextConnection++ % this._connections.length
|
||||||
|
// ].sendRpc(request, stack, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(): void {
|
connect(): void {
|
||||||
|
@ -308,4 +318,8 @@ export class MultiSessionConnection extends EventEmitter {
|
||||||
changeTransport(factory: TransportFactory): void {
|
changeTransport(factory: TransportFactory): void {
|
||||||
this._connections.forEach((conn) => conn.changeTransport(factory))
|
this._connections.forEach((conn) => conn.changeTransport(factory))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPoolSize(): number {
|
||||||
|
return this._connections.length
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,12 @@ import { tl } from '@mtcute/tl'
|
||||||
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
|
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
|
||||||
|
|
||||||
import { ITelegramStorage } from '../storage'
|
import { ITelegramStorage } from '../storage'
|
||||||
import { ICryptoProvider, Logger, sleep } from '../utils'
|
import {
|
||||||
|
createControllablePromise,
|
||||||
|
ICryptoProvider,
|
||||||
|
Logger,
|
||||||
|
sleep,
|
||||||
|
} from '../utils'
|
||||||
import { ConfigManager } from './config-manager'
|
import { ConfigManager } from './config-manager'
|
||||||
import { MultiSessionConnection } from './multi-session-connection'
|
import { MultiSessionConnection } from './multi-session-connection'
|
||||||
import { PersistentConnectionParams } from './persistent-connection'
|
import { PersistentConnectionParams } from './persistent-connection'
|
||||||
|
@ -18,6 +23,16 @@ import { defaultTransportFactory, TransportFactory } from './transports'
|
||||||
|
|
||||||
export type ConnectionKind = 'main' | 'upload' | 'download' | 'downloadSmall'
|
export type ConnectionKind = 'main' | 'upload' | 'download' | 'downloadSmall'
|
||||||
|
|
||||||
|
const CLIENT_ERRORS = {
|
||||||
|
'303': 1,
|
||||||
|
'400': 1,
|
||||||
|
'401': 1,
|
||||||
|
'403': 1,
|
||||||
|
'404': 1,
|
||||||
|
'406': 1,
|
||||||
|
'420': 1,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params passed into {@link NetworkManager} by {@link TelegramClient}.
|
* Params passed into {@link NetworkManager} by {@link TelegramClient}.
|
||||||
* This type is intended for internal usage only.
|
* This type is intended for internal usage only.
|
||||||
|
@ -62,8 +77,9 @@ const defaultConnectionCountDelegate: ConnectionCountDelegate = (
|
||||||
case 'upload':
|
case 'upload':
|
||||||
return isPremium || (dcId !== 2 && dcId !== 4) ? 8 : 4
|
return isPremium || (dcId !== 2 && dcId !== 4) ? 8 : 4
|
||||||
case 'download':
|
case 'download':
|
||||||
|
return 8 // fixme isPremium ? 8 : 2
|
||||||
case 'downloadSmall':
|
case 'downloadSmall':
|
||||||
return isPremium ? 8 : 2
|
return 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,13 +95,14 @@ export interface NetworkManagerExtraParams {
|
||||||
usePfs?: boolean
|
usePfs?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection count for each connection kind
|
* Connection count for each connection kind.
|
||||||
|
* The function should be pure to avoid unexpected behavior.
|
||||||
*
|
*
|
||||||
* Defaults to TDLib logic:
|
* Defaults to TDLib logic:
|
||||||
* - main: handled internally, **cannot be changed here**
|
* - main: handled internally, **cannot be changed here**
|
||||||
* - upload: if premium or dc id is other than 2 or 4, then 8, otherwise 4
|
* - upload: if premium or dc id is other than 2 or 4, then 8, otherwise 4
|
||||||
* - download: if premium then 8, otherwise 2
|
* - download: if premium then 8, otherwise 2
|
||||||
* - downloadSmall: if premium then 8, otherwise 2
|
* - downloadSmall: 2
|
||||||
*/
|
*/
|
||||||
connectionCount?: ConnectionCountDelegate
|
connectionCount?: ConnectionCountDelegate
|
||||||
|
|
||||||
|
@ -174,7 +191,24 @@ export class DcConnectionManager {
|
||||||
)
|
)
|
||||||
|
|
||||||
download = new MultiSessionConnection(
|
download = new MultiSessionConnection(
|
||||||
this.__baseConnectionParams(),
|
// this.__baseConnectionParams(),
|
||||||
|
// fixme
|
||||||
|
{
|
||||||
|
...this.__baseConnectionParams(),
|
||||||
|
dc: {
|
||||||
|
_: 'dcOption',
|
||||||
|
ipv6: false,
|
||||||
|
mediaOnly: true,
|
||||||
|
tcpoOnly: false,
|
||||||
|
cdn: false,
|
||||||
|
static: false,
|
||||||
|
thisPortOnly: false,
|
||||||
|
id: 2,
|
||||||
|
ipAddress: '149.154.167.222',
|
||||||
|
port: 443,
|
||||||
|
secret: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
this.manager._connectionCount(
|
this.manager._connectionCount(
|
||||||
'download',
|
'download',
|
||||||
this._dc.id,
|
this._dc.id,
|
||||||
|
@ -313,6 +347,10 @@ export class DcConnectionManager {
|
||||||
connection.on('request-auth', () => {
|
connection.on('request-auth', () => {
|
||||||
this.main.requestAuth()
|
this.main.requestAuth()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
connection.on('error', (err, conn) => {
|
||||||
|
this.manager.params._emitError(err, conn)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsPrimary(isPrimary: boolean): void {
|
setIsPrimary(isPrimary: boolean): void {
|
||||||
|
@ -328,6 +366,22 @@ export class DcConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsPremium(isPremium: boolean): void {
|
||||||
|
this.upload.setCount(
|
||||||
|
this.manager._connectionCount('upload', this._dc.id, isPremium),
|
||||||
|
)
|
||||||
|
this.download.setCount(
|
||||||
|
this.manager._connectionCount('download', this._dc.id, isPremium),
|
||||||
|
)
|
||||||
|
this.downloadSmall.setCount(
|
||||||
|
this.manager._connectionCount(
|
||||||
|
'downloadSmall',
|
||||||
|
this._dc.id,
|
||||||
|
isPremium,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async loadKeys(): Promise<boolean> {
|
async loadKeys(): Promise<boolean> {
|
||||||
const permanent = await this.manager._storage.getAuthKeyFor(this.dcId)
|
const permanent = await this.manager._storage.getAuthKeyFor(this.dcId)
|
||||||
|
|
||||||
|
@ -471,9 +525,9 @@ export class NetworkManager {
|
||||||
Promise.resolve(this._storage.getSelf()).then((self) => {
|
Promise.resolve(this._storage.getSelf()).then((self) => {
|
||||||
if (self?.isBot) {
|
if (self?.isBot) {
|
||||||
// bots may receive tmpSessions, which we should respect
|
// bots may receive tmpSessions, which we should respect
|
||||||
this.config
|
this.config.update(true).catch((e) => {
|
||||||
.update(true)
|
this.params._emitError(e)
|
||||||
.catch((e) => this.params._emitError(e))
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -485,22 +539,37 @@ export class NetworkManager {
|
||||||
// this._cleanupPrimaryConnection()
|
// this._cleanupPrimaryConnection()
|
||||||
// )
|
// )
|
||||||
|
|
||||||
dc.main.on('error', (err, conn) => this.params._emitError(err, conn))
|
|
||||||
|
|
||||||
dc.loadKeys()
|
dc.loadKeys()
|
||||||
.catch((e) => this.params._emitError(e))
|
.catch((e) => {
|
||||||
.then(() => dc.main.ensureConnected())
|
this.params._emitError(e)
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
dc.main.ensureConnected()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _dcCreationPromise: Record<number, Promise<void>> = {}
|
||||||
async _getOtherDc(dcId: number): Promise<DcConnectionManager> {
|
async _getOtherDc(dcId: number): Promise<DcConnectionManager> {
|
||||||
if (!this._dcConnections[dcId]) {
|
if (!this._dcConnections[dcId]) {
|
||||||
|
if (dcId in this._dcCreationPromise) {
|
||||||
|
this._log.debug('waiting for DC %d to be created', dcId)
|
||||||
|
await this._dcCreationPromise[dcId]
|
||||||
|
|
||||||
|
return this._dcConnections[dcId]
|
||||||
|
}
|
||||||
|
|
||||||
|
const promise = createControllablePromise<void>()
|
||||||
|
this._dcCreationPromise[dcId] = promise
|
||||||
|
|
||||||
this._log.debug('creating new DC %d', dcId)
|
this._log.debug('creating new DC %d', dcId)
|
||||||
|
|
||||||
|
try {
|
||||||
const dcOption = await this.config.findOption({
|
const dcOption = await this.config.findOption({
|
||||||
dcId,
|
dcId,
|
||||||
allowIpv6: this.params.useIpv6,
|
allowIpv6: this.params.useIpv6,
|
||||||
preferIpv6: this.params.useIpv6,
|
preferIpv6: this.params.useIpv6,
|
||||||
allowMedia: false,
|
allowMedia: true,
|
||||||
|
preferMedia: true,
|
||||||
cdn: false,
|
cdn: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -514,6 +583,10 @@ export class NetworkManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dcConnections[dcId] = dc
|
this._dcConnections[dcId] = dc
|
||||||
|
promise.resolve()
|
||||||
|
} catch (e) {
|
||||||
|
promise.reject(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._dcConnections[dcId]
|
return this._dcConnections[dcId]
|
||||||
|
@ -532,7 +605,7 @@ export class NetworkManager {
|
||||||
|
|
||||||
const dc = new DcConnectionManager(this, defaultDc.id, defaultDc)
|
const dc = new DcConnectionManager(this, defaultDc.id, defaultDc)
|
||||||
this._dcConnections[defaultDc.id] = dc
|
this._dcConnections[defaultDc.id] = dc
|
||||||
await this._switchPrimaryDc(dc)
|
this._switchPrimaryDc(dc)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _exportAuthTo(manager: DcConnectionManager): Promise<void> {
|
private async _exportAuthTo(manager: DcConnectionManager): Promise<void> {
|
||||||
|
@ -575,16 +648,28 @@ export class NetworkManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsPremium(isPremium: boolean): void {
|
||||||
|
this._log.debug('setting isPremium to %s', isPremium)
|
||||||
|
this.params.isPremium = isPremium
|
||||||
|
Object.values(this._dcConnections).forEach((dc) => {
|
||||||
|
dc.setIsPremium(isPremium)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async notifyLoggedIn(auth: tl.auth.TypeAuthorization): Promise<void> {
|
async notifyLoggedIn(auth: tl.auth.TypeAuthorization): Promise<void> {
|
||||||
if (
|
if (
|
||||||
auth._ === 'auth.authorizationSignUpRequired' ||
|
auth._ === 'auth.authorizationSignUpRequired' ||
|
||||||
auth.user._ === 'userEmpty'
|
auth.user._ === 'userEmpty'
|
||||||
) { return }
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (auth.tmpSessions) {
|
if (auth.tmpSessions) {
|
||||||
this._primaryDc?.main.setCount(auth.tmpSessions)
|
this._primaryDc?.main.setCount(auth.tmpSessions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setIsPremium(auth.user.premium!)
|
||||||
|
|
||||||
await this.exportAuth()
|
await this.exportAuth()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,8 +774,12 @@ export class NetworkManager {
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
lastError = e
|
lastError = e
|
||||||
|
|
||||||
if (e instanceof tl.errors.InternalError) {
|
if (e.code && !(e.code in CLIENT_ERRORS)) {
|
||||||
this._log.warn('Telegram is having internal issues: %s', e)
|
this._log.warn(
|
||||||
|
'Telegram is having internal issues: %d %s, retrying',
|
||||||
|
e.code,
|
||||||
|
e.message,
|
||||||
|
)
|
||||||
|
|
||||||
if (e.message === 'WORKER_BUSY_TOO_LONG_RETRY') {
|
if (e.message === 'WORKER_BUSY_TOO_LONG_RETRY') {
|
||||||
// according to tdlib, "it is dangerous to resend query without timeout, so use 1"
|
// according to tdlib, "it is dangerous to resend query without timeout, so use 1"
|
||||||
|
@ -769,6 +858,32 @@ export class NetworkManager {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPoolSize(kind: ConnectionKind, dcId?: number) {
|
||||||
|
const dc = dcId ? this._dcConnections[dcId] : this._primaryDc
|
||||||
|
|
||||||
|
if (!dc) {
|
||||||
|
if (!this._primaryDc) {
|
||||||
|
throw new Error('Not connected to any DC')
|
||||||
|
}
|
||||||
|
|
||||||
|
// guess based on the provided delegate. it is most likely correct,
|
||||||
|
// but we should give actual values if possible
|
||||||
|
return this._connectionCount(
|
||||||
|
kind,
|
||||||
|
dcId ?? this._primaryDc.dcId,
|
||||||
|
this.params.isPremium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dc[kind].getPoolSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrimaryDcId() {
|
||||||
|
if (!this._primaryDc) throw new Error('Not connected to any DC')
|
||||||
|
|
||||||
|
return this._primaryDc.dcId
|
||||||
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
for (const dc of Object.values(this._dcConnections)) {
|
for (const dc of Object.values(this._dcConnections)) {
|
||||||
dc.main.destroy()
|
dc.main.destroy()
|
||||||
|
|
|
@ -86,11 +86,29 @@ export abstract class PersistentConnection extends EventEmitter {
|
||||||
|
|
||||||
onTransportReady(): void {
|
onTransportReady(): void {
|
||||||
// transport ready does not mean actual mtproto is ready
|
// transport ready does not mean actual mtproto is ready
|
||||||
|
|
||||||
if (this._sendOnceConnected.length) {
|
if (this._sendOnceConnected.length) {
|
||||||
this._transport.send(Buffer.concat(this._sendOnceConnected))
|
const sendNext = () => {
|
||||||
|
if (!this._sendOnceConnected.length) {
|
||||||
|
this.onConnected()
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
this._sendOnceConnected = []
|
|
||||||
|
const data = this._sendOnceConnected.shift()!
|
||||||
|
this._transport
|
||||||
|
.send(data)
|
||||||
|
.then(sendNext)
|
||||||
|
.catch((err) => {
|
||||||
|
this.log.error('error sending queued data: %s', err)
|
||||||
|
this._sendOnceConnected.unshift(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
sendNext()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.onConnected()
|
this.onConnected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +143,12 @@ export abstract class PersistentConnection extends EventEmitter {
|
||||||
this._consequentFails,
|
this._consequentFails,
|
||||||
this._previousWait,
|
this._previousWait,
|
||||||
)
|
)
|
||||||
if (wait === false) return this.destroy()
|
|
||||||
|
if (wait === false) {
|
||||||
|
this.destroy()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.emit('wait', wait)
|
this.emit('wait', wait)
|
||||||
|
|
||||||
|
|
|
@ -75,19 +75,13 @@ export class SessionConnection extends PersistentConnection {
|
||||||
NodeJS.Timeout
|
NodeJS.Timeout
|
||||||
][] = []
|
][] = []
|
||||||
|
|
||||||
private _next429Timeout = 1000
|
|
||||||
private _current429Timeout?: NodeJS.Timeout
|
|
||||||
|
|
||||||
private _lastPingRtt = NaN
|
|
||||||
private _lastPingTime = 0
|
|
||||||
private _lastPingMsgId = Long.ZERO
|
|
||||||
private _lastSessionCreatedUid = Long.ZERO
|
|
||||||
|
|
||||||
private _usePfs = this.params.usePfs ?? false
|
private _usePfs = this.params.usePfs ?? false
|
||||||
private _isPfsBindingPending = false
|
private _isPfsBindingPending = false
|
||||||
private _isPfsBindingPendingInBackground = false
|
private _isPfsBindingPendingInBackground = false
|
||||||
private _pfsUpdateTimeout?: NodeJS.Timeout
|
private _pfsUpdateTimeout?: NodeJS.Timeout
|
||||||
|
|
||||||
|
private _inactivityPendingFlush = false
|
||||||
|
|
||||||
private _readerMap: TlReaderMap
|
private _readerMap: TlReaderMap
|
||||||
private _writerMap: TlWriterMap
|
private _writerMap: TlWriterMap
|
||||||
|
|
||||||
|
@ -149,9 +143,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
|
|
||||||
reset(forever = false): void {
|
reset(forever = false): void {
|
||||||
this._session.initConnectionCalled = false
|
this._session.initConnectionCalled = false
|
||||||
this._resetLastPing(true)
|
|
||||||
this._flushTimer.reset()
|
this._flushTimer.reset()
|
||||||
clearTimeout(this._current429Timeout!)
|
|
||||||
|
|
||||||
if (forever) {
|
if (forever) {
|
||||||
this.removeAllListeners()
|
this.removeAllListeners()
|
||||||
|
@ -242,26 +234,15 @@ export class SessionConnection extends PersistentConnection {
|
||||||
this._onAllFailed(`transport error ${error.code}`)
|
this._onAllFailed(`transport error ${error.code}`)
|
||||||
|
|
||||||
if (error.code === 429) {
|
if (error.code === 429) {
|
||||||
// all active queries must be resent
|
this._session.onTransportFlood(
|
||||||
const timeout = this._next429Timeout
|
this.emit.bind(this, 'flood-done'),
|
||||||
|
|
||||||
this._next429Timeout = Math.min(this._next429Timeout * 2, 16000)
|
|
||||||
clearTimeout(this._current429Timeout!)
|
|
||||||
this._current429Timeout = setTimeout(() => {
|
|
||||||
this._current429Timeout = undefined
|
|
||||||
this._flushTimer.emitNow()
|
|
||||||
}, timeout)
|
|
||||||
|
|
||||||
this.log.debug(
|
|
||||||
'transport flood, waiting for %d ms before proceeding',
|
|
||||||
timeout,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('api-error', error)
|
this.emit('error', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onConnectionUsable() {
|
protected onConnectionUsable() {
|
||||||
|
@ -622,9 +603,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
// rpc_result
|
// rpc_result
|
||||||
message.uint()
|
message.uint()
|
||||||
|
|
||||||
this._sendAck(messageId)
|
return this._onRpcResult(messageId, message)
|
||||||
|
|
||||||
return this._onRpcResult(message)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are safe.. i guess
|
// we are safe.. i guess
|
||||||
|
@ -648,7 +627,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
}
|
}
|
||||||
const message = message_ as mtp.TlObject
|
const message = message_ as mtp.TlObject
|
||||||
|
|
||||||
this.log.verbose('received %s (msg_id: %l)', message._, messageId)
|
this.log.debug('received %s (msg_id: %l)', message._, messageId)
|
||||||
this._session.recentIncomingMsgIds.add(messageId)
|
this._session.recentIncomingMsgIds.add(messageId)
|
||||||
|
|
||||||
switch (message._) {
|
switch (message._) {
|
||||||
|
@ -738,7 +717,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onRpcResult(message: TlBinaryReader): void {
|
private _onRpcResult(messageId: Long, message: TlBinaryReader): void {
|
||||||
if (this._usable && this.params.inactivityTimeout) {
|
if (this._usable && this.params.inactivityTimeout) {
|
||||||
this._rescheduleInactivity()
|
this._rescheduleInactivity()
|
||||||
}
|
}
|
||||||
|
@ -790,9 +769,12 @@ export class SessionConnection extends PersistentConnection {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._sendAck(messageId)
|
||||||
|
|
||||||
// special case for auth key binding
|
// special case for auth key binding
|
||||||
if (msg._ !== 'rpc') {
|
if (msg._ !== 'rpc') {
|
||||||
if (msg._ === 'bind') {
|
if (msg._ === 'bind') {
|
||||||
|
this._sendAck(messageId)
|
||||||
msg.promise.resolve(message.object())
|
msg.promise.resolve(message.object())
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -902,7 +884,9 @@ export class SessionConnection extends PersistentConnection {
|
||||||
const msg = this._session.pendingMessages.get(msgId)
|
const msg = this._session.pendingMessages.get(msgId)
|
||||||
|
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
|
if (!this._session.recentOutgoingMsgIds.has(msgId)) {
|
||||||
this.log.warn('received ack for unknown message %l', msgId)
|
this.log.warn('received ack for unknown message %l', msgId)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -969,7 +953,6 @@ export class SessionConnection extends PersistentConnection {
|
||||||
// e.g. when server returns 429
|
// e.g. when server returns 429
|
||||||
|
|
||||||
// most service messages can be omitted as stale
|
// most service messages can be omitted as stale
|
||||||
this._resetLastPing(true)
|
|
||||||
|
|
||||||
for (const msgId of this._session.pendingMessages.keys()) {
|
for (const msgId of this._session.pendingMessages.keys()) {
|
||||||
const info = this._session.pendingMessages.get(msgId)!
|
const info = this._session.pendingMessages.get(msgId)!
|
||||||
|
@ -1025,7 +1008,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
reason,
|
reason,
|
||||||
)
|
)
|
||||||
// restart ping
|
// restart ping
|
||||||
this._resetLastPing(true)
|
this._session.resetLastPing(true)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'rpc': {
|
case 'rpc': {
|
||||||
|
@ -1093,16 +1076,6 @@ export class SessionConnection extends PersistentConnection {
|
||||||
this._session.pendingMessages.delete(msgId)
|
this._session.pendingMessages.delete(msgId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resetLastPing(withTime = false): void {
|
|
||||||
if (withTime) this._lastPingTime = 0
|
|
||||||
|
|
||||||
if (!this._lastPingMsgId.isZero()) {
|
|
||||||
this._session.pendingMessages.delete(this._lastPingMsgId)
|
|
||||||
}
|
|
||||||
|
|
||||||
this._lastPingMsgId = Long.ZERO
|
|
||||||
}
|
|
||||||
|
|
||||||
private _registerOutgoingMsgId(msgId: Long): Long {
|
private _registerOutgoingMsgId(msgId: Long): Long {
|
||||||
this._session.recentOutgoingMsgIds.add(msgId)
|
this._session.recentOutgoingMsgIds.add(msgId)
|
||||||
|
|
||||||
|
@ -1142,8 +1115,8 @@ export class SessionConnection extends PersistentConnection {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const rtt = Date.now() - this._lastPingTime
|
const rtt = Date.now() - this._session.lastPingTime
|
||||||
this._lastPingRtt = rtt
|
this._session.lastPingRtt = rtt
|
||||||
|
|
||||||
if (info.containerId.neq(msgId)) {
|
if (info.containerId.neq(msgId)) {
|
||||||
this._onMessageAcked(info.containerId)
|
this._onMessageAcked(info.containerId)
|
||||||
|
@ -1155,7 +1128,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
pingId,
|
pingId,
|
||||||
rtt,
|
rtt,
|
||||||
)
|
)
|
||||||
this._resetLastPing()
|
this._session.resetLastPing()
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onBadServerSalt(msg: mtp.RawMt_bad_server_salt): void {
|
private _onBadServerSalt(msg: mtp.RawMt_bad_server_salt): void {
|
||||||
|
@ -1211,7 +1184,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
serverSalt,
|
serverSalt,
|
||||||
uniqueId,
|
uniqueId,
|
||||||
}: mtp.RawMt_new_session_created): void {
|
}: mtp.RawMt_new_session_created): void {
|
||||||
if (uniqueId.eq(this._lastSessionCreatedUid)) {
|
if (uniqueId.eq(this._session.lastSessionCreatedUid)) {
|
||||||
this.log.debug(
|
this.log.debug(
|
||||||
'received new_session_created with the same uid = %l, ignoring',
|
'received new_session_created with the same uid = %l, ignoring',
|
||||||
uniqueId,
|
uniqueId,
|
||||||
|
@ -1221,7 +1194,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this._lastSessionCreatedUid.isZero() &&
|
!this._session.lastSessionCreatedUid.isZero() &&
|
||||||
!this.params.disableUpdates
|
!this.params.disableUpdates
|
||||||
) {
|
) {
|
||||||
// force the client to fetch missed updates
|
// force the client to fetch missed updates
|
||||||
|
@ -1277,10 +1250,12 @@ export class SessionConnection extends PersistentConnection {
|
||||||
const info = this._session.pendingMessages.get(msgId)
|
const info = this._session.pendingMessages.get(msgId)
|
||||||
|
|
||||||
if (!info) {
|
if (!info) {
|
||||||
this.log.info(
|
if (!this._session.recentOutgoingMsgIds.has(msgId)) {
|
||||||
|
this.log.warn(
|
||||||
'received message info about unknown message %l',
|
'received message info about unknown message %l',
|
||||||
msgId,
|
msgId,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1417,7 +1392,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
this._session.queuedAcks.push(msgId)
|
this._session.queuedAcks.push(msgId)
|
||||||
|
|
||||||
if (this._session.queuedAcks.length >= 100) {
|
if (this._session.queuedAcks.length >= 100) {
|
||||||
this._flushTimer.emitNow()
|
this._flushTimer.emitWhenIdle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1586,49 +1561,36 @@ export class SessionConnection extends PersistentConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _hasPendingServiceMessages(): boolean {
|
|
||||||
return Boolean(
|
|
||||||
this._session.queuedRpc.length ||
|
|
||||||
this._session.queuedAcks.length ||
|
|
||||||
this._session.queuedStateReq.length ||
|
|
||||||
this._session.queuedResendReq.length,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected _onInactivityTimeout() {
|
protected _onInactivityTimeout() {
|
||||||
// we should send all pending acks and other service messages
|
// we should send all pending acks and other service messages
|
||||||
// before dropping the connection
|
// before dropping the connection
|
||||||
|
|
||||||
if (!this._hasPendingServiceMessages) {
|
if (!this._session.hasPendingMessages) {
|
||||||
this.log.debug('no pending service messages, closing connection')
|
this.log.debug('no pending service messages, closing connection')
|
||||||
super._onInactivityTimeout()
|
super._onInactivityTimeout()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this._flush(() => {
|
this._inactivityPendingFlush = true
|
||||||
if (this._hasPendingServiceMessages) {
|
this._flush()
|
||||||
// the callback will be called again once all pending messages are sent
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log.debug('pending service messages sent, closing connection')
|
flushWhenIdle(): void {
|
||||||
this._flushTimer.reset()
|
this._flushTimer.emitWhenIdle()
|
||||||
super._onInactivityTimeout()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _flush(callback?: () => void): void {
|
private _flush(): void {
|
||||||
if (
|
if (
|
||||||
!this._session._authKey.ready ||
|
!this._session._authKey.ready ||
|
||||||
this._isPfsBindingPending ||
|
this._isPfsBindingPending ||
|
||||||
this._current429Timeout
|
this._session.current429Timeout
|
||||||
) {
|
) {
|
||||||
this.log.debug(
|
this.log.debug(
|
||||||
'skipping flush, connection is not usable (auth key ready = %b, pfs binding pending = %b, 429 timeout = %b)',
|
'skipping flush, connection is not usable (auth key ready = %b, pfs binding pending = %b, 429 timeout = %b)',
|
||||||
this._session._authKey.ready,
|
this._session._authKey.ready,
|
||||||
this._isPfsBindingPending,
|
this._isPfsBindingPending,
|
||||||
Boolean(this._current429Timeout),
|
Boolean(this._session.current429Timeout),
|
||||||
)
|
)
|
||||||
|
|
||||||
// it will be flushed once connection is usable
|
// it will be flushed once connection is usable
|
||||||
|
@ -1636,7 +1598,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this._doFlush(callback)
|
this._doFlush()
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.log.error('flush error: %s', e.stack)
|
this.log.error('flush error: %s', e.stack)
|
||||||
// should not happen unless there's a bug in the code
|
// should not happen unless there's a bug in the code
|
||||||
|
@ -1645,19 +1607,22 @@ export class SessionConnection extends PersistentConnection {
|
||||||
// schedule next flush
|
// schedule next flush
|
||||||
// if there are more queued requests, flush immediately
|
// if there are more queued requests, flush immediately
|
||||||
// (they likely didn't fit into one message)
|
// (they likely didn't fit into one message)
|
||||||
if (
|
if (this._session.hasPendingMessages) {
|
||||||
this._session.queuedRpc.length ||
|
// we schedule it on the next tick, so we can load-balance
|
||||||
this._session.queuedAcks.length ||
|
// between multiple connections using the same session
|
||||||
this._session.queuedStateReq.length ||
|
this._flushTimer.emitWhenIdle()
|
||||||
this._session.queuedResendReq.length
|
} else if (this._inactivityPendingFlush) {
|
||||||
) {
|
this.log.debug('pending messages sent, closing connection')
|
||||||
this._flush(callback)
|
this._flushTimer.reset()
|
||||||
|
this._inactivityPendingFlush = false
|
||||||
|
|
||||||
|
super._onInactivityTimeout()
|
||||||
} else {
|
} else {
|
||||||
this._flushTimer.emitBefore(this._lastPingTime + 60000)
|
this._flushTimer.emitBefore(this._session.lastPingTime + 60000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _doFlush(callback?: () => void): void {
|
private _doFlush(): void {
|
||||||
this.log.debug(
|
this.log.debug(
|
||||||
'flushing send queue. queued rpc: %d',
|
'flushing send queue. queued rpc: %d',
|
||||||
this._session.queuedRpc.length,
|
this._session.queuedRpc.length,
|
||||||
|
@ -1716,13 +1681,15 @@ export class SessionConnection extends PersistentConnection {
|
||||||
|
|
||||||
const getStateTime = now + 1500
|
const getStateTime = now + 1500
|
||||||
|
|
||||||
if (now - this._lastPingTime > 60000) {
|
if (now - this._session.lastPingTime > 60000) {
|
||||||
if (!this._lastPingMsgId.isZero()) {
|
if (!this._session.lastPingMsgId.isZero()) {
|
||||||
this.log.warn(
|
this.log.warn(
|
||||||
"didn't receive pong for previous ping (msg_id = %l)",
|
"didn't receive pong for previous ping (msg_id = %l)",
|
||||||
this._lastPingMsgId,
|
this._session.lastPingMsgId,
|
||||||
|
)
|
||||||
|
this._session.pendingMessages.delete(
|
||||||
|
this._session.lastPingMsgId,
|
||||||
)
|
)
|
||||||
this._session.pendingMessages.delete(this._lastPingMsgId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pingId = randomLong()
|
pingId = randomLong()
|
||||||
|
@ -1731,7 +1698,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
pingId,
|
pingId,
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lastPingTime = Date.now()
|
this._session.lastPingTime = Date.now()
|
||||||
|
|
||||||
pingRequest = TlBinaryWriter.serializeObject(this._writerMap, obj)
|
pingRequest = TlBinaryWriter.serializeObject(this._writerMap, obj)
|
||||||
containerSize += pingRequest.length + 16
|
containerSize += pingRequest.length + 16
|
||||||
|
@ -1836,13 +1803,17 @@ export class SessionConnection extends PersistentConnection {
|
||||||
// if message was already assigned a msg_id,
|
// if message was already assigned a msg_id,
|
||||||
// we must wrap it in a container with a newer msg_id
|
// we must wrap it in a container with a newer msg_id
|
||||||
if (msg.msgId) forceContainer = true
|
if (msg.msgId) forceContainer = true
|
||||||
|
|
||||||
|
// having >1 upload.getFile within a container seems to cause flood_wait errors
|
||||||
|
// also a crutch for load-balancing
|
||||||
|
if (msg.method === 'upload.getFile') break
|
||||||
}
|
}
|
||||||
|
|
||||||
packetSize += containerSize
|
packetSize += containerSize
|
||||||
messageCount += containerMessageCount + rpcToSend.length
|
messageCount += containerMessageCount + rpcToSend.length
|
||||||
|
|
||||||
if (!messageCount) {
|
if (!messageCount) {
|
||||||
this.log.debug('flush failed: nothing to flush')
|
this.log.debug('flush did not happen: nothing to flush')
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1875,7 +1846,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
pingMsgId = this._registerOutgoingMsgId(
|
pingMsgId = this._registerOutgoingMsgId(
|
||||||
this._session.writeMessage(writer, pingRequest),
|
this._session.writeMessage(writer, pingRequest),
|
||||||
)
|
)
|
||||||
this._lastPingMsgId = pingMsgId
|
this._session.lastPingMsgId = pingMsgId
|
||||||
const pingPending: PendingMessage = {
|
const pingPending: PendingMessage = {
|
||||||
_: 'ping',
|
_: 'ping',
|
||||||
pingId: pingId!,
|
pingId: pingId!,
|
||||||
|
@ -2065,7 +2036,6 @@ export class SessionConnection extends PersistentConnection {
|
||||||
this._session
|
this._session
|
||||||
.encryptMessage(result)
|
.encryptMessage(result)
|
||||||
.then((enc) => this.send(enc))
|
.then((enc) => this.send(enc))
|
||||||
.then(callback)
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.log.error(
|
this.log.error(
|
||||||
'error while sending pending messages (root msg_id = %l): %s',
|
'error while sending pending messages (root msg_id = %l): %s',
|
||||||
|
|
|
@ -48,7 +48,9 @@ export abstract class BaseTcpTransport
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
connect(dc: tl.RawDcOption, testMode: boolean): void {
|
connect(dc: tl.RawDcOption, testMode: boolean): void {
|
||||||
if (this._state !== TransportState.Idle) { throw new Error('Transport is not IDLE') }
|
if (this._state !== TransportState.Idle) {
|
||||||
|
throw new Error('Transport is not IDLE')
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.packetCodecInitialized) {
|
if (!this.packetCodecInitialized) {
|
||||||
this._packetCodec.setup?.(this._crypto, this.log)
|
this._packetCodec.setup?.(this._crypto, this.log)
|
||||||
|
@ -69,7 +71,9 @@ export abstract class BaseTcpTransport
|
||||||
this.handleConnect.bind(this),
|
this.handleConnect.bind(this),
|
||||||
)
|
)
|
||||||
|
|
||||||
this._socket.on('data', (data) => this._packetCodec.feed(data))
|
this._socket.on('data', (data) => {
|
||||||
|
this._packetCodec.feed(data)
|
||||||
|
})
|
||||||
this._socket.on('error', this.handleError.bind(this))
|
this._socket.on('error', this.handleError.bind(this))
|
||||||
this._socket.on('close', this.close.bind(this))
|
this._socket.on('close', this.close.bind(this))
|
||||||
}
|
}
|
||||||
|
@ -87,7 +91,7 @@ export abstract class BaseTcpTransport
|
||||||
this._packetCodec.reset()
|
this._packetCodec.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleError(error: Error): Promise<void> {
|
handleError(error: Error): void {
|
||||||
this.log.error('error: %s', error.stack)
|
this.log.error('error: %s', error.stack)
|
||||||
this.emit('error', error)
|
this.emit('error', error)
|
||||||
}
|
}
|
||||||
|
@ -99,7 +103,11 @@ export abstract class BaseTcpTransport
|
||||||
if (initialMessage.length) {
|
if (initialMessage.length) {
|
||||||
this._socket!.write(initialMessage, (err) => {
|
this._socket!.write(initialMessage, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
this.emit('error', err)
|
this.log.error(
|
||||||
|
'failed to write initial message: %s',
|
||||||
|
err.stack,
|
||||||
|
)
|
||||||
|
this.emit('error')
|
||||||
this.close()
|
this.close()
|
||||||
} else {
|
} else {
|
||||||
this._state = TransportState.Ready
|
this._state = TransportState.Ready
|
||||||
|
@ -113,12 +121,20 @@ export abstract class BaseTcpTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
async send(bytes: Buffer): Promise<void> {
|
async send(bytes: Buffer): Promise<void> {
|
||||||
if (this._state !== TransportState.Ready) { throw new Error('Transport is not READY') }
|
if (this._state !== TransportState.Ready) {
|
||||||
|
throw new Error('Transport is not READY')
|
||||||
|
}
|
||||||
|
|
||||||
const framed = await this._packetCodec.encode(bytes)
|
const framed = await this._packetCodec.encode(bytes)
|
||||||
|
|
||||||
return new Promise((res, rej) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._socket!.write(framed, (err) => (err ? rej(err) : res()))
|
this._socket!.write(framed, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error)
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,6 @@ export interface IEncryptionScheme {
|
||||||
decrypt(data: Buffer): MaybeAsync<Buffer>
|
decrypt(data: Buffer): MaybeAsync<Buffer>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IHashMethod {
|
|
||||||
update(data: Buffer): MaybeAsync<void>
|
|
||||||
|
|
||||||
digest(): MaybeAsync<Buffer>
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICryptoProvider {
|
export interface ICryptoProvider {
|
||||||
initialize?(): MaybeAsync<void>
|
initialize?(): MaybeAsync<void>
|
||||||
|
|
||||||
|
@ -38,8 +32,6 @@ export interface ICryptoProvider {
|
||||||
|
|
||||||
createAesEcb(key: Buffer): IEncryptionScheme
|
createAesEcb(key: Buffer): IEncryptionScheme
|
||||||
|
|
||||||
createMd5(): IHashMethod
|
|
||||||
|
|
||||||
factorizePQ(pq: Buffer): MaybeAsync<[Buffer, Buffer]>
|
factorizePQ(pq: Buffer): MaybeAsync<[Buffer, Buffer]>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {
|
||||||
BaseCryptoProvider,
|
BaseCryptoProvider,
|
||||||
ICryptoProvider,
|
ICryptoProvider,
|
||||||
IEncryptionScheme,
|
IEncryptionScheme,
|
||||||
IHashMethod,
|
|
||||||
} from './abstract'
|
} from './abstract'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -108,15 +107,6 @@ export class ForgeCryptoProvider
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
createMd5(): IHashMethod {
|
|
||||||
const hash = forge.md.md5.create()
|
|
||||||
|
|
||||||
return {
|
|
||||||
update: (data) => hash.update(data.toString('binary')),
|
|
||||||
digest: () => Buffer.from(hash.digest().data, 'binary'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hmacSha256(data: Buffer, key: Buffer): MaybeAsync<Buffer> {
|
hmacSha256(data: Buffer, key: Buffer): MaybeAsync<Buffer> {
|
||||||
const hmac = forge.hmac.create()
|
const hmac = forge.hmac.create()
|
||||||
hmac.start('sha256', key.toString('binary'))
|
hmac.start('sha256', key.toString('binary'))
|
||||||
|
|
|
@ -11,7 +11,6 @@ import {
|
||||||
BaseCryptoProvider,
|
BaseCryptoProvider,
|
||||||
ICryptoProvider,
|
ICryptoProvider,
|
||||||
IEncryptionScheme,
|
IEncryptionScheme,
|
||||||
IHashMethod,
|
|
||||||
} from './abstract'
|
} from './abstract'
|
||||||
|
|
||||||
export class NodeCryptoProvider
|
export class NodeCryptoProvider
|
||||||
|
@ -83,10 +82,6 @@ export class NodeCryptoProvider
|
||||||
return createHash('sha256').update(data).digest()
|
return createHash('sha256').update(data).digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
createMd5(): IHashMethod {
|
|
||||||
return createHash('md5') as unknown as IHashMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
hmacSha256(data: Buffer, key: Buffer): MaybeAsync<Buffer> {
|
hmacSha256(data: Buffer, key: Buffer): MaybeAsync<Buffer> {
|
||||||
return createHmac('sha256', key).update(data).digest()
|
return createHmac('sha256', key).update(data).digest()
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,9 +84,16 @@ export class Logger {
|
||||||
|
|
||||||
if (m === '%j') {
|
if (m === '%j') {
|
||||||
return JSON.stringify(val, (k, v) => {
|
return JSON.stringify(val, (k, v) => {
|
||||||
if (typeof v === 'object' && v.type === 'Buffer' && Array.isArray(v.data)) {
|
if (
|
||||||
|
typeof v === 'object' &&
|
||||||
|
v.type === 'Buffer' &&
|
||||||
|
Array.isArray(v.data)
|
||||||
|
) {
|
||||||
let str = Buffer.from(v.data).toString('base64')
|
let str = Buffer.from(v.data).toString('base64')
|
||||||
if (str.length > 300) str = str.slice(0, 300) + '...'
|
|
||||||
|
if (str.length > 300) {
|
||||||
|
str = str.slice(0, 300) + '...'
|
||||||
|
}
|
||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
@ -143,10 +150,10 @@ export class LogManager extends Logger {
|
||||||
static DEBUG = 4
|
static DEBUG = 4
|
||||||
static VERBOSE = 5
|
static VERBOSE = 5
|
||||||
|
|
||||||
constructor() {
|
constructor(tag = 'base') {
|
||||||
// workaround because we cant pass this to super
|
// workaround because we cant pass this to super
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
super(null as any, 'base')
|
super(null as any, tag)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
;(this as any).mgr = this
|
;(this as any).mgr = this
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,31 +164,6 @@ export function testCryptoProvider(c: ICryptoProvider): void {
|
||||||
'99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b',
|
'99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should calculate md5', async () => {
|
|
||||||
const test = async (...parts: string[]): Promise<Buffer> => {
|
|
||||||
const md5 = c.createMd5()
|
|
||||||
for (const p of parts) await md5.update(Buffer.from(p, 'hex'))
|
|
||||||
|
|
||||||
return md5.digest()
|
|
||||||
}
|
|
||||||
|
|
||||||
expect((await test()).toString('hex')).eq(
|
|
||||||
'd41d8cd98f00b204e9800998ecf8427e',
|
|
||||||
)
|
|
||||||
expect((await test('aaeeff')).toString('hex')).eq(
|
|
||||||
'9c20ec5e212b4fcfa4666a8b165c6d5d',
|
|
||||||
)
|
|
||||||
expect((await test('aaeeffffeeaa')).toString('hex')).eq(
|
|
||||||
'cf216071768a7b610d079e5eb7b68b74',
|
|
||||||
)
|
|
||||||
expect((await test('aaeeff', 'ffeeaa')).toString('hex')).eq(
|
|
||||||
'cf216071768a7b610d079e5eb7b68b74',
|
|
||||||
)
|
|
||||||
expect((await test('aa', 'ee', 'ff', 'ffeeaa')).toString('hex')).eq(
|
|
||||||
'cf216071768a7b610d079e5eb7b68b74',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('NodeCryptoProvider', () => {
|
describe('NodeCryptoProvider', () => {
|
||||||
|
|
533
pnpm-lock.yaml
533
pnpm-lock.yaml
|
@ -34,11 +34,11 @@ importers:
|
||||||
specifier: 8.5.4
|
specifier: 8.5.4
|
||||||
version: 8.5.4
|
version: 8.5.4
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: 5.59.8
|
specifier: 6.4.0
|
||||||
version: 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.42.0)(typescript@5.0.4)
|
version: 6.4.0(@typescript-eslint/parser@6.4.0)(eslint@8.47.0)(typescript@5.0.4)
|
||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: 5.59.8
|
specifier: 6.4.0
|
||||||
version: 5.59.8(eslint@8.42.0)(typescript@5.0.4)
|
version: 6.4.0(eslint@8.47.0)(typescript@5.0.4)
|
||||||
chai:
|
chai:
|
||||||
specifier: 4.3.7
|
specifier: 4.3.7
|
||||||
version: 4.3.7
|
version: 4.3.7
|
||||||
|
@ -46,23 +46,23 @@ importers:
|
||||||
specifier: 3.2.0
|
specifier: 3.2.0
|
||||||
version: 3.2.0
|
version: 3.2.0
|
||||||
eslint:
|
eslint:
|
||||||
specifier: 8.42.0
|
specifier: 8.47.0
|
||||||
version: 8.42.0
|
version: 8.47.0
|
||||||
eslint-config-prettier:
|
eslint-config-prettier:
|
||||||
specifier: 8.8.0
|
specifier: 8.8.0
|
||||||
version: 8.8.0(eslint@8.42.0)
|
version: 8.8.0(eslint@8.47.0)
|
||||||
eslint-import-resolver-typescript:
|
eslint-import-resolver-typescript:
|
||||||
specifier: 3.5.5
|
specifier: 3.6.0
|
||||||
version: 3.5.5(@typescript-eslint/parser@5.59.8)(eslint-plugin-import@2.27.5)(eslint@8.42.0)
|
version: 3.6.0(@typescript-eslint/parser@6.4.0)(eslint-plugin-import@2.28.0)(eslint@8.47.0)
|
||||||
eslint-plugin-ascii:
|
eslint-plugin-ascii:
|
||||||
specifier: 1.0.0
|
specifier: 1.0.0
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
eslint-plugin-import:
|
eslint-plugin-import:
|
||||||
specifier: 2.27.5
|
specifier: 2.28.0
|
||||||
version: 2.27.5(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0)
|
version: 2.28.0(@typescript-eslint/parser@6.4.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0)
|
||||||
eslint-plugin-simple-import-sort:
|
eslint-plugin-simple-import-sort:
|
||||||
specifier: 10.0.0
|
specifier: 10.0.0
|
||||||
version: 10.0.0(eslint@8.42.0)
|
version: 10.0.0(eslint@8.47.0)
|
||||||
glob:
|
glob:
|
||||||
specifier: 10.2.6
|
specifier: 10.2.6
|
||||||
version: 10.2.6
|
version: 10.2.6
|
||||||
|
@ -351,6 +351,11 @@ importers:
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
/@aashutoshrathi/word-wrap@1.2.6:
|
||||||
|
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@ampproject/remapping@2.2.0:
|
/@ampproject/remapping@2.2.0:
|
||||||
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
|
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
@ -723,14 +728,14 @@ packages:
|
||||||
'@jridgewell/trace-mapping': 0.3.9
|
'@jridgewell/trace-mapping': 0.3.9
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.42.0):
|
/@eslint-community/eslint-utils@4.4.0(eslint@8.47.0):
|
||||||
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
|
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
eslint-visitor-keys: 3.4.1
|
eslint-visitor-keys: 3.4.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@eslint-community/regexpp@4.5.1:
|
/@eslint-community/regexpp@4.5.1:
|
||||||
|
@ -738,13 +743,18 @@ packages:
|
||||||
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@eslint/eslintrc@2.0.3:
|
/@eslint-community/regexpp@4.6.2:
|
||||||
resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==}
|
resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==}
|
||||||
|
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@eslint/eslintrc@2.1.2:
|
||||||
|
resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
debug: 4.3.4(supports-color@8.1.1)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
espree: 9.5.2
|
espree: 9.6.1
|
||||||
globals: 13.20.0
|
globals: 13.20.0
|
||||||
ignore: 5.2.0
|
ignore: 5.2.0
|
||||||
import-fresh: 3.3.0
|
import-fresh: 3.3.0
|
||||||
|
@ -755,8 +765,8 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@eslint/js@8.42.0:
|
/@eslint/js@8.47.0:
|
||||||
resolution: {integrity: sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==}
|
resolution: {integrity: sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -886,18 +896,6 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@pkgr/utils@2.4.1:
|
|
||||||
resolution: {integrity: sha512-JOqwkgFEyi+OROIyq7l4Jy28h/WwhDnG/cPkXG2Z1iFbubB6jsHW1NDvmyOzTBxHr3yg68YGirmh1JUgMqa+9w==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
|
||||||
dependencies:
|
|
||||||
cross-spawn: 7.0.3
|
|
||||||
fast-glob: 3.2.12
|
|
||||||
is-glob: 4.0.3
|
|
||||||
open: 9.1.0
|
|
||||||
picocolors: 1.0.0
|
|
||||||
tslib: 2.5.3
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@tokenizer/token@0.3.0:
|
/@tokenizer/token@0.3.0:
|
||||||
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
|
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -941,8 +939,8 @@ packages:
|
||||||
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
|
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/json-schema@7.0.11:
|
/@types/json-schema@7.0.12:
|
||||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/json5@0.0.29:
|
/@types/json5@0.0.29:
|
||||||
|
@ -984,133 +982,134 @@ packages:
|
||||||
'@types/node': 18.16.0
|
'@types/node': 18.16.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/eslint-plugin@5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.42.0)(typescript@5.0.4):
|
/@typescript-eslint/eslint-plugin@6.4.0(@typescript-eslint/parser@6.4.0)(eslint@8.47.0)(typescript@5.0.4):
|
||||||
resolution: {integrity: sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==}
|
resolution: {integrity: sha512-62o2Hmc7Gs3p8SLfbXcipjWAa6qk2wZGChXG2JbBtYpwSRmti/9KHLqfbLs9uDigOexG+3PaQ9G2g3201FWLKg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@typescript-eslint/parser': ^5.0.0
|
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/regexpp': 4.5.1
|
'@eslint-community/regexpp': 4.5.1
|
||||||
'@typescript-eslint/parser': 5.59.8(eslint@8.42.0)(typescript@5.0.4)
|
'@typescript-eslint/parser': 6.4.0(eslint@8.47.0)(typescript@5.0.4)
|
||||||
'@typescript-eslint/scope-manager': 5.59.8
|
'@typescript-eslint/scope-manager': 6.4.0
|
||||||
'@typescript-eslint/type-utils': 5.59.8(eslint@8.42.0)(typescript@5.0.4)
|
'@typescript-eslint/type-utils': 6.4.0(eslint@8.47.0)(typescript@5.0.4)
|
||||||
'@typescript-eslint/utils': 5.59.8(eslint@8.42.0)(typescript@5.0.4)
|
'@typescript-eslint/utils': 6.4.0(eslint@8.47.0)(typescript@5.0.4)
|
||||||
|
'@typescript-eslint/visitor-keys': 6.4.0
|
||||||
debug: 4.3.4(supports-color@8.1.1)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
grapheme-splitter: 1.0.4
|
graphemer: 1.4.0
|
||||||
ignore: 5.2.0
|
ignore: 5.2.4
|
||||||
natural-compare-lite: 1.4.0
|
natural-compare: 1.4.0
|
||||||
semver: 7.5.1
|
semver: 7.5.4
|
||||||
tsutils: 3.21.0(typescript@5.0.4)
|
ts-api-utils: 1.0.1(typescript@5.0.4)
|
||||||
typescript: 5.0.4
|
typescript: 5.0.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/parser@5.59.8(eslint@8.42.0)(typescript@5.0.4):
|
/@typescript-eslint/parser@6.4.0(eslint@8.47.0)(typescript@5.0.4):
|
||||||
resolution: {integrity: sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==}
|
resolution: {integrity: sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/scope-manager': 5.59.8
|
'@typescript-eslint/scope-manager': 6.4.0
|
||||||
'@typescript-eslint/types': 5.59.8
|
'@typescript-eslint/types': 6.4.0
|
||||||
'@typescript-eslint/typescript-estree': 5.59.8(typescript@5.0.4)
|
'@typescript-eslint/typescript-estree': 6.4.0(typescript@5.0.4)
|
||||||
|
'@typescript-eslint/visitor-keys': 6.4.0
|
||||||
debug: 4.3.4(supports-color@8.1.1)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
typescript: 5.0.4
|
typescript: 5.0.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/scope-manager@5.59.8:
|
/@typescript-eslint/scope-manager@6.4.0:
|
||||||
resolution: {integrity: sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==}
|
resolution: {integrity: sha512-TUS7vaKkPWDVvl7GDNHFQMsMruD+zhkd3SdVW0d7b+7Zo+bd/hXJQ8nsiUZMi1jloWo6c9qt3B7Sqo+flC1nig==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 5.59.8
|
'@typescript-eslint/types': 6.4.0
|
||||||
'@typescript-eslint/visitor-keys': 5.59.8
|
'@typescript-eslint/visitor-keys': 6.4.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/type-utils@5.59.8(eslint@8.42.0)(typescript@5.0.4):
|
/@typescript-eslint/type-utils@6.4.0(eslint@8.47.0)(typescript@5.0.4):
|
||||||
resolution: {integrity: sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==}
|
resolution: {integrity: sha512-TvqrUFFyGY0cX3WgDHcdl2/mMCWCDv/0thTtx/ODMY1QhEiyFtv/OlLaNIiYLwRpAxAtOLOY9SUf1H3Q3dlwAg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '*'
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 5.59.8(typescript@5.0.4)
|
'@typescript-eslint/typescript-estree': 6.4.0(typescript@5.0.4)
|
||||||
'@typescript-eslint/utils': 5.59.8(eslint@8.42.0)(typescript@5.0.4)
|
'@typescript-eslint/utils': 6.4.0(eslint@8.47.0)(typescript@5.0.4)
|
||||||
debug: 4.3.4(supports-color@8.1.1)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
tsutils: 3.21.0(typescript@5.0.4)
|
ts-api-utils: 1.0.1(typescript@5.0.4)
|
||||||
typescript: 5.0.4
|
typescript: 5.0.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/types@5.59.8:
|
/@typescript-eslint/types@6.4.0:
|
||||||
resolution: {integrity: sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==}
|
resolution: {integrity: sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/typescript-estree@5.59.8(typescript@5.0.4):
|
/@typescript-eslint/typescript-estree@6.4.0(typescript@5.0.4):
|
||||||
resolution: {integrity: sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==}
|
resolution: {integrity: sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 5.59.8
|
'@typescript-eslint/types': 6.4.0
|
||||||
'@typescript-eslint/visitor-keys': 5.59.8
|
'@typescript-eslint/visitor-keys': 6.4.0
|
||||||
debug: 4.3.4(supports-color@8.1.1)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
semver: 7.5.1
|
semver: 7.5.4
|
||||||
tsutils: 3.21.0(typescript@5.0.4)
|
ts-api-utils: 1.0.1(typescript@5.0.4)
|
||||||
typescript: 5.0.4
|
typescript: 5.0.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/utils@5.59.8(eslint@8.42.0)(typescript@5.0.4):
|
/@typescript-eslint/utils@6.4.0(eslint@8.47.0)(typescript@5.0.4):
|
||||||
resolution: {integrity: sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==}
|
resolution: {integrity: sha512-BvvwryBQpECPGo8PwF/y/q+yacg8Hn/2XS+DqL/oRsOPK+RPt29h5Ui5dqOKHDlbXrAeHUTnyG3wZA0KTDxRZw==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^7.0.0 || ^8.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0)
|
'@eslint-community/eslint-utils': 4.4.0(eslint@8.47.0)
|
||||||
'@types/json-schema': 7.0.11
|
'@types/json-schema': 7.0.12
|
||||||
'@types/semver': 7.5.0
|
'@types/semver': 7.5.0
|
||||||
'@typescript-eslint/scope-manager': 5.59.8
|
'@typescript-eslint/scope-manager': 6.4.0
|
||||||
'@typescript-eslint/types': 5.59.8
|
'@typescript-eslint/types': 6.4.0
|
||||||
'@typescript-eslint/typescript-estree': 5.59.8(typescript@5.0.4)
|
'@typescript-eslint/typescript-estree': 6.4.0(typescript@5.0.4)
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
eslint-scope: 5.1.1
|
semver: 7.5.4
|
||||||
semver: 7.5.1
|
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/visitor-keys@5.59.8:
|
/@typescript-eslint/visitor-keys@6.4.0:
|
||||||
resolution: {integrity: sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==}
|
resolution: {integrity: sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^16.0.0 || >=18.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 5.59.8
|
'@typescript-eslint/types': 6.4.0
|
||||||
eslint-visitor-keys: 3.4.1
|
eslint-visitor-keys: 3.4.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -1126,12 +1125,12 @@ packages:
|
||||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/acorn-jsx@5.3.2(acorn@8.8.2):
|
/acorn-jsx@5.3.2(acorn@8.10.0):
|
||||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
|
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.8.2
|
acorn: 8.10.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/acorn-walk@8.2.0:
|
/acorn-walk@8.2.0:
|
||||||
|
@ -1139,6 +1138,12 @@ packages:
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/acorn@8.10.0:
|
||||||
|
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/acorn@8.8.2:
|
/acorn@8.8.2:
|
||||||
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
|
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
|
@ -1322,6 +1327,17 @@ packages:
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/array.prototype.findlastindex@1.2.2:
|
||||||
|
resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
call-bind: 1.0.2
|
||||||
|
define-properties: 1.2.0
|
||||||
|
es-abstract: 1.21.2
|
||||||
|
es-shim-unscopables: 1.0.0
|
||||||
|
get-intrinsic: 1.2.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/array.prototype.flat@1.3.1:
|
/array.prototype.flat@1.3.1:
|
||||||
resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==}
|
resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -1379,6 +1395,7 @@ packages:
|
||||||
/big-integer@1.6.51:
|
/big-integer@1.6.51:
|
||||||
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
|
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/binary-extensions@2.2.0:
|
/binary-extensions@2.2.0:
|
||||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||||
|
@ -1403,13 +1420,6 @@ packages:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/bplist-parser@0.2.0:
|
|
||||||
resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==}
|
|
||||||
engines: {node: '>= 5.10.0'}
|
|
||||||
dependencies:
|
|
||||||
big-integer: 1.6.51
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/brace-expansion@1.1.11:
|
/brace-expansion@1.1.11:
|
||||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1451,13 +1461,6 @@ packages:
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/bundle-name@3.0.0:
|
|
||||||
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
dependencies:
|
|
||||||
run-applescript: 5.0.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/cacache@16.0.7:
|
/cacache@16.0.7:
|
||||||
resolution: {integrity: sha512-a4zfQpp5vm4Ipdvbj+ZrPonikRhm6WBEd4zT1Yc1DXsmAxrPgDwWBLF/u/wTVXSFPIgOJ1U3ghSa2Xm4s3h28w==}
|
resolution: {integrity: sha512-a4zfQpp5vm4Ipdvbj+ZrPonikRhm6WBEd4zT1Yc1DXsmAxrPgDwWBLF/u/wTVXSFPIgOJ1U3ghSa2Xm4s3h28w==}
|
||||||
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
|
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
|
||||||
|
@ -1905,24 +1908,6 @@ packages:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/default-browser-id@3.0.0:
|
|
||||||
resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
dependencies:
|
|
||||||
bplist-parser: 0.2.0
|
|
||||||
untildify: 4.0.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/default-browser@4.0.0:
|
|
||||||
resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==}
|
|
||||||
engines: {node: '>=14.16'}
|
|
||||||
dependencies:
|
|
||||||
bundle-name: 3.0.0
|
|
||||||
default-browser-id: 3.0.0
|
|
||||||
execa: 7.1.1
|
|
||||||
titleize: 3.0.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/default-require-extensions@3.0.0:
|
/default-require-extensions@3.0.0:
|
||||||
resolution: {integrity: sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==}
|
resolution: {integrity: sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -1930,11 +1915,6 @@ packages:
|
||||||
strip-bom: 4.0.0
|
strip-bom: 4.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/define-lazy-prop@3.0.0:
|
|
||||||
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/define-properties@1.2.0:
|
/define-properties@1.2.0:
|
||||||
resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
|
resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -2204,13 +2184,13 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-config-prettier@8.8.0(eslint@8.42.0):
|
/eslint-config-prettier@8.8.0(eslint@8.47.0):
|
||||||
resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==}
|
resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=7.0.0'
|
eslint: '>=7.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-import-resolver-node@0.3.7:
|
/eslint-import-resolver-node@0.3.7:
|
||||||
|
@ -2218,13 +2198,13 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
is-core-module: 2.12.1
|
is-core-module: 2.12.1
|
||||||
resolve: 1.22.2
|
resolve: 1.22.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.59.8)(eslint-plugin-import@2.27.5)(eslint@8.42.0):
|
/eslint-import-resolver-typescript@3.6.0(@typescript-eslint/parser@6.4.0)(eslint-plugin-import@2.28.0)(eslint@8.47.0):
|
||||||
resolution: {integrity: sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==}
|
resolution: {integrity: sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '*'
|
eslint: '*'
|
||||||
|
@ -2232,14 +2212,13 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4(supports-color@8.1.1)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
enhanced-resolve: 5.14.1
|
enhanced-resolve: 5.14.1
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0)
|
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.4.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0)
|
||||||
eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0)
|
eslint-plugin-import: 2.28.0(@typescript-eslint/parser@6.4.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0)
|
||||||
|
fast-glob: 3.3.1
|
||||||
get-tsconfig: 4.6.0
|
get-tsconfig: 4.6.0
|
||||||
globby: 13.1.4
|
|
||||||
is-core-module: 2.12.1
|
is-core-module: 2.12.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
synckit: 0.8.5
|
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@typescript-eslint/parser'
|
- '@typescript-eslint/parser'
|
||||||
- eslint-import-resolver-node
|
- eslint-import-resolver-node
|
||||||
|
@ -2247,7 +2226,7 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0):
|
/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.4.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0):
|
||||||
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
|
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -2268,11 +2247,11 @@ packages:
|
||||||
eslint-import-resolver-webpack:
|
eslint-import-resolver-webpack:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/parser': 5.59.8(eslint@8.42.0)(typescript@5.0.4)
|
'@typescript-eslint/parser': 6.4.0(eslint@8.47.0)(typescript@5.0.4)
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
eslint-import-resolver-node: 0.3.7
|
eslint-import-resolver-node: 0.3.7
|
||||||
eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.8)(eslint-plugin-import@2.27.5)(eslint@8.42.0)
|
eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@6.4.0)(eslint-plugin-import@2.28.0)(eslint@8.47.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -2281,8 +2260,8 @@ packages:
|
||||||
resolution: {integrity: sha512-NT2asS7tLkXMKBk0GuX6eDUZvb5DWTFDCt7R6a8tvWs5P0my2ybxmCFy3Afxgdcam+wQRAn8JrldLmcK0H5Axg==}
|
resolution: {integrity: sha512-NT2asS7tLkXMKBk0GuX6eDUZvb5DWTFDCt7R6a8tvWs5P0my2ybxmCFy3Afxgdcam+wQRAn8JrldLmcK0H5Axg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0):
|
/eslint-plugin-import@2.28.0(@typescript-eslint/parser@6.4.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0):
|
||||||
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
|
resolution: {integrity: sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@typescript-eslint/parser': '*'
|
'@typescript-eslint/parser': '*'
|
||||||
|
@ -2291,22 +2270,25 @@ packages:
|
||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/parser': 5.59.8(eslint@8.42.0)(typescript@5.0.4)
|
'@typescript-eslint/parser': 6.4.0(eslint@8.47.0)(typescript@5.0.4)
|
||||||
array-includes: 3.1.6
|
array-includes: 3.1.6
|
||||||
|
array.prototype.findlastindex: 1.2.2
|
||||||
array.prototype.flat: 1.3.1
|
array.prototype.flat: 1.3.1
|
||||||
array.prototype.flatmap: 1.3.1
|
array.prototype.flatmap: 1.3.1
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
eslint-import-resolver-node: 0.3.7
|
eslint-import-resolver-node: 0.3.7
|
||||||
eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0)
|
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.4.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0)
|
||||||
has: 1.0.3
|
has: 1.0.3
|
||||||
is-core-module: 2.12.1
|
is-core-module: 2.12.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
|
object.fromentries: 2.0.6
|
||||||
|
object.groupby: 1.0.0
|
||||||
object.values: 1.1.6
|
object.values: 1.1.6
|
||||||
resolve: 1.22.2
|
resolve: 1.22.4
|
||||||
semver: 6.3.0
|
semver: 6.3.1
|
||||||
tsconfig-paths: 3.14.2
|
tsconfig-paths: 3.14.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- eslint-import-resolver-typescript
|
- eslint-import-resolver-typescript
|
||||||
|
@ -2314,24 +2296,16 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-simple-import-sort@10.0.0(eslint@8.42.0):
|
/eslint-plugin-simple-import-sort@10.0.0(eslint@8.47.0):
|
||||||
resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==}
|
resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=5.0.0'
|
eslint: '>=5.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.42.0
|
eslint: 8.47.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-scope@5.1.1:
|
/eslint-scope@7.2.2:
|
||||||
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
|
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
|
||||||
engines: {node: '>=8.0.0'}
|
|
||||||
dependencies:
|
|
||||||
esrecurse: 4.3.0
|
|
||||||
estraverse: 4.3.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/eslint-scope@7.2.0:
|
|
||||||
resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==}
|
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
esrecurse: 4.3.0
|
esrecurse: 4.3.0
|
||||||
|
@ -2343,15 +2317,20 @@ packages:
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint@8.42.0:
|
/eslint-visitor-keys@3.4.3:
|
||||||
resolution: {integrity: sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==}
|
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
|
||||||
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/eslint@8.47.0:
|
||||||
|
resolution: {integrity: sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0)
|
'@eslint-community/eslint-utils': 4.4.0(eslint@8.47.0)
|
||||||
'@eslint-community/regexpp': 4.5.1
|
'@eslint-community/regexpp': 4.6.2
|
||||||
'@eslint/eslintrc': 2.0.3
|
'@eslint/eslintrc': 2.1.2
|
||||||
'@eslint/js': 8.42.0
|
'@eslint/js': 8.47.0
|
||||||
'@humanwhocodes/config-array': 0.11.10
|
'@humanwhocodes/config-array': 0.11.10
|
||||||
'@humanwhocodes/module-importer': 1.0.1
|
'@humanwhocodes/module-importer': 1.0.1
|
||||||
'@nodelib/fs.walk': 1.2.8
|
'@nodelib/fs.walk': 1.2.8
|
||||||
|
@ -2361,9 +2340,9 @@ packages:
|
||||||
debug: 4.3.4(supports-color@8.1.1)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
doctrine: 3.0.0
|
doctrine: 3.0.0
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
eslint-scope: 7.2.0
|
eslint-scope: 7.2.2
|
||||||
eslint-visitor-keys: 3.4.1
|
eslint-visitor-keys: 3.4.3
|
||||||
espree: 9.5.2
|
espree: 9.6.1
|
||||||
esquery: 1.5.0
|
esquery: 1.5.0
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
fast-deep-equal: 3.1.3
|
fast-deep-equal: 3.1.3
|
||||||
|
@ -2373,7 +2352,6 @@ packages:
|
||||||
globals: 13.20.0
|
globals: 13.20.0
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.2.0
|
ignore: 5.2.0
|
||||||
import-fresh: 3.3.0
|
|
||||||
imurmurhash: 0.1.4
|
imurmurhash: 0.1.4
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
is-path-inside: 3.0.3
|
is-path-inside: 3.0.3
|
||||||
|
@ -2383,21 +2361,20 @@ packages:
|
||||||
lodash.merge: 4.6.2
|
lodash.merge: 4.6.2
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
natural-compare: 1.4.0
|
natural-compare: 1.4.0
|
||||||
optionator: 0.9.1
|
optionator: 0.9.3
|
||||||
strip-ansi: 6.0.1
|
strip-ansi: 6.0.1
|
||||||
strip-json-comments: 3.1.1
|
|
||||||
text-table: 0.2.0
|
text-table: 0.2.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/espree@9.5.2:
|
/espree@9.6.1:
|
||||||
resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==}
|
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.8.2
|
acorn: 8.10.0
|
||||||
acorn-jsx: 5.3.2(acorn@8.8.2)
|
acorn-jsx: 5.3.2(acorn@8.10.0)
|
||||||
eslint-visitor-keys: 3.4.1
|
eslint-visitor-keys: 3.4.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/esprima@4.0.1:
|
/esprima@4.0.1:
|
||||||
|
@ -2420,11 +2397,6 @@ packages:
|
||||||
estraverse: 5.3.0
|
estraverse: 5.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/estraverse@4.3.0:
|
|
||||||
resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
|
|
||||||
engines: {node: '>=4.0'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/estraverse@5.3.0:
|
/estraverse@5.3.0:
|
||||||
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
|
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
|
@ -2484,8 +2456,8 @@ packages:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/fast-glob@3.2.11:
|
/fast-glob@3.2.12:
|
||||||
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
|
resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
|
||||||
engines: {node: '>=8.6.0'}
|
engines: {node: '>=8.6.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
|
@ -2495,8 +2467,8 @@ packages:
|
||||||
micromatch: 4.0.5
|
micromatch: 4.0.5
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/fast-glob@3.2.12:
|
/fast-glob@3.3.1:
|
||||||
resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
|
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
|
||||||
engines: {node: '>=8.6.0'}
|
engines: {node: '>=8.6.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
|
@ -2834,23 +2806,12 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
array-union: 2.1.0
|
array-union: 2.1.0
|
||||||
dir-glob: 3.0.1
|
dir-glob: 3.0.1
|
||||||
fast-glob: 3.2.11
|
fast-glob: 3.2.12
|
||||||
ignore: 5.2.0
|
ignore: 5.2.0
|
||||||
merge2: 1.4.1
|
merge2: 1.4.1
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/globby@13.1.4:
|
|
||||||
resolution: {integrity: sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
|
||||||
dependencies:
|
|
||||||
dir-glob: 3.0.1
|
|
||||||
fast-glob: 3.2.11
|
|
||||||
ignore: 5.2.0
|
|
||||||
merge2: 1.4.1
|
|
||||||
slash: 4.0.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/gopd@1.0.1:
|
/gopd@1.0.1:
|
||||||
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2860,10 +2821,6 @@ packages:
|
||||||
/graceful-fs@4.2.10:
|
/graceful-fs@4.2.10:
|
||||||
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
|
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
|
||||||
|
|
||||||
/grapheme-splitter@1.0.4:
|
|
||||||
resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/graphemer@1.4.0:
|
/graphemer@1.4.0:
|
||||||
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -3031,6 +2988,11 @@ packages:
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/ignore@5.2.4:
|
||||||
|
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/import-fresh@3.3.0:
|
/import-fresh@3.3.0:
|
||||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
@ -3125,6 +3087,12 @@ packages:
|
||||||
has: 1.0.3
|
has: 1.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/is-core-module@2.13.0:
|
||||||
|
resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==}
|
||||||
|
dependencies:
|
||||||
|
has: 1.0.3
|
||||||
|
dev: true
|
||||||
|
|
||||||
/is-date-object@1.0.5:
|
/is-date-object@1.0.5:
|
||||||
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
|
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -3132,18 +3100,6 @@ packages:
|
||||||
has-tostringtag: 1.0.0
|
has-tostringtag: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/is-docker@2.2.1:
|
|
||||||
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
hasBin: true
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/is-docker@3.0.0:
|
|
||||||
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
|
||||||
hasBin: true
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/is-extglob@2.1.1:
|
/is-extglob@2.1.1:
|
||||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -3172,14 +3128,6 @@ packages:
|
||||||
is-extglob: 2.1.1
|
is-extglob: 2.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/is-inside-container@1.0.0:
|
|
||||||
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
|
|
||||||
engines: {node: '>=14.16'}
|
|
||||||
hasBin: true
|
|
||||||
dependencies:
|
|
||||||
is-docker: 3.0.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/is-lambda@1.0.1:
|
/is-lambda@1.0.1:
|
||||||
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
|
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -3297,13 +3245,6 @@ packages:
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/is-wsl@2.2.0:
|
|
||||||
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dependencies:
|
|
||||||
is-docker: 2.2.1
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/isarray@1.0.0:
|
/isarray@1.0.0:
|
||||||
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -3887,10 +3828,6 @@ packages:
|
||||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/natural-compare-lite@1.4.0:
|
|
||||||
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/natural-compare@1.4.0:
|
/natural-compare@1.4.0:
|
||||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -4079,6 +4016,24 @@ packages:
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/object.fromentries@2.0.6:
|
||||||
|
resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
call-bind: 1.0.2
|
||||||
|
define-properties: 1.2.0
|
||||||
|
es-abstract: 1.21.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/object.groupby@1.0.0:
|
||||||
|
resolution: {integrity: sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==}
|
||||||
|
dependencies:
|
||||||
|
call-bind: 1.0.2
|
||||||
|
define-properties: 1.2.0
|
||||||
|
es-abstract: 1.21.2
|
||||||
|
get-intrinsic: 1.2.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/object.values@1.1.6:
|
/object.values@1.1.6:
|
||||||
resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==}
|
resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -4107,26 +4062,16 @@ packages:
|
||||||
mimic-fn: 4.0.0
|
mimic-fn: 4.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/open@9.1.0:
|
/optionator@0.9.3:
|
||||||
resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==}
|
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
||||||
engines: {node: '>=14.16'}
|
|
||||||
dependencies:
|
|
||||||
default-browser: 4.0.0
|
|
||||||
define-lazy-prop: 3.0.0
|
|
||||||
is-inside-container: 1.0.0
|
|
||||||
is-wsl: 2.2.0
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/optionator@0.9.1:
|
|
||||||
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
|
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@aashutoshrathi/word-wrap': 1.2.6
|
||||||
deep-is: 0.1.4
|
deep-is: 0.1.4
|
||||||
fast-levenshtein: 2.0.6
|
fast-levenshtein: 2.0.6
|
||||||
levn: 0.4.1
|
levn: 0.4.1
|
||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
type-check: 0.4.0
|
type-check: 0.4.0
|
||||||
word-wrap: 1.2.3
|
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/p-limit@2.3.0:
|
/p-limit@2.3.0:
|
||||||
|
@ -4514,6 +4459,15 @@ packages:
|
||||||
supports-preserve-symlinks-flag: 1.0.0
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/resolve@1.22.4:
|
||||||
|
resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
is-core-module: 2.13.0
|
||||||
|
path-parse: 1.0.7
|
||||||
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/restore-cursor@3.1.0:
|
/restore-cursor@3.1.0:
|
||||||
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
|
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -4550,13 +4504,6 @@ packages:
|
||||||
glob: 10.2.6
|
glob: 10.2.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/run-applescript@5.0.0:
|
|
||||||
resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
dependencies:
|
|
||||||
execa: 5.1.1
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/run-parallel@1.2.0:
|
/run-parallel@1.2.0:
|
||||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4599,6 +4546,11 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/semver@6.3.1:
|
||||||
|
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/semver@7.5.0:
|
/semver@7.5.0:
|
||||||
resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==}
|
resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -4614,6 +4566,14 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache: 6.0.0
|
lru-cache: 6.0.0
|
||||||
|
|
||||||
|
/semver@7.5.4:
|
||||||
|
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
lru-cache: 6.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/serialize-javascript@6.0.0:
|
/serialize-javascript@6.0.0:
|
||||||
resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==}
|
resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4677,11 +4637,6 @@ packages:
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/slash@4.0.0:
|
|
||||||
resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/slice-ansi@3.0.0:
|
/slice-ansi@3.0.0:
|
||||||
resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
|
resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -4950,14 +4905,6 @@ packages:
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/synckit@0.8.5:
|
|
||||||
resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==}
|
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
|
||||||
dependencies:
|
|
||||||
'@pkgr/utils': 2.4.1
|
|
||||||
tslib: 2.5.3
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/tapable@2.2.1:
|
/tapable@2.2.1:
|
||||||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
@ -5023,11 +4970,6 @@ packages:
|
||||||
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
|
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/titleize@3.0.0:
|
|
||||||
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/to-fast-properties@2.0.0:
|
/to-fast-properties@2.0.0:
|
||||||
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -5053,6 +4995,15 @@ packages:
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/ts-api-utils@1.0.1(typescript@5.0.4):
|
||||||
|
resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==}
|
||||||
|
engines: {node: '>=16.13.0'}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=4.2.0'
|
||||||
|
dependencies:
|
||||||
|
typescript: 5.0.4
|
||||||
|
dev: true
|
||||||
|
|
||||||
/ts-node@10.9.1(@types/node@18.16.0)(typescript@5.0.4):
|
/ts-node@10.9.1(@types/node@18.16.0)(typescript@5.0.4):
|
||||||
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -5102,24 +5053,10 @@ packages:
|
||||||
strip-bom: 3.0.0
|
strip-bom: 3.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/tslib@1.14.1:
|
|
||||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/tslib@2.5.3:
|
/tslib@2.5.3:
|
||||||
resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==}
|
resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/tsutils@3.21.0(typescript@5.0.4):
|
|
||||||
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
|
||||||
engines: {node: '>= 6'}
|
|
||||||
peerDependencies:
|
|
||||||
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
|
|
||||||
dependencies:
|
|
||||||
tslib: 1.14.1
|
|
||||||
typescript: 5.0.4
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/tunnel-agent@0.6.0:
|
/tunnel-agent@0.6.0:
|
||||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -5223,11 +5160,6 @@ packages:
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/untildify@4.0.0:
|
|
||||||
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/uri-js@4.4.1:
|
/uri-js@4.4.1:
|
||||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -5301,11 +5233,6 @@ packages:
|
||||||
string-width: 4.2.3
|
string-width: 4.2.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/word-wrap@1.2.3:
|
|
||||||
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/workerpool@6.2.1:
|
/workerpool@6.2.1:
|
||||||
resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==}
|
resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
Loading…
Reference in a new issue