chore!: removed crypto-node

This commit is contained in:
alina sireneva
2025-02-09 16:03:14 +03:00
parent dc743d2b66
commit 3c065ea78e
26 changed files with 84 additions and 915 deletions

View File

@@ -21,7 +21,6 @@ export default mergeConfig(baseConfig, {
fileParallelism: false, // leads to ERR_INSUFFICIENT_RESOURCES
// 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/**',
// ],
},

View File

@@ -16,7 +16,7 @@ export default defineConfig({
: collectTestEntrypoints({
// https://github.com/oven-sh/bun/issues/4145 prevents us from using vitest directly
// so we have to use bun's native test runner
skipPackages: ['create-bot', 'crypto-node'],
skipPackages: ['create-bot'],
// bun:test doesn't support certain features of vitest, so we'll skip them for now
// https://github.com/oven-sh/bun/issues/1825
skipTests: [

View File

@@ -15,7 +15,7 @@ export default defineConfig({
? [process.env.ENTRYPOINT]
: collectTestEntrypoints({
// these packages rely on node apis and are not meant to be run under deno
skipPackages: ['create-bot', 'crypto-node', 'bun', 'node'],
skipPackages: ['create-bot', 'bun', 'node'],
skipTests: [
// uses timers
'core/src/network/config-manager.test.ts',

View File

@@ -1,50 +0,0 @@
# this workflow is invoked from @mtcute/crypto-node build config to generate prebuilt binaries
name: Generate prebuilt @mtcute/crypto-node
on:
workflow_dispatch:
inputs:
commit:
description: 'Commit to build'
required: true
default: 'HEAD'
hash:
description: 'Hash of the input files'
required: true
default: ''
jobs:
build:
strategy:
matrix:
platform:
- ubuntu-20.04
- macos-13
- macos-14
- windows-2022
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit }}
- uses: actions/setup-node@v3
with:
node-version: 18.x
- if: ${{ startsWith(matrix.platform, 'windows') }}
run: pip.exe install setuptools
- if: ${{ !startsWith(matrix.platform, 'windows') && !startsWith(matrix.platform, 'macos') }}
run: python3 -m pip install setuptools
- if: ${{ startsWith(matrix.platform, 'macos') }}
run: python3 -m pip install --break-system-packages setuptools
- name: 'Build'
run: npx -y prebuildify@6.0.1 --napi --strip
working-directory: packages/crypto-node
- if: ${{ !startsWith(matrix.platform, 'macos') }}
name: 'Build (arm64)'
run: npx -y prebuildify@6.0.1 --napi --strip --arch arm64
working-directory: packages/crypto-node
- name: 'Upload'
uses: actions/upload-artifact@v4
with:
name: prebuilt-${{ matrix.platform }}-${{ inputs.hash }}
path: packages/crypto-node/prebuilds

View File

@@ -55,8 +55,6 @@ pnpm create @mtcute/bot
🏭 want to integrate it into your existing nodejs app? use the nodejs package:
```bash
pnpm add @mtcute/node
# optional, for faster crypto
pnpm add @mtcute/crypto-node
```
✨ building something for web? use the web package:

View File

@@ -44,20 +44,6 @@ await tg.sendText('self', html`Hello from <b>MTCute</b>!`)
```
4. That's literally it! Happy hacking 🚀
### Native crypto addon
mtcute also provides `@mtcute/crypto-node` package, that implements
a native Node.js addon for crypto functions used in MTProto.
Using this addon improves overall library performance (especially when uploading/downloading files),
so it is advised that you install it as well:
```bash
pnpm add @mtcute/crypto-node
```
When using `@mtcute/node`, native addon is loaded automatically,
no extra steps are required.
## Bun
Support for Bun is provided in `@mtcute/bun` package, and

View File

@@ -48,7 +48,7 @@
"@fuman/utils": "0.0.4",
"@types/bun": "1.1.14",
"@types/deno": "npm:@teidesu/deno-types@1.46.3",
"@types/node": "20.10.0",
"@types/node": "22.13.1",
"@types/ws": "8.5.4",
"@vitest/browser": "2.0.5",
"@vitest/coverage-v8": "2.0.5",

View File

@@ -1,3 +0,0 @@
.vs
build
prebuilds

View File

@@ -1,32 +0,0 @@
# @mtcute/crypto-node
📖 [API Reference](https://ref.mtcute.dev/modules/_mtcute_crypto_node.html)
Native extension for NodeJS that improves performance of the most used
cryptographic mode in Telegram (IGE), which is not implemented directly by OpenSSL.
Uses OpenSSL under the hood to provide maximum performance
## Installation
You will need all the pre-requisites for [node-gyp](https://github.com/nodejs/node-gyp#installation).
Pre-built packages are currently not available.
Then, install the package as usual. The native library will be built automatically.
## Usage
```typescript
import { TelegramClient } from '@mtcute/core'
import { NodeNativeCryptoProvider } from '@mtcute/crypto-node'
const tg = new TelegramClient({
...,
crypto: () => new NodeNativeCryptoProvider()
})
```
> **Tip**: When using `@mtcute/node`, this will be done automatically for you.
## Benchmarks
See https://github.com/mtcute/benchmarks

View File

@@ -1,18 +0,0 @@
{
"targets": [
{
"target_name": "crypto",
"sources": [
"lib/entry.cpp",
"lib/ige256.cpp",
],
"cflags_cc": [
"-std=c++17"
],
"defines": [
"OPENSSL_API_COMPAT=0x10100001L",
"OPENSSL_CONFIGURED_API=0x30000000L",
]
}
]
}

View File

@@ -1,205 +0,0 @@
/* eslint-disable no-restricted-globals */
import { spawn } from 'node:child_process'
import { createHash } from 'node:crypto'
import * as fs from 'node:fs'
import path from 'node:path'
import { Readable } from 'node:stream'
import { fileURLToPath } from 'node:url'
import * as glob from 'glob'
import { getCurrentBranch, getCurrentCommit } from '../../scripts/git-utils.js'
const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url)))
const GITHUB_TOKEN = process.env.GITHUB_TOKEN
let SKIP_PREBUILT = process.env.BUILD_FOR_DOCS === '1'
if (!GITHUB_TOKEN && !SKIP_PREBUILT) {
console.warn('GITHUB_TOKEN is required to publish crypto-node, skipping prebuilt artifacts')
SKIP_PREBUILT = true
}
const GITHUB_HEADERS = {
'Authorization': `Bearer ${GITHUB_TOKEN}`,
'Content-Type': 'application/json',
'X-GitHub-Api-Version': '2022-11-28',
}
const API_PREFIX = 'https://api.github.com/repos/mtcute/mtcute/actions/workflows/node-prebuilt.yaml'
const PLATFORMS = ['ubuntu', 'macos', 'windows']
async function findArtifactsByHash(hash) {
const runs = await fetch(`${API_PREFIX}/runs?per_page=100`, { headers: GITHUB_HEADERS }).then(r => r.json())
for (const run of runs.workflow_runs) {
if (run.conclusion !== 'success' || run.status !== 'completed') continue
const artifacts = await fetch(`${run.url}/artifacts`, { headers: GITHUB_HEADERS })
.then(r => r.json())
.then(r => r.artifacts)
for (const it of artifacts) {
if (it.expired) continue
const parts = it.name.split('-')
if (parts[0] === 'prebuilt'
&& PLATFORMS.includes(parts[1])
&& parts[3] === hash) {
return artifacts
}
}
}
return null
}
async function runWorkflow(commit, hash) {
const createRes = await fetch(`${API_PREFIX}/dispatches`, {
method: 'POST',
headers: GITHUB_HEADERS,
body: JSON.stringify({
ref: getCurrentBranch(),
inputs: { commit, hash },
}),
})
if (createRes.status !== 204) {
const text = await createRes.text()
throw new Error(`Failed to run workflow: ${createRes.status} ${text}`)
}
// wait for the workflow to finish
// github api is awesome and doesn't return the run id, so let's just assume it's the last one
await new Promise(resolve => setTimeout(resolve, 5000))
const runsRes = await fetch(`${API_PREFIX}/runs`, {
headers: GITHUB_HEADERS,
}).then(r => r.json())
let run = runsRes.workflow_runs[0]
while (run.status === 'queued' || run.status === 'in_progress') {
await new Promise(resolve => setTimeout(resolve, 5000))
run = await fetch(run.url, { headers: GITHUB_HEADERS }).then(r => r.json())
}
if (run.status !== 'completed') {
throw new Error(`Workflow ${run.id} failed: ${run.status}`)
}
if (run.conclusion !== 'success') {
throw new Error(`Workflow ${run.id} failed: ${run.conclusion}`)
}
// fetch artifacts
const artifacts = await fetch(`${run.url}/artifacts`, { headers: GITHUB_HEADERS })
.then(r => r.json())
.then(r => r.artifacts)
// validate their names
for (const it of artifacts) {
const parts = it.name.split('-')
if (parts[0] !== 'prebuilt'
|| !PLATFORMS.includes(parts[1])
|| parts[3] !== hash) {
throw new Error(`Invalid artifact name: ${it.name}`)
}
}
return artifacts
}
async function extractArtifacts(artifacts) {
fs.mkdirSync(path.join(__dirname, 'dist/prebuilds'), { recursive: true })
await Promise.all(
artifacts.map(async (it) => {
const platform = it.name.split('-').slice(1, 3).join('-')
const res = await fetch(it.archive_download_url, {
headers: GITHUB_HEADERS,
redirect: 'manual',
})
if (res.status !== 302) {
const text = await res.text()
throw new Error(`Failed to download artifact ${it.name}: ${res.status} ${text}`)
}
const zip = await fetch(res.headers.get('location'))
const outFile = path.join(__dirname, 'dist/prebuilds', `${platform}.zip`)
const stream = fs.createWriteStream(outFile)
await new Promise((resolve, reject) => {
stream.on('finish', resolve)
stream.on('error', reject)
Readable.fromWeb(zip.body).pipe(stream)
})
// extract the zip
await new Promise((resolve, reject) => {
const child = spawn('unzip', [outFile, '-d', path.join(__dirname, 'dist/prebuilds')], {
stdio: 'inherit',
})
child.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Failed to extract ${outFile}: ${code}`))
} else {
resolve()
}
})
})
fs.unlinkSync(outFile)
}),
)
}
/** @type {import('@fuman/build/vite').CustomBuildConfig} */
export default () => ({
async finalize({ packageDir, outDir }) {
const libDir = path.resolve(packageDir, 'lib')
if (!SKIP_PREBUILT) {
// generate sources hash
const hashes = []
for (const file of glob.sync(path.join(libDir, '**/*'))) {
const hash = createHash('sha256')
hash.update(fs.readFileSync(file))
hashes.push(hash.digest('hex'))
}
const hash = createHash('sha256')
.update(hashes.join('\n'))
.digest('hex')
console.log(hash)
console.log('[i] Checking for prebuilt artifacts for %s', hash)
let artifacts = await findArtifactsByHash(hash)
if (!artifacts) {
console.log('[i] No artifacts found, running workflow')
artifacts = await runWorkflow(getCurrentCommit(), hash)
}
console.log('[i] Extracting artifacts')
await extractArtifacts(artifacts)
}
// copy native sources and binding.gyp file
fs.cpSync(libDir, path.join(outDir, 'lib'), { recursive: true })
const bindingGyp = fs.readFileSync(path.join(packageDir, 'binding.gyp'), 'utf8')
fs.writeFileSync(
path.join(outDir, 'binding.gyp'),
bindingGyp
// replace paths to crypto
.replace(/"\.\.\/crypto/g, '"crypto'),
)
// for some unknown fucking reason ts doesn't do this
fs.copyFileSync(path.join(packageDir, 'src/native.cjs'), path.join(outDir, 'native.cjs'))
},
})

View File

@@ -1,110 +0,0 @@
#include <assert.h>
#define NAPI_VERSION 1
#include <node_api.h>
#include "ige256.h"
#ifndef NODE_GYP_MODULE_NAME
#define NODE_GYP_MODULE_NAME crypto
#endif
// maybe i love macros a bit too much
#define CALL_ASSERT_OK(code) \
status = code; \
assert(status == napi_ok);
#define THROW_WRONG_ARGS \
napi_throw_type_error(env, NULL, "Wrong arguments"); \
return NULL;
#define CHECK_ARG_COUNT(cnt) \
if (argc < cnt) { \
THROW_WRONG_ARGS \
}
#define CHECK_ARG_BUFFER(idx) \
CALL_ASSERT_OK(napi_is_buffer(env, args[idx], &is_buf)) \
if (!is_buf) { \
THROW_WRONG_ARGS \
}
#define READ_BUF_ARG(idx, out_buf, out_size) \
CALL_ASSERT_OK(napi_get_buffer_info(env, args[idx], (void**) out_buf, out_size))
#define READ_BOOL_ARG(idx, out) \
CALL_ASSERT_OK(napi_get_value_bool(env, args[idx], out))
#define READ_ARGS(n) \
size_t argc = n; \
napi_value args[n]; \
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL); \
assert(status == napi_ok);
#define WRAP_KEY_IV_METHOD(name, ivSize) \
static napi_value node_##name(napi_env env, napi_callback_info info) { \
napi_status status; \
bool is_buf; \
\
uint8_t* input_buf; \
uint8_t* key_buf; \
uint8_t* iv_buf; \
uint8_t* output_buf; \
\
size_t size; \
\
READ_ARGS(3) \
\
CHECK_ARG_COUNT(3) \
CHECK_ARG_BUFFER(0) \
CHECK_ARG_BUFFER(1) \
CHECK_ARG_BUFFER(2) \
\
READ_BUF_ARG(1, &key_buf, &size); \
if (size != 32) { \
THROW_WRONG_ARGS \
} \
READ_BUF_ARG(2, &iv_buf, &size); \
if (size != ivSize) { \
THROW_WRONG_ARGS \
} \
READ_BUF_ARG(0, &input_buf, &size); \
if (size % 16 != 0) { \
THROW_WRONG_ARGS \
} \
\
napi_value ret; \
CALL_ASSERT_OK(napi_create_buffer(env, size, (void**) &output_buf, &ret)); \
\
name(env, input_buf, size, key_buf, iv_buf, output_buf); \
\
return ret; \
}
WRAP_KEY_IV_METHOD(ige256_encrypt, 32)
WRAP_KEY_IV_METHOD(ige256_decrypt, 32)
#define DECLARE_NAPI_METHOD(name, func) \
{ name, 0, func, 0, 0, 0, napi_default, 0 }
#define EXPORT_METHOD(name, func) \
desc = DECLARE_NAPI_METHOD(name, func); \
CALL_ASSERT_OK(napi_define_properties(env, exports, 1, &desc));
static napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_property_descriptor desc;
// nodejs is bundled with openssl, thus the only
// mode that it makes sense to implement in native code is
// IGE, since it is not implemented by openssl.
//
// benchmarks have shown that openssl is much faster
// than this implementation for cbc and ctr modes.
EXPORT_METHOD("ige256_encrypt", node_ige256_encrypt)
EXPORT_METHOD("ige256_decrypt", node_ige256_decrypt)
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

