1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-17 19:41:06 +03:00

Add support for lua scripts in client & muilti, fix client socket initiator, implement simple cluster nodes discovery strategy

This commit is contained in:
leibale
2021-05-31 10:39:40 -04:00
parent 15cf27423a
commit 4cbcc90bbb
11 changed files with 416 additions and 76 deletions

View File

@@ -29,9 +29,8 @@
* optionally filtered master(RW) & optionally filtered slaves(R) (?)
## Lua Scripts
* Create `RedisLuaScript` class
* In `RedisClient` (with TypeScript mapping)
* In `RedisMultiCommand` (with TypeScript mapping)
* ~~In `RedisClient` (with TypeScript mapping)~~
* ~~In `RedisMultiCommand` (with TypeScript mapping)~~
* In `RedisCluster` (with TypeScript mapping)
## Multi

View File

@@ -3,6 +3,7 @@ import { once } from 'events';
import { itWithClient, TEST_REDIS_SERVERS, TestRedisServers } from './test-utils';
import RedisClient from './client';
import { AbortError } from './errors';
import { defineScript } from './lua-script';
describe('Client', () => {
describe('authentication', () => {
@@ -142,6 +143,64 @@ describe('Client', () => {
.exec()
);
});
it('with script', async () => {
const client = RedisClient.create({
scripts: {
add: defineScript({
NUMBER_OF_KEYS: 0,
SCRIPT: 'return ARGV[1] + 1;',
transformArguments(number: number): Array<string> {
return [number.toString()];
},
transformReply(reply: number): number {
return reply;
}
})
}
});
await client.connect();
try {
assert.deepEqual(
await client.multi()
.add(1)
.exec(),
[2]
);
} finally {
await client.disconnect();
}
});
});
it('scripts', async () => {
const client = RedisClient.create({
scripts: {
add: defineScript({
NUMBER_OF_KEYS: 0,
SCRIPT: 'return ARGV[1] + 1;',
transformArguments(number: number): Array<string> {
return [number.toString()];
},
transformReply(reply: number): number {
return reply;
}
})
}
});
await client.connect();
try {
assert.equal(
await client.add(1),
2
);
} finally {
await client.disconnect();
}
});
itWithClient(TestRedisServers.OPEN, 'should reconnect after DEBUG RESTART', async client => {
@@ -160,8 +219,10 @@ describe('Client', () => {
});
await client.select(1);
await client.set('key', 'value');
await assert.rejects(client.sendCommand(['DEBUG', 'RESTART']));
// assert.equal(await client.get('key'), 'value');
assert.equal(
(await client.clientInfo()).db,
1
);
});
});

View File

