test: run tests in browser

This commit is contained in:
alina 🌸 2023-11-29 20:31:18 +03:00
parent 51e67a5113
commit a36cdf1d20
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
47 changed files with 1073 additions and 569 deletions

50
.config/vite.browser.mts Normal file
View file

@ -0,0 +1,50 @@
/// <reference types="vitest" />
import { defineConfig, mergeConfig } from 'vite'
import * as cjsLexer from 'cjs-module-lexer'
import esbuild from 'esbuild'
import baseConfig from './vite.mjs'
await cjsLexer.init()
export default mergeConfig(baseConfig, defineConfig({
test: {
browser: {
enabled: true,
name: 'chromium',
provider: 'playwright',
slowHijackESM: false,
},
fakeTimers: {
toFake: ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'Date']
},
// for whatever reason using exclude-s makes the vite never start the browser, so we use skip-s instead.
// exclude: [
// './packages/crypto-node/**',
// './packages/node/**',
// ],
},
plugins: [
{
name: 'fixup-cjs',
async transform(code, id) {
if (!id.match(/\/packages\/tl\/.*\.js$/)) return code
const lexed = cjsLexer.parse(code)
const r = await esbuild.transform(code, { format: 'esm' })
code = r.code.replace(/export default require_stdin\(\);/, '')
code += 'const __exp = require_stdin()\n'
for (const exp of lexed.exports) {
code += `export const ${exp} = __exp.${exp}\n`
}
return code
}
}
],
define: {
'import.meta.env.TEST_ENV': '"browser"'
}
}))

View file

@ -12,4 +12,7 @@ export default defineConfig({
],
},
},
define: {
'import.meta.env.TEST_ENV': '"node"'
}
})

20
.github/actions/init/action.yml vendored Normal file
View file

@ -0,0 +1,20 @@
inputs:
node-version:
default: '18.x'
runs:
using: 'composite'
steps:
- name: Use Node.js ${{ inputs.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ inputs.node-version }}
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- run: pnpm install --frozen-lockfile
shell: bash
- name: 'TL codegen'
run: pnpm -C packages/tl run gen-code
shell: bash

View file

@ -20,21 +20,10 @@ jobs:
if: github.repository == 'mtcute/mtcute' # do not run on forks
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/checkout@v4
- uses: ./.github/actions/init
- name: Setup Pages
uses: actions/configure-pages@v3
- run: pnpm install --frozen-lockfile
- name: 'TL codegen'
run: pnpm -C packages/tl run gen-code
- name: Build
run: pnpm run -r build
- name: Build docs

View file

@ -29,17 +29,7 @@ jobs:
with:
fetch-depth: 0
token: ${{ secrets.BOT_PAT }}
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- run: pnpm install --frozen-lockfile
- name: 'TL codegen'
run: pnpm -C packages/tl run gen-code
- uses: ./.github/actions/init
- name: Initialize configs
run: |
git config user.name "mtcute-bot"

View file

@ -9,33 +9,33 @@ on:
branches: [ master ]
jobs:
test:
lint:
runs-on: ubuntu-latest
if: github.actor != 'mtcute-bot' # do not run after release
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- run: pnpm install --frozen-lockfile
- name: 'TL codegen'
run: pnpm -C packages/tl run gen-code
- uses: ./.github/actions/init
- name: 'TypeScript'
run: pnpm run lint:tsc:ci
- name: 'ESLint'
run: pnpm run lint:ci
- name: 'Circular dependencies'
run: pnpm run lint:dpdm
- run: pnpm run test:ci
test-node:
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/init
with:
node-version: ${{ matrix.node-version }}
- name: 'Run tests'
run: pnpm run test:ci
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
if: ${{ matrix.node-version == '18.x' }} # to avoid uploading twice
@ -43,9 +43,25 @@ jobs:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
files: ./coverage/coverage-final.json
test-web:
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
browser: [chromium, firefox]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/init
- name: 'Initialize browser'
run: pnpm exec playwright install --with-deps ${{ matrix.browser }}
- name: 'Run tests'
run: pnpm run test:browser --browser.name=${{ matrix.browser }}
e2e:
runs-on: ubuntu-latest
needs: test
needs: [test-node, test-web]
steps:
- uses: actions/checkout@v4
- name: Run end-to-end tests

View file