View File

@@ -1,92 +0,0 @@
#include <node_api.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include "ige256.h"
#define THROW_OPENSSL_ERROR \
napi_throw_error(env, NULL, ERR_error_string(ERR_get_error(), NULL)); \
return;
void ige256_encrypt(napi_env env, uint8_t* in, uint32_t length, uint8_t* key, uint8_t* iv, uint8_t* out) {
EVP_CIPHER_CTX *ctx;
uint32_t i, j;
uint8_t* iv1;
uint8_t* iv2;
uint8_t* block;
int written;
iv1 = &iv[0];
iv2 = &iv[16];
if (!(ctx = EVP_CIPHER_CTX_new())) {
THROW_OPENSSL_ERROR
}
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, NULL)) {
THROW_OPENSSL_ERROR
}
for (i = 0; i < length; i += AES_BLOCK_SIZE) {
block = &out[i];
for (j = 0; j < AES_BLOCK_SIZE; ++j)
block[j] = in[i + j] ^ iv1[j];
if (1 != EVP_EncryptUpdate(ctx, block, &written, block, AES_BLOCK_SIZE)) {
THROW_OPENSSL_ERROR
}
for (j = 0; j < AES_BLOCK_SIZE; ++j)
block[j] ^= iv2[j];
iv1 = block;
iv2 = &in[i];
}
EVP_CIPHER_CTX_free(ctx);
}
void ige256_decrypt(napi_env env, uint8_t* in, uint32_t length, uint8_t* key, uint8_t* iv, uint8_t* out) {
EVP_CIPHER_CTX *ctx;
uint32_t i, j;
uint8_t* iv1;
uint8_t* iv2;
uint8_t* block;
int written;
iv1 = &iv[16];
iv2 = &iv[0];
if (!(ctx = EVP_CIPHER_CTX_new())) {
THROW_OPENSSL_ERROR
}
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, NULL)) {
THROW_OPENSSL_ERROR
}
if (1 != EVP_CIPHER_CTX_set_padding(ctx, 0)) {
THROW_OPENSSL_ERROR
}
for (i = 0; i < length; i += AES_BLOCK_SIZE) {
block = &out[i];
for (j = 0; j < AES_BLOCK_SIZE; ++j)
block[j] = in[i + j] ^ iv1[j];
if (1 != EVP_DecryptUpdate(ctx, block, &written, block, AES_BLOCK_SIZE)) {
THROW_OPENSSL_ERROR
}
for (j = 0; j < AES_BLOCK_SIZE; ++j)
block[j] ^= iv2[j];
iv1 = block;
iv2 = &in[i];
}
}

