From a36cdf1d204397297d21d33d37f7889970502668 Mon Sep 17 00:00:00 2001 From: Alina Sireneva Date: Wed, 29 Nov 2023 20:31:18 +0300 Subject: [PATCH] test: run tests in browser --- .config/vite.browser.mts | 50 ++ .config/vite.mts | 3 + .github/actions/init/action.yml | 20 + .github/workflows/docs.yaml | 15 +- .github/workflows/release.yaml | 12 +- .github/workflows/test.yaml | 52 +- e2e/ts/utils.ts | 2 +- package.json | 13 +- packages/client/package.json | 6 +- packages/client/scripts/generate-client.cjs | 2 +- packages/client/src/client.ts | 2 +- .../src/types/peers/chat-event/index.ts | 2 +- packages/client/src/types/updates/index.ts | 4 +- .../client/src/utils/stream-utils.test.ts | 38 +- packages/core/package.json | 15 +- packages/core/src/network/index.ts | 2 +- .../network/transports/intermediate.test.ts | 6 +- .../core/src/network/transports/tcp.test.ts | 271 +++++----- packages/core/src/storage/json.test.ts | 7 +- .../core/src/utils/crypto/mtproto.test.ts | 87 ++-- packages/core/src/utils/crypto/node.test.ts | 18 +- packages/core/src/utils/crypto/utils.test.ts | 8 +- packages/core/src/utils/logger.test.ts | 18 +- .../tests/node-native-crypto.test.ts | 13 +- packages/dispatcher/src/context/index.ts | 2 +- packages/dispatcher/src/filters/index.ts | 3 +- packages/sqlite/test/sqlite.test.ts | 80 +-- packages/test/src/client.test.ts | 5 +- packages/test/src/crypto.ts | 36 +- packages/test/src/schema.ts | 8 +- packages/tl-runtime/package.json | 9 +- .../tl-runtime/src/encodings/base64.test.ts | 39 +- packages/tl-runtime/src/encodings/hex.test.ts | 27 +- .../tl-runtime/src/encodings/utf8.test.ts | 37 +- packages/tl-runtime/src/reader.test.ts | 20 +- packages/tl-runtime/src/writer.test.ts | 25 +- packages/wasm/build.config.cjs | 2 + packages/wasm/package.json | 6 +- packages/wasm/src/init.web.ts | 2 +- packages/wasm/tests/ctr.test.ts | 77 ++- packages/wasm/tests/gunzip.test.ts | 24 +- packages/wasm/tests/hash.test.ts | 17 +- packages/wasm/tests/ige.test.ts | 14 +- packages/wasm/tests/zlib.test.ts | 28 +- pnpm-lock.yaml | 482 ++++++++++++++++-- scripts/build-package.js | 25 + tsconfig.json | 8 +- 47 files changed, 1073 insertions(+), 569 deletions(-) create mode 100644 .config/vite.browser.mts create mode 100644 .github/actions/init/action.yml diff --git a/.config/vite.browser.mts b/.config/vite.browser.mts new file mode 100644 index 00000000..4b5b0d90 --- /dev/null +++ b/.config/vite.browser.mts @@ -0,0 +1,50 @@ +/// +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"' + } +})) diff --git a/.config/vite.mts b/.config/vite.mts index d533ada6..aa150bb8 100644 --- a/.config/vite.mts +++ b/.config/vite.mts @@ -12,4 +12,7 @@ export default defineConfig({ ], }, }, + define: { + 'import.meta.env.TEST_ENV': '"node"' + } }) diff --git a/.github/actions/init/action.yml b/.github/actions/init/action.yml new file mode 100644 index 00000000..ec461fea --- /dev/null +++ b/.github/actions/init/action.yml @@ -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 \ No newline at end of file diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index b3717582..e40670e6 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -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 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a7d3cf74..5b0746a6 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -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" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 868d094d..d969a9d8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -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 diff --git a/e2e/ts/utils.ts b/e2e/ts/utils.ts index 7e14ca6c..f747f8be 100644 --- a/e2e/ts/utils.ts +++ b/e2e/ts/utils.ts @@ -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) { diff --git a/package.json b/package.json index 2d3caaaa..af2fba8f 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/client/package.json b/packages/client/package.json index e3fb81d8..f8215ecf 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -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:^", diff --git a/packages/client/scripts/generate-client.cjs b/packages/client/scripts/generate-client.cjs index d6cee0f2..e4bf48b7 100644 --- a/packages/client/scripts/generate-client.cjs +++ b/packages/client/scripts/generate-client.cjs @@ -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`)) diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index 702022df..a8ef31c0 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -5075,7 +5075,7 @@ export interface TelegramClient extends BaseTelegramClient { }): Promise } -export { TelegramClientOptions } +export type { TelegramClientOptions } export class TelegramClient extends BaseTelegramClient { constructor(opts: TelegramClientOptions) { diff --git a/packages/client/src/types/peers/chat-event/index.ts b/packages/client/src/types/peers/chat-event/index.ts index 1875fde3..35e53a7b 100644 --- a/packages/client/src/types/peers/chat-event/index.ts +++ b/packages/client/src/types/peers/chat-event/index.ts @@ -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( diff --git a/packages/client/src/types/updates/index.ts b/packages/client/src/types/updates/index.ts index c6f26a89..c5c52172 100644 --- a/packages/client/src/types/updates/index.ts +++ b/packages/client/src/types/updates/index.ts @@ -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, diff --git a/packages/client/src/utils/stream-utils.test.ts b/packages/client/src/utils/stream-utils.test.ts index 2098d644..e07aebc8 100644 --- a/packages/client/src/utils/stream-utils.test.ts +++ b/packages/client/src/utils/stream-utils.test.ts @@ -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 }) }) -}) +} diff --git a/packages/core/package.json b/packages/core/package.json index 078ea846..eb1924d1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -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": { diff --git a/packages/core/src/network/index.ts b/packages/core/src/network/index.ts index 4973595f..7057a4f0 100644 --- a/packages/core/src/network/index.ts +++ b/packages/core/src/network/index.ts @@ -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' diff --git a/packages/core/src/network/transports/intermediate.test.ts b/packages/core/src/network/transports/intermediate.test.ts index 52670516..3f8f3de4 100644 --- a/packages/core/src/network/transports/intermediate.test.ts +++ b/packages/core/src/network/transports/intermediate.test.ts @@ -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') }) }) diff --git a/packages/core/src/network/transports/tcp.test.ts b/packages/core/src/network/transports/tcp.test.ts index ceb546a7..1ef0b80d 100644 --- a/packages/core/src/network/transports/tcp.test.ts +++ b/packages/core/src/network/transports/tcp.test.ts @@ -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 - } + // 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 + } - 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', () => {}) +} diff --git a/packages/core/src/storage/json.test.ts b/packages/core/src/storage/json.test.ts index 4aa14c97..0be416af 100644 --- a/packages/core/src/storage/json.test.ts +++ b/packages/core/src/storage/json.test.ts @@ -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 }]) diff --git a/packages/core/src/utils/crypto/mtproto.test.ts b/packages/core/src/utils/crypto/mtproto.test.ts index 667fcff3..d64b5cf4 100644 --- a/packages/core/src/utils/crypto/mtproto.test.ts +++ b/packages/core/src/utils/crypto/mtproto.test.ts @@ -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'), ]) }) }) diff --git a/packages/core/src/utils/crypto/node.test.ts b/packages/core/src/utils/crypto/node.test.ts index 549ae186..13fdc573 100644 --- a/packages/core/src/utils/crypto/node.test.ts +++ b/packages/core/src/utils/crypto/node.test.ts @@ -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', () => {}) +} diff --git a/packages/core/src/utils/crypto/utils.test.ts b/packages/core/src/utils/crypto/utils.test.ts index cd4faed4..e457dacf 100644 --- a/packages/core/src/utils/crypto/utils.test.ts +++ b/packages/core/src/utils/crypto/utils.test.ts @@ -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') }) }) diff --git a/packages/core/src/utils/logger.test.ts b/packages/core/src/utils/logger.test.ts index c1a4813e..50bebc91 100644 --- a/packages/core/src/utils/logger.test.ts +++ b/packages/core/src/utils/logger.test.ts @@ -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() diff --git a/packages/crypto-node/tests/node-native-crypto.test.ts b/packages/crypto-node/tests/node-native-crypto.test.ts index 336534f5..435a03bb 100644 --- a/packages/crypto-node/tests/node-native-crypto.test.ts +++ b/packages/crypto-node/tests/node-native-crypto.test.ts @@ -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', () => {}) +} diff --git a/packages/dispatcher/src/context/index.ts b/packages/dispatcher/src/context/index.ts index 27c36013..aeafdf77 100644 --- a/packages/dispatcher/src/context/index.ts +++ b/packages/dispatcher/src/context/index.ts @@ -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' diff --git a/packages/dispatcher/src/filters/index.ts b/packages/dispatcher/src/filters/index.ts index 73c8a129..3cb8bb92 100644 --- a/packages/dispatcher/src/filters/index.ts +++ b/packages/dispatcher/src/filters/index.ts @@ -1,3 +1,4 @@ import * as filters from './bundle.js' import UpdateFilter = filters.UpdateFilter -export { filters, UpdateFilter } +export { filters } +export type { UpdateFilter } diff --git a/packages/sqlite/test/sqlite.test.ts b/packages/sqlite/test/sqlite.test.ts index 5c79ea8a..6dedb356 100644 --- a/packages/sqlite/test/sqlite.test.ts +++ b/packages/sqlite/test/sqlite.test.ts @@ -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', () => {}) +} diff --git a/packages/test/src/client.test.ts b/packages/test/src/client.test.ts index aa5ca6ce..3fab4667 100644 --- a/packages/test/src/client.test.ts +++ b/packages/test/src/client.test.ts @@ -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(() => {}) }) diff --git a/packages/test/src/crypto.ts b/packages/test/src/crypto.ts index 104d7efe..cd68b8b0 100644 --- a/packages/test/src/crypto.ts +++ b/packages/test/src/crypto.ts @@ -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) } diff --git a/packages/test/src/schema.ts b/packages/test/src/schema.ts index 3889f5c9..61f17567 100644 --- a/packages/test/src/schema.ts +++ b/packages/test/src/schema.ts @@ -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() diff --git a/packages/tl-runtime/package.json b/packages/tl-runtime/package.json index 3a5d6a72..9144dbcf 100644 --- a/packages/tl-runtime/package.json +++ b/packages/tl-runtime/package.json @@ -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": { diff --git a/packages/tl-runtime/src/encodings/base64.test.ts b/packages/tl-runtime/src/encodings/base64.test.ts index 83333ea4..1441e5c7 100644 --- a/packages/tl-runtime/src/encodings/base64.test.ts +++ b/packages/tl-runtime/src/encodings/base64.test.ts @@ -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') - }) -}) diff --git a/packages/tl-runtime/src/encodings/hex.test.ts b/packages/tl-runtime/src/encodings/hex.test.ts index 7e106c8a..3eb8185a 100644 --- a/packages/tl-runtime/src/encodings/hex.test.ts +++ b/packages/tl-runtime/src/encodings/hex.test.ts @@ -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') - }) -}) diff --git a/packages/tl-runtime/src/encodings/utf8.test.ts b/packages/tl-runtime/src/encodings/utf8.test.ts index 6d9c4526..fcc9e0c0 100644 --- a/packages/tl-runtime/src/encodings/utf8.test.ts +++ b/packages/tl-runtime/src/encodings/utf8.test.ts @@ -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) - }) }) diff --git a/packages/tl-runtime/src/reader.test.ts b/packages/tl-runtime/src/reader.test.ts index f919f78b..becbaca0 100644 --- a/packages/tl-runtime/src/reader.test.ts +++ b/packages/tl-runtime/src/reader.test.ts @@ -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]) diff --git a/packages/tl-runtime/src/writer.test.ts b/packages/tl-runtime/src/writer.test.ts index 9dac7788..ee7a78e8 100644 --- a/packages/tl-runtime/src/writer.test.ts +++ b/packages/tl-runtime/src/writer.test.ts @@ -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 = { diff --git a/packages/wasm/build.config.cjs b/packages/wasm/build.config.cjs index a8c383ce..163724d9 100644 --- a/packages/wasm/build.config.cjs +++ b/packages/wasm/build.config.cjs @@ -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')) }, diff --git a/packages/wasm/package.json b/packages/wasm/package.json index a19ee81a..16b171d7 100644 --- a/packages/wasm/package.json +++ b/packages/wasm/package.json @@ -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:^" } } diff --git a/packages/wasm/src/init.web.ts b/packages/wasm/src/init.web.ts index 51f09013..6e0cc1e1 100644 --- a/packages/wasm/src/init.web.ts +++ b/packages/wasm/src/init.web.ts @@ -2,7 +2,7 @@ import { InitInput } from './types.js' export async function loadWasmBinary(input?: InitInput): Promise { if (typeof input === 'undefined') { - input = new URL('../mtcute.wasm', import.meta.url) + input = new URL('../lib/mtcute.wasm', import.meta.url) } if ( diff --git a/packages/wasm/tests/ctr.test.ts b/packages/wasm/tests/ctr.test.ts index c302617c..ebe38127 100644 --- a/packages/wasm/tests/ctr.test.ts +++ b/packages/wasm/tests/ctr.test.ts @@ -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 diff --git a/packages/wasm/tests/gunzip.test.ts b/packages/wasm/tests/gunzip.test.ts index ee3d3c0d..9a004a6c 100644 --- a/packages/wasm/tests/gunzip.test.ts +++ b/packages/wasm/tests/gunzip.test.ts @@ -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) diff --git a/packages/wasm/tests/hash.test.ts b/packages/wasm/tests/hash.test.ts index bb6d6779..2f85f1bb 100644 --- a/packages/wasm/tests/hash.test.ts +++ b/packages/wasm/tests/hash.test.ts @@ -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) diff --git a/packages/wasm/tests/ige.test.ts b/packages/wasm/tests/ige.test.ts index 121020c0..1edca67e 100644 --- a/packages/wasm/tests/ige.test.ts +++ b/packages/wasm/tests/ige.test.ts @@ -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', () => { diff --git a/packages/wasm/tests/zlib.test.ts b/packages/wasm/tests/zlib.test.ts index 03488807..4f67a514 100644 --- a/packages/wasm/tests/zlib.test.ts +++ b/packages/wasm/tests/zlib.test.ts @@ -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) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e7b075d..28babacf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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 diff --git a/scripts/build-package.js b/scripts/build-package.js index 4909afeb..9976e5cb 100644 --- a/scripts/build-package.js +++ b/scripts/build-package.js @@ -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)) } diff --git a/tsconfig.json b/tsconfig.json index 46f8f0a1..2b6ef48e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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,