@ -1,4 +1,4 @@
import type { BaseTelegramClientOptions } from '@mtcute/core'
import { BaseTelegramClientOptions } from '@mtcute/core'
export const getApiParams = (): BaseTelegramClientOptions => {
if (!process.env.API_ID || !process.env.API_HASH) {

View file

@ -8,14 +8,16 @@
"scripts": {
"prepare": "husky install .config/husky",
"postinstall": "node scripts/validate-deps-versions.mjs",
"test": "vitest --config .config/vite.mts run && pnpm run -r test",
"test": "pnpm run -r test && vitest --config .config/vite.mts run",
"test:dev": "vitest --config .config/vite.mts watch",
"test:ui": "vitest --config .config/vite.mts --ui",
"test:coverage": "vitest --config .config/vite.mts run --coverage",
"test:ci": "vitest --config .config/vite.mts run --coverage.enabled --coverage.reporter=json",
"test:browser": "vitest --config .config/vite.browser.mts run",
"test:browser:dev": "vitest --config .config/vite.browser.mts watch",
"lint": "eslint .",
"lint:ci": "NODE_OPTIONS=\\\"--max_old_space_size=8192\\\" eslint --config .config/eslint.ci.js .",
"lint:tsc": "pnpm -r --parallel exec tsc --build",
"lint:tsc": "pnpm -r --workspace-concurrency=4 exec tsc --build",
"lint:tsc:ci": "pnpm -r exec tsc --build",
"lint:dpdm": "dpdm -T --no-warning --no-tree --exit-code circular:1 packages/*",
"lint:fix": "eslint --fix .",
@ -30,14 +32,18 @@
"devDependencies": {
"@commitlint/cli": "17.6.5",
"@commitlint/config-conventional": "17.6.5",
"@types/node": "20.10.0",
"@types/node-forge": "1.3.2",
"@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "6.4.0",
"@typescript-eslint/parser": "6.4.0",
"@vitest/browser": "0.34.6",
"@vitest/coverage-v8": "0.34.6",
"@vitest/ui": "0.34.6",
"cjs-module-lexer": "1.2.3",
"dotenv-flow": "3.2.0",
"dpdm": "3.14.0",
"esbuild": "0.18.20",
"eslint": "8.47.0",
"eslint-config-prettier": "8.8.0",
"eslint-import-resolver-typescript": "3.6.0",
@ -48,6 +54,7 @@
"husky": "8.0.3",
"lint-staged": "13.2.2",
"node-forge": "1.3.1",
"playwright": "^1.40.1",
"prettier": "3.0.3",
"rimraf": "5.0.1",
"semver": "7.5.1",
@ -55,7 +62,7 @@
"tsconfig-paths": "4.2.0",
"typedoc": "0.25.3",
"typescript": "5.0.4",
"vite": "4.5.0",
"vite": "5.0.3",
"vitest": "0.34.6"
},
"prettier": "./.config/prettier.cjs",

View file

@ -29,10 +29,8 @@
}
},
"browser": {
"./cjs/methods/files/_platform.js": "./cjs/methods/files/_platform.web.js",
"./esm/methods/files/_platform.js": "./esm/methods/files/_platform.web.js",
"./cjs/methods/files/download-file.js": "./cjs/methods/files/download-file.web.js",
"./esm/methods/files/download-file.js": "./esm/methods/files/download-file.web.js"
"./src/methods/files/_platform.js": "./src/methods/files/_platform.web.js",
"./src/methods/files/download-file.js": "./src/methods/files/download-file.web.js"
},
"dependencies": {
"@mtcute/core": "workspace:^",

View file

@ -632,7 +632,7 @@ on(name: string, handler: (...args: any[]) => void): this\n`)
)
output.write('}\n')
output.write('\nexport { TelegramClientOptions }\n')
output.write('\nexport type { TelegramClientOptions }\n')
output.write('\nexport class TelegramClient extends BaseTelegramClient {\n')
state.fields.forEach(({ code }) => output.write(`protected ${code}\n`))

View file

@ -5075,7 +5075,7 @@ export interface TelegramClient extends BaseTelegramClient {
}): Promise<User>
}
export { TelegramClientOptions }
export type { TelegramClientOptions }
export class TelegramClient extends BaseTelegramClient {
constructor(opts: TelegramClientOptions) {

View file

@ -7,7 +7,7 @@ import { User } from '../user.js'
import { _actionFromTl, ChatAction } from './actions.js'
export * from './actions.js'
export { ChatEventFilters, InputChatEventFilters } from './filters.js'
export type { ChatEventFilters, InputChatEventFilters } from './filters.js'
export class ChatEvent {
constructor(

View file

@ -2,7 +2,8 @@ import type { CallbackQuery, InlineQuery, Message } from '../../types/index.js'
import { BotChatJoinRequestUpdate } from './bot-chat-join-request.js'
import { BotStoppedUpdate } from './bot-stopped.js'
import { ChatJoinRequestUpdate } from './chat-join-request.js'
import { ChatMemberUpdate, ChatMemberUpdateType } from './chat-member-update.js'
import { ChatMemberUpdate } from './chat-member-update.js'
export type { ChatMemberUpdateType } from './chat-member-update.js'
import { ChosenInlineResult } from './chosen-inline-result.js'
import { DeleteMessageUpdate } from './delete-message-update.js'
import { DeleteStoryUpdate } from './delete-story-update.js'
@ -19,7 +20,6 @@ export {
BotStoppedUpdate,
ChatJoinRequestUpdate,
ChatMemberUpdate,
ChatMemberUpdateType,
ChosenInlineResult,
DeleteMessageUpdate,
DeleteStoryUpdate,

View file

@ -83,23 +83,25 @@ describe('createChunkedReader', () => {
})
})
describe('nodeReadableToWeb', () => {
it('should correctly convert a readable stream', async () => {
const stream = new Readable({
read() {
// eslint-disable-next-line no-restricted-globals
this.push(Buffer.from([1, 2, 3]))
// eslint-disable-next-line no-restricted-globals
this.push(Buffer.from([4, 5, 6]))
this.push(null)
},
if (import.meta.env.TEST_ENV === 'node') {
describe('nodeReadableToWeb', () => {
it('should correctly convert a readable stream', async () => {
const stream = new Readable({
read() {
// eslint-disable-next-line no-restricted-globals
this.push(Buffer.from([1, 2, 3]))
// eslint-disable-next-line no-restricted-globals
this.push(Buffer.from([4, 5, 6]))
this.push(null)
},
})
const webStream = nodeReadableToWeb(stream)
const reader = webStream.getReader()
expect(await reader.read()).to.deep.equal({ value: new Uint8Array([1, 2, 3]), done: false })
expect(await reader.read()).to.deep.equal({ value: new Uint8Array([4, 5, 6]), done: false })
expect(await reader.read()).to.deep.equal({ value: undefined, done: true })
})
const webStream = nodeReadableToWeb(stream)
const reader = webStream.getReader()
expect(await reader.read()).to.deep.equal({ value: new Uint8Array([1, 2, 3]), done: false })
expect(await reader.read()).to.deep.equal({ value: new Uint8Array([4, 5, 6]), done: false })
expect(await reader.read()).to.deep.equal({ value: undefined, done: true })
})
})
}

View file

@ -11,16 +11,11 @@
"build": "pnpm run -w build-package core"
},
"browser": {
"./cjs/utils/platform/crypto.js": "./cjs/utils/platform/crypto.web.js",
"./esm/utils/platform/crypto.js": "./esm/utils/platform/crypto.web.js",
"./cjs/utils/platform/transport.js": "./cjs/utils/platform/transport.web.js",
"./esm/utils/platform/transport.js": "./esm/utils/platform/transport.web.js",
"./cjs/utils/platform/logging.js": "./cjs/utils/platform/logging.web.js",
"./esm/utils/platform/logging.js": "./esm/utils/platform/logging.web.js",
"./cjs/utils/platform/random.js": "./cjs/utils/platform/random.web.js",
"./esm/utils/platform/random.js": "./esm/utils/platform/random.web.js",
"./cjs/storage/json-file.js": false,
"./esm/storage/json-file.js": false
"./src/utils/platform/crypto.js": "./src/utils/platform/crypto.web.js",
"./src/utils/platform/transport.js": "./src/utils/platform/transport.web.js",
"./src/utils/platform/logging.js": "./src/utils/platform/logging.web.js",
"./src/utils/platform/random.js": "./src/utils/platform/random.web.js",
"./src/storage/json-file.js": false
},
"distOnlyFields": {
"exports": {

View file

@ -1,4 +1,4 @@
export { ConnectionKind, NetworkManagerExtraParams, RpcCallOptions } from './network-manager.js'
export type { ConnectionKind, NetworkManagerExtraParams, RpcCallOptions } from './network-manager.js'
export * from './reconnection.js'
export * from './session-connection.js'
export * from './transports/index.js'

View file

@ -4,7 +4,6 @@ import { defaultTestCryptoProvider, useFakeMathRandom } from '@mtcute/test'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'
import { IntermediatePacketCodec, PaddedIntermediatePacketCodec, TransportError } from '../../index.js'
import { concatBuffers } from '../../utils/index.js'
describe('IntermediatePacketCodec', () => {
it('should return correct tag', () => {
@ -82,10 +81,7 @@ describe('IntermediatePacketCodec', () => {
it('should correctly frame packets', () => {
const data = hexDecodeToBuffer('6cfeffff')
// eslint-disable-next-line no-restricted-globals
expect(Buffer.from(new IntermediatePacketCodec().encode(data))).toEqual(
concatBuffers([new Uint8Array([0x04, 0x00, 0x00, 0x00]), data]),
)
expect(hexEncode(new IntermediatePacketCodec().encode(data))).toEqual('040000006cfeffff')
})
})

View file

@ -1,150 +1,155 @@
import { Socket } from 'net'
import { describe, expect, it, MockedObject, vi } from 'vitest'
import { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test'
if (import.meta.env.TEST_ENV === 'node') {
vi.doMock('net', () => ({
connect: vi.fn().mockImplementation((port: number, ip: string, cb: () => void) => {
cb()
import { defaultProductionDc, hexDecodeToBuffer, LogManager } from '../../utils/index.js'
import { TransportState } from './abstract.js'
import { TcpTransport } from './tcp.js'
return {
on: vi.fn(),
write: vi.fn().mockImplementation((data: Uint8Array, cb: () => void) => {
cb()
}),
end: vi.fn(),
removeAllListeners: vi.fn(),
destroy: vi.fn(),
}
}),
}))
vi.mock('net', () => ({
connect: vi.fn().mockImplementation((port: number, ip: string, cb: () => void) => {
cb()
return {
on: vi.fn(),
write: vi.fn().mockImplementation((data: Uint8Array, cb: () => void) => {
cb()
}),
end: vi.fn(),
removeAllListeners: vi.fn(),
destroy: vi.fn(),
}
}),
}))
describe('TcpTransport', async () => {
const net = await import('net')
const connect = vi.mocked(net.connect)
const getLastSocket = () => {
return connect.mock.results[connect.mock.results.length - 1].value as MockedObject<Socket>
}
// we need to do these imports here because basically all of them import `net`
const { defaultTestCryptoProvider, u8HexDecode } = await import('@mtcute/test')
const create = async () => {
const transport = new TcpTransport()
const logger = new LogManager()
logger.level = 0
transport.setup(await defaultTestCryptoProvider(), logger)
const { TcpTransport } = await import('./tcp.js')
const { defaultProductionDc, hexDecodeToBuffer, LogManager } = await import('../../utils/index.js')
const { TransportState } = await import('./abstract.js')
return transport
}
describe('TcpTransport', () => {
const getLastSocket = () => {
return connect.mock.results[connect.mock.results.length - 1].value as MockedObject<Socket>
}
it('should initiate a tcp connection to the given dc', async () => {
const t = await create()
const create = async () => {
const transport = new TcpTransport()
const logger = new LogManager()
logger.level = 0
transport.setup(await defaultTestCryptoProvider(), logger)
t.connect(defaultProductionDc.main, false)
return transport
}
expect(connect).toHaveBeenCalledOnce()
expect(connect).toHaveBeenCalledWith(
defaultProductionDc.main.port,
defaultProductionDc.main.ipAddress,
expect.any(Function),
)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
})
it('should initiate a tcp connection to the given dc', async () => {
const t = await create()
it('should set up event handlers', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
t.connect(defaultProductionDc.main, false)
const socket = getLastSocket()
expect(socket.on).toHaveBeenCalledTimes(3)
expect(socket.on).toHaveBeenCalledWith('data', expect.any(Function))
expect(socket.on).toHaveBeenCalledWith('error', expect.any(Function))
expect(socket.on).toHaveBeenCalledWith('close', expect.any(Function))
})
it('should write packet codec tag once connected', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
const socket = getLastSocket()
await vi.waitFor(() =>
expect(socket.write).toHaveBeenCalledWith(
u8HexDecode('eeeeeeee'), // intermediate
expect(connect).toHaveBeenCalledOnce()
expect(connect).toHaveBeenCalledWith(
defaultProductionDc.main.port,
defaultProductionDc.main.ipAddress,
expect.any(Function),
),
)
)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
})
it('should set up event handlers', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
const socket = getLastSocket()
expect(socket.on).toHaveBeenCalledTimes(3)
expect(socket.on).toHaveBeenCalledWith('data', expect.any(Function))
expect(socket.on).toHaveBeenCalledWith('error', expect.any(Function))
expect(socket.on).toHaveBeenCalledWith('close', expect.any(Function))
})
it('should write packet codec tag once connected', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
const socket = getLastSocket()
await vi.waitFor(() =>
expect(socket.write).toHaveBeenCalledWith(
u8HexDecode('eeeeeeee'), // intermediate
expect.any(Function),
),
)
})
it('should write to the underlying socket', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
await t.send(hexDecodeToBuffer('00010203040506070809'))
const socket = getLastSocket()
expect(socket.write).toHaveBeenCalledWith(u8HexDecode('0a00000000010203040506070809'), expect.any(Function))
})
it('should correctly close', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
t.close()
const socket = getLastSocket()
expect(socket.removeAllListeners).toHaveBeenCalledOnce()
expect(socket.destroy).toHaveBeenCalledOnce()
})
it('should feed data to the packet codec', async () => {
const t = await create()
const codec = t._packetCodec
const spyFeed = vi.spyOn(codec, 'feed')
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
const socket = getLastSocket()
const onDataCall = socket.on.mock.calls.find((c) => (c as string[])[0] === 'data') as unknown as [
string,
(data: Uint8Array) => void,
]
onDataCall[1](u8HexDecode('00010203040506070809'))
expect(spyFeed).toHaveBeenCalledWith(u8HexDecode('00010203040506070809'))
})
it('should propagate errors', async () => {
const t = await create()
const spyEmit = vi.spyOn(t, 'emit').mockImplementation(() => true)
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
const socket = getLastSocket()
const onErrorCall = socket.on.mock.calls.find((c) => (c as string[])[0] === 'error') as unknown as [
string,
(error: Error) => void,
]
onErrorCall[1](new Error('test error'))
expect(spyEmit).toHaveBeenCalledWith('error', new Error('test error'))
})
})
it('should write to the underlying socket', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
await t.send(hexDecodeToBuffer('00010203040506070809'))
const socket = getLastSocket()
expect(socket.write).toHaveBeenCalledWith(u8HexDecode('0a00000000010203040506070809'), expect.any(Function))
})
it('should correctly close', async () => {
const t = await create()
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
t.close()
const socket = getLastSocket()
expect(socket.removeAllListeners).toHaveBeenCalledOnce()
expect(socket.destroy).toHaveBeenCalledOnce()
})
it('should feed data to the packet codec', async () => {
const t = await create()
const codec = t._packetCodec
const spyFeed = vi.spyOn(codec, 'feed')
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
const socket = getLastSocket()
const onDataCall = socket.on.mock.calls.find((c) => (c as string[])[0] === 'data') as unknown as [
string,
(data: Uint8Array) => void,
]
onDataCall[1](u8HexDecode('00010203040506070809'))
expect(spyFeed).toHaveBeenCalledWith(u8HexDecode('00010203040506070809'))
})
it('should propagate errors', async () => {
const t = await create()
const spyEmit = vi.spyOn(t, 'emit').mockImplementation(() => true)
t.connect(defaultProductionDc.main, false)
await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))
const socket = getLastSocket()
const onErrorCall = socket.on.mock.calls.find((c) => (c as string[])[0] === 'error') as unknown as [
string,
(error: Error) => void,
]
onErrorCall[1](new Error('test error'))
expect(spyEmit).toHaveBeenCalledWith('error', new Error('test error'))
})
})
} else {
describe.skip('TcpTransport', () => {})
}

View file

@ -4,6 +4,9 @@ import { stubPeerUser } from '@mtcute/test'
import { JsonMemoryStorage } from './json.js'
// eslint-disable-next-line no-restricted-globals
const createBuffer = import.meta.env.TEST_ENV === 'node' ? Buffer.from : (d: number[]) => new Uint8Array(d)
describe('JsonMemoryStorage', () => {
class ExtJsonMemoryStorage extends JsonMemoryStorage {
loadJson(json: string): void {
@ -25,9 +28,9 @@ describe('JsonMemoryStorage', () => {
s.setUpdatesPts(123)
s.setUpdatesQts(456)
// eslint-disable-next-line no-restricted-globals
s.setAuthKeyFor(1, Buffer.from([1, 2, 3]))
s.setAuthKeyFor(1, createBuffer([1, 2, 3]))
// eslint-disable-next-line no-restricted-globals
s.setTempAuthKeyFor(2, 0, Buffer.from([4, 5, 6]), 1234567890)
s.setTempAuthKeyFor(2, 0, createBuffer([4, 5, 6]), 1234567890)
s.setState('someState', 'someValue')
s.updatePeers([{ ...stubPeerUser, updated: 0 }])

View file

@ -1,80 +1,85 @@
/* eslint-disable no-restricted-globals */
import { describe, expect, it, vi } from 'vitest'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test'
import { concatBuffers, hexDecodeToBuffer, hexEncode } from '../index.js'
import { createAesIgeForMessage, createAesIgeForMessageOld, generateKeyAndIvFromNonce } from './mtproto.js'
import { NodeCryptoProvider } from './node.js'
const authKey = Buffer.alloc(
2048 / 8,
Buffer.from('98cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4bf73c3622dec230e0', 'hex'),
)
const messageKey = Buffer.from('25d701f2a29205526757825a99eb2d32')
const authKeyChunk = hexDecodeToBuffer('98cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4bf73c3622dec230e0')
const authKey = concatBuffers(Array.from({ length: 8 }, () => authKeyChunk))
const messageKey = hexDecodeToBuffer('25d701f2a29205526757825a99eb2d32')
describe('mtproto 2.0', async () => {
const crypto = await defaultTestCryptoProvider()
const createAesIgeSpy = vi.spyOn(crypto, 'createAesIge')
beforeEach(() => void createAesIgeSpy.mockClear())
describe('mtproto 2.0', () => {
it('should correctly derive message key and iv for client', () => {
const crypto = new NodeCryptoProvider()
const spy = vi.spyOn(crypto, 'createAesIge')
createAesIgeForMessage(crypto, authKey, messageKey, true)
expect(spy).toHaveBeenCalledWith(
Buffer.from('7acac59ab48cd370e478daf6c64545ab9f32d5c9197f25febe052110f61875ca', 'hex'),
Buffer.from('2746ccc19fc260c08f3d2696389f415392103dbcc3a8bf69da9394c3c3d95bd3', 'hex'),
expect(hexEncode(createAesIgeSpy.mock.calls[0][0])).toEqual(
'af3f8e1ffa75f4c981eec33a3e5bbaa2ea48f9bb93e91597627eb1f67960a0c9',
)
expect(hexEncode(createAesIgeSpy.mock.calls[0][1])).toEqual(
'9874d77f95155b35221bff94b7df4594c6996e2a62e44fcb7d93c8c4e41b79ee',
)
})
it('should correctly derive message key and iv for server', () => {
const crypto = new NodeCryptoProvider()
const spy = vi.spyOn(crypto, 'createAesIge')
createAesIgeForMessage(crypto, authKey, messageKey, false)
expect(spy).toHaveBeenCalledWith(
Buffer.from('c7cf179e7ebab144ba87de05415db4157d2fc66df4790b2fd405a6c8cbe4c0b3', 'hex'),
Buffer.from('0916a7bd9880eacd4eeb868577a4c6a50e76fca4ac5c1bcfbafe3b9f76ccd806', 'hex'),
expect(hexEncode(createAesIgeSpy.mock.calls[0][0])).toEqual(
'd4b378e1e0525f10ff9d4c42807ccce5b30a033a8088c0b922b5259421751648',
)
expect(hexEncode(createAesIgeSpy.mock.calls[0][1])).toEqual(
'4d7194f42f0135d2fd83050b403265b4c40ee3e9e9fba56f0f4d8ea6bcb121f5',
)
})
})
describe('mtproto 1.0', () => {
it('should correctly derive message key and iv for client', () => {
const crypto = new NodeCryptoProvider()
const spy = vi.spyOn(crypto, 'createAesIge')
describe('mtproto 1.0', async () => {
const crypto = await defaultTestCryptoProvider()
const createAesIgeSpy = vi.spyOn(crypto, 'createAesIge')
beforeEach(() => void createAesIgeSpy.mockClear())
it('should correctly derive message key and iv for client', () => {
createAesIgeForMessageOld(crypto, authKey, messageKey, true)
expect(spy).toHaveBeenCalledWith(
Buffer.from('aad61cb5b7be5e8435174d74665f8a978e85806d0970ad4958642ca49e3c8834', 'hex'),
Buffer.from('4065736fe6586e94aad9f024062f1b9988e8a44e2aff4e11aad61cb5b7be5e84', 'hex'),
expect(hexEncode(createAesIgeSpy.mock.calls[0][0])).toEqual(
'1fc7b40b1d9ffbdaf4d652525a748864259698f89214abf27c0d36cb9d4cd5db',
)
expect(hexEncode(createAesIgeSpy.mock.calls[0][1])).toEqual(
'7251fbda39ec5e6e089f15ded5963b03d6d8d0f7078898431fc7b40b1d9ffbda',
)
})
it('should correctly derive message key and iv for server', () => {
const crypto = new NodeCryptoProvider()
const spy = vi.spyOn(crypto, 'createAesIge')
createAesIgeForMessageOld(crypto, authKey, messageKey, false)
expect(spy).toHaveBeenCalledWith(
Buffer.from('d57682a17105e43b92bc5025ea80e88ef708240fc19450dfe072a8760f9534da', 'hex'),
Buffer.from('07addff7beeb7705ef3a9d5090bd73c992d57291bb8a7079d57682a17105e43b', 'hex'),
expect(hexEncode(createAesIgeSpy.mock.calls[0][0])).toEqual(
'af0e4e01318654be40ab42b125909d43b44bdeef571ff1a5dfb81474ae26d467',
)
expect(hexEncode(createAesIgeSpy.mock.calls[0][1])).toEqual(
'15c9ba6021d2c5cf04f0842540ae216a970b4eac8f46ef01af0e4e01318654be',
)
})
})
describe('mtproto key/iv from nonce', () => {
it('should correctly derive message key and iv for given nonces', () => {
const crypto = new NodeCryptoProvider()
describe('mtproto key/iv from nonce', async () => {
const crypto = await defaultTestCryptoProvider()
it('should correctly derive message key and iv for given nonces', () => {
const res = generateKeyAndIvFromNonce(
crypto,
Buffer.from('8af24c551836e5ed7002f5857e6e71b2', 'hex'),
Buffer.from('3bf48b2d3152f383d82d1f2b32ac7fb5', 'hex'),
u8HexDecode('8af24c551836e5ed7002f5857e6e71b2'),
u8HexDecode('3bf48b2d3152f383d82d1f2b32ac7fb5'),
)
expect(res).to.eql([
Buffer.from('b0b5ffeadff0249fa6292f5ae0351556fd6619ba5dd4809601669292456d3e5a', 'hex'),
Buffer.from('13fef5bfd8c46b12dfd1753013b86cc012e1ce8ed6f8ecdd7bf36f3a3bf48b2d', 'hex'),
u8HexDecode('b0b5ffeadff0249fa6292f5ae0351556fd6619ba5dd4809601669292456d3e5a'),
u8HexDecode('13fef5bfd8c46b12dfd1753013b86cc012e1ce8ed6f8ecdd7bf36f3a3bf48b2d'),
])
})
})

View file

@ -2,14 +2,12 @@ import { describe } from 'vitest'
import { testCryptoProvider } from '@mtcute/test'
import { NodeCryptoProvider } from './node.js'
if (import.meta.env.TEST_ENV === 'node') {
describe('NodeCryptoProvider', async () => {
const { NodeCryptoProvider } = await import('./node.js')
describe('NodeCryptoProvider', () => {
if (typeof process === 'undefined') {
console.warn('Skipping NodeCryptoProvider tests')
return
}
testCryptoProvider(new NodeCryptoProvider())
})
testCryptoProvider(new NodeCryptoProvider())
})
} else {
describe.skip('NodeCryptoProvider', () => {})
}

View file

@ -10,8 +10,8 @@ describe('xorBuffer', () => {
const key = utf8EncodeToBuffer('xor')
const xored = xorBuffer(data, key)
expect(data.toString()).eq('hello')
expect(key.toString()).eq('xor')
expect(utf8Decode(data)).eq('hello')
expect(utf8Decode(key)).eq('xor')
expect(hexEncode(xored)).eq('100a1e6c6f')
})
@ -45,7 +45,7 @@ describe('xorBufferInPlace', () => {
xorBufferInPlace(data, key)
expect(hexEncode(data)).eq('100a1e6c6f')
expect(key.toString()).eq('xor')
expect(utf8Decode(key)).eq('xor')
})
it('second call should decode content', () => {
@ -56,6 +56,6 @@ describe('xorBufferInPlace', () => {
expect(hexEncode(data)).eq('100a1e6c6f')
xorBufferInPlace(data, key)
expect(data.toString()).eq('hello')
expect(utf8Decode(data)).eq('hello')
})
})

View file

@ -130,16 +130,18 @@ describe('logger', () => {
expect(spy).toHaveBeenCalledWith(3, 3, 'base', 'test {"a":1}', [])
})
it('should format buffers inside as hex strings', () => {
const [mgr, spy] = createManager()
if (import.meta.env.TEST_ENV === 'node') {
it('should format Buffers inside as hex strings', () => {
const [mgr, spy] = createManager()
// eslint-disable-next-line no-restricted-globals
mgr.info('test %j', { a: Buffer.from([1, 2, 3]) })
mgr.info('test Uint8Array %j', { a: new Uint8Array([1, 2, 3]) })
// eslint-disable-next-line no-restricted-globals
mgr.info('test %j', { a: Buffer.from([1, 2, 3]) })
mgr.info('test Uint8Array %j', { a: new Uint8Array([1, 2, 3]) })
expect(spy).toHaveBeenCalledWith(3, 3, 'base', 'test {"a":"010203"}', [])
expect(spy).toHaveBeenCalledWith(3, 3, 'base', 'test Uint8Array {"a":"010203"}', [])
})
expect(spy).toHaveBeenCalledWith(3, 3, 'base', 'test {"a":"010203"}', [])
expect(spy).toHaveBeenCalledWith(3, 3, 'base', 'test Uint8Array {"a":"010203"}', [])
})
}
it('should trim long buffers', () => {
const [mgr, spy] = createManager()

View file

@ -2,9 +2,12 @@ import { describe } from 'vitest'
import { testCryptoProvider } from '@mtcute/test'
import { NodeNativeCryptoProvider } from '../src/index.js'
if (import.meta.env.TEST_ENV === 'node') {
describe('NodeNativeCryptoProvider', async () => {
const { NodeNativeCryptoProvider } = await import('../src/index.js')
describe('NodeNativeCryptoProvider', () => {
// eslint-disable-next-line
testCryptoProvider(new NodeNativeCryptoProvider())
})
testCryptoProvider(new NodeNativeCryptoProvider())
})
} else {
describe.skip('NodeNativeCryptoProvider', () => {})
}

View file

@ -4,5 +4,5 @@ export * from './chat-join-request.js'
export * from './chosen-inline-result.js'
export * from './inline-query.js'
export * from './message.js'
export { UpdateContextType } from './parse.js'
export type { UpdateContextType } from './parse.js'
export * from './pre-checkout-query.js'

View file

@ -1,3 +1,4 @@
import * as filters from './bundle.js'
import UpdateFilter = filters.UpdateFilter
export { filters, UpdateFilter }
export { filters }
export type { UpdateFilter }

View file

@ -4,47 +4,51 @@ import { stubPeerUser, testStateStorage, testStorage } from '@mtcute/test'
import { SqliteStorage } from '../src/index.js'
describe('SqliteStorage', () => {
testStorage(new SqliteStorage(), {
// sqlite implements "unimportant" updates, which are batched once every 30sec (tested below)
skipEntityOverwrite: true,
customTests: (s) => {
describe('batching', () => {
beforeAll(() => void vi.useFakeTimers())
afterAll(() => void vi.useRealTimers())
if (import.meta.env.TEST_ENV === 'node') {
describe('SqliteStorage', () => {
testStorage(new SqliteStorage(), {
// sqlite implements "unimportant" updates, which are batched once every 30sec (tested below)
skipEntityOverwrite: true,
customTests: (s) => {
describe('batching', () => {
beforeAll(() => void vi.useFakeTimers())
afterAll(() => void vi.useRealTimers())
it('should batch entity writes', async () => {
s.updatePeers([stubPeerUser])
s.updatePeers([{ ...stubPeerUser, username: 'test123' }])
s.save()
it('should batch entity writes', async () => {
s.updatePeers([stubPeerUser])
s.updatePeers([{ ...stubPeerUser, username: 'test123' }])
s.save()
// eslint-disable-next-line
expect(Object.keys(s['_pendingUnimportant'])).toEqual([String(stubPeerUser.id)])
// not yet updated
expect(s.getPeerByUsername(stubPeerUser.username!)).not.toBeNull()
expect(s.getPeerByUsername('test123')).toBeNull()
// eslint-disable-next-line
expect(Object.keys(s['_pendingUnimportant'])).toEqual([String(stubPeerUser.id)])
// not yet updated
expect(s.getPeerByUsername(stubPeerUser.username!)).not.toBeNull()
expect(s.getPeerByUsername('test123')).toBeNull()
await vi.advanceTimersByTimeAsync(30001)
await vi.advanceTimersByTimeAsync(30001)
expect(s.getPeerByUsername(stubPeerUser.username!)).toBeNull()
expect(s.getPeerByUsername('test123')).not.toBeNull()
expect(s.getPeerByUsername(stubPeerUser.username!)).toBeNull()
expect(s.getPeerByUsername('test123')).not.toBeNull()
})
it('should batch update state writes', () => {
s.setUpdatesPts(123)
s.setUpdatesQts(456)
s.setUpdatesDate(789)
s.setUpdatesSeq(999)
// not yet updated
expect(s.getUpdatesState()).toBeNull()
s.save()
expect(s.getUpdatesState()).toEqual([123, 456, 789, 999])
})
})
it('should batch update state writes', () => {
s.setUpdatesPts(123)
s.setUpdatesQts(456)
s.setUpdatesDate(789)
s.setUpdatesSeq(999)
// not yet updated
expect(s.getUpdatesState()).toBeNull()
s.save()
expect(s.getUpdatesState()).toEqual([123, 456, 789, 999])
})
})
},
},
})
testStateStorage(new SqliteStorage())
})
testStateStorage(new SqliteStorage())
})
} else {
describe.skip('SqliteStorage', () => {})
}

View file

@ -1,6 +1,7 @@
/* eslint-disable no-restricted-globals */
import { describe, expect, it } from 'vitest'
import { hexEncode } from '@mtcute/core/utils.js'
import { StubTelegramClient } from './client.js'
import { createStub } from './stub.js'
@ -23,7 +24,7 @@ describe('client stub', () => {
const client = new StubTelegramClient()
client.onRawMessage((msg) => {
log.push(`message ctor=${Buffer.from(msg.slice(0, 4)).toString('hex')}`)
log.push(`message ctor=${hexEncode(msg.subarray(0, 4))}`)
client.close().catch(() => {})
})

View file

@ -1,4 +1,3 @@
/* eslint-disable no-restricted-globals */
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
import { gzipSync, inflateSync } from 'zlib'
@ -76,6 +75,28 @@ export async function defaultTestCryptoProvider(source = DEFAULT_ENTROPY): Promi
export function testCryptoProvider(c: ICryptoProvider): void {
beforeAll(() => c.initialize?.())
function gzipSyncWrap(data: Uint8Array) {
if (import.meta.env.TEST_ENV === 'browser') {
// @ts-expect-error fucking crutch because @jspm/core uses Buffer.isBuffer for some reason
data._isBuffer = true
return new Uint8Array(gzipSync(data))
}
return gzipSync(data)
}
function inflateSyncWrap(data: Uint8Array) {
if (import.meta.env.TEST_ENV === 'browser') {
// @ts-expect-error fucking crutch because @jspm/core uses Buffer.isBuffer for some reason
data._isBuffer = true
return new Uint8Array(inflateSync(data))
}
return inflateSync(data)
}
it('should calculate sha1', () => {
expect(hexEncode(c.sha1(utf8EncodeToBuffer('')))).to.eq('da39a3ee5e6b4b0d3255bfef95601890afd80709')
expect(hexEncode(c.sha1(utf8EncodeToBuffer('hello')))).to.eq('aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d')
@ -188,21 +209,19 @@ export function testCryptoProvider(c: ICryptoProvider): void {
expect(compressed).not.toBeNull()
const decompressed = inflateSync(compressed!)
const decompressed = inflateSyncWrap(compressed!)
expect(compressed!.length).toBeLessThan(data.length)
// eslint-disable-next-line no-restricted-globals
expect(decompressed).toEqual(Buffer.from(data))
expect(hexEncode(decompressed)).toEqual(hexEncode(data))
})
it('should correctly gunzip', () => {
const data = new Uint8Array(1000).fill(0x42)
const compressed = gzipSync(data)
const compressed = gzipSyncWrap(data)
const decompressed = c.gunzip(compressed)
// eslint-disable-next-line no-restricted-globals
expect(Buffer.from(decompressed)).toEqual(Buffer.from(data))
expect(hexEncode(decompressed)).toEqual(hexEncode(data))
})
describe('randomBytes', () => {
@ -229,7 +248,8 @@ export function testCryptoProvider(c: ICryptoProvider): void {
export function u8HexDecode(hex: string) {
const buf = hexDecodeToBuffer(hex)
if (Buffer.isBuffer(buf)) {
// eslint-disable-next-line no-restricted-globals
if (import.meta.env.TEST_ENV === 'node' && Buffer.isBuffer(buf)) {
return new Uint8Array(buf)
}

View file

@ -1,4 +1,6 @@
import { createRequire } from 'module'
import * as schema_ from '@mtcute/tl/api-schema.json' assert { type: 'json' }
const schema = ('default' in schema_ ? schema_.default : schema_) as { e: TlEntry[] }
import type { TlEntry } from '@mtcute/tl-utils'
@ -14,10 +16,6 @@ export function getEntriesMap() {
}
}
const schema = createRequire(import.meta.url)('@mtcute/tl/api-schema.json') as {
e: TlEntry[]
}
_cachedEntriesMap = new Map()
_cachedUnionsMap = new Map()

View file

@ -11,12 +11,9 @@
"build": "pnpm run -w build-package tl-runtime"
},
"browser": {
"./cjs/encodings/base64.js": "./cjs/encodings/base64.web.js",
"./esm/encodings/base64.js": "./esm/encodings/base64.web.js",
"./cjs/encodings/hex.js": "./cjs/encodings/hex.web.js",
"./esm/encodings/hex.js": "./esm/encodings/hex.web.js",
"./cjs/encodings/utf8.js": "./cjs/encodings/utf8.web.js",
"./esm/encodings/utf8.js": "./esm/encodings/utf8.web.js"
"./src/encodings/hex.js": "./src/encodings/hex.web.js",
"./src/encodings/utf8.js": "./src/encodings/utf8.web.js",
"./src/encodings/base64.js": "./src/encodings/base64.web.js"
},
"distOnlyFields": {
"exports": {

View file

@ -1,7 +1,8 @@
import { describe, expect, it } from 'vitest'
import { base64Decode, base64DecodeToBuffer, base64Encode } from './base64.js'
import { base64Decode as base64DecodeWeb, base64Encode as base64EncodeWeb } from './base64.web.js'
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const _imported = await import(import.meta.env.TEST_ENV === 'node' ? './base64.js' : './base64.web.js')
const { base64Decode, base64DecodeToBuffer, base64Encode } = _imported as typeof import('./base64.js')
describe('base64', () => {
it('should decode base64 string to existing buffer', () => {
@ -36,37 +37,3 @@ describe('base64', () => {
expect(base64Encode(buf, true)).toEqual('AQIDBA')
})
})
describe('base64.web', () => {
it('should decode base64 string to existing buffer', () => {
const buf = new Uint8Array(4)
base64DecodeWeb(buf, 'AQIDBA==')
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode base64 string to new buffer', () => {
const buf = base64DecodeToBuffer('AQIDBA==')
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to base64 string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(base64EncodeWeb(buf)).toEqual('AQIDBA==')
})
it('should decode url-safe base64 string to existing buffer', () => {
const buf = new Uint8Array(4)
base64DecodeWeb(buf, 'AQIDBA', true)
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode url-safe base64 string to new buffer', () => {
const buf = base64DecodeToBuffer('AQIDBA', true)
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to url-safe base64 string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(base64EncodeWeb(buf, true)).toEqual('AQIDBA')
})
})

View file

@ -1,11 +1,8 @@
import { describe, expect, it } from 'vitest'
import { hexDecode, hexDecodeToBuffer, hexEncode } from './hex.js'
import {
hexDecode as hexDecodeWeb,
hexDecodeToBuffer as hexDecodeToBufferWeb,
hexEncode as hexEncodeWeb,
} from './hex.web.js'
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const _imported = await import(import.meta.env.TEST_ENV === 'node' ? './hex.js' : './hex.web.js')
const { hexDecode, hexDecodeToBuffer, hexEncode } = _imported as typeof import('./hex.js')
describe('hex', () => {
it('should decode hex string to existing buffer', () => {
@ -24,21 +21,3 @@ describe('hex', () => {
expect(hexEncode(buf)).toEqual('01020304')
})
})
describe('hex.web', () => {
it('should decode hex string to existing buffer', () => {
const buf = new Uint8Array(4)
hexDecodeWeb(buf, '01020304')
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode hex string to new buffer', () => {
const buf = hexDecodeToBufferWeb('01020304')
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to hex string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(hexEncodeWeb(buf)).toEqual('01020304')
})
})

View file

@ -1,15 +1,8 @@
import { describe, expect, it } from 'vitest'
import { byteLengthUtf8, utf8Decode, utf8Encode, utf8EncodeToBuffer } from './utf8.js'
import {
byteLengthUtf8 as byteLengthUtf8Web,
utf8Decode as utf8DecodeWeb,
utf8Encode as utf8EncodeWeb,
utf8EncodeToBuffer as utf8EncodeToBufferWeb,
} from './utf8.web.js'
// since we use TextEncoder or native Buffer, we can skip testing the utf8 encoding itself
// we only need to test that the functions work as expected with offsets and lengths
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const _imported = await import(import.meta.env.TEST_ENV === 'node' ? './utf8.js' : './utf8.web.js')
const { byteLengthUtf8, utf8Decode, utf8Encode, utf8EncodeToBuffer } = _imported as typeof import('./utf8.js')
describe('utf8', () => {
it('should encode utf8 string into existing buffer', () => {
@ -29,24 +22,6 @@ describe('utf8', () => {
})
})
describe('utf8.web', () => {
it('should encode utf8 string into existing buffer', () => {
const buf = new Uint8Array(4)
utf8EncodeWeb(buf, 'abcd')
expect(buf).toEqual(new Uint8Array([97, 98, 99, 100]))
})
it('should encode utf8 string into new buffer', () => {
const buf = utf8EncodeToBufferWeb('abcd')
expect(buf).toEqual(new Uint8Array([97, 98, 99, 100]))
})
it('should decode utf8 string from existing buffer', () => {
const buf = new Uint8Array([97, 98, 99, 100])
expect(utf8DecodeWeb(buf)).toEqual('abcd')
})
})
describe('byteLengthUtf8', () => {
it('should return byte length of utf8 string', () => {
expect(byteLengthUtf8('abcd')).toEqual(4)
@ -56,10 +31,4 @@ describe('byteLengthUtf8', () => {
expect(byteLengthUtf8('абвг')).toEqual(8)
expect(byteLengthUtf8('🌸')).toEqual(4)
})
it('should work in web', () => {
expect(byteLengthUtf8Web('abcd')).toEqual(4)
expect(byteLengthUtf8Web('абвг')).toEqual(8)
expect(byteLengthUtf8Web('🌸')).toEqual(4)
})
})

View file

@ -1,13 +1,26 @@
// eslint-disable-next-line max-len
/* eslint-disable @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-argument */
import { randomBytes } from 'crypto'
// import { randomBytes } from 'crypto'
import Long from 'long'
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from './encodings/hex.js'
import { TlBinaryReader, TlReaderMap } from './reader.js'
let randomBytes: (n: number) => Uint8Array
if (import.meta.env.TEST_ENV === 'node') {
randomBytes = await import('crypto').then((m) => m.randomBytes)
} else {
randomBytes = (n: number) => {
const buf = new Uint8Array(n)
crypto.getRandomValues(buf)
return buf
}
}
describe('TlBinaryReader', () => {
it('should read int32', () => {
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0])).int()).toEqual(0)
@ -111,10 +124,9 @@ describe('TlBinaryReader', () => {
expect(reader.pos).toEqual(252)
const random1000bytes = randomBytes(1000)
// eslint-disable-next-line no-restricted-globals
const buffer = Buffer.alloc(1010)
const buffer = new Uint8Array(1010)
buffer[0] = 254
buffer.writeIntLE(1000, 1, 3)
new DataView(buffer.buffer).setUint32(1, 1000, true)
buffer.set(random1000bytes, 4)
reader = TlBinaryReader.manual(buffer)
expect([...reader.bytes()]).toEqual([...random1000bytes])

View file

@ -1,11 +1,23 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { randomBytes } from 'crypto'
import Long from 'long'
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '../src/encodings/hex.js'
import { TlBinaryWriter, TlSerializationCounter, TlWriterMap } from './writer.js'
let randomBytes: (n: number) => Uint8Array
if (import.meta.env.TEST_ENV === 'node') {
randomBytes = await import('crypto').then((m) => m.randomBytes)
} else {
randomBytes = (n: number) => {
const buf = new Uint8Array(n)
crypto.getRandomValues(buf)
return buf
}
}
describe('TlBinaryWriter', () => {
const testSingleMethod = (size: number, fn: (w: TlBinaryWriter) => void, map?: TlWriterMap): string => {
const w = TlBinaryWriter.alloc(map, size)
@ -69,17 +81,14 @@ describe('TlBinaryWriter', () => {
expect(testSingleMethod(8, (w) => w.bytes(new Uint8Array([1, 2, 3, 4])))).toEqual('0401020304000000')
const random250bytes = randomBytes(250)
expect(testSingleMethod(252, (w) => w.bytes(random250bytes))).toEqual(
'fa' + random250bytes.toString('hex') + '00',
)
expect(testSingleMethod(252, (w) => w.bytes(random250bytes))).toEqual(`fa${hexEncode(random250bytes)}00`)
const random1000bytes = randomBytes(1000)
// eslint-disable-next-line no-restricted-globals
const buffer = Buffer.alloc(1004)
const buffer = new Uint8Array(1004)
buffer[0] = 254
buffer.writeIntLE(1000, 1, 3)
new DataView(buffer.buffer).setUint32(1, 1000, true)
buffer.set(random1000bytes, 4)
expect(testSingleMethod(1004, (w) => w.bytes(random1000bytes))).toEqual(buffer.toString('hex'))
expect(testSingleMethod(1004, (w) => w.bytes(random1000bytes))).toEqual(hexEncode(buffer))
})
const stubObjectsMap: TlWriterMap = {

View file

@ -13,7 +13,9 @@ module.exports = ({ path: { join }, fs, outDir, packageDir, transformFile }) =>
}
fixWasmPath('cjs/init.js')
fixWasmPath('cjs/init.web.js')
fixWasmPath('esm/init.js')
fixWasmPath('esm/init.web.js')
fs.cpSync(join(packageDir, 'lib/mtcute.wasm'), join(outDir, 'mtcute.wasm'))
},

View file

@ -13,8 +13,7 @@
"build:wasm": "docker build --output=lib --target=binaries lib"
},
"browser": {
"./cjs/init.js": "./cjs/init.web.js",
"./esm/init.js": "./esm/init.web.js"
"./src/init.js": "./src/init.web.js"
},
"distOnlyFields": {
"exports": {
@ -24,5 +23,8 @@
},
"./mtcute.wasm": "./mtcute.wasm"
}
},
"devDependencies": {
"@mtcute/tl-runtime": "workspace:^"
}
}

View file

@ -2,7 +2,7 @@ import { InitInput } from './types.js'
export async function loadWasmBinary(input?: InitInput): Promise<WebAssembly.Instance> {
if (typeof input === 'undefined') {
input = new URL('../mtcute.wasm', import.meta.url)
input = new URL('../lib/mtcute.wasm', import.meta.url)
}
if (

View file

@ -1,6 +1,7 @@
/* eslint-disable no-restricted-globals */
import { beforeAll, describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'
import { __getWasm, createCtr256, ctr256, freeCtr256, initAsync } from '../src/index.js'
beforeAll(async () => {
@ -8,24 +9,22 @@ beforeAll(async () => {
})
describe('aes-ctr', () => {
const key = Buffer.from('603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4', 'hex')
const iv = Buffer.from('F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF', 'hex')
const key = hexDecodeToBuffer('603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4')
const iv = hexDecodeToBuffer('F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF')
describe('NIST', () => {
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CTR.pdf
const data = Buffer.from(
const data = hexDecodeToBuffer(
`6BC1BEE2 2E409F96 E93D7E11 7393172A
AE2D8A57 1E03AC9C 9EB76FAC 45AF8E51
30C81C46 A35CE411 E5FBC119 1A0A52EF
F69F2445 DF4F9B17 AD2B417B E66C3710`.replace(/\s/g, ''),
'hex',
)
const dataEnc = Buffer.from(
const dataEnc = hexDecodeToBuffer(
`601EC313 775789A5 B7A7F504 BBF3D228
F443E3CA 4D62B59A CA84E990 CACAF5C5
2B0930DA A23DE94C E87017BA 2D84988D
DFC9C58D B67AADA6 13C2DD08 457941A6`.replace(/\s/g, ''),
'hex',
)
it('should correctly encrypt', () => {
@ -33,7 +32,7 @@ describe('aes-ctr', () => {
const res = ctr256(ctr, data)
freeCtr256(ctr)
expect(Buffer.from(res).toString('hex')).toEqual(dataEnc.toString('hex'))
expect(hexEncode(res)).toEqual(hexEncode(dataEnc))
})
it('should correctly decrypt', () => {
@ -41,15 +40,15 @@ describe('aes-ctr', () => {
const res = ctr256(ctr, dataEnc)
freeCtr256(ctr)
expect(Buffer.from(res).toString('hex')).toEqual(data.toString('hex'))
expect(hexEncode(res)).toEqual(hexEncode(data))
})
})
describe('stream', () => {
const data = Buffer.from('6BC1BEE22E409F96E93D7E117393172A', 'hex')
const dataEnc1 = Buffer.from('601ec313775789a5b7a7f504bbf3d228', 'hex')
const dataEnc2 = Buffer.from('31afd77f7d218690bd0ef82dfcf66cbe', 'hex')
const dataEnc3 = Buffer.from('7000927e2f2192cbe4b6a8b2441ddd48', 'hex')
const data = hexDecodeToBuffer('6BC1BEE22E409F96E93D7E117393172A')
const dataEnc1 = hexDecodeToBuffer('601ec313775789a5b7a7f504bbf3d228')
const dataEnc2 = hexDecodeToBuffer('31afd77f7d218690bd0ef82dfcf66cbe')
const dataEnc3 = hexDecodeToBuffer('7000927e2f2192cbe4b6a8b2441ddd48')
it('should correctly encrypt', () => {
const ctr = createCtr256(key, iv)
@ -59,9 +58,9 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).toEqual(dataEnc1.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(dataEnc2.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(dataEnc3.toString('hex'))
expect(hexEncode(res1)).toEqual(hexEncode(dataEnc1))
expect(hexEncode(res2)).toEqual(hexEncode(dataEnc2))
expect(hexEncode(res3)).toEqual(hexEncode(dataEnc3))
})
it('should correctly decrypt', () => {
@ -72,20 +71,20 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(data.toString('hex'))
expect(hexEncode(res1)).toEqual(hexEncode(data))
expect(hexEncode(res2)).toEqual(hexEncode(data))
expect(hexEncode(res3)).toEqual(hexEncode(data))
})
})
describe('stream (unaligned)', () => {
const data = Buffer.from('6BC1BEE22E40', 'hex')
const dataEnc1 = Buffer.from('601ec3137757', 'hex')
const dataEnc2 = Buffer.from('7df2e078a555', 'hex')
const dataEnc3 = Buffer.from('a3a17be0742e', 'hex')
const dataEnc4 = Buffer.from('025ced833746', 'hex')
const dataEnc5 = Buffer.from('3ff238dea125', 'hex')
const dataEnc6 = Buffer.from('1055a52302dc', 'hex')
const data = hexDecodeToBuffer('6BC1BEE22E40')
const dataEnc1 = hexDecodeToBuffer('601ec3137757')
const dataEnc2 = hexDecodeToBuffer('7df2e078a555')
const dataEnc3 = hexDecodeToBuffer('a3a17be0742e')
const dataEnc4 = hexDecodeToBuffer('025ced833746')
const dataEnc5 = hexDecodeToBuffer('3ff238dea125')
const dataEnc6 = hexDecodeToBuffer('1055a52302dc')
it('should correctly encrypt', () => {
const ctr = createCtr256(key, iv)
@ -98,12 +97,12 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).toEqual(dataEnc1.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(dataEnc2.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(dataEnc3.toString('hex'))
expect(Buffer.from(res4).toString('hex')).toEqual(dataEnc4.toString('hex'))
expect(Buffer.from(res5).toString('hex')).toEqual(dataEnc5.toString('hex'))
expect(Buffer.from(res6).toString('hex')).toEqual(dataEnc6.toString('hex'))
expect(hexEncode(res1)).toEqual(hexEncode(dataEnc1))
expect(hexEncode(res2)).toEqual(hexEncode(dataEnc2))
expect(hexEncode(res3)).toEqual(hexEncode(dataEnc3))
expect(hexEncode(res4)).toEqual(hexEncode(dataEnc4))
expect(hexEncode(res5)).toEqual(hexEncode(dataEnc5))
expect(hexEncode(res6)).toEqual(hexEncode(dataEnc6))
})
it('should correctly decrypt', () => {
@ -117,17 +116,17 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res4).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res5).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res6).toString('hex')).toEqual(data.toString('hex'))
expect(hexEncode(res1)).toEqual(hexEncode(data))
expect(hexEncode(res2)).toEqual(hexEncode(data))
expect(hexEncode(res3)).toEqual(hexEncode(data))
expect(hexEncode(res4)).toEqual(hexEncode(data))
expect(hexEncode(res5)).toEqual(hexEncode(data))
expect(hexEncode(res6)).toEqual(hexEncode(data))
})
})
it('should not leak memory', () => {
const data = Buffer.from('6BC1BEE22E409F96E93D7E117393172A', 'hex')
const data = hexDecodeToBuffer('6BC1BEE22E409F96E93D7E117393172A')
const mem = __getWasm().memory.buffer
const memSize = mem.byteLength

View file

@ -1,17 +1,29 @@
/* eslint-disable no-restricted-globals */
import { beforeAll, describe, expect, it } from 'vitest'
import { gzipSync } from 'zlib'
import { utf8Decode, utf8EncodeToBuffer } from '@mtcute/tl-runtime'
import { __getWasm, gunzip, initAsync } from '../src/index.js'
beforeAll(async () => {
await initAsync()
})
function gzipSyncWrap(data: Uint8Array) {
if (import.meta.env.TEST_ENV === 'browser') {
// @ts-expect-error fucking crutch because @jspm/core uses Buffer.isBuffer for some reason
data._isBuffer = true
return new Uint8Array(gzipSync(data))
}
return gzipSync(data)
}
describe('gunzip', () => {
it('should correctly read zlib headers', () => {
const wasm = __getWasm()
const data = gzipSync(Buffer.from('hello world'))
const data = gzipSyncWrap(utf8EncodeToBuffer('hello world'))
const inputPtr = wasm.__malloc(data.length)
new Uint8Array(wasm.memory.buffer).set(data, inputPtr)
@ -21,11 +33,11 @@ describe('gunzip', () => {
it('should correctly inflate', () => {
const data = Array.from({ length: 1000 }, () => 'a').join('')
const res = gzipSync(Buffer.from(data))
const res = gzipSyncWrap(utf8EncodeToBuffer(data))
expect(res).not.toBeNull()
expect(res.length).toBeLessThan(100)
expect(gunzip(res)).toEqual(new Uint8Array(Buffer.from(data)))
expect(gunzip(res)).toEqual(new Uint8Array(utf8EncodeToBuffer(data)))
})
it('should not leak memory', () => {
@ -33,11 +45,11 @@ describe('gunzip', () => {
for (let i = 0; i < 100; i++) {
const data = Array.from({ length: 1000 }, () => 'a').join('')
const deflated = gzipSync(Buffer.from(data))
const deflated = gzipSyncWrap(utf8EncodeToBuffer(data))
const res = gunzip(deflated)
expect(Buffer.from(res).toString()).toEqual(data)
expect(utf8Decode(res)).toEqual(data)
}
expect(__getWasm().memory.buffer.byteLength).toEqual(memSize)

View file

@ -1,6 +1,7 @@
/* eslint-disable no-restricted-globals */
import { beforeAll, describe, expect, it } from 'vitest'
import { hexEncode, utf8EncodeToBuffer } from '@mtcute/tl-runtime'
import { __getWasm, initAsync, sha1, sha256 } from '../src/index.js'
beforeAll(async () => {
@ -9,11 +10,9 @@ beforeAll(async () => {
describe('sha256', () => {
it('should correctly calculate sha-256 hash', () => {
const hash = sha256(Buffer.from('abc'))
const hash = sha256(utf8EncodeToBuffer('abc'))
expect(Buffer.from(hash).toString('hex')).toEqual(
'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad',
)
expect(hexEncode(hash)).toEqual('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')
})
it('should not leak memory', () => {
@ -21,7 +20,7 @@ describe('sha256', () => {
const memSize = mem.byteLength
for (let i = 0; i < 100; i++) {
sha256(Buffer.from('abc'))
sha256(utf8EncodeToBuffer('abc'))
}
expect(mem.byteLength).toEqual(memSize)
@ -30,9 +29,9 @@ describe('sha256', () => {
describe('sha1', () => {
it('should correctly calculate sha-1 hash', () => {
const hash = sha1(Buffer.from('abc'))
const hash = sha1(utf8EncodeToBuffer('abc'))
expect(Buffer.from(hash).toString('hex')).toEqual('a9993e364706816aba3e25717850c26c9cd0d89d')
expect(hexEncode(hash)).toEqual('a9993e364706816aba3e25717850c26c9cd0d89d')
})
it('should not leak memory', () => {
@ -40,7 +39,7 @@ describe('sha1', () => {
const memSize = mem.byteLength
for (let i = 0; i < 100; i++) {
sha1(Buffer.from('abc'))
sha1(utf8EncodeToBuffer('abc'))
}
expect(mem.byteLength).toEqual(memSize)

View file

@ -1,6 +1,8 @@
/* eslint-disable no-restricted-globals */
import { beforeAll, describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'
import { __getWasm, ige256Decrypt, ige256Encrypt, initAsync } from '../src/index.js'
beforeAll(async () => {
@ -8,22 +10,22 @@ beforeAll(async () => {
})
describe('aes-ige', () => {
const key = Buffer.from('5468697320697320616E20696D706C655468697320697320616E20696D706C65', 'hex')
const iv = Buffer.from('6D656E746174696F6E206F6620494745206D6F646520666F72204F70656E5353', 'hex')
const key = hexDecodeToBuffer('5468697320697320616E20696D706C655468697320697320616E20696D706C65')
const iv = hexDecodeToBuffer('6D656E746174696F6E206F6620494745206D6F646520666F72204F70656E5353')
const data = Buffer.from('99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b', 'hex')
const dataEnc = Buffer.from('792ea8ae577b1a66cb3bd92679b8030ca54ee631976bd3a04547fdcb4639fa69', 'hex')
const data = hexDecodeToBuffer('99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b')
const dataEnc = hexDecodeToBuffer('792ea8ae577b1a66cb3bd92679b8030ca54ee631976bd3a04547fdcb4639fa69')
it('should correctly encrypt', () => {
const aes = ige256Encrypt(data, key, iv)
expect(Buffer.from(aes).toString('hex')).toEqual(dataEnc.toString('hex'))
expect(hexEncode(aes)).toEqual(hexEncode(dataEnc))
})
it('should correctly decrypt', () => {
const aes = ige256Decrypt(dataEnc, key, iv)
expect(Buffer.from(aes).toString('hex')).toEqual(data.toString('hex'))
expect(hexEncode(aes)).toEqual(hexEncode(data))
})
it('should not leak memory', () => {

View file

@ -1,34 +1,46 @@
/* eslint-disable no-restricted-globals */
import { beforeAll, describe, expect, it } from 'vitest'
import { inflateSync } from 'zlib'
import { utf8Decode, utf8EncodeToBuffer } from '@mtcute/tl-runtime'
import { __getWasm, deflateMaxSize, initAsync } from '../src/index.js'
beforeAll(async () => {
await initAsync()
})
function inflateSyncWrap(data: Uint8Array) {
if (import.meta.env.TEST_ENV === 'browser') {
// @ts-expect-error fucking crutch because @jspm/core uses Buffer.isBuffer for some reason
data._isBuffer = true
return new Uint8Array(inflateSync(data))
}
return inflateSync(data)
}
describe('zlib deflate', () => {
it('should add zlib headers', () => {
const res = deflateMaxSize(Buffer.from('hello world'), 100)
const res = deflateMaxSize(utf8EncodeToBuffer('hello world'), 100)
expect(res).not.toBeNull()
expect(res!.slice(0, 2)).toEqual(new Uint8Array([0x78, 0x9c]))
})
it('should return null if compressed data is larger than size', () => {
const res = deflateMaxSize(Buffer.from('hello world'), 1)
const res = deflateMaxSize(utf8EncodeToBuffer('hello world'), 1)
expect(res).toBeNull()
})
it('should correctly deflate', () => {
const data = Array.from({ length: 1000 }, () => 'a').join('')
const res = deflateMaxSize(Buffer.from(data), 100)
const res = deflateMaxSize(utf8EncodeToBuffer(data), 100)
expect(res).not.toBeNull()
expect(res!.length).toBeLessThan(100)
expect(inflateSync(res!)).toEqual(Buffer.from(data))
expect(inflateSyncWrap(res!)).toEqual(utf8EncodeToBuffer(data))
})
it('should not leak memory', () => {
@ -36,11 +48,11 @@ describe('zlib deflate', () => {
for (let i = 0; i < 100; i++) {
const data = Array.from({ length: 1000 }, () => 'a').join('')
const deflated = deflateMaxSize(Buffer.from(data), 100)
const deflated = deflateMaxSize(utf8EncodeToBuffer(data), 100)
const res = inflateSync(deflated!)
const res = inflateSyncWrap(deflated!)
expect(Buffer.from(res).toString()).toEqual(data)
expect(utf8Decode(res)).toEqual(data)
}
expect(__getWasm().memory.buffer.byteLength).toEqual(memSize)

View file

@ -18,6 +18,9 @@ importers:
'@commitlint/config-conventional':
specifier: 17.6.5
version: 17.6.5
'@types/node':
specifier: 20.10.0
version: 20.10.0
'@types/node-forge':
specifier: 1.3.2
version: 1.3.2
@ -30,18 +33,27 @@ importers:
'@typescript-eslint/parser':
specifier: 6.4.0
version: 6.4.0(eslint@8.47.0)(typescript@5.0.4)
'@vitest/browser':
specifier: 0.34.6
version: 0.34.6(esbuild@0.18.20)(vitest@0.34.6)
'@vitest/coverage-v8':
specifier: 0.34.6
version: 0.34.6(vitest@0.34.6)
'@vitest/ui':
specifier: 0.34.6
version: 0.34.6(vitest@0.34.6)
cjs-module-lexer:
specifier: 1.2.3
version: 1.2.3
dotenv-flow:
specifier: 3.2.0
version: 3.2.0
dpdm:
specifier: 3.14.0
version: 3.14.0
esbuild:
specifier: 0.18.20
version: 0.18.20
eslint:
specifier: 8.47.0
version: 8.47.0
@ -72,6 +84,9 @@ importers:
node-forge:
specifier: 1.3.1
version: 1.3.1
playwright:
specifier: ^1.40.1
version: 1.40.1
prettier:
specifier: 3.0.3
version: 3.0.3
@ -83,7 +98,7 @@ importers:
version: 7.5.1
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.16.0)(typescript@5.0.4)
version: 10.9.1(@types/node@20.10.0)(typescript@5.0.4)
tsconfig-paths:
specifier: 4.2.0
version: 4.2.0
@ -94,11 +109,11 @@ importers:
specifier: 5.0.4
version: 5.0.4
vite:
specifier: 4.5.0
version: 4.5.0(@types/node@18.16.0)
specifier: 5.0.3
version: 5.0.3(@types/node@20.10.0)
vitest:
specifier: 0.34.6
version: 0.34.6(@vitest/ui@0.34.6)
version: 0.34.6(@vitest/browser@0.34.6)(@vitest/ui@0.34.6)(playwright@1.40.1)
packages/client:
dependencies:
@ -297,7 +312,7 @@ importers:
version: 5.2.3
vitest:
specifier: ^0.34.6
version: 0.34.6(@vitest/ui@0.34.6)
version: 0.34.6(@vitest/browser@0.34.6)(@vitest/ui@0.34.6)(playwright@1.40.1)
devDependencies:
'@mtcute/tl-utils':
specifier: workspace:^
@ -347,7 +362,11 @@ importers:
specifier: workspace:^
version: link:../tl-runtime
packages/wasm: {}
packages/wasm:
devDependencies:
'@mtcute/tl-runtime':
specifier: workspace:^
version: link:../tl-runtime
packages:
@ -475,15 +494,15 @@ packages:
'@commitlint/execute-rule': 17.4.0
'@commitlint/resolve-extends': 17.4.4
'@commitlint/types': 17.4.4
'@types/node': 18.16.0
'@types/node': 20.10.0
chalk: 4.1.2
cosmiconfig: 8.1.3
cosmiconfig-typescript-loader: 4.3.0(@types/node@18.16.0)(cosmiconfig@8.1.3)(ts-node@10.9.1)(typescript@5.0.4)
cosmiconfig-typescript-loader: 4.3.0(@types/node@20.10.0)(cosmiconfig@8.1.3)(ts-node@10.9.1)(typescript@5.0.4)
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
resolve-from: 5.0.0
ts-node: 10.9.1(@types/node@18.16.0)(typescript@5.0.4)
ts-node: 10.9.1(@types/node@20.10.0)(typescript@5.0.4)
typescript: 5.0.4
transitivePeerDependencies:
- '@swc/core'
@ -572,6 +591,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/android-arm64@0.19.8:
resolution: {integrity: sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
optional: true
/@esbuild/android-arm@0.18.20:
resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
engines: {node: '>=12'}
@ -580,6 +607,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/android-arm@0.19.8:
resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
optional: true
/@esbuild/android-x64@0.18.20:
resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
engines: {node: '>=12'}
@ -588,6 +623,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/android-x64@0.19.8:
resolution: {integrity: sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
optional: true
/@esbuild/darwin-arm64@0.18.20:
resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
engines: {node: '>=12'}
@ -596,6 +639,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/darwin-arm64@0.19.8:
resolution: {integrity: sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optional: true
/@esbuild/darwin-x64@0.18.20:
resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
engines: {node: '>=12'}
@ -604,6 +655,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/darwin-x64@0.19.8:
resolution: {integrity: sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
optional: true
/@esbuild/freebsd-arm64@0.18.20:
resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
engines: {node: '>=12'}
@ -612,6 +671,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/freebsd-arm64@0.19.8:
resolution: {integrity: sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
optional: true
/@esbuild/freebsd-x64@0.18.20:
resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
engines: {node: '>=12'}
@ -620,6 +687,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/freebsd-x64@0.19.8:
resolution: {integrity: sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
optional: true
/@esbuild/linux-arm64@0.18.20:
resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
engines: {node: '>=12'}
@ -628,6 +703,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-arm64@0.19.8:
resolution: {integrity: sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-arm@0.18.20:
resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
engines: {node: '>=12'}
@ -636,6 +719,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-arm@0.19.8:
resolution: {integrity: sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-ia32@0.18.20:
resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
engines: {node: '>=12'}
@ -644,6 +735,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-ia32@0.19.8:
resolution: {integrity: sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-loong64@0.18.20:
resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
engines: {node: '>=12'}
@ -652,6 +751,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-loong64@0.19.8:
resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-mips64el@0.18.20:
resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
engines: {node: '>=12'}
@ -660,6 +767,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-mips64el@0.19.8:
resolution: {integrity: sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-ppc64@0.18.20:
resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
engines: {node: '>=12'}
@ -668,6 +783,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-ppc64@0.19.8:
resolution: {integrity: sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-riscv64@0.18.20:
resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
engines: {node: '>=12'}
@ -676,6 +799,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-riscv64@0.19.8:
resolution: {integrity: sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-s390x@0.18.20:
resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
engines: {node: '>=12'}
@ -684,6 +815,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-s390x@0.19.8:
resolution: {integrity: sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-x64@0.18.20:
resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
engines: {node: '>=12'}
@ -692,6 +831,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-x64@0.19.8:
resolution: {integrity: sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/netbsd-x64@0.18.20:
resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
engines: {node: '>=12'}
@ -700,6 +847,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/netbsd-x64@0.19.8:
resolution: {integrity: sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
optional: true
/@esbuild/openbsd-x64@0.18.20:
resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
engines: {node: '>=12'}
@ -708,6 +863,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/openbsd-x64@0.19.8:
resolution: {integrity: sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
optional: true
/@esbuild/sunos-x64@0.18.20:
resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
engines: {node: '>=12'}
@ -716,6 +879,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/sunos-x64@0.19.8:
resolution: {integrity: sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
optional: true
/@esbuild/win32-arm64@0.18.20:
resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
engines: {node: '>=12'}
@ -724,6 +895,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/win32-arm64@0.19.8:
resolution: {integrity: sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
optional: true
/@esbuild/win32-ia32@0.18.20:
resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
engines: {node: '>=12'}
@ -732,6 +911,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/win32-ia32@0.19.8:
resolution: {integrity: sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
optional: true
/@esbuild/win32-x64@0.18.20:
resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
engines: {node: '>=12'}
@ -740,6 +927,14 @@ packages:
requiresBuild: true
optional: true
/@esbuild/win32-x64@0.19.8:
resolution: {integrity: sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
optional: true
/@eslint-community/eslint-utils@4.4.0(eslint@8.47.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -873,6 +1068,9 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.11
dev: true
/@jspm/core@2.0.1:
resolution: {integrity: sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==}
/@ljharb/through@2.3.11:
resolution: {integrity: sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==}
engines: {node: '>= 0.4'}
@ -924,6 +1122,103 @@ packages:
/@polka/url@1.0.0-next.23:
resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
/@rollup/pluginutils@5.0.5:
resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@types/estree': 1.0.5
estree-walker: 2.0.2
picomatch: 2.3.1
/@rollup/rollup-android-arm-eabi@4.6.0:
resolution: {integrity: sha512-keHkkWAe7OtdALGoutLY3utvthkGF+Y17ws9LYT8pxMBYXaCoH/8dXS2uzo6e8+sEhY7y/zi5RFo22Dy2lFpDw==}
cpu: [arm]
os: [android]
requiresBuild: true
optional: true
/@rollup/rollup-android-arm64@4.6.0:
resolution: {integrity: sha512-y3Kt+34smKQNWilicPbBz/MXEY7QwDzMFNgwEWeYiOhUt9MTWKjHqe3EVkXwT2fR7izOvHpDWZ0o2IyD9SWX7A==}
cpu: [arm64]
os: [android]
requiresBuild: true
optional: true
/@rollup/rollup-darwin-arm64@4.6.0:
resolution: {integrity: sha512-oLzzxcUIHltHxOCmaXl+pkIlU+uhSxef5HfntW7RsLh1eHm+vJzjD9Oo4oUKso4YuP4PpbFJNlZjJuOrxo8dPg==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optional: true
/@rollup/rollup-darwin-x64@4.6.0:
resolution: {integrity: sha512-+ANnmjkcOBaV25n0+M0Bere3roeVAnwlKW65qagtuAfIxXF9YxUneRyAn/RDcIdRa7QrjRNJL3jR7T43ObGe8Q==}
cpu: [x64]
os: [darwin]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm-gnueabihf@4.6.0:
resolution: {integrity: sha512-tBTSIkjSVUyrekddpkAqKOosnj1Fc0ZY0rJL2bIEWPKqlEQk0paORL9pUIlt7lcGJi3LzMIlUGXvtNi1Z6MOCQ==}
cpu: [arm]
os: [linux]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm64-gnu@4.6.0:
resolution: {integrity: sha512-Ed8uJI3kM11de9S0j67wAV07JUNhbAqIrDYhQBrQW42jGopgheyk/cdcshgGO4fW5Wjq97COCY/BHogdGvKVNQ==}
cpu: [arm64]
os: [linux]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm64-musl@4.6.0:
resolution: {integrity: sha512-mZoNQ/qK4D7SSY8v6kEsAAyDgznzLLuSFCA3aBHZTmf3HP/dW4tNLTtWh9+LfyO0Z1aUn+ecpT7IQ3WtIg3ViQ==}
cpu: [arm64]
os: [linux]
requiresBuild: true
optional: true
/@rollup/rollup-linux-x64-gnu@4.6.0:
resolution: {integrity: sha512-rouezFHpwCqdEXsqAfNsTgSWO0FoZ5hKv5p+TGO5KFhyN/dvYXNMqMolOb8BkyKcPqjYRBeT+Z6V3aM26rPaYg==}
cpu: [x64]
os: [linux]
requiresBuild: true
optional: true
/@rollup/rollup-linux-x64-musl@4.6.0:
resolution: {integrity: sha512-Bbm+fyn3S6u51urfj3YnqBXg5vI2jQPncRRELaucmhBVyZkbWClQ1fEsRmdnCPpQOQfkpg9gZArvtMVkOMsh1w==}
cpu: [x64]
os: [linux]
requiresBuild: true
optional: true
/@rollup/rollup-win32-arm64-msvc@4.6.0:
resolution: {integrity: sha512-+MRMcyx9L2kTrTUzYmR61+XVsliMG4odFb5UmqtiT8xOfEicfYAGEuF/D1Pww1+uZkYhBqAHpvju7VN+GnC3ng==}
cpu: [arm64]
os: [win32]
requiresBuild: true
optional: true
/@rollup/rollup-win32-ia32-msvc@4.6.0:
resolution: {integrity: sha512-rxfeE6K6s/Xl2HGeK6cO8SiQq3k/3BYpw7cfhW5Bk2euXNEpuzi2cc7llxx1si1QgwfjNtdRNTGqdBzGlFZGFw==}
cpu: [ia32]
os: [win32]
requiresBuild: true
optional: true
/@rollup/rollup-win32-x64-msvc@4.6.0:
resolution: {integrity: sha512-QqmCsydHS172Y0Kc13bkMXvipbJSvzeglBncJG3LsYJSiPlxYACz7MmJBs4A8l1oU+jfhYEIC/+AUSlvjmiX/g==}
cpu: [x64]
os: [win32]
requiresBuild: true
optional: true
/@sinclair/typebox@0.27.8:
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
@ -951,7 +1246,7 @@ packages:
/@types/better-sqlite3@7.6.4:
resolution: {integrity: sha512-dzrRZCYPXIXfSR1/surNbJ/grU3scTaygS0OMzjlGf71i9sc2fGyHPXXiXmEvNIoE0cGwsanEFMVJxPXmco9Eg==}
dependencies:
'@types/node': 18.16.0
'@types/node': 20.10.0
dev: true
/@types/chai-subset@1.3.5:
@ -962,6 +1257,9 @@ packages:
/@types/chai@4.3.5:
resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==}
/@types/estree@1.0.5:
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
/@types/events@3.0.0:
resolution: {integrity: sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==}
dev: false
@ -996,11 +1294,13 @@ packages:
/@types/node-forge@1.3.2:
resolution: {integrity: sha512-TzX3ahoi9xbmaoT58smrBu7oa6dQXb/+PTNCslZyD/55tlJ/osofIMClzZsoo6buDFrg7e4DvVGkZqVgv6OLxw==}
dependencies:
'@types/node': 18.16.0
'@types/node': 20.10.0
dev: true
/@types/node@18.16.0:
resolution: {integrity: sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==}
/@types/node@20.10.0:
resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==}
dependencies:
undici-types: 5.26.5
/@types/normalize-package-data@2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
@ -1013,13 +1313,13 @@ packages:
/@types/through@0.0.32:
resolution: {integrity: sha512-7XsfXIsjdfJM2wFDRAtEWp3zb2aVPk5QeyZxGlVK57q4u26DczMHhJmlhr0Jqv0THwxam/L8REXkj8M2I/lcvw==}
dependencies:
'@types/node': 18.16.0
'@types/node': 20.10.0
dev: true
/@types/ws@8.5.4:
resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==}
dependencies:
'@types/node': 18.16.0
'@types/node': 20.10.0
dev: true
/@typescript-eslint/eslint-plugin@6.4.0(@typescript-eslint/parser@6.4.0)(eslint@8.47.0)(typescript@5.0.4):
@ -1153,6 +1453,20 @@ packages:
eslint-visitor-keys: 3.4.1
dev: true
/@vitest/browser@0.34.6(esbuild@0.18.20)(vitest@0.34.6):
resolution: {integrity: sha512-XCIGROVgw3L+PwYw/T2l+HP/SPrXvh2MfmQNU3aULl5ekE+QVj9A1RYu/1mcYXdac9ES4ahxUz6n4wgcVd9tbA==}
peerDependencies:
vitest: '>=0.34.0'
dependencies:
estree-walker: 3.0.3
magic-string: 0.30.5
modern-node-polyfills: 1.0.0(esbuild@0.18.20)
sirv: 2.0.3
vitest: 0.34.6(@vitest/browser@0.34.6)(@vitest/ui@0.34.6)(playwright@1.40.1)
transitivePeerDependencies:
- esbuild
- rollup
/@vitest/coverage-v8@0.34.6(vitest@0.34.6):
resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==}
peerDependencies:
@ -1169,7 +1483,7 @@ packages:
std-env: 3.4.3
test-exclude: 6.0.0
v8-to-istanbul: 9.1.3
vitest: 0.34.6(@vitest/ui@0.34.6)
vitest: 0.34.6(@vitest/browser@0.34.6)(@vitest/ui@0.34.6)(playwright@1.40.1)
transitivePeerDependencies:
- supports-color
dev: true
@ -1212,7 +1526,7 @@ packages:
pathe: 1.1.1
picocolors: 1.0.0
sirv: 2.0.3
vitest: 0.34.6(@vitest/ui@0.34.6)
vitest: 0.34.6(@vitest/browser@0.34.6)(@vitest/ui@0.34.6)(playwright@1.40.1)
/@vitest/utils@0.34.6:
resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==}
@ -1654,6 +1968,10 @@ packages:
engines: {node: '>=10'}
dev: false
/cjs-module-lexer@1.2.3:
resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==}
dev: true
/clean-stack@2.2.0:
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
engines: {node: '>=6'}
@ -1792,7 +2110,7 @@ packages:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: false
/cosmiconfig-typescript-loader@4.3.0(@types/node@18.16.0)(cosmiconfig@8.1.3)(ts-node@10.9.1)(typescript@5.0.4):
/cosmiconfig-typescript-loader@4.3.0(@types/node@20.10.0)(cosmiconfig@8.1.3)(ts-node@10.9.1)(typescript@5.0.4):
resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==}
engines: {node: '>=12', npm: '>=6'}
peerDependencies:
@ -1801,9 +2119,9 @@ packages:
ts-node: '>=10'
typescript: '>=3'
dependencies:
'@types/node': 18.16.0
'@types/node': 20.10.0
cosmiconfig: 8.1.3
ts-node: 10.9.1(@types/node@18.16.0)(typescript@5.0.4)
ts-node: 10.9.1(@types/node@20.10.0)(typescript@5.0.4)
typescript: 5.0.4
dev: true
@ -2232,6 +2550,35 @@ packages:
'@esbuild/win32-ia32': 0.18.20
'@esbuild/win32-x64': 0.18.20
/esbuild@0.19.8:
resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.19.8
'@esbuild/android-arm64': 0.19.8
'@esbuild/android-x64': 0.19.8
'@esbuild/darwin-arm64': 0.19.8
'@esbuild/darwin-x64': 0.19.8
'@esbuild/freebsd-arm64': 0.19.8
'@esbuild/freebsd-x64': 0.19.8
'@esbuild/linux-arm': 0.19.8
'@esbuild/linux-arm64': 0.19.8
'@esbuild/linux-ia32': 0.19.8
'@esbuild/linux-loong64': 0.19.8
'@esbuild/linux-mips64el': 0.19.8
'@esbuild/linux-ppc64': 0.19.8
'@esbuild/linux-riscv64': 0.19.8
'@esbuild/linux-s390x': 0.19.8
'@esbuild/linux-x64': 0.19.8
'@esbuild/netbsd-x64': 0.19.8
'@esbuild/openbsd-x64': 0.19.8
'@esbuild/sunos-x64': 0.19.8
'@esbuild/win32-arm64': 0.19.8
'@esbuild/win32-ia32': 0.19.8
'@esbuild/win32-x64': 0.19.8
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
@ -2464,6 +2811,14 @@ packages:
engines: {node: '>=4.0'}
dev: true
/estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
/estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
dependencies:
'@types/estree': 1.0.5
/esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@ -2654,6 +3009,13 @@ packages:
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
optional: true
/fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@ -3804,6 +4166,19 @@ packages:
pkg-types: 1.0.3
ufo: 1.3.1
/modern-node-polyfills@1.0.0(esbuild@0.18.20):
resolution: {integrity: sha512-w1yb6ae5qSUJJ2u41krkUAxs+L7i9143Qam8EuXwDMeZHxl1JN8RfTSXG4S2bt0RHIRMeoWm/HCeO0pNIHmIYQ==}
engines: {node: '>=14.0.0'}
peerDependencies:
esbuild: ^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0
dependencies:
'@jspm/core': 2.0.1
'@rollup/pluginutils': 5.0.5
esbuild: 0.18.20
local-pkg: 0.4.3
transitivePeerDependencies:
- rollup
/mrmime@1.0.1:
resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==}
engines: {node: '>=10'}
@ -4190,6 +4565,20 @@ packages:
mlly: 1.4.2
pathe: 1.1.1
/playwright-core@1.40.1:
resolution: {integrity: sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==}
engines: {node: '>=16'}
hasBin: true
/playwright@1.40.1:
resolution: {integrity: sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==}
engines: {node: '>=16'}
hasBin: true
dependencies:
playwright-core: 1.40.1
optionalDependencies:
fsevents: 2.3.2
/postcss@8.4.31:
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
engines: {node: ^10 || ^12 || >=14}
@ -4432,11 +4821,23 @@ packages:
glob: 10.2.6
dev: true
/rollup@3.29.4:
resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
/rollup@4.6.0:
resolution: {integrity: sha512-R8i5Her4oO1LiMQ3jKf7MUglYV/mhQ5g5OKeld5CnkmPdIGo79FDDQYqPhq/PCVuTQVuxsWgIbDy9F+zdHn80w==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.6.0
'@rollup/rollup-android-arm64': 4.6.0
'@rollup/rollup-darwin-arm64': 4.6.0
'@rollup/rollup-darwin-x64': 4.6.0
'@rollup/rollup-linux-arm-gnueabihf': 4.6.0
'@rollup/rollup-linux-arm64-gnu': 4.6.0
'@rollup/rollup-linux-arm64-musl': 4.6.0
'@rollup/rollup-linux-x64-gnu': 4.6.0
'@rollup/rollup-linux-x64-musl': 4.6.0
'@rollup/rollup-win32-arm64-msvc': 4.6.0
'@rollup/rollup-win32-ia32-msvc': 4.6.0
'@rollup/rollup-win32-x64-msvc': 4.6.0
fsevents: 2.3.3
/run-applescript@5.0.0:
@ -4929,7 +5330,7 @@ packages:
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@20.10.0)(typescript@5.0.4):
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
@ -4948,7 +5349,7 @@ packages:
'@tsconfig/node12': 1.0.9
'@tsconfig/node14': 1.0.1
'@tsconfig/node16': 1.0.2
'@types/node': 18.16.0
'@types/node': 20.10.0
acorn: 8.10.0
acorn-walk: 8.2.0
arg: 4.1.3
@ -5076,6 +5477,9 @@ packages:
which-boxed-primitive: 1.0.2
dev: true
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
/unique-filename@1.1.1:
resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==}
dependencies:
@ -5127,7 +5531,7 @@ packages:
spdx-expression-parse: 3.0.1
dev: true
/vite-node@0.34.6(@types/node@18.16.0):
/vite-node@0.34.6(@types/node@20.10.0):
resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
engines: {node: '>=v14.18.0'}
hasBin: true
@ -5137,7 +5541,7 @@ packages:
mlly: 1.4.2
pathe: 1.1.1
picocolors: 1.0.0
vite: 4.5.0(@types/node@18.16.0)
vite: 5.0.3(@types/node@20.10.0)
transitivePeerDependencies:
- '@types/node'
- less
@ -5148,12 +5552,12 @@ packages:
- supports-color
- terser
/vite@4.5.0(@types/node@18.16.0):
resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==}
engines: {node: ^14.18.0 || >=16.0.0}
/vite@5.0.3(@types/node@20.10.0):
resolution: {integrity: sha512-WgEq8WEKpZ8c0DL4M1+E+kBZEJyjBmGVrul6z8Ljfhv+PPbNF4aGq014DwNYxGz2FGq6NKL0N8usdiESWd2l2w==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': '>= 14'
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
@ -5176,14 +5580,14 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 18.16.0
esbuild: 0.18.20
'@types/node': 20.10.0
esbuild: 0.19.8
postcss: 8.4.31
rollup: 3.29.4
rollup: 4.6.0
optionalDependencies:
fsevents: 2.3.3
/vitest@0.34.6(@vitest/ui@0.34.6):
/vitest@0.34.6(@vitest/browser@0.34.6)(@vitest/ui@0.34.6)(playwright@1.40.1):
resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==}
engines: {node: '>=v14.18.0'}
hasBin: true
@ -5216,7 +5620,8 @@ packages:
dependencies:
'@types/chai': 4.3.5
'@types/chai-subset': 1.3.5
'@types/node': 18.16.0
'@types/node': 20.10.0
'@vitest/browser': 0.34.6(esbuild@0.18.20)(vitest@0.34.6)
'@vitest/expect': 0.34.6
'@vitest/runner': 0.34.6
'@vitest/snapshot': 0.34.6
@ -5232,12 +5637,13 @@ packages:
magic-string: 0.30.5
pathe: 1.1.1
picocolors: 1.0.0
playwright: 1.40.1
std-env: 3.4.3
strip-literal: 1.3.0
tinybench: 2.5.1
tinypool: 0.7.0
vite: 4.5.0(@types/node@18.16.0)
vite-node: 0.34.6(@types/node@18.16.0)
vite: 5.0.3(@types/node@20.10.0)
vite-node: 0.34.6(@types/node@20.10.0)
why-is-node-running: 2.2.2
transitivePeerDependencies:
- less

View file

@ -114,6 +114,31 @@ function buildPackageJson() {
delete pkgJson.typedoc
function maybeFixPath(p, repl) {
if (!p) return p
if (p.startsWith('./src/')) {
return repl + p.slice(6)
}
return p
}
if (pkgJson.browser) {
for (const key of Object.keys(pkgJson.browser)) {
if (!key.startsWith('./src/')) continue
const path = key.slice(6)
pkgJson.browser[`./esm/${path}`] = maybeFixPath(pkgJson.browser[key], './esm/')
if (buildConfig.buildCjs) {
pkgJson.browser[`./cjs/${path}`] = maybeFixPath(pkgJson.browser[key], './cjs/')
}
delete pkgJson.browser[key]
}
}
fs.writeFileSync(path.join(packageDir, 'dist/package.json'), JSON.stringify(pkgJson, null, 2))
}

View file

@ -16,7 +16,13 @@
"incremental": true,
"stripInternal": true,
"skipLibCheck": true,
"composite": true
"composite": true,
"types": [
"node",
"vite/client"
],
"resolveJsonModule": true,
"isolatedModules": true,
},
"ts-node": {
"esm": true,