View File

@@ -1,12 +0,0 @@
#include <stdint.h>
#include <node_api.h>
#ifndef IGE256_H
#define IGE256_H
#define AES_BLOCK_SIZE 16
void ige256_encrypt(napi_env env, uint8_t* in, uint32_t length, uint8_t* key, uint8_t* iv, uint8_t* out);
void ige256_decrypt(napi_env env, uint8_t* in, uint32_t length, uint8_t* key, uint8_t* iv, uint8_t* out);
#endif // IGE256_H

View File

@@ -1,32 +0,0 @@
{
"name": "@mtcute/crypto-node",
"type": "module",
"version": "0.19.0",
"private": true,
"description": "Native crypto implementation for NodeJS",
"author": "alina sireneva <alina@tei.su>",
"license": "MIT",
"sideEffects": false,
"exports": {
".": "./src/index.ts",
"./native.js": "./src/native.cjs"
},
"scripts": {
"install": "node-gyp-build",
"rebuild": "node-gyp configure && node-gyp -j 16 rebuild",
"clean": "node-gyp clean"
},
"dependencies": {
"@mtcute/node": "workspace:^",
"node-gyp-build": "4.8.1"
},
"devDependencies": {
"@mtcute/test": "workspace:^"
},
"fuman": {
"jsr": "skip",
"keepScripts": [
"install"
]
}
}

