diff --git a/README.md b/README.md index db0fa71cc7f..c5f0ea1a1c9 100644 --- a/README.md +++ b/README.md @@ -38,24 +38,22 @@ npm install redis@next import { createClient } from 'redis'; (async () => { - const client = createClient(); + const client = createClient(); - client.on('error', (err) => console.log('Redis Client Error', err)); + client.on('error', (err) => console.log('Redis Client Error', err)); - await client.connect(); + await client.connect(); - await client.set('key', 'value'); - const value = await client.get('key'); + await client.set('key', 'value'); + const value = await client.get('key'); })(); ``` -The above code connects to localhost on port 6379. To connect to a different host or port, use a connection string in the format `[redis[s]:]//[[username][:password]@][host][:port]`: +The above code connects to localhost on port 6379. To connect to a different host or port, use a connection string in the format `redis[s]://[[username][:password]@][host][:port][/db-number]`: ```typescript createClient({ - socket: { - url: 'redis://alice:foobared@awesome.redis.server:6380' - } + url: 'redis://alice:foobared@awesome.redis.server:6380', }); ``` @@ -79,8 +77,8 @@ Modifiers to commands are specified using a JavaScript object: ```typescript await client.set('key', 'value', { - EX: 10, - NX: true + EX: 10, + NX: true, }); ``` @@ -108,11 +106,11 @@ Start a [transaction](https://redis.io/topics/transactions) by calling `.multi() ```typescript await client.set('another-key', 'another-value'); -const [ setKeyReply, otherKeyValue ] = await client.multi() - .set('key', 'value') - .get('another-key') - .exec() -]); // ['OK', 'another-value'] +const [setKeyReply, otherKeyValue] = await client + .multi() + .set('key', 'value') + .get('another-key') + .exec(); // ['OK', 'another-value'] ``` You can also [watch](https://redis.io/topics/transactions#optimistic-locking-using-check-and-set) keys by calling `.watch()`. Your transaction will abort if any of the watched keys change. @@ -128,10 +126,7 @@ This pattern works especially well for blocking commands—such as `BLPOP` and ` ```typescript import { commandOptions } from 'redis'; -const blPopPromise = client.blPop( - commandOptions({ isolated: true }), - 'key' -); +const blPopPromise = client.blPop(commandOptions({ isolated: true }), 'key'); await client.lPush('key', ['1', '2']); @@ -153,12 +148,12 @@ await subscriber.connect(); Once you have one, simply subscribe and unsubscribe as needed: ```typescript -await subscriber.subscribe('channel', message => { - console.log(message); // 'message' +await subscriber.subscribe('channel', (message) => { + console.log(message); // 'message' }); await subscriber.pSubscribe('channe*', (message, channel) => { - console.log(message, channel); // 'message', 'channel' + console.log(message, channel); // 'message', 'channel' }); await subscriber.unsubscribe('channel'); @@ -178,26 +173,29 @@ await publisher.publish('channel', 'message'); ```typescript for await (const key of client.scanIterator()) { - // use the key! - await client.get(key); + // use the key! + await client.get(key); } ``` This works with `HSCAN`, `SSCAN`, and `ZSCAN` too: ```typescript -for await (const member of client.hScanIterator('hash')) {} -for await (const { field, value } of client.sScanIterator('set')) {} -for await (const { member, score } of client.zScanIterator('sorted-set')) {} +for await (const member of client.hScanIterator('hash')) { +} +for await (const { field, value } of client.sScanIterator('set')) { +} +for await (const { member, score } of client.zScanIterator('sorted-set')) { +} ``` You can override the default options by providing a configuration object: ```typescript client.scanIterator({ - TYPE: 'string', // `SCAN` only - MATCH: 'patter*', - COUNT: 100 + TYPE: 'string', // `SCAN` only + MATCH: 'patter*', + COUNT: 100, }); ``` @@ -209,27 +207,26 @@ Define new functions using [Lua scripts](https://redis.io/commands/eval) which e import { createClient, defineScript } from 'redis'; (async () => { - const client = createClient({ - scripts: { - add: defineScript({ - NUMBER_OF_KEYS: 1, - SCRIPT: - 'local val = redis.pcall("GET", KEYS[1]);' + - 'return val + ARGV[1];', - transformArguments(key: string, toAdd: number): Array { - return [key, number.toString()]; - }, - transformReply(reply: number): number { - return reply; - } - }) - } - }); - - await client.connect(); - - await client.set('key', '1'); - await client.add('key', 2); // 3 + const client = createClient({ + scripts: { + add: defineScript({ + NUMBER_OF_KEYS: 1, + SCRIPT: + "local val = redis.pcall('GET', KEYS[1]);' + 'return val + ARGV[1];", + transformArguments(key: string, toAdd: number): Array { + return [key, number.toString()]; + }, + transformReply(reply: number): number { + return reply; + }, + }), + }, + }); + + await client.connect(); + + await client.set('key', '1'); + await client.add('key', 2); // 3 })(); ``` @@ -241,22 +238,25 @@ Connecting to a cluster is a bit different. Create the client by specifying some import { createCluster } from 'redis'; (async () => { - const cluster = createCluster({ - rootNodes: [{ - host: '10.0.0.1', - port: 30001 - }, { - host: '10.0.0.2', - port: 30002 - }] - }); - - cluster.on('error', (err) => console.log('Redis Cluster Error', err)); - - await cluster.connect(); - - await cluster.set('key', 'value'); - const value = await cluster.get('key'); + const cluster = createCluster({ + rootNodes: [ + { + host: '10.0.0.1', + port: 30001, + }, + { + host: '10.0.0.2', + port: 30002, + }, + ], + }); + + cluster.on('error', (err) => console.log('Redis Cluster Error', err)); + + await cluster.connect(); + + await cluster.set('key', 'value'); + const value = await cluster.get('key'); })(); ``` @@ -273,8 +273,8 @@ Of course, if you don't do something with your Promises you're certain to get [u ```typescript await Promise.all([ - client.set('Tm9kZSBSZWRpcw==', 'users:1'), - client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw==') + client.set('Tm9kZSBSZWRpcw==', 'users:1'), + client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw=='), ]); ``` @@ -284,7 +284,9 @@ If you'd like to contribute, check out the [contributing guide](CONTRIBUTING.md) Thank you to all the people who already contributed to Node Redis! - + + + ## License diff --git a/docs/FAQ.md b/docs/FAQ.md index b5074e73025..cfdb2ecaf42 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -8,6 +8,6 @@ When a socket closed unexpectedly, all the commands that were already sent will ## How are commands batched? -Commands are pipelined using [`queueMicrotask`](https://nodejs.org/api/globals.html#globals_queuemicrotask_callback). Commands from the same "tick" will be sent in batches and respect the [`writableHighWaterMark`](https://nodejs.org/api/stream.html#stream_new_stream_writable_options). +Commands are pipelined using [`queueMicrotask`](https://nodejs.org/api/globals.html#globals_queuemicrotask_callback). If `socket.write()` returns `false`—meaning that ["all or part of the data was queued in user memory"](https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback:~:text=all%20or%20part%20of%20the%20data%20was%20queued%20in%20user%20memory)—the commands will stack in memory until the [`drain`](https://nodejs.org/api/net.html#net_event_drain) event is fired. diff --git a/docs/client-configuration.md b/docs/client-configuration.md index 4b93340ad8f..11fdb0a6819 100644 --- a/docs/client-configuration.md +++ b/docs/client-configuration.md @@ -1,24 +1,26 @@ # `createClient` configuration -| Property | Default | Description | -|--------------------------|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------| -| socket | | Object defining socket connection properties | -| socket.url | | `[redis[s]:]//[[username][:password]@][host][:port]` | -| socket.host | `'localhost'` | Hostname to connect to | -| socket.port | `6379` | Port to connect to | -| socket.username | | ACL username ([see ACL guide](https://redis.io/topics/acl)) | -| socket.password | | ACL password or the old "--requirepass" password | -| socket.connectTimeout | `5000` | The timeout for connecting to the Redis Server (in milliseconds) | -| socket.noDelay | `true` | Enable/disable the use of [`Nagle's algorithm`](https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay) | -| socket.keepAlive | `5000` | Enable/disable the [`keep-alive`](https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay) functionality | -| socket.tls | | Set to `true` to enable [TLS Configuration](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback) | -| socket.reconnectStrategy | `retries => Math.min(retries * 50, 500)` | A function containing the [Reconnect Strategy](#reconnect-strategy) logic | -| modules | | Object defining which [Redis Modules](https://redis.io/modules) to include (TODO - document) | -| scripts | | Object defining Lua scripts to use with this client. See [Lua Scripts](../README.md#lua-scripts) | -| commandsQueueMaxLength | | Maximum length of the client's internal command queue | -| readonly | `false` | Connect in [`READONLY`](https://redis.io/commands/readonly) mode | -| legacyMode | `false` | Maintain some backwards compatibility (see the [Migration Guide](v3-to-v4.md)) | -| isolationPoolOptions | | See the [Isolated Execution Guide](./isolated-execution.md) | +| Property | Default | Description | +|--------------------------|------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| url | | `redis[s]://[[username][:password]@][host][:port][/db-number]` (see [`redis`](https://www.iana.org/assignments/uri-schemes/prov/redis) and [`rediss`](https://www.iana.org/assignments/uri-schemes/prov/rediss) IANA registration for more details) | +| socket | | Object defining socket connection properties | +| socket.host | `'localhost'` | Hostname to connect to | +| socket.port | `6379` | Port to connect to | +| socket.path | | UNIX Socket to connect to | +| socket.connectTimeout | `5000` | The timeout for connecting to the Redis Server (in milliseconds) | +| socket.noDelay | `true` | Enable/disable the use of [`Nagle's algorithm`](https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay) | +| socket.keepAlive | `5000` | Enable/disable the [`keep-alive`](https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay) functionality | +| socket.tls | | Set to `true` to enable [TLS Configuration](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback) | +| socket.reconnectStrategy | `retries => Math.min(retries * 50, 500)` | A function containing the [Reconnect Strategy](#reconnect-strategy) logic | +| username | | ACL username ([see ACL guide](https://redis.io/topics/acl)) | +| password | | ACL password or the old "--requirepass" password | +| database | | Database number to connect to (see [`SELECT`](https://redis.io/commands/select) command) | +| modules | | Object defining which [Redis Modules](https://redis.io/modules) to include (TODO - document) | +| scripts | | Object defining Lua Scripts to use with this client (see [Lua Scripts](../README.md#lua-scripts)) | +| commandsQueueMaxLength | | Maximum length of the client's internal command queue | +| readonly | `false` | Connect in [`READONLY`](https://redis.io/commands/readonly) mode | +| legacyMode | `false` | Maintain some backwards compatibility (see the [Migration Guide](v3-to-v4.md)) | +| isolationPoolOptions | | See the [Isolated Execution Guide](./isolated-execution.md) | ## Reconnect Strategy diff --git a/lib/client.spec.ts b/lib/client.spec.ts index f73049d2286..2cf6ea4964e 100644 --- a/lib/client.spec.ts +++ b/lib/client.spec.ts @@ -5,6 +5,7 @@ import RedisClient from './client'; import { AbortError, ClientClosedError, ConnectionTimeoutError, WatchError } from './errors'; import { defineScript } from './lua-script'; import { spy } from 'sinon'; +import { RedisNetSocketOptions } from './socket'; export const SQUARE_SCRIPT = defineScript({ NUMBER_OF_KEYS: 0, @@ -18,6 +19,81 @@ export const SQUARE_SCRIPT = defineScript({ }); describe('Client', () => { + describe('parseURL', () => { + it('redis://user:secret@localhost:6379/0', () => { + assert.deepEqual( + RedisClient.parseURL('redis://user:secret@localhost:6379/0'), + { + socket: { + host: 'localhost', + port: 6379 + }, + username: 'user', + password: 'secret', + database: 0 + } + ); + }); + + it('rediss://user:secret@localhost:6379/0', () => { + assert.deepEqual( + RedisClient.parseURL('rediss://user:secret@localhost:6379/0'), + { + socket: { + host: 'localhost', + port: 6379, + tls: true + }, + username: 'user', + password: 'secret', + database: 0 + } + ); + }); + + it('Invalid protocol', () => { + assert.throws( + () => RedisClient.parseURL('redi://user:secret@localhost:6379/0'), + TypeError + ); + }); + + it('Invalid pathname', () => { + assert.throws( + () => RedisClient.parseURL('redis://user:secret@localhost:6379/NaN'), + TypeError + ); + }); + + it('redis://localhost', () => { + assert.deepEqual( + RedisClient.parseURL('redis://localhost'), + { + socket: { + host: 'localhost', + } + } + ); + }); + + it('createClient with url', async () => { + const client = RedisClient.create({ + url: `redis://localhost:${(TEST_REDIS_SERVERS[TestRedisServers.OPEN].socket as RedisNetSocketOptions)!.port!.toString()}/1` + }); + + await client.connect(); + + try { + assert.equal( + await client.ping(), + 'PONG' + ); + } finally { + await client.disconnect(); + } + }) + }); + describe('authentication', () => { itWithClient(TestRedisServers.PASSWORD, 'Client should be authenticated', async client => { assert.equal( @@ -28,10 +104,8 @@ describe('Client', () => { it('should not retry connecting if failed due to wrong auth', async () => { const client = RedisClient.create({ - socket: { - ...TEST_REDIS_SERVERS[TestRedisServers.PASSWORD], - password: 'wrongpassword' - } + ...TEST_REDIS_SERVERS[TestRedisServers.PASSWORD], + password: 'wrongpassword' }); await assert.rejects( @@ -49,7 +123,7 @@ describe('Client', () => { describe('legacyMode', () => { const client = RedisClient.create({ - socket: TEST_REDIS_SERVERS[TestRedisServers.OPEN], + ...TEST_REDIS_SERVERS[TestRedisServers.OPEN], scripts: { square: SQUARE_SCRIPT }, @@ -173,9 +247,7 @@ describe('Client', () => { describe('events', () => { it('connect, ready, end', async () => { - const client = RedisClient.create({ - socket: TEST_REDIS_SERVERS[TestRedisServers.OPEN] - }); + const client = RedisClient.create(TEST_REDIS_SERVERS[TestRedisServers.OPEN]); await Promise.all([ client.connect(), @@ -195,6 +267,13 @@ describe('Client', () => { assert.equal(await client.sendCommand(['PING']), 'PONG'); }); + itWithClient(TestRedisServers.OPEN, 'bufferMode', async client => { + assert.deepEqual( + await client.sendCommand(['PING'], undefined, true), + Buffer.from('PONG') + ); + }); + describe('AbortController', () => { before(function () { if (!global.AbortController) { @@ -509,6 +588,9 @@ describe('Client', () => { assert.ok(channelListener1.calledOnce); assert.ok(channelListener2.calledTwice); assert.ok(patternListener.calledThrice); + + // should be able to send commands when unsubsribed from all channels (see #1652) + await assert.doesNotReject(subscriber.ping()); } finally { await subscriber.disconnect(); } @@ -540,9 +622,7 @@ describe('Client', () => { }); it('client.quit', async () => { - const client = RedisClient.create({ - socket: TEST_REDIS_SERVERS[TestRedisServers.OPEN] - }); + const client = RedisClient.create(TEST_REDIS_SERVERS[TestRedisServers.OPEN]); await client.connect(); diff --git a/lib/client.ts b/lib/client.ts index ed06317c14c..93afee1ff1a 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -1,6 +1,6 @@ -import RedisSocket, { RedisSocketOptions } from './socket'; +import RedisSocket, { RedisSocketOptions, RedisNetSocketOptions, RedisTlsSocketOptions } from './socket'; import RedisCommandsQueue, { PubSubListener, PubSubSubscribeCommands, PubSubUnsubscribeCommands, QueueCommandOptions } from './commands-queue'; -import COMMANDS from './commands'; +import COMMANDS, { TransformArgumentsReply } from './commands'; import { RedisCommand, RedisModules, RedisReply } from './commands'; import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command'; import EventEmitter from 'events'; @@ -12,9 +12,14 @@ import { HScanTuple } from './commands/HSCAN'; import { encodeCommand, extendWithDefaultCommands, extendWithModulesAndScripts, transformCommandArguments } from './commander'; import { Pool, Options as PoolOptions, createPool } from 'generic-pool'; import { ClientClosedError } from './errors'; +import { URL } from 'url'; -export interface RedisClientOptions { +export interface RedisClientOptions { + url?: string; socket?: RedisSocketOptions; + username?: string; + password?: string; + database?: number; modules?: M; scripts?: S; commandsQueueMaxLength?: number; @@ -43,55 +48,25 @@ type WithScripts = { export type WithPlugins = WithCommands & WithModules & WithScripts; -export type RedisClientType = +export type RedisClientType = WithPlugins & RedisClient; export interface ClientCommandOptions extends QueueCommandOptions { isolated?: boolean; } -export default class RedisClient extends EventEmitter { +export default class RedisClient extends EventEmitter { static commandOptions(options: ClientCommandOptions): CommandOptions { return commandOptions(options); } - static async commandsExecutor( - this: RedisClient, - command: RedisCommand, - args: Array - ): Promise> { - const { args: redisArgs, options } = transformCommandArguments(command, args); - - const reply = command.transformReply( - await this.#sendCommand(redisArgs, options), - redisArgs.preserve - ); - - return reply; - } - - static async #scriptsExecutor( - this: RedisClient, - script: RedisLuaScript, - args: Array - ): Promise { - const { args: redisArgs, options } = transformCommandArguments(script, args); - - const reply = script.transformReply( - await this.executeScript(script, redisArgs, options), - redisArgs.preserve - ); - - return reply; - } - - static create(options?: RedisClientOptions): RedisClientType { + static create(options?: RedisClientOptions): RedisClientType { const Client = (extendWithModulesAndScripts({ BaseClass: RedisClient, modules: options?.modules, - modulesCommandsExecutor: RedisClient.commandsExecutor, + modulesCommandsExecutor: RedisClient.prototype.commandsExecutor, scripts: options?.scripts, - scriptsExecutor: RedisClient.#scriptsExecutor + scriptsExecutor: RedisClient.prototype.scriptsExecutor })); if (Client !== RedisClient) { @@ -101,6 +76,45 @@ export default class RedisClient { + // https://www.iana.org/assignments/uri-schemes/prov/redis + const { hostname, port, protocol, username, password, pathname } = new URL(url), + parsed: RedisClientOptions<{}, {}> = { + socket: { + host: hostname + } + }; + + if (protocol === 'rediss:') { + (parsed.socket as RedisTlsSocketOptions).tls = true; + } else if (protocol !== 'redis:') { + throw new TypeError('Invalid protocol'); + } + + if (port) { + (parsed.socket as RedisNetSocketOptions).port = Number(port); + } + + if (username) { + parsed.username = username; + } + + if (password) { + parsed.password = password; + } + + if (pathname.length > 1) { + const database = Number(pathname.substring(1)); + if (isNaN(database)) { + throw new TypeError('Invalid pathname'); + } + + parsed.database = database; + } + + return parsed; + } + readonly #options?: RedisClientOptions; readonly #socket: RedisSocket; readonly #queue: RedisCommandsQueue; @@ -108,7 +122,7 @@ export default class RedisClient = {}; #selectedDB = 0; - get options(): RedisClientOptions | null | undefined { + get options(): RedisClientOptions | undefined { return this.#options; } @@ -126,7 +140,7 @@ export default class RedisClient) { super(); - this.#options = options; + this.#options = this.#initiateOptions(options); this.#socket = this.#initiateSocket(); this.#queue = this.#initiateQueue(); this.#isolationPool = createPool({ @@ -140,6 +154,23 @@ export default class RedisClient): RedisClientOptions | undefined { + if (options?.url) { + const parsed = RedisClient.parseURL(options.url); + if (options.socket) { + parsed.socket = Object.assign(options.socket, parsed.socket); + } + + Object.assign(options, parsed); + } + + if (options?.database) { + this.#selectedDB = options.database; + } + + return options; + } + #initiateSocket(): RedisSocket { const socketInitiator = async (): Promise => { const v4Commands = this.#options?.legacyMode ? this.#v4 : this, @@ -153,8 +184,8 @@ export default class RedisClient this.#socket.write(encodedCommands) - ); + return new RedisCommandsQueue(this.#options?.commandsQueueMaxLength); } #legacyMode(): void { @@ -247,6 +275,72 @@ export default class RedisClient): Promise> { + const { args: redisArgs, options } = transformCommandArguments(command, args); + + return command.transformReply( + await this.#sendCommand(redisArgs, options, command.BUFFER_MODE), + redisArgs.preserve, + ); + } + + sendCommand(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise { + return this.#sendCommand(args, options, bufferMode); + } + + // using `#sendCommand` cause `sendCommand` is overwritten in legacy mode + async #sendCommand(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise { + if (!this.#socket.isOpen) { + throw new ClientClosedError(); + } + + if (options?.isolated) { + return this.executeIsolated(isolatedClient => + isolatedClient.sendCommand(args, { + ...options, + isolated: false + }) + ); + } + + const promise = this.#queue.addCommand(args, options, bufferMode); + this.#tick(); + return await promise; + } + + async scriptsExecutor(script: RedisLuaScript, args: Array): Promise> { + const { args: redisArgs, options } = transformCommandArguments(script, args); + + return script.transformReply( + await this.executeScript(script, redisArgs, options, script.BUFFER_MODE), + redisArgs.preserve + ); + } + + async executeScript(script: RedisLuaScript, args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise> { + try { + return await this.#sendCommand([ + 'EVALSHA', + script.SHA1, + script.NUMBER_OF_KEYS.toString(), + ...args + ], options, bufferMode); + } catch (err: any) { + if (!err?.message?.startsWith?.('NOSCRIPT')) { + throw err; + } + + return await this.#sendCommand([ + 'EVAL', + script.SCRIPT, + script.NUMBER_OF_KEYS.toString(), + ...args + ], options, bufferMode); + } + } + + + async SELECT(db: number): Promise; async SELECT(options: CommandOptions, db: number): Promise; async SELECT(options?: any, db?: any): Promise { @@ -299,7 +393,7 @@ export default class RedisClient { return this.#socket.quit(() => { - const promise = this.#queue.addEncodedCommand(encodeCommand(['QUIT'])); + const promise = this.#queue.addCommand(['QUIT']); this.#tick(); return promise; }); @@ -307,64 +401,43 @@ export default class RedisClient(args: Array, options?: ClientCommandOptions): Promise { - return this.#sendCommand(args, options); - } + #tick(): void { + if (!this.#socket.isSocketExists) { + return; + } - // using `#sendCommand` cause `sendCommand` is overwritten in legacy mode - #sendCommand(args: Array, options?: ClientCommandOptions): Promise { - return this.sendEncodedCommand(encodeCommand(args), options); - } + this.#socket.cork(); - async sendEncodedCommand(encodedCommand: string, options?: ClientCommandOptions): Promise { - if (!this.#socket.isOpen) { - throw new ClientClosedError(); - } + while (true) { + const args = this.#queue.getCommandToSend(); + if (args === undefined) break; - if (options?.isolated) { - return this.executeIsolated(isolatedClient => - isolatedClient.sendEncodedCommand(encodedCommand, { - ...options, - isolated: false - }) - ); - } + let writeResult; + for (const toWrite of encodeCommand(args)) { + writeResult = this.#socket.write(toWrite); + } - const promise = this.#queue.addEncodedCommand(encodedCommand, options); - this.#tick(); - return await promise; + if (!writeResult) { + break; + } + } } executeIsolated(fn: (client: RedisClientType) => T | Promise): Promise { return this.#isolationPool.use(fn); } - async executeScript(script: RedisLuaScript, args: Array, options?: ClientCommandOptions): Promise> { - try { - return await this.#sendCommand([ - 'EVALSHA', - script.SHA1, - script.NUMBER_OF_KEYS.toString(), - ...args - ], options); - } catch (err: any) { - if (!err?.message?.startsWith?.('NOSCRIPT')) { - throw err; - } - - return await this.#sendCommand([ - 'EVAL', - script.SCRIPT, - script.NUMBER_OF_KEYS.toString(), - ...args - ], options); - } + multi(): RedisMultiCommandType { + return new (this as any).Multi( + this.#multiExecutor.bind(this), + this.#options + ); } #multiExecutor(commands: Array, chainId?: symbol): Promise> { const promise = Promise.all( - commands.map(({encodedCommand}) => { - return this.#queue.addEncodedCommand(encodedCommand, RedisClient.commandOptions({ + commands.map(({ args }) => { + return this.#queue.addCommand(args, RedisClient.commandOptions({ chainId })); }) @@ -375,13 +448,6 @@ export default class RedisClient { - return new (this as any).Multi( - this.#multiExecutor.bind(this), - this.#options - ); - } - async* scanIterator(options?: ScanCommandOptions): AsyncIterable { let cursor = 0; do { @@ -438,32 +504,7 @@ export default class RedisClient this.#tick()); - this.#isTickQueued = true; - return; - } - - const isBuffering = this.#queue.executeChunk(chunkRecommendedSize); - if (isBuffering === true) { - this.#socket.once('drain', () => this.#tick()); - } else if (isBuffering === false) { - this.#tick(); - return; - } - - this.#isTickQueued = false; - } } -extendWithDefaultCommands(RedisClient, RedisClient.commandsExecutor); +extendWithDefaultCommands(RedisClient, RedisClient.prototype.commandsExecutor); (RedisClient.prototype as any).Multi = RedisMultiCommand.extend(); diff --git a/lib/cluster-slots.ts b/lib/cluster-slots.ts index 5fae5b92342..a5155cc53db 100644 --- a/lib/cluster-slots.ts +++ b/lib/cluster-slots.ts @@ -172,7 +172,7 @@ export default class RedisClusterSlots { + getClient(firstKey?: string | Buffer, isReadonly?: boolean): RedisClientType { if (!firstKey) { return this.#getRandomClient(); } diff --git a/lib/cluster.ts b/lib/cluster.ts index 2c1b23465ee..4be0e268207 100644 --- a/lib/cluster.ts +++ b/lib/cluster.ts @@ -1,4 +1,4 @@ -import { RedisCommand, RedisModules } from './commands'; +import { RedisCommand, RedisModules, TransformArgumentsReply } from './commands'; import RedisClient, { ClientCommandOptions, RedisClientType, WithPlugins } from './client'; import { RedisSocketOptions } from './socket'; import RedisClusterSlots, { ClusterNode } from './cluster-slots'; @@ -15,11 +15,11 @@ export interface RedisClusterOptions { maxCommandRedirections?: number; } -export type RedisClusterType = - WithPlugins & RedisCluster; +export type RedisClusterType = + WithPlugins & RedisCluster; -export default class RedisCluster extends EventEmitter { - static #extractFirstKey(command: RedisCommand, originalArgs: Array, redisArgs: Array): string | undefined { +export default class RedisCluster extends EventEmitter { + static #extractFirstKey(command: RedisCommand, originalArgs: Array, redisArgs: TransformArgumentsReply): string | Buffer | undefined { if (command.FIRST_KEY_INDEX === undefined) { return undefined; } else if (typeof command.FIRST_KEY_INDEX === 'number') { @@ -29,53 +29,13 @@ export default class RedisCluster - ): Promise> { - const { args: redisArgs, options } = transformCommandArguments(command, args); - - const reply = command.transformReply( - await this.sendCommand( - RedisCluster.#extractFirstKey(command, args, redisArgs), - command.IS_READ_ONLY, - redisArgs, - options - ), - redisArgs.preserve - ); - - return reply; - } - - static async #scriptsExecutor( - this: RedisCluster, - script: RedisLuaScript, - args: Array - ): Promise { - const { args: redisArgs, options } = transformCommandArguments(script, args); - - const reply = script.transformReply( - await this.executeScript( - script, - args, - redisArgs, - options - ), - redisArgs.preserve - ); - - return reply; - } - - static create(options?: RedisClusterOptions): RedisClusterType { + static create(options?: RedisClusterOptions): RedisClusterType { return new (extendWithModulesAndScripts({ BaseClass: RedisCluster, modules: options?.modules, - modulesCommandsExecutor: RedisCluster.commandsExecutor, + modulesCommandsExecutor: RedisCluster.prototype.commandsExecutor, scripts: options?.scripts, - scriptsExecutor: RedisCluster.#scriptsExecutor + scriptsExecutor: RedisCluster.prototype.scriptsExecutor }))(options); } @@ -91,37 +51,75 @@ export default class RedisCluster { + return new (Object.getPrototypeOf(this).constructor)(this.#options); + } + async connect(): Promise { return this.#slots.connect(); } + async commandsExecutor(command: RedisCommand, args: Array): Promise> { + const { args: redisArgs, options } = transformCommandArguments(command, args); + + const reply = command.transformReply( + await this.sendCommand( + RedisCluster.#extractFirstKey(command, args, redisArgs), + command.IS_READ_ONLY, + redisArgs, + options, + command.BUFFER_MODE + ), + redisArgs.preserve + ); + + return reply; + } + async sendCommand( - firstKey: string | undefined, + firstKey: string | Buffer | undefined, isReadonly: boolean | undefined, - args: Array, + args: TransformArgumentsReply, options?: ClientCommandOptions, + bufferMode?: boolean, redirections = 0 ): Promise> { const client = this.#slots.getClient(firstKey, isReadonly); try { - return await client.sendCommand(args, options); + return await client.sendCommand(args, options, bufferMode); } catch (err: any) { const shouldRetry = await this.#handleCommandError(err, client, redirections); if (shouldRetry === true) { - return this.sendCommand(firstKey, isReadonly, args, options, redirections + 1); + return this.sendCommand(firstKey, isReadonly, args, options, bufferMode, redirections + 1); } else if (shouldRetry) { - return shouldRetry.sendCommand(args, options); + return shouldRetry.sendCommand(args, options, bufferMode); } throw err; } } + async scriptsExecutor(script: RedisLuaScript, args: Array): Promise> { + const { args: redisArgs, options } = transformCommandArguments(script, args); + + const reply = script.transformReply( + await this.executeScript( + script, + args, + redisArgs, + options + ), + redisArgs.preserve + ); + + return reply; + } + async executeScript( script: RedisLuaScript, originalArgs: Array, - redisArgs: Array, + redisArgs: TransformArgumentsReply, options?: ClientCommandOptions, redirections = 0 ): Promise> { @@ -131,13 +129,13 @@ export default class RedisCluster { - return client.sendEncodedCommand(encodedCommand, RedisClient.commandOptions({ + commands.map(({ args }) => { + return client.sendCommand(args, RedisClient.commandOptions({ chainId })); }) @@ -201,5 +199,4 @@ export default class RedisCluster): string { + const arr = []; + for (const item of encodeCommand(...args)) { + arr.push(item.toString()); + } + + return arr.join(''); +} + describe('Commander', () => { describe('encodeCommand (see #1628)', () => { it('1 byte', () => { assert.equal( - encodeCommand(['a', 'z']), + encodeCommandToString(['a', 'z']), '*2\r\n$1\r\na\r\n$1\r\nz\r\n' ); }); it('2 bytes', () => { assert.equal( - encodeCommand(['א', 'ת']), + encodeCommandToString(['א', 'ת']), '*2\r\n$2\r\nא\r\n$2\r\nת\r\n' ); }); it('4 bytes', () => { assert.equal( - encodeCommand(['🐣', '🐤']), + encodeCommandToString(['🐣', '🐤']), '*2\r\n$4\r\n🐣\r\n$4\r\n🐤\r\n' ); }); + + it('with a buffer', () => { + assert.equal( + encodeCommandToString([Buffer.from('string')]), + '*1\r\n$6\r\nstring\r\n' + ); + }); }); }); diff --git a/lib/commander.ts b/lib/commander.ts index e8ff91cc7bf..78823516448 100644 --- a/lib/commander.ts +++ b/lib/commander.ts @@ -94,16 +94,15 @@ export function transformCommandArguments( }; } -export function encodeCommand(args: Array): string { - const encoded = [ - `*${args.length}`, - `$${Buffer.byteLength(args[0]).toString()}`, - args[0] - ]; - - for (let i = 1; i < args.length; i++) { - encoded.push(`$${Buffer.byteLength(args[i]).toString()}`, args[i]); - } +const DELIMITER = '\r\n'; + +export function* encodeCommand(args: TransformArgumentsReply): IterableIterator { + yield `*${args.length}${DELIMITER}`; - return encoded.join('\r\n') + '\r\n'; + for (const arg of args) { + const byteLength = typeof arg === 'string' ? Buffer.byteLength(arg): arg.length; + yield `$${byteLength.toString()}${DELIMITER}`; + yield arg; + yield DELIMITER; + } } diff --git a/lib/commands-queue.ts b/lib/commands-queue.ts index cae3fd6130e..ef87184193f 100644 --- a/lib/commands-queue.ts +++ b/lib/commands-queue.ts @@ -2,17 +2,15 @@ import LinkedList from 'yallist'; import RedisParser from 'redis-parser'; import { AbortError } from './errors'; import { RedisReply } from './commands'; -import { encodeCommand } from './commander'; export interface QueueCommandOptions { asap?: boolean; - signal?: any; // TODO: `AbortSignal` type is incorrect chainId?: symbol; + signal?: any; // TODO: `AbortSignal` type is incorrect } interface CommandWaitingToBeSent extends CommandWaitingForReply { - encodedCommand: string; - byteLength: number; + args: Array; chainId?: symbol; abort?: { signal: any; // TODO: `AbortSignal` type is incorrect @@ -24,10 +22,9 @@ interface CommandWaitingForReply { resolve(reply?: any): void; reject(err: Error): void; channelsCounter?: number; + bufferMode?: boolean; } -export type CommandsQueueExecutor = (encodedCommands: string) => boolean | undefined; - export enum PubSubSubscribeCommands { SUBSCRIBE = 'SUBSCRIBE', PSUBSCRIBE = 'PSUBSCRIBE' @@ -57,16 +54,8 @@ export default class RedisCommandsQueue { readonly #maxLength: number | null | undefined; - readonly #executor: CommandsQueueExecutor; - readonly #waitingToBeSent = new LinkedList(); - #waitingToBeSentCommandsLength = 0; - - get waitingToBeSentCommandsLength() { - return this.#waitingToBeSentCommandsLength; - } - readonly #waitingForReply = new LinkedList(); readonly #pubSubState = { @@ -114,12 +103,11 @@ export default class RedisCommandsQueue { #chainInExecution: symbol | undefined; - constructor(maxLength: number | null | undefined, executor: CommandsQueueExecutor) { + constructor(maxLength: number | null | undefined) { this.#maxLength = maxLength; - this.#executor = executor; } - addEncodedCommand(encodedCommand: string, options?: QueueCommandOptions): Promise { + addCommand(args: Array, options?: QueueCommandOptions, bufferMode?: boolean): Promise { if (this.#pubSubState.subscribing || this.#pubSubState.subscribed) { return Promise.reject(new Error('Cannot send commands in PubSub mode')); } else if (this.#maxLength && this.#waitingToBeSent.length + this.#waitingForReply.length >= this.#maxLength) { @@ -130,11 +118,11 @@ export default class RedisCommandsQueue { return new Promise((resolve, reject) => { const node = new LinkedList.Node({ - encodedCommand, - byteLength: Buffer.byteLength(encodedCommand), + args, chainId: options?.chainId, + bufferMode, resolve, - reject + reject, }); if (options?.signal) { @@ -157,8 +145,6 @@ export default class RedisCommandsQueue { } else { this.#waitingToBeSent.pushNode(node); } - - this.#waitingToBeSentCommandsLength += node.value.byteLength; }); } @@ -185,8 +171,9 @@ export default class RedisCommandsQueue { unsubscribe(command: PubSubUnsubscribeCommands, channels?: string | Array, listener?: PubSubListener): Promise { const listeners = command === PubSubUnsubscribeCommands.UNSUBSCRIBE ? this.#pubSubListeners.channels : this.#pubSubListeners.patterns; if (!channels) { + const size = listeners.size; listeners.clear(); - return this.#pushPubSubCommand(command); + return this.#pushPubSubCommand(command, size); } const channelsToUnsubscribe = []; @@ -213,31 +200,24 @@ export default class RedisCommandsQueue { return this.#pushPubSubCommand(command, channelsToUnsubscribe); } - #pushPubSubCommand(command: PubSubSubscribeCommands | PubSubUnsubscribeCommands, channels?: Array): Promise { + #pushPubSubCommand(command: PubSubSubscribeCommands | PubSubUnsubscribeCommands, channels: number | Array): Promise { return new Promise((resolve, reject) => { const isSubscribe = command === PubSubSubscribeCommands.SUBSCRIBE || command === PubSubSubscribeCommands.PSUBSCRIBE, inProgressKey = isSubscribe ? 'subscribing' : 'unsubscribing', commandArgs: Array = [command]; + let channelsCounter: number; - if (channels?.length) { + if (typeof channels === 'number') { // unsubscribe only + channelsCounter = channels; + } else { commandArgs.push(...channels); channelsCounter = channels.length; - } else { - // unsubscribe only - channelsCounter = ( - command[0] === 'P' ? - this.#pubSubListeners.patterns : - this.#pubSubListeners.channels - ).size; } this.#pubSubState[inProgressKey] += channelsCounter; - const encodedCommand = encodeCommand(commandArgs), - byteLength = Buffer.byteLength(encodedCommand); this.#waitingToBeSent.push({ - encodedCommand, - byteLength, + args: commandArgs, channelsCounter, resolve: () => { this.#pubSubState[inProgressKey] -= channelsCounter; @@ -249,7 +229,6 @@ export default class RedisCommandsQueue { reject(); } }); - this.#waitingToBeSentCommandsLength += byteLength; }); } @@ -267,47 +246,25 @@ export default class RedisCommandsQueue { ]); } - executeChunk(recommendedSize: number): boolean | undefined { - if (!this.#waitingToBeSent.length) return; - - const encoded: Array = []; - let size = 0, - lastCommandChainId: symbol | undefined; - for (const command of this.#waitingToBeSent) { - encoded.push(command.encodedCommand); - size += command.byteLength; - if (size > recommendedSize) { - lastCommandChainId = command.chainId; - break; - } - } - - if (!lastCommandChainId && encoded.length === this.#waitingToBeSent.length) { - lastCommandChainId = this.#waitingToBeSent.tail!.value.chainId; - } - - lastCommandChainId ??= this.#waitingToBeSent.tail?.value.chainId; - - this.#executor(encoded.join('')); - - for (let i = 0; i < encoded.length; i++) { - const waitingToBeSent = this.#waitingToBeSent.shift()!; - if (waitingToBeSent.abort) { - waitingToBeSent.abort.signal.removeEventListener('abort', waitingToBeSent.abort.listener); - } + getCommandToSend(): Array | undefined { + const toSend = this.#waitingToBeSent.shift(); + if (toSend) { this.#waitingForReply.push({ - resolve: waitingToBeSent.resolve, - reject: waitingToBeSent.reject, - channelsCounter: waitingToBeSent.channelsCounter + resolve: toSend.resolve, + reject: toSend.reject, + channelsCounter: toSend.channelsCounter, + bufferMode: toSend.bufferMode }); } - this.#chainInExecution = lastCommandChainId; - this.#waitingToBeSentCommandsLength -= size; + this.#chainInExecution = toSend?.chainId; + + return toSend?.args; } parseResponse(data: Buffer): void { + this.#parser.setReturnBuffers(!!this.#waitingForReply.head?.value.bufferMode); this.#parser.execute(data); } diff --git a/lib/commands/ACL_DELUSER.ts b/lib/commands/ACL_DELUSER.ts index 7fb4904be41..85a916c4379 100644 --- a/lib/commands/ACL_DELUSER.ts +++ b/lib/commands/ACL_DELUSER.ts @@ -1,6 +1,7 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; -export function transformArguments(username: string | Array): Array { +export function transformArguments(username: string | Array): TransformArgumentsReply { return pushVerdictArguments(['ACL', 'DELUSER'], username); } diff --git a/lib/commands/ACL_SETUSER.ts b/lib/commands/ACL_SETUSER.ts index b2829ca964f..e55a8942e02 100644 --- a/lib/commands/ACL_SETUSER.ts +++ b/lib/commands/ACL_SETUSER.ts @@ -1,6 +1,7 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyString } from './generic-transformers'; -export function transformArguments(username: string, rule: string | Array): Array { +export function transformArguments(username: string, rule: string | Array): TransformArgumentsReply { return pushVerdictArguments(['ACL', 'SETUSER', username], rule); } diff --git a/lib/commands/BITOP.ts b/lib/commands/BITOP.ts index fe7d339f5d1..bb965da6dfa 100644 --- a/lib/commands/BITOP.ts +++ b/lib/commands/BITOP.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 2; type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT'; -export function transformArguments(operation: BitOperations, destKey: string, key: string | Array): Array { +export function transformArguments(operation: BitOperations, destKey: string, key: string | Array): TransformArgumentsReply { return pushVerdictArguments(['BITOP', operation, destKey], key); } diff --git a/lib/commands/BLPOP.ts b/lib/commands/BLPOP.ts index 7c352951fb3..1061f5e113a 100644 --- a/lib/commands/BLPOP.ts +++ b/lib/commands/BLPOP.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(keys: string | Array, timeout: number): Array { +export function transformArguments(keys: string | Buffer | Array, timeout: number): TransformArgumentsReply { const args = pushVerdictArguments(['BLPOP'], keys); args.push(timeout.toString()); diff --git a/lib/commands/BRPOP.ts b/lib/commands/BRPOP.ts index a03c278309a..93ded4dbf1a 100644 --- a/lib/commands/BRPOP.ts +++ b/lib/commands/BRPOP.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string | Array, timeout: number): Array { +export function transformArguments(key: string | Array, timeout: number): TransformArgumentsReply { const args = pushVerdictArguments(['BRPOP'], key); args.push(timeout.toString()); diff --git a/lib/commands/BZPOPMAX.ts b/lib/commands/BZPOPMAX.ts index ccd84272a50..3db9ca42cbb 100644 --- a/lib/commands/BZPOPMAX.ts +++ b/lib/commands/BZPOPMAX.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string | Array, timeout: number): Array { +export function transformArguments(key: string | Array, timeout: number): TransformArgumentsReply { const args = pushVerdictArguments(['BZPOPMAX'], key); args.push(timeout.toString()); diff --git a/lib/commands/BZPOPMIN.ts b/lib/commands/BZPOPMIN.ts index 0c299cdb9df..9106ae770da 100644 --- a/lib/commands/BZPOPMIN.ts +++ b/lib/commands/BZPOPMIN.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string | Array, timeout: number): Array { +export function transformArguments(key: string | Array, timeout: number): TransformArgumentsReply { const args = pushVerdictArguments(['BZPOPMIN'], key); args.push(timeout.toString()); diff --git a/lib/commands/CLUSTER_SLOTS.spec.ts b/lib/commands/CLUSTER_SLOTS.spec.ts new file mode 100644 index 00000000000..ec6773bcdd4 --- /dev/null +++ b/lib/commands/CLUSTER_SLOTS.spec.ts @@ -0,0 +1,76 @@ +import { strict as assert } from 'assert'; +import { transformArguments, transformReply } from './CLUSTER_SLOTS'; + +describe('CLUSTER SLOTS', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments(), + ['CLUSTER', 'SLOTS'] + ); + }); + + it('transformReply', () => { + assert.deepEqual( + transformReply([ + [ + 0, + 5460, + ['127.0.0.1', 30001, '09dbe9720cda62f7865eabc5fd8857c5d2678366'], + ['127.0.0.1', 30004, '821d8ca00d7ccf931ed3ffc7e3db0599d2271abf'] + ], + [ + 5461, + 10922, + ['127.0.0.1', 30002, 'c9d93d9f2c0c524ff34cc11838c2003d8c29e013'], + ['127.0.0.1', 30005, 'faadb3eb99009de4ab72ad6b6ed87634c7ee410f'] + ], + [ + 10923, + 16383, + ['127.0.0.1', 30003, '044ec91f325b7595e76dbcb18cc688b6a5b434a1'], + ['127.0.0.1', 30006, '58e6e48d41228013e5d9c1c37c5060693925e97e'] + ] + ]), + [{ + from: 0, + to: 5460, + master: { + ip: '127.0.0.1', + port: 30001, + id: '09dbe9720cda62f7865eabc5fd8857c5d2678366' + }, + replicas: [{ + ip: '127.0.0.1', + port: 30004, + id: '821d8ca00d7ccf931ed3ffc7e3db0599d2271abf' + }] + }, { + from: 5461, + to: 10922, + master: { + ip: '127.0.0.1', + port: 30002, + id: 'c9d93d9f2c0c524ff34cc11838c2003d8c29e013' + }, + replicas: [{ + ip: '127.0.0.1', + port: 30005, + id: 'faadb3eb99009de4ab72ad6b6ed87634c7ee410f' + }] + }, { + from: 10923, + to: 16383, + master: { + ip: '127.0.0.1', + port: 30003, + id: '044ec91f325b7595e76dbcb18cc688b6a5b434a1' + }, + replicas: [{ + ip: '127.0.0.1', + port: 30006, + id: '58e6e48d41228013e5d9c1c37c5060693925e97e' + }] + }] + ) + }); +}); diff --git a/lib/commands/CLUSTER_SLOTS.ts b/lib/commands/CLUSTER_SLOTS.ts new file mode 100644 index 00000000000..b4672e731ac --- /dev/null +++ b/lib/commands/CLUSTER_SLOTS.ts @@ -0,0 +1,41 @@ +import { TransformArgumentsReply } from '.'; + +export function transformArguments(): TransformArgumentsReply { + return ['CLUSTER', 'SLOTS']; +} + +type ClusterSlotsRawNode = [ip: string, port: number, id: string]; + +type ClusterSlotsRawReply = Array<[from: number, to: number, master: ClusterSlotsRawNode, ...replicas: Array]>; + +type ClusterSlotsNode = { + ip: string; + port: number; + id: string; +}; + +export type ClusterSlotsReply = Array<{ + from: number; + to: number; + master: ClusterSlotsNode; + replicas: Array; +}>; + +export function transformReply(reply: ClusterSlotsRawReply): ClusterSlotsReply { + return reply.map(([from, to, master, ...replicas]) => { + return { + from, + to, + master: transformNode(master), + replicas: replicas.map(transformNode) + }; + }); +} + +function transformNode([ip, port, id]: ClusterSlotsRawNode): ClusterSlotsNode { + return { + ip, + port, + id + }; +} diff --git a/lib/commands/DEL.ts b/lib/commands/DEL.ts index 3d9a78212f8..f96b6988f1c 100644 --- a/lib/commands/DEL.ts +++ b/lib/commands/DEL.ts @@ -1,6 +1,7 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; -export function transformArguments(keys: string | Array): Array { +export function transformArguments(keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['DEL'], keys); } diff --git a/lib/commands/EXISTS.ts b/lib/commands/EXISTS.ts index 5a76ca833fb..00d10b9eebc 100644 --- a/lib/commands/EXISTS.ts +++ b/lib/commands/EXISTS.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; export const IS_READ_ONLY = true; -export function transformArguments(keys: string | Array): Array { +export function transformArguments(keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['EXISTS'], keys); } diff --git a/lib/commands/GEOHASH.ts b/lib/commands/GEOHASH.ts index a46738955d3..a95ae443408 100644 --- a/lib/commands/GEOHASH.ts +++ b/lib/commands/GEOHASH.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; export const IS_READ_ONLY = true; -export function transformArguments(key: string, member: string | Array): Array { +export function transformArguments(key: string, member: string | Array): TransformArgumentsReply { return pushVerdictArguments(['GEOHASH', key], member); } diff --git a/lib/commands/GEOPOS.spec.ts b/lib/commands/GEOPOS.spec.ts index 98cfa6aa2d3..e15abeff516 100644 --- a/lib/commands/GEOPOS.spec.ts +++ b/lib/commands/GEOPOS.spec.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils'; -import { transformArguments } from './GEOPOS'; +import { transformArguments, transformReply } from './GEOPOS'; describe('GEOPOS', () => { describe('transformArguments', () => { @@ -19,11 +19,49 @@ describe('GEOPOS', () => { }); }); - itWithClient(TestRedisServers.OPEN, 'client.geoPos', async client => { - assert.deepEqual( - await client.geoPos('key', 'member'), - [null] - ); + describe('transformReply', () => { + it('null', () => { + assert.deepEqual( + transformReply([null]), + [null] + ); + }); + + it('with member', () => { + assert.deepEqual( + transformReply([['1', '2']]), + [{ + longitude: '1', + latitude: '2' + }] + ); + }); + }); + + describe('client.geoPos', () => { + itWithClient(TestRedisServers.OPEN, 'null', async client => { + assert.deepEqual( + await client.geoPos('key', 'member'), + [null] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'with member', async client => { + const coordinates = { + longitude: '-122.06429868936538696', + latitude: '37.37749628831998194' + }; + + await client.geoAdd('key', { + member: 'member', + ...coordinates + }); + + assert.deepEqual( + await client.geoPos('key', 'member'), + [coordinates] + ); + }); }); itWithCluster(TestRedisClusters.OPEN, 'cluster.geoPos', async cluster => { diff --git a/lib/commands/GEOPOS.ts b/lib/commands/GEOPOS.ts index 46b0a153ba9..893048cf6da 100644 --- a/lib/commands/GEOPOS.ts +++ b/lib/commands/GEOPOS.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; export const IS_READ_ONLY = true; -export function transformArguments(key: string, member: string | Array): Array { +export function transformArguments(key: string, member: string | Array): TransformArgumentsReply { return pushVerdictArguments(['GEOPOS', key], member); } diff --git a/lib/commands/GEOSEARCHSTORE.spec.ts b/lib/commands/GEOSEARCHSTORE.spec.ts index 1983537077c..ad33c62b78c 100644 --- a/lib/commands/GEOSEARCHSTORE.spec.ts +++ b/lib/commands/GEOSEARCHSTORE.spec.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster, describeHandleMinimumRedisVersion } from '../test-utils'; -import { transformArguments } from './GEOSEARCHSTORE'; +import { transformArguments, transformReply } from './GEOSEARCHSTORE'; describe('GEOSEARCHSTORE', () => { describeHandleMinimumRedisVersion([6, 2]); @@ -40,6 +40,13 @@ describe('GEOSEARCHSTORE', () => { }); }); + it('transformReply with empty array (https://github.com/redis/redis/issues/9261)', () => { + assert.throws( + () => (transformReply as any)([]), + TypeError + ); + }); + itWithClient(TestRedisServers.OPEN, 'client.geoSearchStore', async client => { await client.geoAdd('source', { longitude: 1, diff --git a/lib/commands/GET.ts b/lib/commands/GET.ts index 714ad953d8e..541790e54e4 100644 --- a/lib/commands/GET.ts +++ b/lib/commands/GET.ts @@ -1,11 +1,12 @@ -import { transformReplyString } from './generic-transformers'; +import { TransformArgumentsReply } from '.'; +import { transformReplyStringNull } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; export const IS_READ_ONLY = true; -export function transformArguments(key: string): Array { +export function transformArguments(key: string | Buffer): TransformArgumentsReply { return ['GET', key]; } -export const transformReply = transformReplyString; +export const transformReply = transformReplyStringNull; diff --git a/lib/commands/GETEX.ts b/lib/commands/GETEX.ts index ca1465b7ee5..214dae5c7ab 100644 --- a/lib/commands/GETEX.ts +++ b/lib/commands/GETEX.ts @@ -1,3 +1,4 @@ +import { TransformArgumentsReply } from '.'; import { transformEXAT, transformPXAT, transformReplyStringNull } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; @@ -14,7 +15,7 @@ type GetExModes = { PERSIST: true; }; -export function transformArguments(key: string, mode: GetExModes) { +export function transformArguments(key: string, mode: GetExModes): TransformArgumentsReply { const args = ['GETEX', key]; if ('EX' in mode) { diff --git a/lib/commands/GET_BUFFER.spec.ts b/lib/commands/GET_BUFFER.spec.ts new file mode 100644 index 00000000000..533eb808c49 --- /dev/null +++ b/lib/commands/GET_BUFFER.spec.ts @@ -0,0 +1,22 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils'; + +describe('GET_BUFFER', () => { + itWithClient(TestRedisServers.OPEN, 'client.getBuffer', async client => { + const buffer = Buffer.from('string'); + await client.set('key', buffer); + assert.deepEqual( + buffer, + await client.getBuffer('key') + ); + }); + + itWithCluster(TestRedisClusters.OPEN, 'cluster.getBuffer', async cluster => { + const buffer = Buffer.from('string'); + await cluster.set('key', buffer); + assert.deepEqual( + buffer, + await cluster.getBuffer('key') + ); + }); +}); diff --git a/lib/commands/GET_BUFFER.ts b/lib/commands/GET_BUFFER.ts new file mode 100644 index 00000000000..9d281961130 --- /dev/null +++ b/lib/commands/GET_BUFFER.ts @@ -0,0 +1,7 @@ +import { transformReplyBufferNull } from './generic-transformers'; + +export { FIRST_KEY_INDEX, IS_READ_ONLY, transformArguments } from './GET'; + +export const BUFFER_MODE = true; + +export const transformReply = transformReplyBufferNull; diff --git a/lib/commands/HDEL.ts b/lib/commands/HDEL.ts index ee961931449..4785b0e67f9 100644 --- a/lib/commands/HDEL.ts +++ b/lib/commands/HDEL.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, field: string | Array): Array { +export function transformArguments(key: string, field: string | Array): TransformArgumentsReply { return pushVerdictArguments(['HDEL', key], field); } diff --git a/lib/commands/HMGET.ts b/lib/commands/HMGET.ts index fc0f91d8224..9f26eeba640 100644 --- a/lib/commands/HMGET.ts +++ b/lib/commands/HMGET.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; export const IS_READ_ONLY = true; -export function transformArguments(key: string, fields: string | Array): Array { +export function transformArguments(key: string, fields: string | Array): TransformArgumentsReply { return pushVerdictArguments(['HMGET', key], fields); } diff --git a/lib/commands/HSET.spec.ts b/lib/commands/HSET.spec.ts index af7bcb6eb20..601e7f967e1 100644 --- a/lib/commands/HSET.spec.ts +++ b/lib/commands/HSET.spec.ts @@ -4,6 +4,13 @@ import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from describe('HSET', () => { describe('transformArguments', () => { + it('field, value', () => { + assert.deepEqual( + transformArguments('key', 'field', 'value'), + ['HSET', 'key', 'field', 'value'] + ); + }); + it('Map', () => { assert.deepEqual( transformArguments('key', new Map([['field', 'value']])), @@ -30,7 +37,7 @@ describe('HSET', () => { itWithClient(TestRedisServers.OPEN, 'client.hSet', async client => { assert.equal( - await client.hSet('key', { field: 'value' }), + await client.hSet('key', 'field', 'value'), 1 ); }); diff --git a/lib/commands/HSET.ts b/lib/commands/HSET.ts index 3edaa64b4e8..cbd46061ad8 100644 --- a/lib/commands/HSET.ts +++ b/lib/commands/HSET.ts @@ -1,3 +1,4 @@ +import { TransformArgumentsReply } from '.'; import { transformReplyString } from './generic-transformers'; type HSETObject = Record; @@ -8,10 +9,18 @@ type HSETTuples = Array<[string, string]> | Array; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, value: HSETObject | HSETMap | HSETTuples): Array { +type GenericArguments = [key: string]; + +type SingleFieldArguments = [...generic: GenericArguments, field: string, value: string]; + +type MultipleFieldsArguments = [...generic: GenericArguments, value: HSETObject | HSETMap | HSETTuples]; + +export function transformArguments(...[ key, value, fieldValue ]: SingleFieldArguments | MultipleFieldsArguments): TransformArgumentsReply { const args = ['HSET', key]; - if (value instanceof Map) { + if (typeof value === 'string') { + args.push(value, fieldValue!); + } else if (value instanceof Map) { pushMap(args, value); } else if (Array.isArray(value)) { pushTuples(args, value); diff --git a/lib/commands/LPUSH.ts b/lib/commands/LPUSH.ts index 434ad619cb7..7416d4946ea 100644 --- a/lib/commands/LPUSH.ts +++ b/lib/commands/LPUSH.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, elements: string | Array): Array { +export function transformArguments(key: string, elements: string | Array): TransformArgumentsReply { return pushVerdictArguments(['LPUSH', key], elements);} export const transformReply = transformReplyNumber; diff --git a/lib/commands/LPUSHX.ts b/lib/commands/LPUSHX.ts index f1a989d9625..f89623ace3a 100644 --- a/lib/commands/LPUSHX.ts +++ b/lib/commands/LPUSHX.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, element: string | Array): Array { +export function transformArguments(key: string, element: string | Array): TransformArgumentsReply { return pushVerdictArguments(['LPUSHX', key], element); } diff --git a/lib/commands/PFADD.ts b/lib/commands/PFADD.ts index 3348a98852a..cc99bed7f65 100644 --- a/lib/commands/PFADD.ts +++ b/lib/commands/PFADD.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, element: string | Array): Array { +export function transformArguments(key: string, element: string | Array): TransformArgumentsReply { return pushVerdictArguments(['PFADD', key], element); } diff --git a/lib/commands/PFCOUNT.ts b/lib/commands/PFCOUNT.ts index eac710a3543..52963697adf 100644 --- a/lib/commands/PFCOUNT.ts +++ b/lib/commands/PFCOUNT.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string | Array): Array { +export function transformArguments(key: string | Array): TransformArgumentsReply { return pushVerdictArguments(['PFCOUNT'], key); } diff --git a/lib/commands/PFMERGE.ts b/lib/commands/PFMERGE.ts index 73a4a2edb9a..c4ba11877f7 100644 --- a/lib/commands/PFMERGE.ts +++ b/lib/commands/PFMERGE.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyString } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(destination: string, source: string | Array): Array { +export function transformArguments(destination: string, source: string | Array): TransformArgumentsReply { return pushVerdictArguments(['PFMERGE', destination], source); } diff --git a/lib/commands/PUBSUB_NUMSUB.spec.ts b/lib/commands/PUBSUB_NUMSUB.spec.ts index 74065dbb48f..403732f8f9d 100644 --- a/lib/commands/PUBSUB_NUMSUB.spec.ts +++ b/lib/commands/PUBSUB_NUMSUB.spec.ts @@ -33,7 +33,7 @@ describe('PUBSUB NUMSUB', () => { ); }); - itWithCluster(TestRedisClusters.OPEN, 'cluster.pubSubNumPat', async cluster => { + itWithCluster(TestRedisClusters.OPEN, 'cluster.pubSubNumSub', async cluster => { assert.deepEqual( await cluster.pubSubNumSub(), Object.create(null) diff --git a/lib/commands/RPUSH.ts b/lib/commands/RPUSH.ts index 191d2704e09..665094f47a5 100644 --- a/lib/commands/RPUSH.ts +++ b/lib/commands/RPUSH.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, element: string | Array): Array { +export function transformArguments(key: string, element: string | Array): TransformArgumentsReply { return pushVerdictArguments(['RPUSH', key], element); } diff --git a/lib/commands/RPUSHX.ts b/lib/commands/RPUSHX.ts index a07615a58e0..fe1f969f3f6 100644 --- a/lib/commands/RPUSHX.ts +++ b/lib/commands/RPUSHX.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, element: string | Array): Array { +export function transformArguments(key: string, element: string | Array): TransformArgumentsReply { return pushVerdictArguments(['RPUSHX', key], element); } diff --git a/lib/commands/SADD.ts b/lib/commands/SADD.ts index a14ba1686c0..a432ccfef59 100644 --- a/lib/commands/SADD.ts +++ b/lib/commands/SADD.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, members: string | Array): Array { +export function transformArguments(key: string, members: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SADD', key], members); } diff --git a/lib/commands/SCRIPT_EXISTS.ts b/lib/commands/SCRIPT_EXISTS.ts index b127a0b261b..47a7f456e9b 100644 --- a/lib/commands/SCRIPT_EXISTS.ts +++ b/lib/commands/SCRIPT_EXISTS.ts @@ -1,6 +1,7 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyBooleanArray } from './generic-transformers'; -export function transformArguments(sha1: string | Array): Array { +export function transformArguments(sha1: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SCRIPT', 'EXISTS'], sha1); } diff --git a/lib/commands/SDIFF.ts b/lib/commands/SDIFF.ts index 496ed593370..4d5aaea1a06 100644 --- a/lib/commands/SDIFF.ts +++ b/lib/commands/SDIFF.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(keys: string | Array): Array { +export function transformArguments(keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SDIFF'], keys); } diff --git a/lib/commands/SDIFFSTORE.ts b/lib/commands/SDIFFSTORE.ts index 295433602fb..69883d4124c 100644 --- a/lib/commands/SDIFFSTORE.ts +++ b/lib/commands/SDIFFSTORE.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(destination: string, keys: string | Array): Array { +export function transformArguments(destination: string, keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SDIFFSTORE', destination], keys); } diff --git a/lib/commands/SET.spec.ts b/lib/commands/SET.spec.ts index a587f6c3120..32d138f2920 100644 --- a/lib/commands/SET.spec.ts +++ b/lib/commands/SET.spec.ts @@ -106,7 +106,7 @@ describe('SET', () => { 'OK' ); }); - + itWithClient(TestRedisServers.OPEN, 'with GET on empty key', async client => { assert.equal( await client.set('key', 'value', { diff --git a/lib/commands/SET.ts b/lib/commands/SET.ts index 4d5919cde21..03853b3f7d6 100644 --- a/lib/commands/SET.ts +++ b/lib/commands/SET.ts @@ -1,3 +1,5 @@ +import { TransformArgumentsReply } from '.'; + export const FIRST_KEY_INDEX = 1; interface EX { @@ -38,7 +40,7 @@ interface SetCommonOptions { type SetOptions = SetTTL & SetGuards & (SetCommonOptions | {}); -export function transformArguments(key: string, value: string, options?: SetOptions): Array { +export function transformArguments(key: string | Buffer, value: string | Buffer, options?: SetOptions): TransformArgumentsReply { const args = ['SET', key, value]; if (!options) { diff --git a/lib/commands/SETBIT.ts b/lib/commands/SETBIT.ts index 0cd41d1b975..33b2ff1a838 100644 --- a/lib/commands/SETBIT.ts +++ b/lib/commands/SETBIT.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { BitValue, transformReplyBit } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, offset: number, value: BitValue) { +export function transformArguments(key: string, offset: number, value: BitValue): TransformArgumentsReply { return ['SETBIT', key, offset.toString(), value.toString()]; } diff --git a/lib/commands/SETEX.ts b/lib/commands/SETEX.ts index 57c32db6ffe..320278c9264 100644 --- a/lib/commands/SETEX.ts +++ b/lib/commands/SETEX.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { transformReplyString } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, seconds: number, value: string): Array { +export function transformArguments(key: string | Buffer, seconds: number, value: string): TransformArgumentsReply { return [ 'SETEX', key, diff --git a/lib/commands/SINTER.ts b/lib/commands/SINTER.ts index 104e81b9214..43869652370 100644 --- a/lib/commands/SINTER.ts +++ b/lib/commands/SINTER.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(keys: string | Array): Array { +export function transformArguments(keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SINTER'], keys); } diff --git a/lib/commands/SINTERSTORE.ts b/lib/commands/SINTERSTORE.ts index a7a4d4fd106..5ad1b11cbac 100644 --- a/lib/commands/SINTERSTORE.ts +++ b/lib/commands/SINTERSTORE.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(destination: string, keys: string | Array): Array { +export function transformArguments(destination: string, keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SINTERSTORE', destination], keys); } diff --git a/lib/commands/SREM.ts b/lib/commands/SREM.ts index d1021bb3a19..4ae33245d29 100644 --- a/lib/commands/SREM.ts +++ b/lib/commands/SREM.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, members: string | Array): Array { +export function transformArguments(key: string, members: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SREM', key], members); } diff --git a/lib/commands/SUNION.ts b/lib/commands/SUNION.ts index 3f06138b1b6..705bff29927 100644 --- a/lib/commands/SUNION.ts +++ b/lib/commands/SUNION.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; export const IS_READ_ONLY = true; -export function transformArguments(keys: string | Array): Array { +export function transformArguments(keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SUNION'], keys); } diff --git a/lib/commands/SUNIONSTORE.ts b/lib/commands/SUNIONSTORE.ts index 7a1aab80117..af717f627df 100644 --- a/lib/commands/SUNIONSTORE.ts +++ b/lib/commands/SUNIONSTORE.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(destination: string, keys: string | Array): Array { +export function transformArguments(destination: string, keys: string | Array): TransformArgumentsReply { return pushVerdictArguments(['SUNIONSTORE', destination], keys); } diff --git a/lib/commands/TOUCH.ts b/lib/commands/TOUCH.ts index f2fb0548970..abff4160392 100644 --- a/lib/commands/TOUCH.ts +++ b/lib/commands/TOUCH.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string | Array): Array { +export function transformArguments(key: string | Array): TransformArgumentsReply { return pushVerdictArguments(['TOUCH'], key); } diff --git a/lib/commands/UNLINK.ts b/lib/commands/UNLINK.ts index 9dfe0ca48ea..4647a976e42 100644 --- a/lib/commands/UNLINK.ts +++ b/lib/commands/UNLINK.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string | Array): Array { +export function transformArguments(key: string | Array): TransformArgumentsReply { return pushVerdictArguments(['UNLINK'], key); } diff --git a/lib/commands/WATCH.ts b/lib/commands/WATCH.ts index 5e24ca37952..e644ab0f462 100644 --- a/lib/commands/WATCH.ts +++ b/lib/commands/WATCH.ts @@ -1,6 +1,7 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyString } from './generic-transformers'; -export function transformArguments(key: string | Array): Array { +export function transformArguments(key: string | Array): TransformArgumentsReply { return pushVerdictArguments(['WATCH'], key); } diff --git a/lib/commands/XACK.ts b/lib/commands/XACK.ts index 969f9b6a8b9..a6de28151eb 100644 --- a/lib/commands/XACK.ts +++ b/lib/commands/XACK.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, group: string, id: string | Array): Array { +export function transformArguments(key: string, group: string, id: string | Array): TransformArgumentsReply { return pushVerdictArguments(['XACK', key, group], id); } diff --git a/lib/commands/XDEL.ts b/lib/commands/XDEL.ts index 9d173271c28..083ea77ef0f 100644 --- a/lib/commands/XDEL.ts +++ b/lib/commands/XDEL.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, id: string | Array): Array { +export function transformArguments(key: string, id: string | Array): TransformArgumentsReply { return pushVerdictArguments(['XDEL', key], id); } diff --git a/lib/commands/ZDIFF.ts b/lib/commands/ZDIFF.ts index f557b597ec4..7154947fea7 100644 --- a/lib/commands/ZDIFF.ts +++ b/lib/commands/ZDIFF.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 2; export const IS_READ_ONLY = true; -export function transformArguments(keys: Array | string): Array { +export function transformArguments(keys: Array | string): TransformArgumentsReply { return pushVerdictArgument(['ZDIFF'], keys); } diff --git a/lib/commands/ZDIFFSTORE.ts b/lib/commands/ZDIFFSTORE.ts index de409c0939a..f91d4c869ba 100644 --- a/lib/commands/ZDIFFSTORE.ts +++ b/lib/commands/ZDIFFSTORE.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArgument, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(destination: string, keys: Array | string): Array { +export function transformArguments(destination: string, keys: Array | string): TransformArgumentsReply { return pushVerdictArgument(['ZDIFFSTORE', destination], keys); } diff --git a/lib/commands/ZDIFF_WITHSCORES.ts b/lib/commands/ZDIFF_WITHSCORES.ts index 26effab7189..84126853361 100644 --- a/lib/commands/ZDIFF_WITHSCORES.ts +++ b/lib/commands/ZDIFF_WITHSCORES.ts @@ -1,9 +1,10 @@ +import { TransformArgumentsReply } from '.'; import { transformReplySortedSetWithScores } from './generic-transformers'; import { transformArguments as transformZDiffArguments } from './ZDIFF'; export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZDIFF'; -export function transformArguments(...args: Parameters): Array { +export function transformArguments(...args: Parameters): TransformArgumentsReply { return [ ...transformZDiffArguments(...args), 'WITHSCORES' diff --git a/lib/commands/ZINTER.ts b/lib/commands/ZINTER.ts index 90a42eda0d3..91d7982a8e7 100644 --- a/lib/commands/ZINTER.ts +++ b/lib/commands/ZINTER.ts @@ -1,3 +1,4 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 2; @@ -9,7 +10,7 @@ interface ZInterOptions { AGGREGATE?: 'SUM' | 'MIN' | 'MAX'; } -export function transformArguments(keys: Array | string, options?: ZInterOptions): Array { +export function transformArguments(keys: Array | string, options?: ZInterOptions): TransformArgumentsReply { const args = pushVerdictArgument(['ZINTER'], keys); if (options?.WEIGHTS) { diff --git a/lib/commands/ZINTERSTORE.ts b/lib/commands/ZINTERSTORE.ts index a026916ce1f..6e79e423cb0 100644 --- a/lib/commands/ZINTERSTORE.ts +++ b/lib/commands/ZINTERSTORE.ts @@ -1,3 +1,4 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArgument, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; @@ -7,7 +8,7 @@ interface ZInterStoreOptions { AGGREGATE?: 'SUM' | 'MIN' | 'MAX'; } -export function transformArguments(destination: string, keys: Array | string, options?: ZInterStoreOptions): Array { +export function transformArguments(destination: string, keys: Array | string, options?: ZInterStoreOptions): TransformArgumentsReply { const args = pushVerdictArgument(['ZINTERSTORE', destination], keys); if (options?.WEIGHTS) { diff --git a/lib/commands/ZINTER_WITHSCORES.ts b/lib/commands/ZINTER_WITHSCORES.ts index 0a82228fce9..f4287d1a684 100644 --- a/lib/commands/ZINTER_WITHSCORES.ts +++ b/lib/commands/ZINTER_WITHSCORES.ts @@ -1,9 +1,10 @@ +import { TransformArgumentsReply } from '.'; import { transformReplySortedSetWithScores } from './generic-transformers'; import { transformArguments as transformZInterArguments } from './ZINTER'; export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZINTER'; -export function transformArguments(...args: Parameters): Array { +export function transformArguments(...args: Parameters): TransformArgumentsReply { return [ ...transformZInterArguments(...args), 'WITHSCORES' diff --git a/lib/commands/ZMSCORE.ts b/lib/commands/ZMSCORE.ts index 8a6f73c7836..373adac3cf0 100644 --- a/lib/commands/ZMSCORE.ts +++ b/lib/commands/ZMSCORE.ts @@ -1,10 +1,11 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumberInfinityNullArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; export const IS_READ_ONLY = true; -export function transformArguments(key: string, member: string | Array): Array { +export function transformArguments(key: string, member: string | Array): TransformArgumentsReply { return pushVerdictArguments(['ZMSCORE', key], member); } diff --git a/lib/commands/ZREM.ts b/lib/commands/ZREM.ts index 089b6136afd..8419291f2fd 100644 --- a/lib/commands/ZREM.ts +++ b/lib/commands/ZREM.ts @@ -1,8 +1,9 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArguments, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; -export function transformArguments(key: string, member: string | Array): Array { +export function transformArguments(key: string, member: string | Array): TransformArgumentsReply { return pushVerdictArguments(['ZREM', key], member); } diff --git a/lib/commands/ZUNION.ts b/lib/commands/ZUNION.ts index efdfccb1ff4..87158b8425a 100644 --- a/lib/commands/ZUNION.ts +++ b/lib/commands/ZUNION.ts @@ -1,3 +1,4 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers'; export const FIRST_KEY_INDEX = 2; @@ -9,7 +10,7 @@ interface ZUnionOptions { AGGREGATE?: 'SUM' | 'MIN' | 'MAX'; } -export function transformArguments(keys: Array | string, options?: ZUnionOptions): Array { +export function transformArguments(keys: Array | string, options?: ZUnionOptions): TransformArgumentsReply { const args = pushVerdictArgument(['ZUNION'], keys); if (options?.WEIGHTS) { diff --git a/lib/commands/ZUNIONSTORE.ts b/lib/commands/ZUNIONSTORE.ts index c03f1203706..4ebbdbd8591 100644 --- a/lib/commands/ZUNIONSTORE.ts +++ b/lib/commands/ZUNIONSTORE.ts @@ -1,3 +1,4 @@ +import { TransformArgumentsReply } from '.'; import { pushVerdictArgument, transformReplyNumber } from './generic-transformers'; export const FIRST_KEY_INDEX = 1; @@ -7,7 +8,7 @@ interface ZUnionOptions { AGGREGATE?: 'SUM' | 'MIN' | 'MAX'; } -export function transformArguments(destination: string, keys: Array | string, options?: ZUnionOptions): Array { +export function transformArguments(destination: string, keys: Array | string, options?: ZUnionOptions): TransformArgumentsReply { const args = pushVerdictArgument(['ZUNIONSTORE', destination], keys); if (options?.WEIGHTS) { diff --git a/lib/commands/ZUNION_WITHSCORES.ts b/lib/commands/ZUNION_WITHSCORES.ts index d0cef45cfb1..2215dad9749 100644 --- a/lib/commands/ZUNION_WITHSCORES.ts +++ b/lib/commands/ZUNION_WITHSCORES.ts @@ -1,9 +1,10 @@ +import { TransformArgumentsReply } from '.'; import { transformReplySortedSetWithScores } from './generic-transformers'; import { transformArguments as transformZUnionArguments } from './ZUNION'; export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZUNION'; -export function transformArguments(...args: Parameters): Array { +export function transformArguments(...args: Parameters): TransformArgumentsReply { return [ ...transformZUnionArguments(...args), 'WITHSCORES' diff --git a/lib/commands/generic-transformers.ts b/lib/commands/generic-transformers.ts index 8105bfe903f..bbc12ee113e 100644 --- a/lib/commands/generic-transformers.ts +++ b/lib/commands/generic-transformers.ts @@ -50,6 +50,10 @@ export function transformReplyBit(reply: BitValue): BitValue { return reply; } +export function transformReplyBufferNull(reply: Buffer | null): Buffer | null { + return reply; +} + export function transformReplyVoid(): void {} export interface ScanOptions { @@ -352,11 +356,11 @@ export function pushStringTuplesArguments(args: Array, tuples: StringTup return args; } -export function pushVerdictArguments(args: TransformArgumentsReply, value: string | Array): TransformArgumentsReply { - if (typeof value === 'string') { - args.push(value); - } else { +export function pushVerdictArguments(args: TransformArgumentsReply, value: string | Buffer | Array): TransformArgumentsReply { + if (Array.isArray(value)) { args.push(...value); + } else { + args.push(value); } return args; diff --git a/lib/commands/index.ts b/lib/commands/index.ts index cffb47c668a..89581090e58 100644 --- a/lib/commands/index.ts +++ b/lib/commands/index.ts @@ -34,6 +34,7 @@ import * as CLUSTER_NODES from './CLUSTER_NODES'; import * as CLUSTER_MEET from './CLUSTER_MEET'; import * as CLUSTER_RESET from './CLUSTER_RESET'; import * as CLUSTER_SETSLOT from './CLUSTER_SETSLOT'; +import * as CLUSTER_SLOTS from './CLUSTER_SLOTS'; import * as CONFIG_GET from './CONFIG_GET'; import * as CONFIG_RESETASTAT from './CONFIG_RESETSTAT'; import * as CONFIG_REWRITE from './CONFIG_REWRITE'; @@ -61,6 +62,7 @@ import * as GEOPOS from './GEOPOS'; import * as GEOSEARCH_WITH from './GEOSEARCH_WITH'; import * as GEOSEARCH from './GEOSEARCH'; import * as GEOSEARCHSTORE from './GEOSEARCHSTORE'; +import * as GET_BUFFER from './GET_BUFFER'; import * as GET from './GET'; import * as GETBIT from './GETBIT'; import * as GETDEL from './GETDEL'; @@ -316,6 +318,8 @@ export default { clusterReset: CLUSTER_RESET, CLUSTER_SETSLOT, clusterSetSlot: CLUSTER_SETSLOT, + CLUSTER_SLOTS, + clusterSlots: CLUSTER_SLOTS, CONFIG_GET, configGet: CONFIG_GET, CONFIG_RESETASTAT, @@ -370,6 +374,8 @@ export default { geoSearch: GEOSEARCH, GEOSEARCHSTORE, geoSearchStore: GEOSEARCHSTORE, + GET_BUFFER, + getBuffer: GET_BUFFER, GET, get: GET, GETBIT, @@ -733,15 +739,16 @@ export default { zUnionStore: ZUNIONSTORE }; -export type RedisReply = string | number | Array | null | undefined; +export type RedisReply = string | number | Buffer | Array | null | undefined; -export type TransformArgumentsReply = Array & { preserve?: unknown }; +export type TransformArgumentsReply = Array & { preserve?: unknown }; export interface RedisCommand { FIRST_KEY_INDEX?: number | ((...args: Array) => string); IS_READ_ONLY?: boolean; - transformArguments(...args: Array): TransformArgumentsReply; - transformReply(reply: RedisReply, preserved: unknown): any; + transformArguments(this: void, ...args: Array): TransformArgumentsReply; + BUFFER_MODE?: boolean; + transformReply(this: void, reply: RedisReply, preserved?: unknown): any; } export interface RedisCommands { @@ -749,7 +756,10 @@ export interface RedisCommands { } export interface RedisModule { - [key: string]: RedisCommand; + [command: string]: RedisCommand; } -export type RedisModules = Record; +export interface RedisModules { + [module: string]: RedisModule; +} +// export type RedisModules = Record; diff --git a/lib/lua-script.ts b/lib/lua-script.ts index 183c42f219c..be16f9b9133 100644 --- a/lib/lua-script.ts +++ b/lib/lua-script.ts @@ -13,10 +13,10 @@ export interface SHA1 { export type RedisLuaScript = RedisLuaScriptConfig & SHA1; export interface RedisLuaScripts { - [key: string]: RedisLuaScript; + [script: string]: RedisLuaScript; } -export function defineScript(script: S): S & SHA1 { +export function defineScript(script: RedisLuaScriptConfig): typeof script & SHA1 { return { ...script, SHA1: scriptSha1(script.SCRIPT) diff --git a/lib/multi-command.spec.ts b/lib/multi-command.spec.ts index a78cc8b2e08..52ecfb94b1c 100644 --- a/lib/multi-command.spec.ts +++ b/lib/multi-command.spec.ts @@ -1,6 +1,5 @@ import { strict as assert } from 'assert'; import RedisMultiCommand from './multi-command'; -import { encodeCommand } from './commander'; import { WatchError } from './errors'; import { spy } from 'sinon'; import { SQUARE_SCRIPT } from './client.spec'; @@ -10,11 +9,11 @@ describe('Multi Command', () => { it('simple', async () => { const multi = RedisMultiCommand.create((queue, symbol) => { assert.deepEqual( - queue.map(({encodedCommand}) => encodedCommand), + queue.map(({ args }) => args), [ - encodeCommand(['MULTI']), - encodeCommand(['PING']), - encodeCommand(['EXEC']), + ['MULTI'], + ['PING'], + ['EXEC'], ] ); @@ -55,8 +54,8 @@ describe('Multi Command', () => { it('execAsPipeline', async () => { const multi = RedisMultiCommand.create(queue => { assert.deepEqual( - queue.map(({encodedCommand}) => encodedCommand), - [encodeCommand(['PING'])] + queue.map(({ args }) => args), + [['PING']] ); return Promise.resolve(['PONG']); @@ -75,8 +74,8 @@ describe('Multi Command', () => { it('simple', async () => { const multi = RedisMultiCommand.create(queue => { assert.deepEqual( - queue.map(({encodedCommand}) => encodedCommand), - [encodeCommand(['PING'])] + queue.map(({ args }) => args), + [['PING']] ); return Promise.resolve(['PONG']); @@ -111,10 +110,10 @@ describe('Multi Command', () => { assert.deepEqual( await new MultiWithScript(queue => { assert.deepEqual( - queue.map(({encodedCommand}) => encodedCommand), + queue.map(({ args }) => args), [ - encodeCommand(['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '2']), - encodeCommand(['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '3']), + ['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '2'], + ['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '3'], ] ); diff --git a/lib/multi-command.ts b/lib/multi-command.ts index c8a50765967..a329a5dbf19 100644 --- a/lib/multi-command.ts +++ b/lib/multi-command.ts @@ -2,7 +2,7 @@ import COMMANDS, { TransformArgumentsReply } from './commands'; import { RedisCommand, RedisModules, RedisReply } from './commands'; import { RedisLuaScript, RedisLuaScripts } from './lua-script'; import { RedisClientOptions } from './client'; -import { extendWithModulesAndScripts, extendWithDefaultCommands, encodeCommand } from './commander'; +import { extendWithModulesAndScripts, extendWithDefaultCommands } from './commander'; import { WatchError } from './errors'; type RedisMultiCommandSignature = (...args: Parameters) => RedisMultiCommandType; @@ -21,68 +21,31 @@ type WithScripts = { [P in keyof S]: RedisMultiCommandSignature }; -export type RedisMultiCommandType = RedisMultiCommand & WithCommands & WithModules & WithScripts; +export type RedisMultiCommandType = + RedisMultiCommand & WithCommands & WithModules & WithScripts; export interface MultiQueuedCommand { - encodedCommand: string; + args: TransformArgumentsReply; preservedArguments?: unknown; transformReply?: RedisCommand['transformReply']; } export type RedisMultiExecutor = (queue: Array, chainId?: symbol) => Promise>; -export default class RedisMultiCommand { - static commandsExecutor(this: RedisMultiCommand, command: RedisCommand, args: Array): RedisMultiCommand { - return this.addCommand( - command.transformArguments(...args), - command.transformReply - ); - } - - static #scriptsExecutor( - this: RedisMultiCommand, - script: RedisLuaScript, - args: Array - ): RedisMultiCommand { - const transformedArguments: TransformArgumentsReply = []; - if (this.#scriptsInUse.has(script.SHA1)) { - transformedArguments.push( - 'EVALSHA', - script.SHA1 - ); - } else { - this.#scriptsInUse.add(script.SHA1); - transformedArguments.push( - 'EVAL', - script.SCRIPT - ); - } - - transformedArguments.push(script.NUMBER_OF_KEYS.toString()); - - const scriptArguments = script.transformArguments(...args); - transformedArguments.push(...scriptArguments); - transformedArguments.preserve = scriptArguments.preserve; - - return this.addCommand( - transformedArguments, - script.transformReply - ); - } - +export default class RedisMultiCommand { static extend( clientOptions?: RedisClientOptions ): new (...args: ConstructorParameters) => RedisMultiCommandType { return extendWithModulesAndScripts({ BaseClass: RedisMultiCommand, modules: clientOptions?.modules, - modulesCommandsExecutor: RedisMultiCommand.commandsExecutor, + modulesCommandsExecutor: RedisMultiCommand.prototype.commandsExecutor, scripts: clientOptions?.scripts, - scriptsExecutor: RedisMultiCommand.#scriptsExecutor + scriptsExecutor: RedisMultiCommand.prototype.scriptsExecutor }); } - static create( + static create( executor: RedisMultiExecutor, clientOptions?: RedisClientOptions ): RedisMultiCommandType { @@ -119,7 +82,7 @@ export default class RedisMultiCommand): this => { this.#queue.push({ - encodedCommand: encodeCommand(args.flat() as Array) + args: args.flat() as Array }); return this; } @@ -151,9 +114,45 @@ export default class RedisMultiCommand): void => (this as any).addCommand(name, args); } + commandsExecutor(command: RedisCommand, args: Array): this { + return this.addCommand( + command.transformArguments(...args), + command.transformReply + ); + } + + scriptsExecutor(script: RedisLuaScript, args: Array): this { + const transformedArguments: TransformArgumentsReply = []; + if (this.#scriptsInUse.has(script.SHA1)) { + transformedArguments.push( + 'EVALSHA', + script.SHA1 + ); + } else { + this.#scriptsInUse.add(script.SHA1); + transformedArguments.push( + 'EVAL', + script.SCRIPT + ); + } + + transformedArguments.push(script.NUMBER_OF_KEYS.toString()); + + const scriptArguments = script.transformArguments(...args); + transformedArguments.push(...scriptArguments); + if (scriptArguments.preserve) { + transformedArguments.preserve = scriptArguments.preserve; + } + + return this.addCommand( + transformedArguments, + script.transformReply + ); + } + addCommand(args: TransformArgumentsReply, transformReply?: RedisCommand['transformReply']): this { this.#queue.push({ - encodedCommand: encodeCommand(args), + args, preservedArguments: args.preserve, transformReply }); @@ -170,13 +169,9 @@ export default class RedisMultiCommand); @@ -207,4 +202,4 @@ export default class RedisMultiCommand { connectEvent: string; @@ -44,14 +37,6 @@ export default class RedisSocket extends EventEmitter { static #initiateOptions(options?: RedisSocketOptions): RedisSocketOptions { options ??= {}; if (!RedisSocket.#isUnixSocket(options)) { - if (RedisSocket.#isUrlSocket(options)) { - const url = new URL(options.url); - (options as RedisNetSocketOptions).port = Number(url.port); - (options as RedisNetSocketOptions).host = url.hostname; - options.username = url.username; - options.password = url.password; - } - (options as RedisNetSocketOptions).port ??= 6379; (options as RedisNetSocketOptions).host ??= '127.0.0.1'; } @@ -67,10 +52,6 @@ export default class RedisSocket extends EventEmitter { return Math.min(retries * 50, 500); } - static #isUrlSocket(options: RedisSocketOptions): options is RedisUrlSocketOptions { - return Object.prototype.hasOwnProperty.call(options, 'url'); - } - static #isUnixSocket(options: RedisSocketOptions): options is RedisUnixSocketOptions { return Object.prototype.hasOwnProperty.call(options, 'path'); } @@ -91,10 +72,8 @@ export default class RedisSocket extends EventEmitter { return this.#isOpen; } - get chunkRecommendedSize(): number { - if (!this.#socket) return 0; - - return this.#socket.writableHighWaterMark - this.#socket.writableLength; + get isSocketExists(): boolean { + return !!this.#socket; } constructor(initiator?: RedisSocketInitiator, options?: RedisSocketOptions) { @@ -214,12 +193,12 @@ export default class RedisSocket extends EventEmitter { .catch(err => this.emit('error', err)); } - write(encodedCommands: string): boolean { + write(toWrite: string | Buffer): boolean { if (!this.#socket) { throw new ClientClosedError(); } - return this.#socket.write(encodedCommands); + return this.#socket.write(toWrite); } async disconnect(ignoreIsOpen = false): Promise { @@ -251,4 +230,22 @@ export default class RedisSocket extends EventEmitter { throw err; } } + + #isCorked = false; + + cork(): void { + if (!this.#socket) { + return; + } + + if (!this.#isCorked) { + this.#socket.cork(); + this.#isCorked = true; + + queueMicrotask(() => { + this.#socket?.uncork(); + this.#isCorked = false; + }); + } + } } diff --git a/lib/test-utils.ts b/lib/test-utils.ts index e23d90d47ea..713a1a3434a 100644 --- a/lib/test-utils.ts +++ b/lib/test-utils.ts @@ -1,7 +1,5 @@ import { strict as assert } from 'assert'; -import RedisClient, { RedisClientType } from './client'; -import { RedisModules } from './commands'; -import { RedisLuaScripts } from './lua-script'; +import RedisClient, { RedisClientOptions, RedisClientType } from './client'; import { execSync, spawn } from 'child_process'; import { once } from 'events'; import { RedisSocketOptions } from './socket'; @@ -11,6 +9,8 @@ import RedisCluster, { RedisClusterType } from './cluster'; import { promises as fs } from 'fs'; import { Context as MochaContext } from 'mocha'; import { promiseTimeout } from './utils'; +import { RedisModules } from './commands'; +import { RedisLuaScripts } from './lua-script'; type RedisVersion = [major: number, minor: number, patch: number]; @@ -54,7 +54,7 @@ export enum TestRedisServers { PASSWORD } -export const TEST_REDIS_SERVERS: Record = {}; +export const TEST_REDIS_SERVERS: Record> = {}; export enum TestRedisClusters { OPEN @@ -112,7 +112,7 @@ async function spawnGlobalRedisServer(args?: Array): Promise { const SLOTS = 16384; interface SpawnRedisClusterNodeResult extends SpawnRedisServerResult { - client: RedisClientType + client: RedisClientType } async function spawnRedisClusterNode( @@ -228,13 +228,17 @@ export async function spawnGlobalRedisCluster(type: TestRedisClusters | null, nu async function spawnOpenServer(): Promise { TEST_REDIS_SERVERS[TestRedisServers.OPEN] = { - port: await spawnGlobalRedisServer() + socket: { + port: await spawnGlobalRedisServer() + } }; } async function spawnPasswordServer(): Promise { TEST_REDIS_SERVERS[TestRedisServers.PASSWORD] = { - port: await spawnGlobalRedisServer(['--requirepass', 'password']), + socket: { + port: await spawnGlobalRedisServer(['--requirepass', 'password']), + }, password: 'password' }; @@ -281,15 +285,13 @@ export function describeHandleMinimumRedisVersion(minimumVersion: PartialRedisVe export function itWithClient( type: TestRedisServers, title: string, - fn: (client: RedisClientType) => Promise, + fn: (client: RedisClientType) => Promise, options?: RedisTestOptions ): void { it(title, async function () { if (handleMinimumRedisVersion(this, options?.minimumRedisVersion)) return; - const client = RedisClient.create({ - socket: TEST_REDIS_SERVERS[type] - }); + const client = RedisClient.create(TEST_REDIS_SERVERS[type]); await client.connect(); @@ -306,7 +308,7 @@ export function itWithClient( export function itWithCluster( type: TestRedisClusters, title: string, - fn: (cluster: RedisClusterType) => Promise, + fn: (cluster: RedisClusterType) => Promise, options?: RedisTestOptions ): void { it(title, async function () { @@ -328,7 +330,7 @@ export function itWithCluster( }); } -export function itWithDedicatedCluster(title: string, fn: (cluster: RedisClusterType) => Promise): void { +export function itWithDedicatedCluster(title: string, fn: (cluster: RedisClusterType) => Promise): void { it(title, async function () { this.timeout(10000); @@ -370,4 +372,4 @@ export async function waitTillBeenCalled(spy: SinonSpy): Promise { await promiseTimeout(1); } while (spy.callCount === calls) -} \ No newline at end of file +} diff --git a/lib/ts-declarations/cluster-key-slot.d.ts b/lib/ts-declarations/cluster-key-slot.d.ts index 5774c50fbd4..60421de296b 100644 --- a/lib/ts-declarations/cluster-key-slot.d.ts +++ b/lib/ts-declarations/cluster-key-slot.d.ts @@ -1,3 +1,3 @@ declare module 'cluster-key-slot' { - export default function calculateSlot(key: string): number; + export default function calculateSlot(key: string | Buffer): number; } diff --git a/lib/ts-declarations/redis-parser.d.ts b/lib/ts-declarations/redis-parser.d.ts index 68659616b93..7ec129ed8cd 100644 --- a/lib/ts-declarations/redis-parser.d.ts +++ b/lib/ts-declarations/redis-parser.d.ts @@ -8,6 +8,8 @@ declare module 'redis-parser' { export default class RedisParser { constructor(callbacks: RedisParserCallbacks); + setReturnBuffers(returnBuffers?: boolean): void; + execute(buffer: Buffer): void; } } diff --git a/package-lock.json b/package-lock.json index ac623c60e6a..9fcd62b5996 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "redis", - "version": "4.0.0-rc.1", + "version": "4.0.0-rc.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "redis", - "version": "4.0.0-rc.1", + "version": "4.0.0-rc.2", "license": "MIT", "dependencies": { "cluster-key-slot": "1.1.0", @@ -17,20 +17,20 @@ "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", "@types/mocha": "^9.0.0", - "@types/node": "^16.7.10", - "@types/sinon": "^10.0.2", + "@types/node": "^16.9.6", + "@types/sinon": "^10.0.3", "@types/which": "^2.0.1", "@types/yallist": "^4.0.1", "mocha": "^9.1.1", "nyc": "^15.1.0", - "release-it": "^14.11.5", + "release-it": "^14.11.6", "sinon": "^11.1.2", - "source-map-support": "^0.5.19", + "source-map-support": "^0.5.20", "ts-node": "^10.2.1", - "typedoc": "^0.21.9", + "typedoc": "0.21.9", "typedoc-github-wiki-theme": "^0.5.1", - "typedoc-plugin-markdown": "^3.10.4", - "typescript": "^4.4.2", + "typedoc-plugin-markdown": "3.10.4", + "typescript": "^4.4.3", "which": "^2.0.2" }, "engines": { @@ -59,20 +59,20 @@ } }, "node_modules/@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", + "version": "7.15.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz", + "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/generator": "^7.15.4", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.4", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.5", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -89,12 +89,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz", + "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", "dev": true, "dependencies": { - "@babel/types": "^7.15.0", + "@babel/types": "^7.15.4", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -103,9 +103,9 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", "dev": true, "dependencies": { "@babel/compat-data": "^7.15.0", @@ -121,141 +121,141 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", "dev": true, "dependencies": { - "@babel/types": "^7.15.0" + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", "dev": true, "dependencies": { - "@babel/types": "^7.14.8" + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -271,14 +271,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", - "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", "dev": true, "dependencies": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" @@ -370,9 +370,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", - "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -382,32 +382,32 @@ } }, "node_modules/@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -416,9 +416,9 @@ } }, "node_modules/@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.14.9", @@ -607,9 +607,9 @@ } }, "node_modules/@octokit/auth-token": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", - "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", "dev": true, "dependencies": { "@octokit/types": "^6.0.3" @@ -680,12 +680,12 @@ } }, "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.7.0.tgz", - "integrity": "sha512-G7sgccWRYQMwcHJXkDY/sDxbXeKiZkFQqUtzBCwmrzCNj2GQf3VygQ4T/BFL2crLVpIbenkE/c0ErhYOte2MPw==", + "version": "5.10.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.10.4.tgz", + "integrity": "sha512-Dh+EAMCYR9RUHwQChH94Skl0lM8Fh99auT8ggck/xTzjJrwVzvsd0YH68oRPqp/HxICzmUjLfaQ9sy1o1sfIiA==", "dev": true, "dependencies": { - "@octokit/types": "^6.24.0", + "@octokit/types": "^6.28.1", "deprecation": "^2.3.1" }, "peerDependencies": { @@ -718,15 +718,15 @@ } }, "node_modules/@octokit/rest": { - "version": "18.9.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.9.0.tgz", - "integrity": "sha512-VrmrE8gjpuOoDAGjrQq2j9ZhOE6LxaqxaQg0yMrrEnnQZy2ZcAnr5qbVfKsMF0up/48PRV/VFS/2GSMhA7nTdA==", + "version": "18.10.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.10.0.tgz", + "integrity": "sha512-esHR5OKy38bccL/sajHqZudZCvmv4yjovMJzyXlphaUo7xykmtOdILGJ3aAm0mFHmMLmPFmDMJXf39cAjNJsrw==", "dev": true, "dependencies": { - "@octokit/core": "^3.5.0", - "@octokit/plugin-paginate-rest": "^2.6.2", - "@octokit/plugin-request-log": "^1.0.2", - "@octokit/plugin-rest-endpoint-methods": "5.7.0" + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.0", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.9.0" } }, "node_modules/@octokit/types": { @@ -739,9 +739,9 @@ } }, "node_modules/@sindresorhus/is": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", - "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", + "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", "dev": true, "engines": { "node": ">=10" @@ -840,9 +840,9 @@ "dev": true }, "node_modules/@types/keyv": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.2.tgz", - "integrity": "sha512-/FvAK2p4jQOaJ6CGDHJTqZcUtbZe820qIeTg7o0Shg7drB4JHeL+V/dhSaly7NXx6u8eSee+r7coT+yuJEvDLg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", + "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", "dev": true, "dependencies": { "@types/node": "*" @@ -876,9 +876,9 @@ } }, "node_modules/@types/sinon": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.2.tgz", - "integrity": "sha512-BHn8Bpkapj8Wdfxvh2jWIUoaYB/9/XhsL0oOvBfRagJtKlSl9NWPcFOz2lRukI9szwGxFtYZCTejJSqsGDbdmw==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.3.tgz", + "integrity": "sha512-XUaFuUOQ3A/r6gS1qCU/USMleascaqGeQpGR1AZ5JdRtBPlzijRzKsik1TuGzvdtPA0mdq42JqaJmJ+Afg1LJg==", "dev": true, "dependencies": { "@sinonjs/fake-timers": "^7.1.0" @@ -903,9 +903,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", - "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -915,9 +915,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.1.1.tgz", - "integrity": "sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1032,9 +1032,9 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { "node": ">=8" @@ -1108,12 +1108,12 @@ } }, "node_modules/async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", "dev": true, "dependencies": { - "retry": "0.12.0" + "retry": "0.13.1" } }, "node_modules/asynckit": { @@ -1175,16 +1175,16 @@ } }, "node_modules/boxen": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.0.1.tgz", - "integrity": "sha512-49VBlw+PrWEF51aCmy7QIteYPIFZxSpvqBdP/2itCPPlJ49kj9zg/XPRFrdkne2W+CfwXUls8exMvu1RysZpKA==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", "dev": true, "dependencies": { "ansi-align": "^3.0.0", "camelcase": "^6.2.0", "chalk": "^4.1.0", "cli-boxes": "^2.2.1", - "string-width": "^4.2.0", + "string-width": "^4.2.2", "type-fest": "^0.20.2", "widest-line": "^3.1.0", "wrap-ansi": "^7.0.0" @@ -1249,14 +1249,14 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.16.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", - "integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz", + "integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001251", + "caniuse-lite": "^1.0.30001254", "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.811", + "electron-to-chromium": "^1.3.830", "escalade": "^3.1.1", "node-releases": "^1.1.75" }, @@ -1390,9 +1390,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001252", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz", - "integrity": "sha512-I56jhWDGMtdILQORdusxBOH+Nl/KgQSdDmpJezYddnAkVOmnoU8zwjTV9xAjMIYxr0iPreEAVylCGcmHCjfaOw==", + "version": "1.0.30001259", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001259.tgz", + "integrity": "sha512-V7mQTFhjITxuk9zBpI6nYsiTXhcPe05l+364nZjK7MFK/E7ibvYBSAXr4YcA6oPR8j3ZLM/LN+lUqUVAQEUZFg==", "dev": true, "funding": { "type": "opencollective", @@ -1570,9 +1570,9 @@ "dev": true }, "node_modules/colorette": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", - "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", "dev": true }, "node_modules/combined-stream": { @@ -1626,9 +1626,9 @@ } }, "node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", @@ -1977,9 +1977,9 @@ } }, "node_modules/fastq": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", - "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2217,9 +2217,9 @@ } }, "node_modules/git-url-parse": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.5.0.tgz", - "integrity": "sha512-TZYSMDeM37r71Lqg1mbnMlOqlHd7BSij9qN7XwTkRqSAYFMihGLGhfHwgqQob3GUhEneKnV4nskN9rbQw2KGxA==", + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.6.0.tgz", + "integrity": "sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g==", "dev": true, "dependencies": { "git-up": "^4.0.0" @@ -2615,9 +2615,9 @@ } }, "node_modules/inquirer": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.2.tgz", - "integrity": "sha512-DHLKJwLPNgkfwNmsuEUKSejJFbkv0FMO9SMiQbjI3n5NQuCrSIBqP66ggqyz2a6t2qEolKrMjhQ3+W/xXgUQ+Q==", + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", + "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", "dev": true, "dependencies": { "ansi-escapes": "^4.2.1", @@ -2628,7 +2628,7 @@ "figures": "^3.0.0", "lodash": "^4.17.21", "mute-stream": "0.0.8", - "ora": "^5.3.0", + "ora": "^5.4.1", "run-async": "^2.4.0", "rxjs": "^7.2.0", "string-width": "^4.1.0", @@ -3068,6 +3068,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, "node_modules/just-extend": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", @@ -3214,9 +3220,9 @@ "dev": true }, "node_modules/marked": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.2.tgz", - "integrity": "sha512-TMJQQ79Z0e3rJYazY0tIoMsFzteUGw9fB3FD+gzuIT3zLuG9L9ckIvUfF51apdJkcqc208jJN2KbtPbOvXtbjA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.4.tgz", + "integrity": "sha512-jBo8AOayNaEcvBhNobg6/BLhdsK3NvnKWJg33MAAPbvTWiG4QBn9gpW1+7RssrKu4K1dKlN+0goVQwV41xEfOA==", "dev": true, "bin": { "marked": "bin/marked" @@ -3419,10 +3425,13 @@ } }, "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-aD1fO+xtLiSCc9vuD+sYMxpIuQyhHscGSkBEo2o5LTV/3bTEAYvdUii29n8LlO5uLCmWdGP7uVUVXFo5SRdkLA==", "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, "engines": { "node": "4.x || >=6.0.0" } @@ -3440,9 +3449,9 @@ } }, "node_modules/node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "1.1.76", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", + "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==", "dev": true }, "node_modules/normalize-path": { @@ -4424,25 +4433,25 @@ } }, "node_modules/release-it": { - "version": "14.11.5", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.11.5.tgz", - "integrity": "sha512-9BaPdq7ZKOwtzz3p1mRhg/tOH/cT/y2tUnPYzUwQiVdj42JaGI1Vo2l3WbgK8ICsbFyrhc0tri1+iqI8OvkI1A==", + "version": "14.11.6", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.11.6.tgz", + "integrity": "sha512-6BNcuzFZHThBUBJ/xYw/bxZ+58CAwrwf1zgmjq2Ibl3nlDZbjphHG6iqxkJu7mZ8TIWs6NjloEAhqpjeXoN//Q==", "dev": true, "dependencies": { "@iarna/toml": "2.2.5", - "@octokit/rest": "18.9.0", - "async-retry": "1.3.1", + "@octokit/rest": "18.10.0", + "async-retry": "1.3.3", "chalk": "4.1.2", - "cosmiconfig": "7.0.0", + "cosmiconfig": "7.0.1", "debug": "4.3.2", "deprecated-obj": "2.0.0", "execa": "5.1.1", "form-data": "4.0.0", - "git-url-parse": "11.5.0", + "git-url-parse": "11.6.0", "globby": "11.0.4", "got": "11.8.2", "import-cwd": "3.0.0", - "inquirer": "8.1.2", + "inquirer": "8.1.5", "is-ci": "3.0.0", "lodash": "4.17.21", "mime-types": "2.1.32", @@ -4612,9 +4621,9 @@ } }, "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, "engines": { "node": ">= 4" @@ -4778,7 +4787,7 @@ "integrity": "sha512-xeM7Oc6hY+6iW5O/T5hor8ul7mEprzyl5y4r5zthEHToQNw7MIhREMgU3r2gKDB0NaMLNrkcEQagudCdzE13Lg==", "dev": true, "dependencies": { - "json5": "^2.2.0", + "jsonc-parser": "^3.0.0", "onigasm": "^2.2.5", "vscode-textmate": "5.2.0" } @@ -4798,9 +4807,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", + "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", "dev": true }, "node_modules/sinon": { @@ -4852,9 +4861,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -5073,6 +5082,12 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, "node_modules/ts-node": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", @@ -5216,9 +5231,9 @@ } }, "node_modules/typescript": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", - "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5229,9 +5244,9 @@ } }, "node_modules/uglify-js": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.1.tgz", - "integrity": "sha512-JhS3hmcVaXlp/xSo3PKY5R0JqKs5M3IV+exdLHW99qKvKivPO4Z8qbej6mte17SOPqAOVMjt/XGgWacnFSzM3g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", + "integrity": "sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A==", "dev": true, "optional": true, "bin": { @@ -5381,6 +5396,22 @@ "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5712,20 +5743,20 @@ "dev": true }, "@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", + "version": "7.15.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz", + "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", "dev": true, "requires": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/generator": "^7.15.4", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.4", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.5", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -5735,20 +5766,20 @@ } }, "@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz", + "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", "dev": true, "requires": { - "@babel/types": "^7.15.0", + "@babel/types": "^7.15.4", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, "@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", "dev": true, "requires": { "@babel/compat-data": "^7.15.0", @@ -5758,111 +5789,111 @@ } }, "@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" } }, "@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", "dev": true, "requires": { - "@babel/types": "^7.15.0" + "@babel/types": "^7.15.4" } }, "@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" } }, "@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" } }, "@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" } }, "@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", "dev": true, "requires": { - "@babel/types": "^7.14.8" + "@babel/types": "^7.15.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.4" } }, "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true }, "@babel/helper-validator-option": { @@ -5872,14 +5903,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", - "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", "dev": true, "requires": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/highlight": { @@ -5952,43 +5983,43 @@ } }, "@babel/parser": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", - "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", "dev": true }, "@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", "dev": true, "requires": { "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", "dev": true, "requires": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.14.9", @@ -6129,9 +6160,9 @@ } }, "@octokit/auth-token": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", - "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", "dev": true, "requires": { "@octokit/types": "^6.0.3" @@ -6197,12 +6228,12 @@ "requires": {} }, "@octokit/plugin-rest-endpoint-methods": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.7.0.tgz", - "integrity": "sha512-G7sgccWRYQMwcHJXkDY/sDxbXeKiZkFQqUtzBCwmrzCNj2GQf3VygQ4T/BFL2crLVpIbenkE/c0ErhYOte2MPw==", + "version": "5.10.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.10.4.tgz", + "integrity": "sha512-Dh+EAMCYR9RUHwQChH94Skl0lM8Fh99auT8ggck/xTzjJrwVzvsd0YH68oRPqp/HxICzmUjLfaQ9sy1o1sfIiA==", "dev": true, "requires": { - "@octokit/types": "^6.24.0", + "@octokit/types": "^6.28.1", "deprecation": "^2.3.1" } }, @@ -6232,30 +6263,30 @@ } }, "@octokit/rest": { - "version": "18.9.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.9.0.tgz", - "integrity": "sha512-VrmrE8gjpuOoDAGjrQq2j9ZhOE6LxaqxaQg0yMrrEnnQZy2ZcAnr5qbVfKsMF0up/48PRV/VFS/2GSMhA7nTdA==", + "version": "18.10.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.10.0.tgz", + "integrity": "sha512-esHR5OKy38bccL/sajHqZudZCvmv4yjovMJzyXlphaUo7xykmtOdILGJ3aAm0mFHmMLmPFmDMJXf39cAjNJsrw==", "dev": true, "requires": { - "@octokit/core": "^3.5.0", - "@octokit/plugin-paginate-rest": "^2.6.2", - "@octokit/plugin-request-log": "^1.0.2", - "@octokit/plugin-rest-endpoint-methods": "5.7.0" + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.0", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.9.0" } }, "@octokit/types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.26.0.tgz", - "integrity": "sha512-RDxZBAFMtqs1ZPnbUu1e7ohPNfoNhTiep4fErY7tZs995BeHu369Vsh5woMIaFbllRWEZBfvTCS4hvDnMPiHrA==", + "version": "6.28.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.28.1.tgz", + "integrity": "sha512-XlxDoQLFO5JnFZgKVQTYTvXRsQFfr/GwDUU108NJ9R5yFPkA2qXhTJjYuul3vE4eLXP40FA2nysOu2zd6boE+w==", "dev": true, "requires": { - "@octokit/openapi-types": "^10.0.0" + "@octokit/openapi-types": "^10.2.2" } }, "@sindresorhus/is": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", - "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", + "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", "dev": true }, "@sinonjs/commons": { @@ -6345,9 +6376,9 @@ "dev": true }, "@types/keyv": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.2.tgz", - "integrity": "sha512-/FvAK2p4jQOaJ6CGDHJTqZcUtbZe820qIeTg7o0Shg7drB4JHeL+V/dhSaly7NXx6u8eSee+r7coT+yuJEvDLg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", + "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", "dev": true, "requires": { "@types/node": "*" @@ -6360,9 +6391,9 @@ "dev": true }, "@types/node": { - "version": "16.7.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.10.tgz", - "integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==", + "version": "16.9.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.6.tgz", + "integrity": "sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==", "dev": true }, "@types/parse-json": { @@ -6381,9 +6412,9 @@ } }, "@types/sinon": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.2.tgz", - "integrity": "sha512-BHn8Bpkapj8Wdfxvh2jWIUoaYB/9/XhsL0oOvBfRagJtKlSl9NWPcFOz2lRukI9szwGxFtYZCTejJSqsGDbdmw==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.3.tgz", + "integrity": "sha512-XUaFuUOQ3A/r6gS1qCU/USMleascaqGeQpGR1AZ5JdRtBPlzijRzKsik1TuGzvdtPA0mdq42JqaJmJ+Afg1LJg==", "dev": true, "requires": { "@sinonjs/fake-timers": "^7.1.0" @@ -6408,15 +6439,15 @@ "dev": true }, "acorn": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", - "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true }, "acorn-walk": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.1.1.tgz", - "integrity": "sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, "aggregate-error": { @@ -6502,9 +6533,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { @@ -6560,12 +6591,12 @@ "dev": true }, "async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", "dev": true, "requires": { - "retry": "0.12.0" + "retry": "0.13.1" } }, "asynckit": { @@ -6610,16 +6641,16 @@ } }, "boxen": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.0.1.tgz", - "integrity": "sha512-49VBlw+PrWEF51aCmy7QIteYPIFZxSpvqBdP/2itCPPlJ49kj9zg/XPRFrdkne2W+CfwXUls8exMvu1RysZpKA==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", "dev": true, "requires": { "ansi-align": "^3.0.0", "camelcase": "^6.2.0", "chalk": "^4.1.0", "cli-boxes": "^2.2.1", - "string-width": "^4.2.0", + "string-width": "^4.2.2", "type-fest": "^0.20.2", "widest-line": "^3.1.0", "wrap-ansi": "^7.0.0" @@ -6665,14 +6696,14 @@ "dev": true }, "browserslist": { - "version": "4.16.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", - "integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz", + "integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001251", + "caniuse-lite": "^1.0.30001254", "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.811", + "electron-to-chromium": "^1.3.830", "escalade": "^3.1.1", "node-releases": "^1.1.75" } @@ -6760,9 +6791,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001252", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz", - "integrity": "sha512-I56jhWDGMtdILQORdusxBOH+Nl/KgQSdDmpJezYddnAkVOmnoU8zwjTV9xAjMIYxr0iPreEAVylCGcmHCjfaOw==", + "version": "1.0.30001259", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001259.tgz", + "integrity": "sha512-V7mQTFhjITxuk9zBpI6nYsiTXhcPe05l+364nZjK7MFK/E7ibvYBSAXr4YcA6oPR8j3ZLM/LN+lUqUVAQEUZFg==", "dev": true }, "chalk": { @@ -6894,9 +6925,9 @@ "dev": true }, "colorette": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", - "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", "dev": true }, "combined-stream": { @@ -6944,9 +6975,9 @@ } }, "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", @@ -7209,9 +7240,9 @@ } }, "fastq": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", - "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -7373,9 +7404,9 @@ } }, "git-url-parse": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.5.0.tgz", - "integrity": "sha512-TZYSMDeM37r71Lqg1mbnMlOqlHd7BSij9qN7XwTkRqSAYFMihGLGhfHwgqQob3GUhEneKnV4nskN9rbQw2KGxA==", + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.6.0.tgz", + "integrity": "sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g==", "dev": true, "requires": { "git-up": "^4.0.0" @@ -7654,9 +7685,9 @@ "dev": true }, "inquirer": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.2.tgz", - "integrity": "sha512-DHLKJwLPNgkfwNmsuEUKSejJFbkv0FMO9SMiQbjI3n5NQuCrSIBqP66ggqyz2a6t2qEolKrMjhQ3+W/xXgUQ+Q==", + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", + "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -7667,7 +7698,7 @@ "figures": "^3.0.0", "lodash": "^4.17.21", "mute-stream": "0.0.8", - "ora": "^5.3.0", + "ora": "^5.4.1", "run-async": "^2.4.0", "rxjs": "^7.2.0", "string-width": "^4.1.0", @@ -7988,6 +8019,12 @@ "minimist": "^1.2.5" } }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, "just-extend": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", @@ -8106,9 +8143,9 @@ "dev": true }, "marked": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.2.tgz", - "integrity": "sha512-TMJQQ79Z0e3rJYazY0tIoMsFzteUGw9fB3FD+gzuIT3zLuG9L9ckIvUfF51apdJkcqc208jJN2KbtPbOvXtbjA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.4.tgz", + "integrity": "sha512-jBo8AOayNaEcvBhNobg6/BLhdsK3NvnKWJg33MAAPbvTWiG4QBn9gpW1+7RssrKu4K1dKlN+0goVQwV41xEfOA==", "dev": true }, "merge-stream": { @@ -8263,10 +8300,13 @@ } }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-aD1fO+xtLiSCc9vuD+sYMxpIuQyhHscGSkBEo2o5LTV/3bTEAYvdUii29n8LlO5uLCmWdGP7uVUVXFo5SRdkLA==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } }, "node-preload": { "version": "0.2.1", @@ -8278,9 +8318,9 @@ } }, "node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "1.1.76", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", + "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==", "dev": true }, "normalize-path": { @@ -9025,25 +9065,25 @@ } }, "release-it": { - "version": "14.11.5", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.11.5.tgz", - "integrity": "sha512-9BaPdq7ZKOwtzz3p1mRhg/tOH/cT/y2tUnPYzUwQiVdj42JaGI1Vo2l3WbgK8ICsbFyrhc0tri1+iqI8OvkI1A==", + "version": "14.11.6", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.11.6.tgz", + "integrity": "sha512-6BNcuzFZHThBUBJ/xYw/bxZ+58CAwrwf1zgmjq2Ibl3nlDZbjphHG6iqxkJu7mZ8TIWs6NjloEAhqpjeXoN//Q==", "dev": true, "requires": { "@iarna/toml": "2.2.5", - "@octokit/rest": "18.9.0", - "async-retry": "1.3.1", + "@octokit/rest": "18.10.0", + "async-retry": "1.3.3", "chalk": "4.1.2", - "cosmiconfig": "7.0.0", + "cosmiconfig": "7.0.1", "debug": "4.3.2", "deprecated-obj": "2.0.0", "execa": "5.1.1", "form-data": "4.0.0", - "git-url-parse": "11.5.0", + "git-url-parse": "11.6.0", "globby": "11.0.4", "got": "11.8.2", "import-cwd": "3.0.0", - "inquirer": "8.1.2", + "inquirer": "8.1.5", "is-ci": "3.0.0", "lodash": "4.17.21", "mime-types": "2.1.32", @@ -9171,9 +9211,9 @@ } }, "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true }, "reusify": { @@ -9289,7 +9329,7 @@ "integrity": "sha512-xeM7Oc6hY+6iW5O/T5hor8ul7mEprzyl5y4r5zthEHToQNw7MIhREMgU3r2gKDB0NaMLNrkcEQagudCdzE13Lg==", "dev": true, "requires": { - "json5": "^2.2.0", + "jsonc-parser": "^3.0.0", "onigasm": "^2.2.5", "vscode-textmate": "5.2.0" } @@ -9306,9 +9346,9 @@ } }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", + "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", "dev": true }, "sinon": { @@ -9349,9 +9389,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -9509,6 +9549,12 @@ "is-number": "^7.0.0" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, "ts-node": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", @@ -9603,15 +9649,15 @@ } }, "typescript": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", - "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", "dev": true }, "uglify-js": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.1.tgz", - "integrity": "sha512-JhS3hmcVaXlp/xSo3PKY5R0JqKs5M3IV+exdLHW99qKvKivPO4Z8qbej6mte17SOPqAOVMjt/XGgWacnFSzM3g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", + "integrity": "sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A==", "dev": true, "optional": true }, @@ -9729,6 +9775,22 @@ "defaults": "^1.0.3" } }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 56a7ed38c65..b2ceadbdd16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redis", - "version": "4.0.0-rc.1", + "version": "4.0.0-rc.2", "description": "A high performance Redis client.", "keywords": [ "database", @@ -35,20 +35,20 @@ "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", "@types/mocha": "^9.0.0", - "@types/node": "^16.7.10", - "@types/sinon": "^10.0.2", + "@types/node": "^16.9.6", + "@types/sinon": "^10.0.3", "@types/which": "^2.0.1", "@types/yallist": "^4.0.1", "mocha": "^9.1.1", "nyc": "^15.1.0", - "release-it": "^14.11.5", + "release-it": "^14.11.6", "sinon": "^11.1.2", - "source-map-support": "^0.5.19", + "source-map-support": "^0.5.20", "ts-node": "^10.2.1", - "typedoc": "^0.21.9", + "typedoc": "0.21.9", "typedoc-github-wiki-theme": "^0.5.1", - "typedoc-plugin-markdown": "^3.10.4", - "typescript": "^4.4.2", + "typedoc-plugin-markdown": "3.10.4", + "typescript": "^4.4.3", "which": "^2.0.2" }, "engines": {