@@ -1,14 +1,16 @@
import RedisSocket, { RedisSocketOptions } from './socket';
import RedisCommandsQueue, { QueueCommandOptions } from './commands-queue';
import COMMANDS from './commands/client';
import { RedisCommand, RedisModules, RedisModule, RedisReply } from './commands';
import { RedisCommand, RedisModules, RedisReply } from './commands';
import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command';
import EventEmitter from 'events';
import { CommandOptions, commandOptions, isCommandOptions } from './command-options';
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
export interface RedisClientOptions<M = RedisModules> {
export interface RedisClientOptions<M = RedisModules, S = RedisLuaScripts> {
socket?: RedisSocketOptions;
modules?: M;
scripts?: S;
commandsQueueMaxLength?: number;
readOnly?: boolean;
callbackify?: boolean;
@@ -21,17 +23,21 @@ type WithCommands = {
[P in keyof typeof COMMANDS]: RedisCommandSignature<(typeof COMMANDS)[P]>;
};
type WithModules<M extends Array<RedisModule>> = {
type WithModules<M extends RedisModules> = {
[P in keyof M[number]]: RedisCommandSignature<M[number][P]>;
};
export type RedisClientType<M extends RedisModules> = WithCommands & WithModules<M> & RedisClient<M>;
type WithScripts<S extends RedisLuaScripts> = {
[P in keyof S]: RedisCommandSignature<S[P]>;
};
export type RedisClientType<M extends RedisModules, S extends RedisLuaScripts> = WithCommands & WithModules<M> & WithScripts<S> & RedisClient<M, S>;
export interface ClientCommandOptions extends QueueCommandOptions {
duplicateConnection?: boolean;
}
export default class RedisClient<M extends RedisModules = RedisModules> extends EventEmitter {
export default class RedisClient<M extends RedisModules = RedisModules, S extends RedisLuaScripts = RedisLuaScripts> extends EventEmitter {
static defineCommand(on: any, name: string, command: RedisCommand): void {
on[name] = async function (...args: Array<unknown>): Promise<unknown> {
const options = isCommandOptions(args[0]) && args.shift();
@@ -62,31 +68,36 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
};
}
static create<M extends RedisModules>(options?: RedisClientOptions<M>): RedisClientType<M> {
return <any>new RedisClient<M>(options);
static create<M extends RedisModules, S extends RedisLuaScripts>(options?: RedisClientOptions<M, S>): RedisClientType<M, S> {
return <any>new RedisClient<M, S>(options);
}
static commandOptions(options: ClientCommandOptions): CommandOptions<ClientCommandOptions> {
return commandOptions(options);
};
readonly #options?: RedisClientOptions<M>;
readonly #options?: RedisClientOptions<M, S>;
readonly #socket: RedisSocket;
readonly #queue: RedisCommandsQueue;
readonly #Multi: typeof RedisMultiCommand & { new(): RedisMultiCommandType<M> };
readonly #Multi: typeof RedisMultiCommand & { new(): RedisMultiCommandType<M, S> };
#selectedDB = 0;
get options(): RedisClientOptions<M> | null | undefined {
return this.#options;
}
get isOpen(): boolean {
return this.#socket.isOpen;
}
constructor(options?: RedisClientOptions<M>) {
constructor(options?: RedisClientOptions<M, S>) {
super();
this.#options = options;
this.#socket = this.#initiateSocket();
this.#queue = this.#initiateQueue();
this.#Multi = this.#initiateMulti();
this.#initiateModules();
this.#initiateScripts();
this.#callbackify();
}
@@ -95,15 +106,15 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
const promises = [];
if (this.#options?.socket?.password) {
promises.push((this as any).auth(this.#options?.socket));
promises.push((this as any).auth(RedisClient.commandOptions({ asap: true }), this.#options?.socket));
}
if (this.#options?.readOnly) {
promises.push((this as any).readOnly());
promises.push((this as any).readOnly(RedisClient.commandOptions({ asap: true })));
}
if (this.#selectedDB !== 0) {
promises.push((this as any).select(this.#selectedDB));
promises.push((this as any).select(RedisClient.commandOptions({ asap: true }), this.#selectedDB));
}
await Promise.all(promises);
@@ -131,7 +142,7 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
);
}
#initiateMulti(): typeof RedisMultiCommand & { new(): RedisMultiCommandType<M> } {
#initiateMulti(): typeof RedisMultiCommand & { new(): RedisMultiCommandType<M, S> } {
const executor = async (commands: Array<MultiQueuedCommand>): Promise<Array<RedisReply>> => {
const promise = Promise.all(
commands.map(({encodedCommand}) => {
@@ -145,11 +156,10 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
return (replies[replies.length - 1] as Array<RedisReply>);
};
const modules = this.#options?.modules;
const options = this.#options;
return <any>class extends RedisMultiCommand {
constructor() {
super(executor, modules);
super(executor, options?.modules, options?.scripts);
}
};
}
@@ -165,6 +175,34 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
}
}
#initiateScripts(): void {
if (!this.#options?.scripts) return;
for (const [name, script] of Object.entries(this.#options.scripts)) {
(this as any)[name] = async function (...args: Parameters<typeof script.transformArguments>): Promise<ReturnType<typeof script.transformReply>> {
const options = isCommandOptions(args[0]) && args[0];
return script.transformReply(
await this.#executeScript(script, [
script.NUMBER_OF_KEYS.toString(),
...script.transformArguments(options ? args.slice(1) : args)
])
);
};
}
}
async #executeScript<S extends RedisLuaScript>(script: S, args: Array<string>): Promise<ReturnType<S['transformReply']>> {
try {
return await this.sendCommand(['EVALSHA', script.SHA, ...args]);
} catch (err: any) {
if (!err?.message?.startsWith?.('NOSCRIPT')) {
throw err;
}
return await this.sendCommand(['EVAL', script.SCRIPT, ...args]);
}
}
#callbackify(): void {
if (!this.#options?.callbackify) return;
@@ -183,7 +221,7 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
}
}
duplicate(): RedisClientType<M> {
duplicate(): RedisClientType<M, S> {
return RedisClient.create(this.#options);
}
@@ -191,8 +229,15 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
await this.#socket.connect();
}
async SELECT(db: number): Promise<void> {
await this.sendCommand(['SELECT', db.toString()]);
async SELECT(db: number): Promise<void>;
async SELECT(options: CommandOptions<ClientCommandOptions>, db: number): Promise<void>;
async SELECT(options?: any, db?: any): Promise<void> {
if (!isCommandOptions(options)) {
db = options;
options = null;
}
await this.sendCommand(['SELECT', db.toString()], options);
this.#selectedDB = db;
}
@@ -218,7 +263,7 @@ export default class RedisClient<M extends RedisModules = RedisModules> extends
return await promise;
}
multi(): RedisMultiCommandType<M> {
multi(): RedisMultiCommandType<M, S> {
return new this.#Multi();
}

View File

@@ -33,11 +33,20 @@ export default class RedisClusterSlots {
}
async discover(): Promise<void> {
// TODO
throw new Error('None of the cluster node is available');
// TODO: shuffle?
for (const client of this.#clientByKey.values()) {
try {
await this.#discoverNodes(client.options?.socket);
return;
} catch (err) {
// this.emit('error', err);
}
}
async #discoverNodes(socketOptions: RedisSocketOptions) {
throw new Error('None of the cluster nodes is available');
}
async #discoverNodes(socketOptions?: RedisSocketOptions) {
const client = RedisClient.create({
socket: socketOptions
});

View File

@@ -0,0 +1,85 @@
export function transformArguments(): Array<string> {
return ['CLIENT', 'INFO'];
}
interface ClientInfoReply {
id: number;
addr: string;
laddr: string;
fd: number;
name: string;
age: number;
idle: number;
flags: string;
db: number;
sub: number;
psub: number;
multi: number;
qbuf: number;
qbufFree: number;
argvMem: number;
obl: number;
oll: number;
omem: number;
totMem: number;
events: string;
cmd: string;
user: string;
redir: number;
}
const REGEX = /=([^\s]*)/g;
export function transformReply(reply: string): ClientInfoReply {
const [
[, id],
[, addr],
[, laddr],
[, fd],
[, name],
[, age],
[, idle],
[, flags],
[, db],
[, sub],
[, psub],
[, multi],
[, qbuf],
[, qbufFree],
[, argvMem],
[, obl],
[, oll],
[, omem],
[, totMem],
[, events],
[, cmd],
[, user],
[, redir]
] = [...reply.matchAll(REGEX)];
return {
id: Number(id),
addr,
laddr,
fd: Number(fd),
name,
age: Number(age),
idle: Number(idle),
flags,
db: Number(db),
sub: Number(sub),
psub: Number(psub),
multi: Number(multi),
qbuf: Number(qbuf),
qbufFree: Number(qbufFree),
argvMem: Number(argvMem),
obl: Number(obl),
oll: Number(oll),
omem: Number(omem),
totMem: Number(totMem),
events,
cmd,
user,
redir: Number(redir)
};
}

View File

@@ -1,6 +1,7 @@
import * as APPEND from './APPEND';
import * as AUTH from './AUTH';
import * as BLPOP from './BLPOP';
import * as CLIENT_INFO from './CLIENT_INFO';
import * as CLUSTER_NODES from './CLUSTER_NODES';
import * as COPY from './COPY';
import * as DECR from './DECR';
@@ -42,6 +43,8 @@ export default {
auth: AUTH,
BLPOP,
blPop: BLPOP,
CLIENT_INFO,
clientInfo: CLIENT_INFO,
CLUSTER_NODES,
clusterNodes: CLUSTER_NODES,
COPY,

24
lib/lua-script.ts Normal file
View File

@@ -0,0 +1,24 @@
import { createHash } from 'crypto';
import { RedisCommand } from './commands';
export interface RedisLuaScriptConfig extends RedisCommand {
SCRIPT: string;
NUMBER_OF_KEYS: number;
}
interface SHA {
SHA: string;
}
export type RedisLuaScript = RedisLuaScriptConfig & SHA;
export interface RedisLuaScripts {
[key: string]: RedisLuaScript;
}
export function defineScript<S extends RedisLuaScriptConfig>(script: S): S & SHA {
return {
...script,
SHA: createHash('sha1').update(script.SCRIPT).digest('hex')
};
}

View File

@@ -1,18 +1,23 @@
import COMMANDS from './commands/client';
import { RedisCommand, RedisModule, RedisModules, RedisReply } from './commands';
import { RedisCommand, RedisModules, RedisReply } from './commands';
import RedisCommandsQueue from './commands-queue';
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
type RedisMultiCommandSignature<C extends RedisCommand, M extends RedisModules> = (...args: Parameters<C['transformArguments']>) => RedisMultiCommandType<M>;
type RedisMultiCommandSignature<C extends RedisCommand, M extends RedisModules, S extends RedisLuaScripts> = (...args: Parameters<C['transformArguments']>) => RedisMultiCommandType<M, S>;
type RedisMultiWithCommands<M extends RedisModules> = {
[P in keyof typeof COMMANDS]: RedisMultiCommandSignature<(typeof COMMANDS)[P], M>
type WithCommands<M extends RedisModules, S extends RedisLuaScripts> = {
[P in keyof typeof COMMANDS]: RedisMultiCommandSignature<(typeof COMMANDS)[P], M, S>
};
type RedisMultiWithModules<M extends Array<RedisModule>> = {
[P in keyof M[number]]: RedisMultiCommandSignature<M[number][P], M>
type WithModules<M extends RedisModules, S extends RedisLuaScripts> = {
[P in keyof M[number]]: RedisMultiCommandSignature<M[number][P], M, S>
};
export type RedisMultiCommandType<M extends RedisModules> = RedisMultiCommand & RedisMultiWithCommands<M> & RedisMultiWithModules<M>;
type WithScripts<M extends RedisModules, S extends RedisLuaScripts> = {
[P in keyof S]: RedisMultiCommandSignature<S[P], M, S>
};
export type RedisMultiCommandType<M extends RedisModules, S extends RedisLuaScripts> = RedisMultiCommand & WithCommands<M, S> & WithModules<M, S> & WithScripts<M, S>;
export interface MultiQueuedCommand {
encodedCommand: string;
@@ -21,27 +26,57 @@ export interface MultiQueuedCommand {
export type RedisMultiExecutor = (queue: Array<MultiQueuedCommand>, chainId: Symbol) => Promise<Array<RedisReply>>;
export default class RedisMultiCommand {
static defineCommand(on: any, name: string, command: RedisCommand) {
on[name] = function (...args: Array<unknown>) {
export default class RedisMultiCommand<M extends RedisModules = RedisModules, S extends RedisLuaScripts = RedisLuaScripts> {
static defineCommand(on: any, name: string, command: RedisCommand): void {
on[name] = function (...args: Parameters<typeof command.transformArguments>) {
return this.addCommand(command.transformArguments(...args), command.transformReply);
};
}
static create<M extends RedisModules>(executor: RedisMultiExecutor, modules?: M): RedisMultiCommandType<M> {
return <any>new RedisMultiCommand(executor, modules);
static defineLuaScript(on: any, name: string, script: RedisLuaScript): void {
on[name] = function (...args: Array<unknown>) {
let evalArgs;
if (this.#scriptsInUse.has(name)) {
evalArgs = [
'EVALSHA',
script.SHA
];
} else {
this.#scriptsInUse.add(name);
evalArgs = [
'EVAL',
script.SCRIPT
];
}
return this.addCommand(
[
...evalArgs,
script.NUMBER_OF_KEYS,
...script.transformArguments(...args)
],
script.transformReply
);
};
}
static create<M extends RedisModules, S extends RedisLuaScripts>(executor: RedisMultiExecutor, modules?: M, scripts?: S): RedisMultiCommandType<M, S> {
return <any>new RedisMultiCommand<M, S>(executor, modules, scripts);
}
readonly #executor: RedisMultiExecutor;
readonly #queue: Array<MultiQueuedCommand> = [];
constructor(executor: RedisMultiExecutor, modules?: RedisModules) {
readonly #scriptsInUse = new Set<string>();
constructor(executor: RedisMultiExecutor, modules?: RedisModules, scripts?: RedisLuaScripts) {
this.#executor = executor;
this.#initiateModules(modules);
this.#initiateScripts(scripts);
}
#initiateModules(modules?: RedisModules) {
#initiateModules(modules?: RedisModules): void {
if (!modules) return;
for (const m of modules) {
@@ -51,6 +86,14 @@ export default class RedisMultiCommand {
}
}
#initiateScripts(scripts?: RedisLuaScripts): void {
if (!scripts) return;
for (const [name, script] of Object.entries(scripts)) {
RedisMultiCommand.defineLuaScript(this, name, script);
}
}
addCommand(args: Array<string>, transformReply?: RedisCommand['transformReply']): this {
this.#queue.push({
encodedCommand: RedisCommandsQueue.encodeCommand(args),

View File

@@ -1,6 +1,7 @@
import assert from 'assert/strict';
import RedisClient, { RedisClientType } from './client';
import { RedisModules } from './commands';
import { RedisLuaScripts } from './lua-script';
import { spawn } from 'child_process';
import { once } from 'events';
import tcpPortUsed from 'tcp-port-used';
@@ -35,7 +36,7 @@ async function spawnPasswordServer(): Promise<void> {
};
}
export function itWithClient(type: TestRedisServers, title: string, fn: (client: RedisClientType<RedisModules>) => Promise<void>) {
export function itWithClient(type: TestRedisServers, title: string, fn: (client: RedisClientType<RedisModules, RedisLuaScripts>) => Promise<void>) {
it(title, async () => {
const client = RedisClient.create({
socket: TEST_REDIS_SERVERS[type]

128
package-lock.json generated
View File

@@ -16,7 +16,7 @@
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/mocha": "^8.2.2",
"@types/node": "^15.3.1",
"@types/node": "^15.6.1",
"@types/tcp-port-used": "^1.0.0",
"@types/which": "^2.0.0",
"@types/yallist": "^4.0.0",
@@ -24,8 +24,8 @@
"nyc": "^15.1.0",
"source-map-support": "^0.5.19",
"tcp-port-used": "^1.0.2",
"ts-node": "^9.1.1",
"typescript": "^4.3.1-rc",
"ts-node": "^10.0.0",
"typescript": "^4.3.2",
"which": "^2.0.2"
},
"engines": {
@@ -470,6 +470,30 @@
"node": ">=8"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.7.tgz",
"integrity": "sha512-aBvUmXLQbayM4w3A8TrjwrXs4DZ8iduJnuJLLRGdkWlyakCf1q6uHZJBzXoRA/huAEknG5tcUyQxN3A+In5euQ==",
"dev": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.7.tgz",
"integrity": "sha512-dgasobK/Y0wVMswcipr3k0HpevxFJLijN03A8mYfEPvWvOs14v0ZlYTR4kIgMx8g4+fTyTFv8/jLCIfRqLDJ4A==",
"dev": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.0.tgz",
"integrity": "sha512-RKkL8eTdPv6t5EHgFKIVQgsDapugbuOptNd9OOunN/HAkzmmTnZELx1kNCK0rSdUYGmiFMM3rRQMAWiyp023LQ==",
"dev": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz",
"integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==",
"dev": true
},
"node_modules/@types/mocha": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz",
@@ -480,7 +504,8 @@
"version": "15.6.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
"integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/@types/tcp-port-used": {
"version": "1.0.0",
@@ -692,9 +717,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001228",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz",
"integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==",
"version": "1.0.30001230",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz",
"integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==",
"dev": true,
"funding": {
"type": "opencollective",
@@ -947,9 +972,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.3.738",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.738.tgz",
"integrity": "sha512-vCMf4gDOpEylPSLPLSwAEsz+R3ShP02Y3cAKMZvTqule3XcPp7tgc/0ESI7IS6ZeyBlGClE50N53fIOkcIVnpw==",
"version": "1.3.740",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.740.tgz",
"integrity": "sha512-Mi2m55JrX2BFbNZGKYR+2ItcGnR4O5HhrvgoRRyZQlaMGQULqDhoGkLWHzJoshSzi7k1PUofxcDbNhlFrDZNhg==",
"dev": true
},
"node_modules/emoji-regex": {
@@ -2402,11 +2427,15 @@
}
},
"node_modules/ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz",
"integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==",
"dev": true,
"dependencies": {
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
@@ -2416,15 +2445,27 @@
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"engines": {
"node": ">=10.0.0"
"node": ">=12.0.0"
},
"peerDependencies": {
"@swc/core": ">=1.2.45",
"@swc/wasm": ">=1.2.45",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/ts-node/node_modules/diff": {
@@ -2455,10 +2496,11 @@
}
},
"node_modules/typescript": {
"version": "4.3.1-rc",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.1-rc.tgz",
"integrity": "sha512-L3uJ0gcntaRaKni9aV2amYB+pCDVodKe/B5+IREyvtKGsDOF7cYjchHb/B894skqkgD52ykRuWatIZMqEsHIqA==",
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -3113,6 +3155,30 @@
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
"dev": true
},
"@tsconfig/node10": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.7.tgz",
"integrity": "sha512-aBvUmXLQbayM4w3A8TrjwrXs4DZ8iduJnuJLLRGdkWlyakCf1q6uHZJBzXoRA/huAEknG5tcUyQxN3A+In5euQ==",
"dev": true
},
"@tsconfig/node12": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.7.tgz",
"integrity": "sha512-dgasobK/Y0wVMswcipr3k0HpevxFJLijN03A8mYfEPvWvOs14v0ZlYTR4kIgMx8g4+fTyTFv8/jLCIfRqLDJ4A==",
"dev": true
},
"@tsconfig/node14": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.0.tgz",
"integrity": "sha512-RKkL8eTdPv6t5EHgFKIVQgsDapugbuOptNd9OOunN/HAkzmmTnZELx1kNCK0rSdUYGmiFMM3rRQMAWiyp023LQ==",
"dev": true
},
"@tsconfig/node16": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz",
"integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==",
"dev": true
},
"@types/mocha": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz",
@@ -3292,9 +3358,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001228",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz",
"integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==",
"version": "1.0.30001230",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz",
"integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==",
"dev": true
},
"chalk": {
@@ -3494,9 +3560,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.738",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.738.tgz",
"integrity": "sha512-vCMf4gDOpEylPSLPLSwAEsz+R3ShP02Y3cAKMZvTqule3XcPp7tgc/0ESI7IS6ZeyBlGClE50N53fIOkcIVnpw==",
"version": "1.3.740",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.740.tgz",
"integrity": "sha512-Mi2m55JrX2BFbNZGKYR+2ItcGnR4O5HhrvgoRRyZQlaMGQULqDhoGkLWHzJoshSzi7k1PUofxcDbNhlFrDZNhg==",
"dev": true
},
"emoji-regex": {
@@ -4575,11 +4641,15 @@
}
},
"ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz",
"integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==",
"dev": true,
"requires": {
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
@@ -4612,9 +4682,9 @@
}
},
"typescript": {
"version": "4.3.1-rc",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.1-rc.tgz",
"integrity": "sha512-L3uJ0gcntaRaKni9aV2amYB+pCDVodKe/B5+IREyvtKGsDOF7cYjchHb/B894skqkgD52ykRuWatIZMqEsHIqA==",
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
"dev": true
},
"uuid": {

View File

@@ -34,7 +34,7 @@
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/mocha": "^8.2.2",
"@types/node": "^15.3.1",
"@types/node": "^15.6.1",
"@types/tcp-port-used": "^1.0.0",
"@types/which": "^2.0.0",
"@types/yallist": "^4.0.0",
@@ -42,8 +42,8 @@
"nyc": "^15.1.0",
"source-map-support": "^0.5.19",
"tcp-port-used": "^1.0.2",
"ts-node": "^9.1.1",
"typescript": "^4.3.1-rc",
"ts-node": "^10.0.0",
"typescript": "^4.3.2",
"which": "^2.0.2"
},
"engines": {