View File

@@ -1,26 +0,0 @@
import type { IEncryptionScheme } from '@mtcute/node/utils.js'
import { BaseNodeCryptoProvider } from '@mtcute/node/utils.js'
import { native } from './native.cjs'
const { ige256_decrypt, ige256_encrypt } = native
/**
* Crypto provider for NodeJS that uses a native extension to improve
* performance of the IGE mode.
*
* Other modes are supported natively by OpenSSL, and
* they *are* faster than the custom ones.
*/
export class NodeNativeCryptoProvider extends BaseNodeCryptoProvider {
createAesIge(key: Uint8Array, iv: Uint8Array): IEncryptionScheme {
return {
encrypt(data: Uint8Array): Uint8Array {
return ige256_encrypt(data, key, iv)
},
decrypt(data: Uint8Array): Uint8Array {
return ige256_decrypt(data, key, iv)
},
}
}
}

View File

@@ -1,4 +0,0 @@
// eslint-disable-next-line node/no-path-concat
const native = require('node-gyp-build')(`${__dirname}/..`)
module.exports = { native }

View File

@@ -1,4 +0,0 @@
export const native: {
ige256_encrypt: (data: Uint8Array, key: Uint8Array, iv: Uint8Array) => Uint8Array
ige256_decrypt: (data: Uint8Array, key: Uint8Array, iv: Uint8Array) => Uint8Array
}

View File

@@ -1,12 +0,0 @@
import { testCryptoProvider } from '@mtcute/test'
import { describe } from 'vitest'
if (import.meta.env.TEST_ENV === 'node' || import.meta.env.TEST_ENV === 'bun') {
describe('NodeNativeCryptoProvider', async () => {
const { NodeNativeCryptoProvider } = await import('../src/index.js')
testCryptoProvider(new NodeNativeCryptoProvider())
})
} else {
describe.skip('NodeNativeCryptoProvider', () => {})
}

View File

@@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"references": [
{ "path": "../" }
],
"include": [
"."
]
}

View File

@@ -1,6 +0,0 @@
{
"extends": "../../tsconfig.json",
"include": [
"./src"
]
}

View File

@@ -3,7 +3,6 @@
📖 [API Reference](https://ref.mtcute.dev/modules/_mtcute_node.html)
Node.js support package for mtcute. Includes:
- Support for native crypto addon (must be installed separately, `@mtcute/crypto-node`)
- Terminal I/O via `readline`
- SQLite storage (via `better-sqlite3`)
- TCP transport (via `node:net`)

View File

@@ -1,55 +1,11 @@
import { fileURLToPath } from 'node:url'
/** @type {import('@fuman/build/vite').CustomBuildConfig} */
export default () => {
const clientId = fileURLToPath(new URL('./src/client.ts', import.meta.url))
return {
viteConfig: {
build: {
rollupOptions: {
external: ['@mtcute/crypto-node'],
},
},
},
pluginsPre: [
{
// very much a crutch, but it works
// i couldn't figure out a way to hook into the esm->cjs transform,
// so i'm just replacing the await import with require and then back
name: 'mtcute-node-build-plugin',
transform(code, id) {
if (id === clientId) {
return code.replace('await import(', 'require(')
}
return code
},
generateBundle(output, bundle) {
if (output.format !== 'es') return
let found = false
for (const chunk of Object.values(bundle)) {
if (chunk.code.match(/require\("@mtcute\/crypto-node"\)/)) {
found = true
chunk.code = chunk.code.replace('require("@mtcute/crypto-node")', '(await import("@mtcute/crypto-node"))')
}
}
if (!found) {
throw new Error('Could not find crypto-node import')
}
},
},
export default () => ({
typedoc: {
externalPattern: [
'../core/**',
'../html-parser/**',
'../markdown-parser/**',
'../sqlite/**',
],
typedoc: {
externalPattern: [
'../core/**',
'../html-parser/**',
'../markdown-parser/**',
'../sqlite/**',
],
},
}
}
},
})

View File

@@ -22,16 +22,6 @@ import { TcpTransport } from './utils/tcp.js'
export type { TelegramClientOptions }
let nativeCrypto: any
try {
/* eslint-disable ts/ban-ts-comment,ts/no-unsafe-assignment */
// @ts-ignore not in deps
nativeCrypto = (await import('@mtcute/crypto-node')).NodeNativeCryptoProvider
/* eslint-enable ts/ban-ts-comment,ts/no-unsafe-assignment */
} catch {}
export interface BaseTelegramClientOptions
extends PartialOnly<Omit<BaseTelegramClientOptionsBase, 'storage'>, 'transport' | 'crypto' | 'platform'> {
/**
@@ -49,8 +39,7 @@ export interface BaseTelegramClientOptions
export class BaseTelegramClient extends BaseTelegramClientBase {
constructor(opts: BaseTelegramClientOptions) {
super({
// eslint-disable-next-line
crypto: nativeCrypto ? new nativeCrypto() : new NodeCryptoProvider(),
crypto: new NodeCryptoProvider(),
transport: new TcpTransport(),
platform: new NodePlatform(),
...opts,

View File

@@ -1,4 +1,4 @@
import type { IAesCtr, ICryptoProvider, IEncryptionScheme } from '@mtcute/core/utils.js'
import type { IAesCtr, IEncryptionScheme } from '@mtcute/core/utils.js'
import { createCipheriv, createHash, createHmac, pbkdf2, randomFillSync } from 'node:crypto'
import { readFile } from 'node:fs/promises'
import { createRequire } from 'node:module'
@@ -7,7 +7,7 @@ import { deflateSync, gunzipSync } from 'node:zlib'
import { BaseCryptoProvider } from '@mtcute/core/utils.js'
import { ige256Decrypt, ige256Encrypt, initSync } from '@mtcute/wasm'
export abstract class BaseNodeCryptoProvider extends BaseCryptoProvider {
export class NodeCryptoProvider extends BaseCryptoProvider {
createAesCtr(key: Uint8Array, iv: Uint8Array): IAesCtr {
const cipher = createCipheriv(`aes-${key.length * 8}-ctr`, key, iv)
@@ -66,9 +66,7 @@ export abstract class BaseNodeCryptoProvider extends BaseCryptoProvider {
randomFill(buf: Uint8Array): void {
randomFillSync(buf)
}
}
export class NodeCryptoProvider extends BaseNodeCryptoProvider implements ICryptoProvider {
async initialize(): Promise<void> {
const require = createRequire(import.meta.url)
const wasmFile = require.resolve('@mtcute/wasm/mtcute.wasm')

279
pnpm-lock.yaml generated
View File

@@ -16,7 +16,7 @@ importers:
version: 3.11.2(@typescript-eslint/utils@8.17.0(eslint@9.9.0)(typescript@5.5.4))(@vue/compiler-sfc@3.5.13)(eslint@9.9.0)(typescript@5.5.4)(vitest@2.0.5)
'@fuman/build':
specifier: https://pkg.pr.new/teidesu/fuman/@fuman/build@0b7fee1
version: https://pkg.pr.new/teidesu/fuman/@fuman/build@0b7fee1(tough-cookie@4.1.4)(typedoc@0.27.6(typescript@5.5.4))(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0))
version: https://pkg.pr.new/teidesu/fuman/@fuman/build@0b7fee1(tough-cookie@4.1.4)(typedoc@0.27.6(typescript@5.5.4))(typescript@5.5.4)(vite@5.4.2(@types/node@22.13.1))
'@fuman/utils':
specifier: 0.0.4
version: 0.0.4
@@ -27,14 +27,14 @@ importers:
specifier: npm:@teidesu/deno-types@1.46.3
version: '@teidesu/deno-types@1.46.3'
'@types/node':
specifier: 20.10.0
version: 20.10.0
specifier: 22.13.1
version: 22.13.1
'@types/ws':
specifier: 8.5.4
version: 8.5.4
'@vitest/browser':
specifier: 2.0.5
version: 2.0.5(@types/node@20.10.0)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)
version: 2.0.5(@types/node@22.13.1)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)
'@vitest/coverage-v8':
specifier: 2.0.5
version: 2.0.5(vitest@2.0.5)
@@ -94,16 +94,16 @@ importers:
version: 5.5.4
vite:
specifier: 5.4.2
version: 5.4.2(@types/node@20.10.0)
version: 5.4.2(@types/node@22.13.1)
vite-plugin-dts:
specifier: 4.0.3
version: 4.0.3(@types/node@20.10.0)(rollup@4.27.2)(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0))
version: 4.0.3(@types/node@22.13.1)(rollup@4.27.2)(typescript@5.5.4)(vite@5.4.2(@types/node@22.13.1))
vite-plugin-node-polyfills:
specifier: 0.22.0
version: 0.22.0(rollup@4.27.2)(vite@5.4.2(@types/node@20.10.0))
version: 0.22.0(rollup@4.27.2)(vite@5.4.2(@types/node@22.13.1))
vitest:
specifier: 2.0.5
version: 2.0.5(@types/node@20.10.0)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
version: 2.0.5(@types/node@22.13.1)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
e2e:
dependencies:
@@ -260,19 +260,6 @@ importers:
specifier: ^1.0.3
version: 1.0.3
packages/crypto-node:
dependencies:
'@mtcute/node':
specifier: workspace:^
version: link:../node
node-gyp-build:
specifier: 4.8.1
version: 4.8.1
devDependencies:
'@mtcute/test':
specifier: workspace:^
version: link:../test
packages/deno:
dependencies:
'@db/sqlite':
@@ -424,7 +411,7 @@ importers:
version: 5.2.3
vitest:
specifier: '*'
version: 2.0.5(@types/node@20.12.14)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
version: 2.0.5(@types/node@22.13.1)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
devDependencies:
'@mtcute/tl-utils':
specifier: workspace:^
@@ -1561,6 +1548,9 @@ packages:
'@types/node@20.12.14':
resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==}
'@types/node@22.13.1':
resolution: {integrity: sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==}
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
@@ -3269,10 +3259,6 @@ packages:
resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==}
engines: {node: '>=10'}
node-gyp-build@4.8.1:
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
hasBin: true
node-releases@2.0.18:
resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
@@ -3974,6 +3960,9 @@ packages:
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
undici-types@6.20.0:
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
unist-util-is@6.0.0:
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
@@ -4623,7 +4612,7 @@ snapshots:
dependencies:
levn: 0.4.1
'@fuman/build@https://pkg.pr.new/teidesu/fuman/@fuman/build@0b7fee1(tough-cookie@4.1.4)(typedoc@0.27.6(typescript@5.5.4))(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0))':
'@fuman/build@https://pkg.pr.new/teidesu/fuman/@fuman/build@0b7fee1(tough-cookie@4.1.4)(typedoc@0.27.6(typescript@5.5.4))(typescript@5.5.4)(vite@5.4.2(@types/node@22.13.1))':
dependencies:
'@drizzle-team/brocli': 0.10.2
'@fuman/fetch': 0.0.10(tough-cookie@4.1.4)(zod@3.23.8)
@@ -4638,7 +4627,7 @@ snapshots:
semver: 7.6.3
tinyglobby: 0.2.10
typescript: 5.5.4
vite: 5.4.2(@types/node@20.10.0)
vite: 5.4.2(@types/node@22.13.1)
zod: 3.23.8
optionalDependencies:
typedoc: 0.27.6(typescript@5.5.4)
@@ -4714,23 +4703,16 @@ snapshots:
'@humanwhocodes/retry@0.3.1': {}
'@inquirer/confirm@5.0.2(@types/node@20.10.0)':
'@inquirer/confirm@5.0.2(@types/node@22.13.1)':
dependencies:
'@inquirer/core': 10.1.0(@types/node@20.10.0)
'@inquirer/type': 3.0.1(@types/node@20.10.0)
'@types/node': 20.10.0
'@inquirer/core': 10.1.0(@types/node@22.13.1)
'@inquirer/type': 3.0.1(@types/node@22.13.1)
'@types/node': 22.13.1
'@inquirer/confirm@5.0.2(@types/node@20.12.14)':
dependencies:
'@inquirer/core': 10.1.0(@types/node@20.12.14)
'@inquirer/type': 3.0.1(@types/node@20.12.14)
'@types/node': 20.12.14
optional: true
'@inquirer/core@10.1.0(@types/node@20.10.0)':
'@inquirer/core@10.1.0(@types/node@22.13.1)':
dependencies:
'@inquirer/figures': 1.0.8
'@inquirer/type': 3.0.1(@types/node@20.10.0)
'@inquirer/type': 3.0.1(@types/node@22.13.1)
ansi-escapes: 4.3.2
cli-width: 4.1.0
mute-stream: 2.0.0
@@ -4741,31 +4723,11 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
'@inquirer/core@10.1.0(@types/node@20.12.14)':
dependencies:
'@inquirer/figures': 1.0.8
'@inquirer/type': 3.0.1(@types/node@20.12.14)
ansi-escapes: 4.3.2
cli-width: 4.1.0
mute-stream: 2.0.0
signal-exit: 4.1.0
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.2
transitivePeerDependencies:
- '@types/node'
optional: true
'@inquirer/figures@1.0.8': {}
'@inquirer/type@3.0.1(@types/node@20.10.0)':
'@inquirer/type@3.0.1(@types/node@22.13.1)':
dependencies:
'@types/node': 20.10.0
'@inquirer/type@3.0.1(@types/node@20.12.14)':
dependencies:
'@types/node': 20.12.14
optional: true
'@types/node': 22.13.1
'@isaacs/cliui@8.0.2':
dependencies:
@@ -4867,23 +4829,23 @@ snapshots:
dependencies:
call-bind: 1.0.7
'@microsoft/api-extractor-model@7.29.4(@types/node@20.10.0)':
'@microsoft/api-extractor-model@7.29.4(@types/node@22.13.1)':
dependencies:
'@microsoft/tsdoc': 0.15.0
'@microsoft/tsdoc-config': 0.17.0
'@rushstack/node-core-library': 5.5.1(@types/node@20.10.0)
'@rushstack/node-core-library': 5.5.1(@types/node@22.13.1)
transitivePeerDependencies:
- '@types/node'
'@microsoft/api-extractor@7.47.4(@types/node@20.10.0)':
'@microsoft/api-extractor@7.47.4(@types/node@22.13.1)':
dependencies:
'@microsoft/api-extractor-model': 7.29.4(@types/node@20.10.0)
'@microsoft/api-extractor-model': 7.29.4(@types/node@22.13.1)
'@microsoft/tsdoc': 0.15.0
'@microsoft/tsdoc-config': 0.17.0
'@rushstack/node-core-library': 5.5.1(@types/node@20.10.0)
'@rushstack/node-core-library': 5.5.1(@types/node@22.13.1)
'@rushstack/rig-package': 0.5.3
'@rushstack/terminal': 0.13.3(@types/node@20.10.0)
'@rushstack/ts-command-line': 4.22.3(@types/node@20.10.0)
'@rushstack/terminal': 0.13.3(@types/node@22.13.1)
'@rushstack/ts-command-line': 4.22.3(@types/node@22.13.1)
lodash: 4.17.21
minimatch: 3.0.8
resolve: 1.22.8
@@ -5020,7 +4982,7 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.27.2':
optional: true
'@rushstack/node-core-library@5.5.1(@types/node@20.10.0)':
'@rushstack/node-core-library@5.5.1(@types/node@22.13.1)':
dependencies:
ajv: 8.13.0
ajv-draft-04: 1.0.0(ajv@8.13.0)
@@ -5031,23 +4993,23 @@ snapshots:
resolve: 1.22.8
semver: 7.5.4
optionalDependencies:
'@types/node': 20.10.0
'@types/node': 22.13.1
'@rushstack/rig-package@0.5.3':
dependencies:
resolve: 1.22.8
strip-json-comments: 3.1.1
'@rushstack/terminal@0.13.3(@types/node@20.10.0)':
'@rushstack/terminal@0.13.3(@types/node@22.13.1)':
dependencies:
'@rushstack/node-core-library': 5.5.1(@types/node@20.10.0)
'@rushstack/node-core-library': 5.5.1(@types/node@22.13.1)
supports-color: 8.1.1
optionalDependencies:
'@types/node': 20.10.0
'@types/node': 22.13.1
'@rushstack/ts-command-line@4.22.3(@types/node@20.10.0)':
'@rushstack/ts-command-line@4.22.3(@types/node@22.13.1)':
dependencies:
'@rushstack/terminal': 0.13.3(@types/node@20.10.0)
'@rushstack/terminal': 0.13.3(@types/node@22.13.1)
'@types/argparse': 1.0.38
argparse: 1.0.10
string-argv: 0.3.2
@@ -5150,6 +5112,10 @@ snapshots:
dependencies:
undici-types: 5.26.5
'@types/node@22.13.1':
dependencies:
undici-types: 6.20.0
'@types/normalize-package-data@2.4.4': {}
'@types/openurl@1.0.3':
@@ -5160,7 +5126,7 @@ snapshots:
'@types/through@0.0.33':
dependencies:
'@types/node': 20.10.0
'@types/node': 20.12.14
'@types/tough-cookie@4.0.5': {}
@@ -5168,7 +5134,7 @@ snapshots:
'@types/ws@8.5.13':
dependencies:
'@types/node': 20.10.0
'@types/node': 20.12.14
'@types/ws@8.5.4':
dependencies:
@@ -5294,15 +5260,15 @@ snapshots:
'@typescript-eslint/types': 8.17.0
eslint-visitor-keys: 4.2.0
'@vitest/browser@2.0.5(@types/node@20.10.0)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)':
'@vitest/browser@2.0.5(@types/node@22.13.1)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)':
dependencies:
'@testing-library/dom': 10.4.0
'@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0)
'@vitest/utils': 2.0.5
magic-string: 0.30.12
msw: 2.6.5(@types/node@20.10.0)(typescript@5.5.4)
msw: 2.6.5(@types/node@22.13.1)(typescript@5.5.4)
sirv: 2.0.4
vitest: 2.0.5(@types/node@20.10.0)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
vitest: 2.0.5(@types/node@22.13.1)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
ws: 8.18.0
optionalDependencies:
playwright: 1.42.1
@@ -5312,25 +5278,6 @@ snapshots:
- typescript
- utf-8-validate
'@vitest/browser@2.0.5(@types/node@20.12.14)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)':
dependencies:
'@testing-library/dom': 10.4.0
'@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0)
'@vitest/utils': 2.0.5
magic-string: 0.30.12
msw: 2.6.5(@types/node@20.12.14)(typescript@5.5.4)
sirv: 2.0.4
vitest: 2.0.5(@types/node@20.12.14)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
ws: 8.18.0
optionalDependencies:
playwright: 1.42.1
transitivePeerDependencies:
- '@types/node'
- bufferutil
- typescript
- utf-8-validate
optional: true
'@vitest/coverage-v8@2.0.5(vitest@2.0.5)':
dependencies:
'@ampproject/remapping': 2.3.0
@@ -5345,7 +5292,7 @@ snapshots:
std-env: 3.8.0
test-exclude: 7.0.1
tinyrainbow: 1.2.0
vitest: 2.0.5(@types/node@20.10.0)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
vitest: 2.0.5(@types/node@22.13.1)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
transitivePeerDependencies:
- supports-color
@@ -5355,7 +5302,7 @@ snapshots:
eslint: 9.9.0
optionalDependencies:
typescript: 5.5.4
vitest: 2.0.5(@types/node@20.10.0)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
vitest: 2.0.5(@types/node@22.13.1)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
'@vitest/expect@2.0.5':
dependencies:
@@ -5396,7 +5343,7 @@ snapshots:
pathe: 1.1.2
sirv: 2.0.4
tinyrainbow: 1.2.0
vitest: 2.0.5(@types/node@20.12.14)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
vitest: 2.0.5(@types/node@22.13.1)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)
'@vitest/utils@2.0.5':
dependencies:
@@ -7288,12 +7235,12 @@ snapshots:
ms@2.1.3: {}
msw@2.6.5(@types/node@20.10.0)(typescript@5.5.4):
msw@2.6.5(@types/node@22.13.1)(typescript@5.5.4):
dependencies:
'@bundled-es-modules/cookie': 2.0.1
'@bundled-es-modules/statuses': 1.0.1
'@bundled-es-modules/tough-cookie': 0.1.6
'@inquirer/confirm': 5.0.2(@types/node@20.10.0)
'@inquirer/confirm': 5.0.2(@types/node@22.13.1)
'@mswjs/interceptors': 0.37.0
'@open-draft/deferred-promise': 2.2.0
'@open-draft/until': 2.1.0
@@ -7313,32 +7260,6 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
msw@2.6.5(@types/node@20.12.14)(typescript@5.5.4):
dependencies:
'@bundled-es-modules/cookie': 2.0.1
'@bundled-es-modules/statuses': 1.0.1
'@bundled-es-modules/tough-cookie': 0.1.6
'@inquirer/confirm': 5.0.2(@types/node@20.12.14)
'@mswjs/interceptors': 0.37.0
'@open-draft/deferred-promise': 2.2.0
'@open-draft/until': 2.1.0
'@types/cookie': 0.6.0
'@types/statuses': 2.0.5
chalk: 4.1.2
graphql: 16.9.0
headers-polyfill: 4.0.3
is-node-process: 1.2.0
outvariant: 1.4.3
path-to-regexp: 6.3.0
strict-event-emitter: 0.5.1
type-fest: 4.27.0
yargs: 17.7.2
optionalDependencies:
typescript: 5.5.4
transitivePeerDependencies:
- '@types/node'
optional: true
muggle-string@0.4.1: {}
mute-stream@1.0.0: {}
@@ -7359,8 +7280,6 @@ snapshots:
dependencies:
semver: 7.5.1
node-gyp-build@4.8.1: {}
node-releases@2.0.18: {}
node-stdlib-browser@1.2.1:
@@ -8106,6 +8025,8 @@ snapshots:
undici-types@5.26.5: {}
undici-types@6.20.0: {}
unist-util-is@6.0.0:
dependencies:
'@types/unist': 3.0.3
@@ -8166,13 +8087,13 @@ snapshots:
spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1
vite-node@2.0.5(@types/node@20.10.0):
vite-node@2.0.5(@types/node@22.13.1):
dependencies:
cac: 6.7.14
debug: 4.3.7
pathe: 1.1.2
tinyrainbow: 1.2.0
vite: 5.4.2(@types/node@20.10.0)
vite: 5.4.2(@types/node@22.13.1)
transitivePeerDependencies:
- '@types/node'
- less
@@ -8184,27 +8105,9 @@ snapshots:
- supports-color
- terser
vite-node@2.0.5(@types/node@20.12.14):
vite-plugin-dts@4.0.3(@types/node@22.13.1)(rollup@4.27.2)(typescript@5.5.4)(vite@5.4.2(@types/node@22.13.1)):
dependencies:
cac: 6.7.14
debug: 4.3.7
pathe: 1.1.2
tinyrainbow: 1.2.0
vite: 5.4.2(@types/node@20.12.14)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
vite-plugin-dts@4.0.3(@types/node@20.10.0)(rollup@4.27.2)(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0)):
dependencies:
'@microsoft/api-extractor': 7.47.4(@types/node@20.10.0)
'@microsoft/api-extractor': 7.47.4(@types/node@22.13.1)
'@rollup/pluginutils': 5.1.3(rollup@4.27.2)
'@volar/typescript': 2.4.10
'@vue/language-core': 2.0.29(typescript@5.5.4)
@@ -8216,39 +8119,30 @@ snapshots:
typescript: 5.5.4
vue-tsc: 2.0.29(typescript@5.5.4)
optionalDependencies:
vite: 5.4.2(@types/node@20.10.0)
vite: 5.4.2(@types/node@22.13.1)
transitivePeerDependencies:
- '@types/node'
- rollup
- supports-color
vite-plugin-node-polyfills@0.22.0(rollup@4.27.2)(vite@5.4.2(@types/node@20.10.0)):
vite-plugin-node-polyfills@0.22.0(rollup@4.27.2)(vite@5.4.2(@types/node@22.13.1)):
dependencies:
'@rollup/plugin-inject': 5.0.5(rollup@4.27.2)
node-stdlib-browser: 1.2.1
vite: 5.4.2(@types/node@20.10.0)
vite: 5.4.2(@types/node@22.13.1)
transitivePeerDependencies:
- rollup
vite@5.4.2(@types/node@20.10.0):
vite@5.4.2(@types/node@22.13.1):
dependencies:
esbuild: 0.21.5
postcss: 8.4.49
rollup: 4.27.2
optionalDependencies:
'@types/node': 20.10.0
'@types/node': 22.13.1
fsevents: 2.3.3
vite@5.4.2(@types/node@20.12.14):
dependencies:
esbuild: 0.21.5
postcss: 8.4.49
rollup: 4.27.2
optionalDependencies:
'@types/node': 20.12.14
fsevents: 2.3.3
vitest@2.0.5(@types/node@20.10.0)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5):
vitest@2.0.5(@types/node@22.13.1)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5):
dependencies:
'@ampproject/remapping': 2.3.0
'@vitest/expect': 2.0.5
@@ -8266,47 +8160,12 @@ snapshots:
tinybench: 2.9.0
tinypool: 1.0.2
tinyrainbow: 1.2.0
vite: 5.4.2(@types/node@20.10.0)
vite-node: 2.0.5(@types/node@20.10.0)
vite: 5.4.2(@types/node@22.13.1)
vite-node: 2.0.5(@types/node@22.13.1)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 20.10.0
'@vitest/browser': 2.0.5(@types/node@20.10.0)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)
'@vitest/ui': 2.0.5(vitest@2.0.5)
transitivePeerDependencies:
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
vitest@2.0.5(@types/node@20.12.14)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5):
dependencies:
'@ampproject/remapping': 2.3.0
'@vitest/expect': 2.0.5
'@vitest/pretty-format': 2.1.5
'@vitest/runner': 2.0.5
'@vitest/snapshot': 2.0.5
'@vitest/spy': 2.0.5
'@vitest/utils': 2.0.5
chai: 5.1.2
debug: 4.3.7
execa: 8.0.1
magic-string: 0.30.12
pathe: 1.1.2
std-env: 3.8.0
tinybench: 2.9.0
tinypool: 1.0.2
tinyrainbow: 1.2.0
vite: 5.4.2(@types/node@20.12.14)
vite-node: 2.0.5(@types/node@20.12.14)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 20.12.14
'@vitest/browser': 2.0.5(@types/node@20.12.14)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)
'@types/node': 22.13.1
'@vitest/browser': 2.0.5(@types/node@22.13.1)(playwright@1.42.1)(typescript@5.5.4)(vitest@2.0.5)
'@vitest/ui': 2.0.5(vitest@2.0.5)
transitivePeerDependencies:
- less