From d9c815f50e6814197f4a1f955527addb44871e5c Mon Sep 17 00:00:00 2001
From: Itamar Haber <itamar@redis.com>
Date: Sun, 22 Jan 2023 21:18:34 +0200
Subject: [PATCH 01/20] Initial example

---
 examples/json_search/example.json | 11 +++++
 examples/json_search/index.js     | 67 +++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)
 create mode 100644 examples/json_search/example.json
 create mode 100644 examples/json_search/index.js

diff --git a/examples/json_search/example.json b/examples/json_search/example.json
new file mode 100644
index 00000000000..8404f92efb5
--- /dev/null
+++ b/examples/json_search/example.json
@@ -0,0 +1,11 @@
+{
+    "id": "json_search",
+    "file": "index.js",
+    "highlight": [
+        "10",
+        "44-56",
+        "63"
+    ],
+    "hide": [],
+    "collapse": []
+}
\ No newline at end of file
diff --git a/examples/json_search/index.js b/examples/json_search/index.js
new file mode 100644
index 00000000000..a9e493ebc17
--- /dev/null
+++ b/examples/json_search/index.js
@@ -0,0 +1,67 @@
+import { createClient, SchemaFieldTypes} from 'redis';
+
+const client = createClient();
+
+await client.connect();
+
+// Create an index.
+// https://redis.io/commands/ft.create/
+try {
+  await client.ft.create('idx:users', {
+    '$.name': {
+      type: SchemaFieldTypes.TEXT,
+      SORTABLE: 'UNF'
+    },
+    '$.age': {
+      type: SchemaFieldTypes.NUMERIC,
+      AS: 'age'
+    },
+    '$.coins': {
+      type: SchemaFieldTypes.NUMERIC,
+      AS: 'coins'
+    },
+    '$.email': {
+      type: SchemaFieldTypes.TAG,
+      AS: 'email'
+    }
+  }, {
+    ON: 'JSON',
+    PREFIX: 'noderedis:users'
+  });
+} catch (e) {
+  if (e.message === 'Index already exists') {
+    console.log('Index exists already, skipped creation.');
+  } else {
+    // Something went wrong, perhaps RediSearch isn't installed...
+    console.error(e);
+    process.exit(1);
+  }
+}
+
+// Add some users.
+// https://redis.io/commands/json.set/
+await Promise.all([
+  client.json.set('noderedis:users:1', '$', {
+    name: 'Alice',
+    age: 32,
+    coins: 100,
+    email: 'alice@nonexist.com'
+  }),
+  client.json.set('noderedis:users:2', '$', {
+    name: 'Bob',
+    age: 23,
+    coins: 15,
+    email: 'bob@somewhere.gov'
+  })
+]);
+
+// Search all users under 30
+console.log('Users under 30 years old:');
+console.log(
+  // https://redis.io/commands/ft.search/
+  JSON.stringify(
+    await client.ft.search('idx:users', '@age:[0 30]'),
+    null,
+    2
+  )
+);

From 5c835d1a5923cf255c84f9a0a7fd801d0c9b8844 Mon Sep 17 00:00:00 2001
From: Itamar Haber <itamar@redis.com>
Date: Tue, 14 Mar 2023 15:00:52 +0200
Subject: [PATCH 02/20] Adds anchors

---
 examples/json_search/example.json | 9 +--------
 examples/json_search/index.js     | 7 ++++---
 2 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/examples/json_search/example.json b/examples/json_search/example.json
index 8404f92efb5..6a055e7a2cc 100644
--- a/examples/json_search/example.json
+++ b/examples/json_search/example.json
@@ -1,11 +1,4 @@
 {
     "id": "json_search",
-    "file": "index.js",
-    "highlight": [
-        "10",
-        "44-56",
-        "63"
-    ],
-    "hide": [],
-    "collapse": []
+    "file": "index.js"
 }
\ No newline at end of file
diff --git a/examples/json_search/index.js b/examples/json_search/index.js
index a9e493ebc17..8f5a0bcbca3 100644
--- a/examples/json_search/index.js
+++ b/examples/json_search/index.js
@@ -1,8 +1,9 @@
-import { createClient, SchemaFieldTypes} from 'redis';
-
+// HIDE_START
+// Step 1
+import { createClient, SchemaFieldTypes } from 'redis';
 const client = createClient();
-
 await client.connect();
+// HIDE_END
 
 // Create an index.
 // https://redis.io/commands/ft.create/

From caaca48ca1604f515f153ac77e5fa96ef95523cb Mon Sep 17 00:00:00 2001
From: Igor Malinovskiy <igor.malinovskiy@redis.com>
Date: Mon, 10 Apr 2023 17:42:53 +0200
Subject: [PATCH 03/20] Add Redis.io code examples - Add set & get example -
 Use bash script to test doc tests - Add package.json to doctests - Add
 search-quickstart

---
 .github/workflows/doctests.yml     |  41 +++++
 doctests/README.md                 |  32 ++++
 doctests/package.json              |  12 ++
 doctests/run_examples.sh           |  15 ++
 doctests/search-quickstart.js      | 239 +++++++++++++++++++++++++++++
 doctests/string-set-get-example.js |  26 ++++
 6 files changed, 365 insertions(+)
 create mode 100644 .github/workflows/doctests.yml
 create mode 100644 doctests/README.md
 create mode 100644 doctests/package.json
 create mode 100755 doctests/run_examples.sh
 create mode 100644 doctests/search-quickstart.js
 create mode 100644 doctests/string-set-get-example.js

diff --git a/.github/workflows/doctests.yml b/.github/workflows/doctests.yml
new file mode 100644
index 00000000000..a85d116154b
--- /dev/null
+++ b/.github/workflows/doctests.yml
@@ -0,0 +1,41 @@
+name: Documentation Tests
+
+on:
+  push:
+  pull_request:
+
+  workflow_dispatch:
+
+permissions:
+  contents: read
+
+jobs:
+  doctests:
+    runs-on: ubuntu-latest
+    services:
+      redis-stack:
+        image: redis/redis-stack-server:latest
+        options: >-
+          --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
+        ports:
+          - 6379:6379
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-node@v2.3.0
+        with:
+          node-version: 18
+      - name: Install Packages
+        run: npm ci
+      - name: Build
+        run: npm run build-all
+      - run: |
+          sudo apt update
+          sudo apt install -y redis-tools
+      - name: install doctest deps
+        run: |
+          npm install
+        working-directory: doctests
+      - name: run tests
+        run: |
+          sh run_examples.sh
+        working-directory: doctests
\ No newline at end of file
diff --git a/doctests/README.md b/doctests/README.md
new file mode 100644
index 00000000000..b596eb0b114
--- /dev/null
+++ b/doctests/README.md
@@ -0,0 +1,32 @@
+# Command examples for redis.io
+
+## Setup
+
+To set up the examples folder so that you can run an example / develop one of your own:
+
+```
+$ git clone https://github.com/redis/node-redis.git
+$ cd node-redis
+$ npm install -ws && npm run build-all
+$ cd doctests
+$ npm install
+```
+
+## How to add examples
+
+Create regular node file in the current folder with meaningful name. It makes sense prefix example files with
+command category (e.g. string, set, list, hash, etc) to make navigation in the folder easier.
+
+### Special markup
+
+See https://github.com/redis-stack/redis-stack-website#readme for more details.
+
+## How to test the examples
+
+Just include necessary assertions in the example file and run
+```bash
+sh doctests/run_examples.sh
+```
+to test all examples in the current folder.
+
+See `tests.js` for more details.
diff --git a/doctests/package.json b/doctests/package.json
new file mode 100644
index 00000000000..76db8b3d8c7
--- /dev/null
+++ b/doctests/package.json
@@ -0,0 +1,12 @@
+{
+  "name": "node-redis-doctests",
+  "version": "1.0.0",
+  "description": "Code examples for redis.io",
+  "main": "index.js",
+  "private": true,
+  "type": "module",
+  "dependencies": {
+    "redis": "../"
+  }
+}
+
diff --git a/doctests/run_examples.sh b/doctests/run_examples.sh
new file mode 100755
index 00000000000..ee7b50dc69a
--- /dev/null
+++ b/doctests/run_examples.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+
+basepath=`readlink -f $1`
+if [ $? -ne 0 ]; then
+basepath=`readlink -f $(dirname $0)`
+fi
+echo "No path specified, using ${basepath}"
+
+set -e
+cd ${basepath}
+for i in `ls ${basepath}/*.js`; do
+    redis-cli flushdb
+    node $i
+done
\ No newline at end of file
diff --git a/doctests/search-quickstart.js b/doctests/search-quickstart.js
new file mode 100644
index 00000000000..c25f79f3c13
--- /dev/null
+++ b/doctests/search-quickstart.js
@@ -0,0 +1,239 @@
+// EXAMPLE: search_quickstart
+// REMOVE_START
+import assert from "assert";
+// REMOVE_END
+// HIDE_START
+import {AggregateGroupByReducers, AggregateSteps, createClient, SchemaFieldTypes} from 'redis';
+// HIDE_END
+// STEP_START connect
+const client = createClient();
+client.on('error', err => console.log('Redis Client Error', err));
+
+await client.connect();
+// STEP_END
+
+// STEP_START data_sample
+let bicycle1 = {
+    "brand": "Diaz Ltd",
+    "model": "Dealer Sl",
+    "price": 7315.58,
+    "description": "The Diaz Ltd Dealer Sl is a reliable choice" +
+        " for urban cycling. The Diaz Ltd Dealer Sl " +
+        "is a comfortable choice for urban cycling.",
+    "condition": "used",
+}
+// STEP_END
+let bicycles = [
+    bicycle1,
+    {
+        "brand": "Bridges Group",
+        "model": "Project Pro",
+        "price": 3610.82,
+        "description": "This mountain bike is perfect for mountain biking. The Bridges Group Project Pro is a responsive choice for mountain biking.",
+        "condition": "used",
+    },
+    {
+        "brand": "Vega, Cole and Miller",
+        "model": "Group Advanced",
+        "price": 8961.42,
+        "description": "The Vega, Cole and Miller Group Advanced provides a excellent ride. With its fast carbon frame and 24 gears, this bicycle is perfect for any terrain.",
+        "condition": "used",
+    },
+    {
+        "brand": "Powell-Montgomery",
+        "model": "Angle Race",
+        "price": 4050.27,
+        "description": "The Powell-Montgomery Angle Race is a smooth choice for road cycling. The Powell-Montgomery Angle Race provides a durable ride.",
+        "condition": "used",
+    },
+    {
+        "brand": "Gill-Lewis",
+        "model": "Action Evo",
+        "price": 283.68,
+        "description": "The Gill-Lewis Action Evo provides a smooth ride. The Gill-Lewis Action Evo provides a excellent ride.",
+        "condition": "used",
+    },
+    {
+        "brand": "Rodriguez-Guerrero",
+        "model": "Drama Comp",
+        "price": 4462.55,
+        "description": "This kids bike is perfect for young riders. With its excellent aluminum frame and 12 gears, this bicycle is perfect for any terrain.",
+        "condition": "new",
+    },
+    {
+        "brand": "Moore PLC",
+        "model": "Award Race",
+        "price": 3790.76,
+        "description": "This olive folding bike features a carbon frame and 27.5 inch wheels. This folding bike is perfect for compact storage and transportation.",
+        "condition": "new",
+    },
+    {
+        "brand": "Hall, Haley and Hayes",
+        "model": "Weekend Plus",
+        "price": 2008.4,
+        "description": "The Hall, Haley and Hayes Weekend Plus provides a comfortable ride. This blue kids bike features a steel frame and 29.0 inch wheels.",
+        "condition": "new",
+    },
+    {
+        "brand": "Peck-Carson",
+        "model": "Sun Hybrid",
+        "price": 9874.95,
+        "description": "With its comfortable aluminum frame and 25 gears, this bicycle is perfect for any terrain. The Peck-Carson Sun Hybrid provides a comfortable ride.",
+        "condition": "new",
+    },
+    {
+        "brand": "Fowler Ltd",
+        "model": "Weekend Trail",
+        "price": 3833.71,
+        "description": "The Fowler Ltd Letter Trail is a comfortable choice for transporting cargo. This cargo bike is perfect for transporting cargo.",
+        "condition": "refurbished",
+    },
+]
+// STEP_START define_index
+let schema = {
+    '$.brand': {
+        type: SchemaFieldTypes.TEXT,
+        sortable: true,
+        AS: 'brand'
+    },
+    '$.model': {
+        type: SchemaFieldTypes.TEXT,
+        AS: 'model'
+    },
+    '$.description': {
+        type: SchemaFieldTypes.TEXT,
+        AS: 'description'
+    },
+    '$.price': {
+        type: SchemaFieldTypes.NUMERIC,
+        AS: 'price'
+    },
+    '$.condition': {
+        type: SchemaFieldTypes.TAG,
+        AS: 'condition'
+    },
+}
+// STEP_END
+
+// STEP_START create_index
+try {
+    await client.ft.create('idx:bicycle', schema, {
+        ON: 'JSON',
+        PREFIX: 'bicycle:'
+    });
+} catch (e) {
+    if (e.message === 'Index already exists') {
+        console.log('Index exists already, skipped creation.');
+    } else {
+        // Something went wrong, perhaps RediSearch isn't installed...
+        console.error(e);
+        process.exit(1);
+    }
+}
+// STEP_END
+
+// STEP_START add_documents
+for (let i = 0; i < bicycles.length; i++) {
+    await client.json.set(`bicycle:${i}`, '$', bicycles[i]);
+}
+// STEP_END
+
+// STEP_START query_single_term_and_num_range
+let result = await client.ft.search(
+    'idx:bicycle',
+    'folding @price:[1000 4000]'
+);
+
+console.log(JSON.stringify(result, null, 2));
+/*
+{
+  "total": 1,
+  "documents": [
+    {
+      "id": "bicycle:6",
+      "value": {
+        "brand": "Moore PLC",
+        "model": "Award Race",
+        "price": 3790.76,
+        "description": "This olive folding bike features a carbon frame and 27.5 inch wheels. This folding bike is perfect for compact storage and transportation.",
+        "condition": "new"
+      }
+    }
+  ]
+}
+*/
+// STEP_END
+// REMOVE_START
+assert.equal(result.documents[0].id, "bicycle:6");
+// REMOVE_END
+
+// STEP_START query_single_term_limit_fields
+result = await client.ft.search(
+    'idx:bicycle',
+    'cargo',
+    {
+        RETURN: ['$.price']
+    }
+);
+
+console.log(JSON.stringify(result, null, 2));
+/*
+{
+  "total": 1,
+  "documents": [
+    {
+      "id": "bicycle:9",
+      "value": {
+        "$.price": "3833.71"
+      }
+    }
+  ]
+}
+ */
+// STEP_END
+// REMOVE_START
+assert.equal(result.documents[0].id, "bicycle:9");
+// REMOVE_END
+
+// STEP_START simple_aggregation
+result = await client.ft.aggregate('idx:bicycle', '*', {
+    STEPS: [
+        {
+            type: AggregateSteps.GROUPBY,
+            properties: ['@condition'],
+            REDUCE: [
+                {
+                    type: AggregateGroupByReducers.COUNT,
+                    AS: 'count'
+                }
+            ]
+        }
+    ]
+})
+
+console.log(JSON.stringify(result, null, 2));
+/*
+{
+  "total": 3,
+  "results": [
+    {
+      "condition": "refurbished",
+      "count": "1"
+    },
+    {
+      "condition": "used",
+      "count": "5"
+    },
+    {
+      "condition": "new",
+      "count": "4"
+    }
+  ]
+}
+ */
+// STEP_END
+// REMOVE_START
+assert.equal(result.total, 3);
+// REMOVE_END
+
+await client.quit();
\ No newline at end of file
diff --git a/doctests/string-set-get-example.js b/doctests/string-set-get-example.js
new file mode 100644
index 00000000000..0b0c9138f5a
--- /dev/null
+++ b/doctests/string-set-get-example.js
@@ -0,0 +1,26 @@
+// EXAMPLE: set_and_get
+// REMOVE_START
+import assert from "assert";
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+
+client.on('error', err => console.log('Redis Client Error', err));
+
+await client.connect();
+
+// HIDE_END
+await client.set('bike:1', 'Process 134');
+const value = await client.get('bike:1');
+console.log(value);
+// returns 'Process 134'
+//REMOVE_START
+assert.equal(value, 'Process 134');
+//REMOVE_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
\ No newline at end of file

From 0588b383cbc34685b59a6862b41e7a10dee06559 Mon Sep 17 00:00:00 2001
From: Justin Castilla <59704472+justincastilla@users.noreply.github.com>
Date: Thu, 22 Jun 2023 03:44:35 -0700
Subject: [PATCH 04/20] [DOC-2373] adds js samples to match search-quickstart
 md (#2538)

* [DOC-2373] adds js samples to match search-quickstart md

* Fixes step matching for the Search quickstart

* Update search-quickstart.js

---------

Co-authored-by: Justin Castilla <pxlperfection@gmail.com>
Co-authored-by: Elena Kolevska <elena@kolevska.com>
Co-authored-by: Leibale Eidelman <me@leibale.com>
---
 doctests/search-quickstart.js | 360 +++++++++++++++++-----------------
 1 file changed, 176 insertions(+), 184 deletions(-)

diff --git a/doctests/search-quickstart.js b/doctests/search-quickstart.js
index c25f79f3c13..3bfe4d6b9ad 100644
--- a/doctests/search-quickstart.js
+++ b/doctests/search-quickstart.js
@@ -1,9 +1,9 @@
 // EXAMPLE: search_quickstart
 // REMOVE_START
-import assert from "assert";
+import assert from 'assert';
 // REMOVE_END
 // HIDE_START
-import {AggregateGroupByReducers, AggregateSteps, createClient, SchemaFieldTypes} from 'redis';
+import { AggregateGroupByReducers, AggregateSteps, createClient, SchemaFieldTypes } from 'redis';
 // HIDE_END
 // STEP_START connect
 const client = createClient();
@@ -13,227 +13,219 @@ await client.connect();
 // STEP_END
 
 // STEP_START data_sample
-let bicycle1 = {
-    "brand": "Diaz Ltd",
-    "model": "Dealer Sl",
-    "price": 7315.58,
-    "description": "The Diaz Ltd Dealer Sl is a reliable choice" +
-        " for urban cycling. The Diaz Ltd Dealer Sl " +
-        "is a comfortable choice for urban cycling.",
-    "condition": "used",
-}
-// STEP_END
-let bicycles = [
-    bicycle1,
-    {
-        "brand": "Bridges Group",
-        "model": "Project Pro",
-        "price": 3610.82,
-        "description": "This mountain bike is perfect for mountain biking. The Bridges Group Project Pro is a responsive choice for mountain biking.",
-        "condition": "used",
-    },
-    {
-        "brand": "Vega, Cole and Miller",
-        "model": "Group Advanced",
-        "price": 8961.42,
-        "description": "The Vega, Cole and Miller Group Advanced provides a excellent ride. With its fast carbon frame and 24 gears, this bicycle is perfect for any terrain.",
-        "condition": "used",
-    },
-    {
-        "brand": "Powell-Montgomery",
-        "model": "Angle Race",
-        "price": 4050.27,
-        "description": "The Powell-Montgomery Angle Race is a smooth choice for road cycling. The Powell-Montgomery Angle Race provides a durable ride.",
-        "condition": "used",
-    },
-    {
-        "brand": "Gill-Lewis",
-        "model": "Action Evo",
-        "price": 283.68,
-        "description": "The Gill-Lewis Action Evo provides a smooth ride. The Gill-Lewis Action Evo provides a excellent ride.",
-        "condition": "used",
-    },
-    {
-        "brand": "Rodriguez-Guerrero",
-        "model": "Drama Comp",
-        "price": 4462.55,
-        "description": "This kids bike is perfect for young riders. With its excellent aluminum frame and 12 gears, this bicycle is perfect for any terrain.",
-        "condition": "new",
-    },
-    {
-        "brand": "Moore PLC",
-        "model": "Award Race",
-        "price": 3790.76,
-        "description": "This olive folding bike features a carbon frame and 27.5 inch wheels. This folding bike is perfect for compact storage and transportation.",
-        "condition": "new",
-    },
-    {
-        "brand": "Hall, Haley and Hayes",
-        "model": "Weekend Plus",
-        "price": 2008.4,
-        "description": "The Hall, Haley and Hayes Weekend Plus provides a comfortable ride. This blue kids bike features a steel frame and 29.0 inch wheels.",
-        "condition": "new",
-    },
-    {
-        "brand": "Peck-Carson",
-        "model": "Sun Hybrid",
-        "price": 9874.95,
-        "description": "With its comfortable aluminum frame and 25 gears, this bicycle is perfect for any terrain. The Peck-Carson Sun Hybrid provides a comfortable ride.",
-        "condition": "new",
-    },
-    {
-        "brand": "Fowler Ltd",
-        "model": "Weekend Trail",
-        "price": 3833.71,
-        "description": "The Fowler Ltd Letter Trail is a comfortable choice for transporting cargo. This cargo bike is perfect for transporting cargo.",
-        "condition": "refurbished",
-    },
-]
-// STEP_START define_index
-let schema = {
-    '$.brand': {
-        type: SchemaFieldTypes.TEXT,
-        sortable: true,
-        AS: 'brand'
-    },
-    '$.model': {
-        type: SchemaFieldTypes.TEXT,
-        AS: 'model'
-    },
-    '$.description': {
-        type: SchemaFieldTypes.TEXT,
-        AS: 'description'
-    },
-    '$.price': {
-        type: SchemaFieldTypes.NUMERIC,
-        AS: 'price'
-    },
-    '$.condition': {
-        type: SchemaFieldTypes.TAG,
-        AS: 'condition'
-    },
-}
+const bicycle1 = {
+  brand: 'Velorim',
+  model: 'Jigger',
+  price: 270,
+  description:
+    'Small and powerful, the Jigger is the best ' +
+    'ride for the smallest of tikes! This is the tiniest kids\u2019 ' +
+    'pedal bike on the market available without a coaster brake, the ' +
+    'Jigger is the vehicle of choice for the rare tenacious little' +
+    'rider raring to go.',
+  condition: 'new'
+};
 // STEP_END
-
+const bicycles = [
+  bicycle1,
+  {
+    brand: 'Bicyk',
+    model: 'Hillcraft',
+    price: 1200,
+    description: 'Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\" wheel bike is just too clumsy coming off a 24\" bike. The Hillcraft 26 is just the solution they need!',
+    condition: 'used'
+  },
+  {
+    brand: 'Nord',
+    model: 'Chook air 5',
+    price: 815,
+    description: 'The Chook Air 5 gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails.',
+    condition: 'used'
+  },
+  {
+    brand: 'Eva',
+    model: 'Eva 291',
+    price: 3400,
+    description: 'The sister company to Nord, Eva launched in 2005 as the first and only women-dedicated bicycle brand. Designed by women for women, allEva bikes are optimized for the feminine physique using analytics from a body metrics database. If you like 29ers, try the Eva 291. It\u2019s a brand new bike for 2022.. This full-suspension, cross-country ride has been designed for velocity. The 291 has 100mm of front and rear travel, a superlight aluminum frame and fast-rolling 29-inch wheels. Yippee!',
+    condition: 'used'
+  },
+  {
+    brand: 'Noka Bikes',
+    model: 'Kahuna',
+    price: 3200,
+    description: 'Whether you want to try your hand at XC racing or are looking for a lively trail bike that\'s just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women\u2019s saddle, different bars and unique colourway.',
+    condition: 'used'
+  },
+  {
+    brand: 'Breakout',
+    model: 'XBN 2.1 Alloy',
+    price: 810,
+    description: 'The XBN 2.1 Alloy is our entry-level road bike \u2013 but that\u2019s not to say that it\u2019s a basic machine. With an internal weld aluminium frame, a full carbon fork, and the slick-shifting Claris gears from Shimano\u2019s, this is a bike which doesn\u2019t break the bank and delivers craved performance.',
+    condition: 'new'
+  },
+  {
+    brand: 'ScramBikes',
+    model: 'WattBike',
+    price: 2300,
+    description: 'The WattBike is the best e-bike for people who still feel young at heart. It has a Bafang 1000W mid-drive system and a 48V 17.5AH Samsung Lithium-Ion battery, allowing you to ride for more than 60 miles on one charge. It\u2019s great for tackling hilly terrain or if you just fancy a more leisurely ride. With three working modes, you can choose between E-bike, assisted bicycle, and normal bike modes.',
+    condition: 'new'
+  },
+  {
+    brand: 'Peaknetic',
+    model: 'Secto',
+    price: 430,
+    description: 'If you struggle with stiff fingers or a kinked neck or back after a few minutes on the road, this lightweight, aluminum bike alleviates those issues and allows you to enjoy the ride. From the ergonomic grips to the lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. The rear-inclined seat tube facilitates stability by allowing you to put a foot on the ground to balance at a stop, and the low step-over frame makes it accessible for all ability and mobility levels. The saddle is very soft, with a wide back to support your hip joints and a cutout in the center to redistribute that pressure. Rim brakes deliver satisfactory braking control, and the wide tires provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts facilitate setting up the Roll Low-Entry as your preferred commuter, and the BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder.',
+    condition: 'new'
+  },
+  {
+    brand: 'nHill',
+    model: 'Summit',
+    price: 1200,
+    description: 'This budget mountain bike from nHill performs well both on bike paths and on the trail. The fork with 100mm of travel absorbs rough terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. The Shimano Tourney drivetrain offered enough gears for finding a comfortable pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. Whether you want an affordable bike that you can take to work, but also take trail in mountains on the weekends or you\u2019re just after a stable, comfortable ride for the bike path, the Summit gives a good value for money.',
+    condition: 'new'
+  },
+  {
+    model: 'ThrillCycle',
+    brand: 'BikeShind',
+    price: 815,
+    description: 'An artsy, retro-inspired bicycle that\u2019s as functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn\u2019t suggest taking it to the mountains. Fenders protect you from mud, and a rear basket lets you transport groceries, flowers and books. The ThrillCycle comes with a limited lifetime warranty, so this little guy will last you long past graduation.',
+    condition: 'refurbished'
+  }
+];
 // STEP_START create_index
+const schema = {
+  '$.brand': {
+    type: SchemaFieldTypes.TEXT,
+    SORTABLE: true,
+    AS: 'brand'
+  },
+  '$.model': {
+    type: SchemaFieldTypes.TEXT,
+    AS: 'model'
+  },
+  '$.description': {
+    type: SchemaFieldTypes.TEXT,
+    AS: 'description'
+  },
+  '$.price': {
+    type: SchemaFieldTypes.NUMERIC,
+    AS: 'price'
+  },
+  '$.condition': {
+    type: SchemaFieldTypes.TAG,
+    AS: 'condition'
+  }
+};
+
 try {
-    await client.ft.create('idx:bicycle', schema, {
-        ON: 'JSON',
-        PREFIX: 'bicycle:'
-    });
+  await client.ft.create('idx:bicycle', schema, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+  });
 } catch (e) {
-    if (e.message === 'Index already exists') {
-        console.log('Index exists already, skipped creation.');
-    } else {
-        // Something went wrong, perhaps RediSearch isn't installed...
-        console.error(e);
-        process.exit(1);
-    }
+  if (e.message === 'Index already exists') {
+    console.log('Index exists already, skipped creation.');
+  } else {
+    // Something went wrong, perhaps RediSearch isn't installed...
+    console.error(e);
+    process.exit(1);
+  }
 }
 // STEP_END
 
 // STEP_START add_documents
-for (let i = 0; i < bicycles.length; i++) {
-    await client.json.set(`bicycle:${i}`, '$', bicycles[i]);
-}
+await Promise.all(
+  bicycles.map((bicycle, i) => client.json.set(`bicycle:${i}`, '$', bicycle))
+);
 // STEP_END
 
-// STEP_START query_single_term_and_num_range
-let result = await client.ft.search(
-    'idx:bicycle',
-    'folding @price:[1000 4000]'
-);
+// STEP_START wildcard_query
+let result = await client.ft.search('idx:bicycle', '*', {
+  LIMIT: {
+    from: 0,
+    size: 10
+  }
+});
 
 console.log(JSON.stringify(result, null, 2));
+
 /*
 {
-  "total": 1,
-  "documents": [
-    {
-      "id": "bicycle:6",
-      "value": {
-        "brand": "Moore PLC",
-        "model": "Award Race",
-        "price": 3790.76,
-        "description": "This olive folding bike features a carbon frame and 27.5 inch wheels. This folding bike is perfect for compact storage and transportation.",
-        "condition": "new"
-      }
-    }
-  ]
+  "total": 10,
+  "documents": ...
 }
 */
 // STEP_END
+
 // REMOVE_START
-assert.equal(result.documents[0].id, "bicycle:6");
+assert.equal(result.documents[0].id, 'bicycle:1');
 // REMOVE_END
 
-// STEP_START query_single_term_limit_fields
+// STEP_START query_single_term
 result = await client.ft.search(
-    'idx:bicycle',
-    'cargo',
-    {
-        RETURN: ['$.price']
-    }
-);
+  'idx:bicycle',
+  '@model:Jigger',
+  {
+    LIMIT: {
+    from: 0,
+    size: 10
+  }
+});
 
 console.log(JSON.stringify(result, null, 2));
 /*
 {
   "total": 1,
-  "documents": [
-    {
-      "id": "bicycle:9",
-      "value": {
-        "$.price": "3833.71"
-      }
+  "documents": [{
+    "id": "bicycle:0",
+    "value": {
+      "brand": "Velorim",
+      "model": "Jigger",
+      "price": 270,
+      "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.",
+      "condition": "new"
     }
-  ]
+  }]
 }
  */
 // STEP_END
 // REMOVE_START
-assert.equal(result.documents[0].id, "bicycle:9");
+assert.equal(result.documents[0].id, 'bicycle:0');
 // REMOVE_END
 
-// STEP_START simple_aggregation
-result = await client.ft.aggregate('idx:bicycle', '*', {
-    STEPS: [
-        {
-            type: AggregateSteps.GROUPBY,
-            properties: ['@condition'],
-            REDUCE: [
-                {
-                    type: AggregateGroupByReducers.COUNT,
-                    AS: 'count'
-                }
-            ]
-        }
-    ]
-})
+// STEP_START query_exact_matching
+result = await client.ft.search(
+  'idx:bicycle',
+  '@brand:"Noka Bikes"',
+  {
+    LIMIT: {
+      from: 0,
+      size: 10
+    }
+  }
+);
 
 console.log(JSON.stringify(result, null, 2));
+
 /*
 {
-  "total": 3,
-  "results": [
-    {
-      "condition": "refurbished",
-      "count": "1"
-    },
-    {
-      "condition": "used",
-      "count": "5"
-    },
-    {
-      "condition": "new",
-      "count": "4"
+  "total": 1,
+  "documents": [{
+    "id": "bicycle:4",
+    "value": {
+      "brand": "Noka Bikes",
+      "model": "Kahuna",
+      "price": 3200,
+      "description": "Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway.",
+      "condition": "used"
     }
-  ]
+  }]
 }
- */
+*/
 // STEP_END
+
 // REMOVE_START
-assert.equal(result.total, 3);
-// REMOVE_END
+assert.equal(result.documents[0].id, 'bicycle:4');
+// REMOVE END
 
-await client.quit();
\ No newline at end of file
+await client.quit();

From d268364968a8961b11b930d9cff65ce71cce6e44 Mon Sep 17 00:00:00 2001
From: Igor Malinovskiy <igor.malinovskiy@redis.com>
Date: Tue, 4 Jul 2023 16:55:20 +0200
Subject: [PATCH 05/20] Add hash tutorial

---
 doctests/hash-tutorial.js | 120 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)
 create mode 100644 doctests/hash-tutorial.js

diff --git a/doctests/hash-tutorial.js b/doctests/hash-tutorial.js
new file mode 100644
index 00000000000..12def3f7724
--- /dev/null
+++ b/doctests/hash-tutorial.js
@@ -0,0 +1,120 @@
+// EXAMPLE: hash_tutorial
+// REMOVE_START
+import assert from 'assert';
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+
+client.on('error', err => console.log('Redis Client Error', err));
+
+await client.connect();
+// HIDE_END
+
+// STEP_START set_get_all
+const fieldsAdded = await client.hSet(
+    'bike:1',
+    {
+        model: 'Deimos',
+        brand: 'Ergonom',
+        type: 'Enduro bikes',
+        price: 4972,
+    },
+)
+console.log(`Number of fields were added: ${fieldsAdded}`);
+// Number of fields were added: 4
+//REMOVE_START
+assert.equal(fieldsAdded, 4);
+//REMOVE_END
+
+const model = await client.hGet('bike:1', 'model');
+console.log(`Model: ${model}`);
+// Model: Deimos
+// REMOVE_START
+assert.equal(model, 'Deimos');
+// REMOVE_END
+
+const price = await client.hGet('bike:1', 'price');
+console.log(`Price: ${price}`);
+// Price: 4972
+// REMOVE_START
+assert.equal(price, '4972');
+// REMOVE_END
+
+const bike = await client.hGetAll('bike:1');
+console.log(bike);
+// {
+//   model: 'Deimos',
+//   brand: 'Ergonom',
+//   type: 'Enduro bikes',
+//   price: '4972'
+// }
+// REMOVE_START
+assert.equal(Object.keys(bike).length, 4);
+// REMOVE_END
+// STEP_END
+
+// STEP_START hmget
+const fields = await client.hmGet('bike:1', ['model', 'price']);
+console.log(fields);
+// [ 'Deimos', '4972' ]
+// REMOVE_START
+assert.equal(fields.length, 2);
+// REMOVE_END
+// STEP_END
+
+// STEP_START hincrby
+let newPrice = await client.hIncrBy('bike:1', 'price', 100);
+console.log(newPrice);
+// 5072
+// REMOVE_START
+assert.equal(newPrice, 5072);
+// REMOVE_END
+newPrice = await client.hIncrBy('bike:1', 'price', -100);
+console.log(newPrice);
+// 4972
+// REMOVE_START
+assert.equal(newPrice, 4972);
+// REMOVE_END
+// STEP_END
+
+// STEP_START incrby_get_mget
+let rides = await client.hIncrBy('bike:1:stats', 'rides', 1);
+console.log(rides);
+// 1
+
+rides = await client.hIncrBy('bike:1:stats', 'rides', 1);
+console.log(rides);
+// 2
+
+rides = await client.hIncrBy('bike:1:stats', 'rides', 1);
+console.log(rides);
+// 3
+
+let crashes = await client.hIncrBy('bike:1:stats', 'crashes', 1);
+console.log(crashes);
+// 1
+
+let owners = await client.hIncrBy('bike:1:stats', 'owners', 1);
+console.log(owners);
+// 1
+
+rides = await client.hGet('bike:1:stats', 'rides');
+console.log(`Total rides: ${rides}`);
+// Total rides: 3
+// REMOVE_START
+assert.equal(rides, 3);
+// REMOVE_END
+const stats = await client.hmGet('bike:1:stats', ['crashes', 'owners']);
+console.log(`Bike stats: crashes=${stats[0]}, owners=${stats[1]}`);
+// Bike stats: crashes=1, owners=1
+// REMOVE_START
+assert.equal(stats.length, 2);
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
\ No newline at end of file

From 22f8b2f95828c3123d3379b1604cb4ef266e23f8 Mon Sep 17 00:00:00 2001
From: Justin Castilla <59704472+justincastilla@users.noreply.github.com>
Date: Mon, 21 Aug 2023 11:31:47 -0700
Subject: [PATCH 06/20] DOC 2526 - Add code examples for the List tutorial in
 Node.js (#2583)

* DOC-2526 Add code examples for the List tutorial

* adds formatting

---------

Co-authored-by: Justin Castilla <pxlperfection@gmail.com>
---
 doctests/dt-list.js | 329 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 329 insertions(+)
 create mode 100644 doctests/dt-list.js

diff --git a/doctests/dt-list.js b/doctests/dt-list.js
new file mode 100644
index 00000000000..2defff69fd2
--- /dev/null
+++ b/doctests/dt-list.js
@@ -0,0 +1,329 @@
+// EXAMPLE: list_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = await createClient();
+await client.connect();
+// HIDE_END
+// REMOVE_START
+await client.del('bikes:repairs');
+await client.del('bikes:finished');
+// REMOVE_END
+
+// STEP_START queue
+const res1 = await client.lPush('bikes:repairs', 'bike:1');
+console.log(res1);  // 1
+
+const res2 = await client.lPush('bikes:repairs', 'bike:2');
+console.log(res2);  // 2
+
+const res3 = await client.rPop('bikes:repairs');
+console.log(res3);  // bike:1
+
+const res4 = await client.rPop('bikes:repairs');
+console.log(res4);  // bike:2
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 1);
+assert.equal(res2, 2);
+assert.equal(res3, 'bike:1');
+assert.equal(res4, 'bike:2');
+// REMOVE_END
+
+// STEP_START stack
+const res5 = await client.lPush('bikes:repairs', 'bike:1');
+console.log(res5);  // 1
+
+const res6 = await client.lPush('bikes:repairs', 'bike:2');
+console.log(res6); // 2
+
+const res7 = await client.lPop('bikes:repairs');
+console.log(res7);  // bike:2
+
+const res8 = await client.lPop('bikes:repairs');
+console.log(res8);  // bike:1
+// STEP_END
+
+// REMOVE_START
+assert.equal(res5, 1);
+assert.equal(res6, 2);
+assert.equal(res7, 'bike:2');
+assert.equal(res8, 'bike:1');
+// REMOVE_END
+
+// STEP_START lLen
+const res9 = await client.lLen('bikes:repairs');
+console.log(res9); // 0
+// STEP_END
+
+// REMOVE_START
+assert.equal(res9, 0);
+// REMOVE_END
+
+// STEP_START lMove_lRange
+const res10 = await client.lPush('bikes:repairs', 'bike:1');
+console.log(res10);  // 1
+
+const res11 = await client.lPush('bikes:repairs', 'bike:2');
+console.log(res11);  // 2
+
+const res12 = await client.lMove('bikes:repairs', 'bikes:finished', 'LEFT', 'LEFT');
+console.log(res12);  // 'bike:2'
+
+const res13 = await client.lRange('bikes:repairs', 0, -1);
+console.log(res13);  // ['bike:1']
+
+const res14 = await client.lRange('bikes:finished', 0, -1);
+console.log(res14);  // ['bike:2']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res10, 1);
+assert.equal(res11, 2);
+assert.equal(res12, 'bike:2');
+assert.deepEqual(res13, ['bike:1']);
+assert.deepEqual(res14, ['bike:2']);
+await client.del('bikes:repairs');
+// REMOVE_END
+
+// STEP_START lPush_rPush
+const res15 = await client.rPush('bikes:repairs', 'bike:1');
+console.log(res15);  // 1
+
+const res16 = await client.rPush('bikes:repairs', 'bike:2');
+console.log(res16);  // 2
+
+const res17 = await client.lPush('bikes:repairs', 'bike:important_bike');
+console.log(res17);  // 3
+
+const res18 = await client.lRange('bikes:repairs', 0, -1);
+console.log(res18);  // ['bike:important_bike', 'bike:1', 'bike:2']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res15, 1);
+assert.equal(res16, 2);
+assert.equal(res17, 3);
+assert.deepEqual(res18, ['bike:important_bike', 'bike:1', 'bike:2']);
+await client.del('bikes:repairs');
+// REMOVE_END
+
+// STEP_START variadic
+const res19 = await client.rPush('bikes:repairs', ['bike:1', 'bike:2', 'bike:3']);
+console.log(res19);  // 3
+
+const res20 = await client.lPush(
+  'bikes:repairs', ['bike:important_bike', 'bike:very_important_bike']
+);
+console.log(res20);  // 5
+
+const res21 = await client.lRange('bikes:repairs', 0, -1);
+console.log(res21);  // ['bike:very_important_bike', 'bike:important_bike', 'bike:1', 'bike:2', 'bike:3']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res19, 3);
+assert.equal(res20, 5);
+assert.deepEqual(res21, [
+  'bike:very_important_bike',
+  'bike:important_bike',
+  'bike:1',
+  'bike:2',
+  'bike:3',
+]);
+await client.del('bikes:repairs');
+// REMOVE_END
+
+// STEP_START lPop_rPop
+const res22 = await client.rPush('bikes:repairs', ['bike:1', 'bike:2', 'bike:3']);
+console.log(res22);  // 3
+
+const res23 = await client.rPop('bikes:repairs');
+console.log(res23);  // 'bike:3'
+
+const res24 = await client.lPop('bikes:repairs');
+console.log(res24);  // 'bike:1'
+
+const res25 = await client.rPop('bikes:repairs');
+console.log(res25);  // 'bike:2'
+
+const res26 = await client.rPop('bikes:repairs');
+console.log(res26);  // None
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res22, 3);
+assert.equal(res23, 'bike:3');
+assert.equal(res24, 'bike:1');
+assert.equal(res25, 'bike:2');
+assert.equal(res26, null);
+// REMOVE_END
+
+// STEP_START lTrim
+const res27 = await client.lPush(
+  'bikes:repairs', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5']
+);
+console.log(res27);  // 5
+
+const res28 = await client.lTrim('bikes:repairs', 0, 2);
+console.log(res28);  // true
+
+const res29 = await client.lRange('bikes:repairs', 0, -1);
+console.log(res29);  // ['bike:5', 'bike:4', 'bike:3']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res27, 5);
+assert.equal(res28, 'OK');
+assert.deepEqual(res29, ['bike:5', 'bike:4', 'bike:3']);
+await client.del('bikes:repairs');
+// REMOVE_END
+
+// STEP_START lTrim_end_of_list
+const res27eol = await client.rPush(
+  'bikes:repairs', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5']
+);
+console.log(res27eol);  // 5
+
+const res28eol = await client.lTrim('bikes:repairs', -3, -1);
+console.log(res28eol);  // 'OK'
+
+const res29eol = await client.lRange('bikes:repairs', 0, -1);
+console.log(res29eol);  // ['bike:3', 'bike:4', 'bike:5']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res27eol, 5);
+assert.equal(res28eol, 'OK');
+assert.deepEqual(res29eol, ['bike:3', 'bike:4', 'bike:5']);
+await client.del('bikes:repairs');
+// REMOVE_END
+
+// STEP_START brPop
+const res31 = await client.rPush('bikes:repairs', ['bike:1', 'bike:2']);
+console.log(res31);  // 2
+
+const res32 = await client.brPop('bikes:repairs', 1);
+console.log(res32);  // { key: 'bikes:repairs', element: 'bike:2' }
+
+const res33 = await client.brPop('bikes:repairs', 1);
+console.log(res33);  // { key: 'bikes:repairs', element: 'bike:1' }
+
+const res34 = await client.brPop('bikes:repairs', 1);
+console.log(res34);  // null
+// STEP_END
+
+// REMOVE_START
+assert.equal(res31, 2);
+assert.deepEqual(res32, { key: 'bikes:repairs', element: 'bike:2' });
+assert.deepEqual(res33, { key: 'bikes:repairs', element: 'bike:1' });
+assert.equal(res34, null);
+await client.del('bikes:repairs');
+await client.del('new_bikes');
+// REMOVE_END
+
+// STEP_START rule_1
+const res35 = await client.del('new_bikes');
+console.log(res35); // 0
+
+const res36 = await client.lPush('new_bikes', ['bike:1', 'bike:2', 'bike:3']);
+console.log(res36); // 3
+// STEP_END
+
+// REMOVE_START
+assert.equal(res35, 0);
+assert.equal(res36, 3);
+await client.del('new_bikes');
+// REMOVE_END
+
+// STEP_START rule_1.1
+const res37 = await client.set('new_bikes', 'bike:1');
+console.log(res37);  // 'OK'
+
+const res38 = await client.type('new_bikes');
+console.log(res38);  // 'string'
+
+try {
+  const res39 = await client.lPush('new_bikes', 'bike:2', 'bike:3');
+  // redis.exceptions.ResponseError:
+  // [ErrorReply: WRONGTYPE Operation against a key holding the wrong kind of value]
+}
+catch(e){
+  console.log(e);
+}
+// STEP_END
+
+// REMOVE_START
+assert.equal(res37, 'OK');
+assert.equal(res38, 'string');
+await client.del('new_bikes');
+// REMOVE_END
+
+// STEP_START rule_2
+await client.lPush('bikes:repairs', ['bike:1', 'bike:2', 'bike:3']);
+console.log(res36);  // 3
+
+const res40 = await client.exists('bikes:repairs')
+console.log(res40);  // true
+
+const res41 = await client.lPop('bikes:repairs');
+console.log(res41);  // 'bike:3'
+
+const res42 = await client.lPop('bikes:repairs');
+console.log(res42);  // 'bike:2'
+
+const res43 = await client.lPop('bikes:repairs');
+console.log(res43);  // 'bike:1'
+
+const res44 = await client.exists('bikes:repairs');
+console.log(res44);  // 0
+// STEP_END
+
+// REMOVE_START
+assert.equal(res40, true);
+assert.equal(res41, 'bike:3');
+assert.equal(res42, 'bike:2');
+assert.equal(res43, 'bike:1');
+assert.equal(res44, 0);
+await client.del('bikes:repairs');
+// REMOVE_END
+
+// STEP_START rule_3
+const res45 = await client.del('bikes:repairs');
+console.log(res45);  // 0
+
+const res46 = await client.lLen('bikes:repairs');
+console.log(res46);  // 0
+
+const res47 = await client.lPop('bikes:repairs');
+console.log(res47);  // null
+// STEP_END
+
+// REMOVE_START
+assert.equal(res45, 0);
+assert.equal(res46, 0);
+assert.equal(res47, null);
+// REMOVE_END
+
+// STEP_START lTrim.1
+const res48 = await client.lPush(
+  'bikes:repairs', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5']
+);
+console.log(res48);  // 5
+
+const res49 = await client.lTrim('bikes:repairs', 0, 2);
+console.log(res49);  // 'OK'
+
+const res50 = await client.lRange('bikes:repairs', 0, -1);
+console.log(res50);  // ['bike:5', 'bike:4', 'bike:3']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res48, 5);
+assert.equal(res49, 'OK');
+assert.deepEqual(res50, ['bike:5', 'bike:4', 'bike:3']);
+await client.del('bikes:repairs');
+await client.quit();
+// REMOVE_END
\ No newline at end of file

From 70f3606a3d1f274bc5b37fae23760947522ed05b Mon Sep 17 00:00:00 2001
From: Justin Castilla <59704472+justincastilla@users.noreply.github.com>
Date: Thu, 26 Oct 2023 14:55:29 -0400
Subject: [PATCH 07/20] Doc 2542 - Add code examples for the Geospatial
 tutorial (#2585)

* DOC-2542 Add code examples for the Geospatial tutorial

* adds spaces after properties in objects

---------

Co-authored-by: Justin Castilla <pxlperfection@gmail.com>
---
 doctests/dt-geo.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 doctests/dt-geo.js

diff --git a/doctests/dt-geo.js b/doctests/dt-geo.js
new file mode 100644
index 00000000000..fc552e0fda2
--- /dev/null
+++ b/doctests/dt-geo.js
@@ -0,0 +1,59 @@
+// EXAMPLE: geo_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.del('bikes:rentable')
+// REMOVE_END
+
+// STEP_START geoAdd
+const res1 = await client.geoAdd('bikes:rentable', { 
+  longitude: -122.27652,
+  latitude: 37.805186,
+  member: 'station:1'
+});
+console.log(res1)  // 1
+
+const res2 = await client.geoAdd('bikes:rentable', {
+  longitude: -122.2674626,
+  latitude: 37.8062344,
+  member: 'station:2'
+});
+console.log(res2)  // 1
+
+const res3 = await client.geoAdd('bikes:rentable', {
+  longitude: -122.2469854,
+  latitude: 37.8104049,
+  member: 'station:3'
+})
+console.log(res3)  // 1
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 1);
+assert.equal(res2, 1);
+assert.equal(res3, 1);
+// REMOVE_END
+
+// STEP_START geoSearch
+const res4 = await client.geoSearch(
+  'bikes:rentable', {
+    longitude: -122.27652,
+    latitude: 37.805186,
+  },
+  { radius: 5,
+    unit: 'km'
+  }
+);
+console.log(res4)  // ['station:1', 'station:2', 'station:3']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res4, ['station:1', 'station:2', 'station:3']);
+// REMOVE_END
+await client.quit()

From e7347f8a51820cac24c7e5badf241b5f3990f785 Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Wed, 3 Jul 2024 12:29:04 -0700
Subject: [PATCH 08/20] DOC-3914: re-issue TCE PRs previously issued by
 justincastilla (#2781)

---
 doctests/dt-bitmap.js              |  39 +++
 doctests/dt-hash.js                |  98 +++++++
 doctests/dt-json.js                | 425 +++++++++++++++++++++++++++++
 doctests/dt-set.js                 | 178 ++++++++++++
 doctests/dt-streams.js             | 346 +++++++++++++++++++++++
 doctests/dt-string.js              |  68 +++++
 doctests/hash-tutorial.js          | 120 --------
 doctests/string-set-get-example.js |  26 --
 8 files changed, 1154 insertions(+), 146 deletions(-)
 create mode 100644 doctests/dt-bitmap.js
 create mode 100644 doctests/dt-hash.js
 create mode 100644 doctests/dt-json.js
 create mode 100644 doctests/dt-set.js
 create mode 100644 doctests/dt-streams.js
 create mode 100644 doctests/dt-string.js
 delete mode 100644 doctests/hash-tutorial.js
 delete mode 100644 doctests/string-set-get-example.js

diff --git a/doctests/dt-bitmap.js b/doctests/dt-bitmap.js
new file mode 100644
index 00000000000..b8efb364d0d
--- /dev/null
+++ b/doctests/dt-bitmap.js
@@ -0,0 +1,39 @@
+// EXAMPLE: bitmap_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START ping
+const res1 = await client.setBit("pings:2024-01-01-00:00", 123, 1)
+console.log(res1)  // >>> 0
+
+const res2 = await client.getBit("pings:2024-01-01-00:00", 123)
+console.log(res2)  // >>> 1
+
+const res3 = await client.getBit("pings:2024-01-01-00:00", 456)
+console.log(res3)  // >>> 0
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 0)
+// REMOVE_END
+
+// STEP_START bitcount
+// HIDE_START
+await client.setBit("pings:2024-01-01-00:00", 123, 1)
+// HIDE_END
+const res4 = await client.bitCount("pings:2024-01-01-00:00")
+console.log(res4)  // >>> 1
+// STEP_END
+// REMOVE_START
+assert.equal(res4, 1)
+await client.quit();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/dt-hash.js b/doctests/dt-hash.js
new file mode 100644
index 00000000000..b790a2e8406
--- /dev/null
+++ b/doctests/dt-hash.js
@@ -0,0 +1,98 @@
+// EXAMPLE: hash_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+// STEP_START set_get_all
+const res1 = await client.hSet(
+  'bike:1',
+  {
+    'model': 'Deimos',
+    'brand': 'Ergonom',
+    'type': 'Enduro bikes',
+    'price': 4972,
+  }
+)
+console.log(res1) // 4
+
+const res2 = await client.hGet('bike:1', 'model')
+console.log(res2)  // 'Deimos'
+
+const res3 = await client.hGet('bike:1', 'price')
+console.log(res3)  // '4972'
+
+const res4 = await client.hGetAll('bike:1')
+console.log(res4)  
+/*
+{
+  brand: 'Ergonom',
+  model: 'Deimos',
+  price: '4972',
+  type: 'Enduro bikes'
+}
+*/
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 4);
+assert.equal(res2, 'Deimos');
+assert.equal(res3, '4972');
+assert.deepEqual(res4, {
+  model: 'Deimos',
+  brand: 'Ergonom',
+  type: 'Enduro bikes',
+  price: '4972'
+});
+// REMOVE_END
+
+// STEP_START hmGet
+const res5 = await client.hmGet('bike:1', ['model', 'price'])
+console.log(res5)  // ['Deimos', '4972']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(Object.values(res5), ['Deimos', '4972'])
+// REMOVE_END
+
+// STEP_START hIncrBy
+const res6 = await client.hIncrBy('bike:1', 'price', 100)
+console.log(res6)  // 5072
+const res7 = await client.hIncrBy('bike:1', 'price', -100)
+console.log(res7)  // 4972
+// STEP_END
+
+// REMOVE_START
+assert.equal(res6, 5072)
+assert.equal(res7, 4972)
+// REMOVE_END
+
+// STEP_START hIncrBy_hGet_hMget
+const res11 = await client.hIncrBy('bike:1:stats', 'rides', 1)
+console.log(res11)  // 1
+const res12 = await client.hIncrBy('bike:1:stats', 'rides', 1)
+console.log(res12)  // 2
+const res13 = await client.hIncrBy('bike:1:stats', 'rides', 1)
+console.log(res13)  // 3
+const res14 = await client.hIncrBy('bike:1:stats', 'crashes', 1)
+console.log(res14)  // 1
+const res15 = await client.hIncrBy('bike:1:stats', 'owners', 1)
+console.log(res15)  // 1
+const res16 = await client.hGet('bike:1:stats', 'rides')
+console.log(res16)  // 3
+const res17 = await client.hmGet('bike:1:stats', ['crashes', 'owners'])
+console.log(res17)  // ['1', '1']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res11, 1);
+assert.equal(res12, 2);
+assert.equal(res13, 3);
+assert.equal(res14, 1);
+assert.equal(res15, 1);
+assert.equal(res16, '3');
+assert.deepEqual(res17, ['1', '1']);
+await client.quit();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/dt-json.js b/doctests/dt-json.js
new file mode 100644
index 00000000000..83eee04b586
--- /dev/null
+++ b/doctests/dt-json.js
@@ -0,0 +1,425 @@
+// EXAMPLE: json_tutorial
+// HIDE_START
+import assert from 'assert';
+import {
+  createClient
+} from 'redis';
+
+const client = await createClient();
+await client.connect();
+// HIDE_END
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START set_get
+const res1 = await client.json.set("bike", "$", '"Hyperion"');
+console.log(res1); // OK
+
+const res2 = await client.json.get("bike", "$");
+console.log(res2); // "Hyperion"
+
+const res3 = await client.json.type("bike", "$");
+console.log(res3); //  [ 'string' ]
+// STEP_END
+
+// REMOVE_START
+assert.equal(res2, '"Hyperion"');
+// REMOVE_END
+
+// STEP_START str
+const res4 = await client.json.strLen("bike", "$");
+console.log(res4) //  [10]
+
+const res5 = await client.json.strAppend("bike", '" (Enduro bikes)"');
+console.log(res5) //  27
+
+const res6 = await client.json.get("bike", "$");
+console.log(res6) //  ['"Hyperion"" (Enduro bikes)"']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res6, ['"Hyperion"" (Enduro bikes)"']);
+// REMOVE_END
+
+// STEP_START num
+const res7 = await client.json.set("crashes", "$", 0);
+console.log(res7) //  OK
+
+const res8 = await client.json.numIncrBy("crashes", "$", 1);
+console.log(res8) //  [1]
+
+const res9 = await client.json.numIncrBy("crashes", "$", 1.5);
+console.log(res9) //  [2.5]
+
+const res10 = await client.json.numIncrBy("crashes", "$", -0.75);
+console.log(res10) //  [1.75]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res10, [1.75])
+// REMOVE_END
+
+// STEP_START arr
+const res11 = await client.json.set("newbike", "$", ["Deimos", {"crashes": 0 }, null]);
+console.log(res11); //  OK
+
+const res12 = await client.json.get("newbike", "$");
+console.log(res12); //  [ 'Deimos', { crashes: 0 }, null ]
+
+const res13 = await client.json.get("newbike", "$[1].crashes");
+console.log(res13); //  [ 'Deimos', { crashes: 0 }, null ]
+
+const res14 = await client.json.del("newbike", "$.[-1]");
+console.log(res14); //  [1]
+
+const res15 = await client.json.get("newbike", "$");
+console.log(res15); //  [ 'Deimos', { crashes: 0 } ]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res15, ["Deimos", {
+  "crashes": 0
+}]);
+// REMOVE_END
+
+// STEP_START arr2
+const res16 = await client.json.set("riders", "$", []);
+console.log(res16); //  OK
+
+const res17 = await client.json.arrAppend("riders", "$", "Norem");
+console.log(res17); //  [1]
+
+const res18 = await client.json.get("riders", "$");
+console.log(res18); //  [ 'Norem' ]
+
+const res19 = await client.json.arrInsert("riders", "$", 1, "Prickett", "Royse", "Castilla");
+console.log(res19); //  [4]
+
+const res20 = await client.json.get("riders", "$");
+console.log(res20); //  [ 'Norem', 'Prickett', 'Royse', 'Castilla' ]
+
+const res21 = await client.json.arrTrim("riders", "$", 1, 1);
+console.log(res21); //  [1]
+
+const res22 = await client.json.get("riders", "$");
+console.log(res22); //  [ 'Prickett' ]
+
+const res23 = await client.json.arrPop("riders", "$");
+console.log(res23); //  [ 'Prickett' ]
+
+const res24 = await client.json.arrPop("riders", "$");
+console.log(res24); //  [null]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res24, [null]);
+// REMOVE_END
+
+// STEP_START obj
+const res25 = await client.json.set(
+  "bike:1", "$", {
+    "model": "Deimos",
+    "brand": "Ergonom",
+    "price": 4972
+  }
+);
+console.log(res25); //  OK
+
+const res26 = await client.json.objLen("bike:1", "$");
+console.log(res26); //  [3]
+
+const res27 = await client.json.objKeys("bike:1", "$");
+console.log(res27); //  [['model', 'brand', 'price']]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res27, [
+  ["model", "brand", "price"]
+]);
+// REMOVE_END
+
+// STEP_START set_bikes
+// HIDE_START
+const inventoryJSON = {
+  "inventory": {
+    "mountain_bikes": [{
+        "id": "bike:1",
+        "model": "Phoebe",
+        "description": "This is a mid-travel trail slayer that is a fantastic daily driver or one bike quiver. The Shimano Claris 8-speed groupset gives plenty of gear range to tackle hills and there\u2019s room for mudguards and a rack too.  This is the bike for the rider who wants trail manners with low fuss ownership.",
+        "price": 1920,
+        "specs": {
+          "material": "carbon",
+          "weight": 13.1
+        },
+        "colors": ["black", "silver"],
+      },
+      {
+        "id": "bike:2",
+        "model": "Quaoar",
+        "description": "Redesigned for the 2020 model year, this bike impressed our testers and is the best all-around trail bike we've ever tested. The Shimano gear system effectively does away with an external cassette, so is super low maintenance in terms of wear and teaawait client. All in all it's an impressive package for the price, making it very competitive.",
+        "price": 2072,
+        "specs": {
+          "material": "aluminium",
+          "weight": 7.9
+        },
+        "colors": ["black", "white"],
+      },
+      {
+        "id": "bike:3",
+        "model": "Weywot",
+        "description": "This bike gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. A set of powerful Shimano hydraulic disc brakes provide ample stopping ability. If you're after a budget option, this is one of the best bikes you could get.",
+        "price": 3264,
+        "specs": {
+          "material": "alloy",
+          "weight": 13.8
+        },
+      },
+    ],
+    "commuter_bikes": [{
+        "id": "bike:4",
+        "model": "Salacia",
+        "description": "This bike is a great option for anyone who just wants a bike to get about on With a slick-shifting Claris gears from Shimano\u2019s, this is a bike which doesn\u2019t break the bank and delivers craved performance.  It\u2019s for the rider who wants both efficiency and capability.",
+        "price": 1475,
+        "specs": {
+          "material": "aluminium",
+          "weight": 16.6
+        },
+        "colors": ["black", "silver"],
+      },
+      {
+        "id": "bike:5",
+        "model": "Mimas",
+        "description": "A real joy to ride, this bike got very high scores in last years Bike of the year report. The carefully crafted 50-34 tooth chainset and 11-32 tooth cassette give an easy-on-the-legs bottom gear for climbing, and the high-quality Vittoria Zaffiro tires give balance and grip.It includes a low-step frame , our memory foam seat, bump-resistant shocks and conveniently placed thumb throttle. Put it all together and you get a bike that helps redefine what can be done for this price.",
+        "price": 3941,
+        "specs": {
+          "material": "alloy",
+          "weight": 11.6
+        },
+      },
+    ],
+  }
+};
+// HIDE_END
+
+const res28 = await client.json.set("bikes:inventory", "$", inventoryJSON);
+console.log(res28); //  OK
+// STEP_END
+
+// STEP_START get_bikes
+const res29 = await client.json.get("bikes:inventory", {
+  path: "$.inventory.*"
+});
+console.log(res29);
+/*
+[
+  [
+    {
+      id: 'bike:1',
+      model: 'Phoebe',
+      description: 'This is a mid-travel trail slayer that is a fantastic daily driver or one bike quiver. The Shimano Claris 8-speed groupset gives plenty of gear range to tackle hills and there’s room for mudguards and a rack too.  This is the bike for the rider who wants trail manners with low fuss ownership.',
+      price: 1920,
+      specs: [Object],
+      colors: [Array]
+    },
+    {
+      id: 'bike:2',
+      model: 'Quaoar',
+      description: "Redesigned for the 2020 model year, this bike impressed our testers and is the best all-around trail bike we've ever tested. The Shimano gear system effectively does away with an external cassette, so is super low maintenance in terms of wear and teaawait client. All in all it's an impressive package for the price, making it very competitive.",
+      price: 2072,
+      specs: [Object],
+      colors: [Array]
+    },
+    {
+      id: 'bike:3',
+      model: 'Weywot',
+      description: "This bike gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. A set of powerful Shimano hydraulic disc brakes provide ample stopping ability. If you're after a budget option, this is one of the best bikes you could get.",
+      price: 3264,
+      specs: [Object]
+    }
+  ],
+  [
+    {
+      id: 'bike:4',
+      model: 'Salacia',
+      description: 'This bike is a great option for anyone who just wants a bike to get about on With a slick-shifting Claris gears from Shimano’s, this is a bike which doesn’t break the bank and delivers craved performance.  It’s for the rider who wants both efficiency and capability.',
+      price: 1475,
+      specs: [Object],
+      colors: [Array]
+    },
+    {
+      id: 'bike:5',
+      model: 'Mimas',
+      description: 'A real joy to ride, this bike got very high scores in last years Bike of the year report. The carefully crafted 50-34 tooth chainset and 11-32 tooth cassette give an easy-on-the-legs bottom gear for climbing, and the high-quality Vittoria Zaffiro tires give balance and grip.It includes a low-step frame , our memory foam seat, bump-resistant shocks and conveniently placed thumb throttle. Put it all together and you get a bike that helps redefine what can be done for this price.',
+      price: 3941,
+      specs: [Object]
+    }
+  ]
+]
+*/
+// STEP_END
+
+// STEP_START get_mtnbikes
+const res30 = await client.json.get("bikes:inventory", {
+  path: "$.inventory.mountain_bikes[*].model"
+});
+console.log(res30); //  ['Phoebe', 'Quaoar', 'Weywot']
+
+const res31 = await client.json.get("bikes:inventory", {
+  path: '$.inventory["mountain_bikes"][*].model'
+});
+console.log(res31); //  ['Phoebe', 'Quaoar', 'Weywot']
+
+const res32 = await client.json.get("bikes:inventory", {
+  path: "$..mountain_bikes[*].model"
+});
+console.log(res32); //  ['Phoebe', 'Quaoar', 'Weywot']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res30, ["Phoebe", "Quaoar", "Weywot"]);
+assert.deepEqual(res31, ["Phoebe", "Quaoar", "Weywot"]);
+assert.deepEqual(res32, ["Phoebe", "Quaoar", "Weywot"]);
+// REMOVE_END
+
+// STEP_START get_models
+const res33 = await client.json.get("bikes:inventory", {
+  path: "$..model"
+});
+console.log(res33); //  ['Phoebe', 'Quaoar', 'Weywot', 'Salacia', 'Mimas']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res33, ["Phoebe", "Quaoar", "Weywot", "Salacia", "Mimas"]);
+// REMOVE_END
+
+// STEP_START get2mtnbikes
+const res34 = await client.json.get("bikes:inventory", {
+  path: "$..mountain_bikes[0:2].model"
+});
+console.log(res34); //  ['Phoebe', 'Quaoar']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res34, ["Phoebe", "Quaoar"]);
+// REMOVE_END
+
+// STEP_START filter1
+const res35 = await client.json.get("bikes:inventory", {
+  path: "$..mountain_bikes[?(@.price < 3000 && @.specs.weight < 10)]"
+});
+console.log(res35);
+/*
+[
+  {
+    id: 'bike:2',
+    model: 'Quaoar',
+    description: "Redesigned for the 2020 model year, this bike impressed our testers and is the best all-around trail bike we've ever tested. The Shimano gear system effectively does away with an external cassette, so is super low maintenance in terms of wear and teaawait client. All in all it's an impressive package for the price, making it very competitive.",
+    price: 2072,
+    specs: { material: 'aluminium', weight: 7.9 },
+    colors: [ 'black', 'white' ]
+  }
+]
+*/
+// STEP_END
+
+// STEP_START filter2
+//  names of bikes made from an alloy
+const res36 = await client.json.get("bikes:inventory", {
+  path: "$..[?(@.specs.material == 'alloy')].model"
+});
+console.log(res36); //  ['Weywot', 'Mimas']
+// STEP_END
+// REMOVE_START
+assert.deepEqual(res36, ["Weywot", "Mimas"]);
+// REMOVE_END
+
+// STEP_START filter3
+const res37 = await client.json.get("bikes:inventory", {
+  path: "$..[?(@.specs.material =~ '(?i)al')].model"
+});
+console.log(res37); //  ['Quaoar', 'Weywot', 'Salacia', 'Mimas']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res37, ["Quaoar", "Weywot", "Salacia", "Mimas"]);
+// REMOVE_END
+
+// STEP_START filter4
+const res37a = await client.json.set(
+  'bikes:inventory', 
+  '$.inventory.mountain_bikes[0].regex_pat', 
+  '(?i)al'
+);
+
+const res37b = await client.json.set(
+  'bikes:inventory', 
+  '$.inventory.mountain_bikes[1].regex_pat', 
+  '(?i)al'
+);
+
+const res37c = await client.json.set(
+  'bikes:inventory', 
+  '$.inventory.mountain_bikes[2].regex_pat', 
+  '(?i)al'
+);
+
+const res37d = await client.json.get(
+  'bikes:inventory',
+  '$.inventory.mountain_bikes[?(@.specs.material =~ @.regex_pat)].model'
+);
+console.log(res37d); // ['Quaoar', 'Weywot']
+// STEP_END
+
+// STEP_START update_bikes
+const res38 = await client.json.get("bikes:inventory", {
+  path: "$..price"
+});
+console.log(res38);  //  [1920, 2072, 3264, 1475, 3941]
+
+const res39 = await client.json.numIncrBy("bikes:inventory", "$..price", -100);
+console.log(res39);  //  [1820, 1972, 3164, 1375, 3841]
+
+const res40 = await client.json.numIncrBy("bikes:inventory", "$..price", 100);
+console.log(res40);  //  [1920, 2072, 3264, 1475, 3941]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res40.sort(), [1475, 1920, 2072, 3264, 3941]);
+// REMOVE_END
+
+// STEP_START update_filters1
+const res40a = await client.json.set(
+  'bikes:inventory', 
+  '$.inventory.*[?(@.price<2000)].price', 
+  1500
+);
+
+// Get all prices from the inventory
+const res40b = await client.json.get(
+  'bikes:inventory',
+  '$..price'
+);
+console.log(res40b); // [1500, 2072, 3264, 1500, 3941]
+// STEP_END
+
+// STEP_START update_filters2
+const res41 = await client.json.arrAppend(
+    "bikes:inventory", "$.inventory.*[?(@.price<2000)].colors", "pink"
+);
+console.log(res41);  //  [3, 3]
+
+const res42 = await client.json.get("bikes:inventory", {
+  path: "$..[*].colors"
+});
+console.log(res42);  //  [['black', 'silver', 'pink'], ['black', 'white'], ['black', 'silver', 'pink']]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res42, [
+    ["black", "silver", "pink"],
+    ["black", "white"],
+    ["black", "silver", "pink"],
+]);
+await client.quit();
+// REMOVE_END
diff --git a/doctests/dt-set.js b/doctests/dt-set.js
new file mode 100644
index 00000000000..036b0c4eeec
--- /dev/null
+++ b/doctests/dt-set.js
@@ -0,0 +1,178 @@
+// EXAMPLE: sets_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = await createClient();
+await client.connect();
+// HIDE_END
+// REMOVE_START
+await client.del('bikes:racing:france')
+await client.del('bikes:racing:usa')
+// REMOVE_END
+
+// STEP_START sAdd
+const res1 = await client.sAdd('bikes:racing:france', 'bike:1')
+console.log(res1)  // >>> 1
+
+const res2 = await client.sAdd('bikes:racing:france', 'bike:1')
+console.log(res2)  // >>> 0
+const res3 = await client.sAdd('bikes:racing:france', ['bike:2', 'bike:3'])
+console.log(res3)  // >>> 2
+const res4 = await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
+console.log(res4)  // >>> 2
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 1)
+assert.equal(res2, 0)
+assert.equal(res3, 2) 
+assert.equal(res4, 2) 
+// REMOVE_END
+
+// STEP_START sIsMember
+// HIDE_START
+await client.del('bikes:racing:france')
+await client.del('bikes:racing:usa')
+await client.sAdd('bikes:racing:france', 'bike:1', 'bike:2', 'bike:3')
+await client.sAdd('bikes:racing:usa', 'bike:1', 'bike:4')
+// HIDE_END
+const res5 = await client.sIsMember('bikes:racing:usa', 'bike:1')
+console.log(res5)  // >>> true
+
+const res6 = await client.sIsMember('bikes:racing:usa', 'bike:2')
+console.log(res6)  // >>> false
+// STEP_END
+
+// REMOVE_START
+assert.equal(res5, true)
+assert.equal(res6, false)
+// REMOVE_END
+
+// STEP_START sinster
+// HIDE_START
+await client.del('bikes:racing:france')
+await client.del('bikes:racing:usa')
+await client.sAdd('bikes:racing:france', 'bike:1', 'bike:2', 'bike:3')
+await client.sAdd('bikes:racing:usa', 'bike:1', 'bike:4')
+// HIDE_END
+const res7 = await client.sInter('bikes:racing:france', 'bikes:racing:usa')
+console.log(res7)  // >>> {'bike:1'}
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res7, [ 'bike:1' ])
+// REMOVE_END
+
+// STEP_START sCard
+// HIDE_START
+await client.del('bikes:racing:france')
+await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
+// HIDE_END
+const res8 = await client.sCard('bikes:racing:france')
+console.log(res8)  // >>> 3
+// STEP_END
+
+// REMOVE_START
+assert.equal(res8, 3)
+await client.del('bikes:racing:france')
+// REMOVE_END
+
+// STEP_START sAdd_sMembers
+const res9 = await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
+console.log(res9)  // >>> 3
+
+const res10 = await client.sMembers('bikes:racing:france')
+console.log(res10)  // >>> ['bike:1', 'bike:2', 'bike:3']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res9, 3)
+assert.deepEqual(res10.sort(), ['bike:1', 'bike:2', 'bike:3'])
+// REMOVE_END
+
+// STEP_START smIsMember
+const res11 = await client.sIsMember('bikes:racing:france', 'bike:1')
+console.log(res11)  // >>> true
+
+const res12 = await client.smIsMember('bikes:racing:france', ['bike:2', 'bike:3', 'bike:4'])
+console.log(res12)  // >>> [true, true, false]
+// STEP_END
+
+// REMOVE_START
+assert.equal(res11, true)
+assert.deepEqual(res12, [true, true, false])
+// REMOVE_END
+
+// STEP_START sDiff
+await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
+await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
+const res13 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa'])
+console.log(res13)  // >>> [ 'bike:2', 'bike:3' ]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res13, ['bike:2', 'bike:3'])
+await client.del('bikes:racing:france')
+await client.del('bikes:racing:usa')
+// REMOVE_END
+
+// STEP_START multisets
+await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
+await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
+await client.sAdd('bikes:racing:italy', ['bike:1', 'bike:2', 'bike:3', 'bike:4'])
+
+const res14 = await client.sInter(
+  ['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']
+)
+console.log(res14)  // >>> ['bike:1']
+
+const res15 = await client.sUnion(
+  ['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']
+)
+console.log(res15)  // >>> ['bike:1', 'bike:2', 'bike:3', 'bike:4']
+
+const res16 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy'])
+console.log(res16)  // >>> []
+
+const res17 = await client.sDiff(['bikes:racing:usa', 'bikes:racing:france'])
+console.log(res17)  // >>> ['bike:4']
+
+const res18 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa'])
+console.log(res18)  // >>> ['bike:2', 'bike:3']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res14, ['bike:1'])
+assert.deepEqual(res15.sort(), ['bike:1', 'bike:2', 'bike:3', 'bike:4'])
+assert.deepEqual(res16, [])
+assert.deepEqual(res17, ['bike:4'])
+assert.deepEqual(res18, ['bike:2', 'bike:3'])
+await client.del('bikes:racing:france')
+await client.del('bikes:racing:usa')
+await client.del('bikes:racing:italy')
+// REMOVE_END
+
+debugger;
+
+// STEP_START sRem
+await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5'])
+
+const res19 = await client.sRem('bikes:racing:france', 'bike:1')
+console.log(res19)  // >>> 1
+
+const res20 = await client.sPop('bikes:racing:france')
+console.log(res20)  // >>> bike:3 or other random value
+
+const res21 = await client.sMembers('bikes:racing:france')
+console.log(res21)  // >>> ['bike:2', 'bike:4', 'bike:5']; depends on previous result
+
+const res22 = await client.sRandMember('bikes:racing:france')
+console.log(res22)  // >>> bike:4 or other random value
+// STEP_END
+
+// REMOVE_START
+assert.equal(res19, 1)
+client.quit()
+// none of the other results are deterministic
+// REMOVE_END
diff --git a/doctests/dt-streams.js b/doctests/dt-streams.js
new file mode 100644
index 00000000000..b54357ebb67
--- /dev/null
+++ b/doctests/dt-streams.js
@@ -0,0 +1,346 @@
+// EXAMPLE: stream_tutorial
+// HIDE_START
+import assert from 'assert';
+import {
+  createClient
+} from 'redis';
+
+const client = await createClient();
+await client.connect();
+// HIDE_END
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START xAdd
+const res1 = await client.xAdd(
+  'race:france', '*', {
+    'rider': 'Castilla',
+    'speed': '30.2',
+    'position': '1',
+    'location_id': '1'
+  }
+);
+console.log(res1); // >>> 1700073067968-0 N.B. actual values will differ from these examples
+
+const res2 = await client.xAdd(
+  'race:france', '*', {
+    'rider': 'Norem',
+    'speed': '28.8',
+    'position': '3',
+    'location_id': '1'
+  },
+);
+console.log(res2); // >>> 1692629594113-0
+
+const res3 = await client.xAdd(
+  'race:france', '*', {
+    'rider': 'Prickett',
+    'speed': '29.7',
+    'position': '2',
+    'location_id': '1'
+  },
+);
+console.log(res3); // >>> 1692629613374-0
+// STEP_END
+
+// REMOVE_START
+assert.equal(await client.xLen('race:france'), 3);
+// REMOVE_END
+
+// STEP_START xRange
+const res4 = await client.xRange('race:france', '1691765278160-0', '+', 2);
+console.log(res4); // >>> [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}), ('1692629594113-0', {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'})]
+// STEP_END
+
+// STEP_START xread_block
+const res5 = await client.xRead({
+  key: 'race:france',
+  id: '0-0'
+}, {
+  count: 100,
+  block: 300
+});
+console.log(res5); // >>> [['race:france', [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}), ('1692629594113-0', {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}), ('1692629613374-0', {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'})]]]
+// STEP_END
+
+// STEP_START xAdd_2
+const res6 = await client.xAdd(
+  'race:france', '*', {
+    'rider': 'Castilla',
+    'speed': '29.9',
+    'position': '1',
+    'location_id': '2'
+  }
+);
+console.log(res6); // >>> 1692629676124-0
+// STEP_END
+
+// STEP_START xlen
+const res7 = await client.xLen('race:france');
+console.log(res7); // >>> 4
+// STEP_END
+
+
+// STEP_START xAdd_id
+const res8 = await client.xAdd('race:usa', '0-1', {
+  'racer': 'Castilla'
+});
+console.log(res8); // >>> 0-1
+
+const res9 = await client.xAdd('race:usa', '0-2', {
+  'racer': 'Norem'
+});
+console.log(res9); // >>> 0-2
+// STEP_END
+
+// STEP_START xAdd_bad_id
+try {
+  const res10 = await client.xAdd('race:usa', '0-1', {
+    'racer': 'Prickett'
+  });
+  console.log(res10); // >>> 0-1
+} catch (error) {
+  console.error(error); // >>> WRONGID
+}
+// STEP_END
+
+// STEP_START xadd_7
+const res11a = await client.xAdd('race:usa', '0-*', { racer: 'Norem' });
+console.log(res11a); // >>> 0-3
+// STEP_END
+
+// STEP_START xRange_all
+const res11 = await client.xRange('race:france', '-', '+');
+console.log(res11); // >>> [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}), ('1692629594113-0', {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}), ('1692629613374-0', {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}), ('1692629676124-0', {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'})]
+// STEP_END
+
+// STEP_START xRange_time
+const res12 = await client.xRange('race:france', '1692629576965', '1692629576967');
+console.log(res12); // >>> [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'})]
+// STEP_END
+
+// STEP_START xRange_step_1
+const res13 = await client.xRange('race:france', '-', '+', 2);
+console.log(res13); // >>> [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}), ('1692629594113-0', {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'})]
+// STEP_END
+
+// STEP_START xRange_step_2
+const res14 = await client.xRange('race:france', '(1692629594113-0', '+', 2);
+console.log(res14); // >>> [('1692629613374-0', {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}), ('1692629676124-0', {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'})]
+// STEP_END
+
+// STEP_START xRange_empty
+const res15 = await client.xRange('race:france', '(1692629676124-0', '+', 2);
+console.log(res15); // >>> []
+// STEP_END
+
+// STEP_START xrevrange
+const res16 = await client.xRevRange('race:france', '+', '-', 1);
+console.log(
+  res16
+); // >>> [('1692629676124-0', {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'})]
+// STEP_END
+
+// STEP_START xread
+const res17 = await client.xRead({
+  key: 'race:france',
+  id: '0-0'
+}, {
+  count: 2
+});
+console.log(res17); // >>> [['race:france', [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}), ('1692629594113-0', {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'})]]]
+// STEP_END
+
+// STEP_START xgroup_create
+const res18 = await client.xGroupCreate('race:france', 'france_riders', '$');
+console.log(res18); // >>> True
+// STEP_END
+
+// STEP_START xgroup_create_mkstream
+const res19 = await client.xGroupCreate('race:italy', 'italy_riders', '$', {
+  'MKSTREAM': true
+});
+console.log(res19); // >>> True
+// STEP_END
+
+// STEP_START xgroup_read
+await client.xAdd('race:italy', '*', {
+  'rider': 'Castilla'
+});
+await client.xAdd('race:italy', '*', {
+  'rider': 'Royce'
+});
+await client.xAdd('race:italy', '*', {
+  'rider': 'Sam-Bodden'
+});
+await client.xAdd('race:italy', '*', {
+  'rider': 'Prickett'
+});
+await client.xAdd('race:italy', '*', {
+  'rider': 'Norem'
+});
+
+const res20 = await client.xReadGroup(
+  'italy_riders',
+  'Alice', {
+    key: 'race:italy',
+    id: '>'
+  }, {
+    'COUNT': 1
+  }
+);
+console.log(res20); // >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]]
+// STEP_END
+
+// STEP_START xgroup_read_id
+const res21 = await client.xReadGroup(
+  'italy_riders',
+  'Alice', {
+    key: 'race:italy',
+    id: '0'
+  }, {
+    'COUNT': 1
+  }
+);
+console.log(res21); // >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]]
+// STEP_END
+
+// STEP_START xack
+const res22 = await client.xAck('race:italy', 'italy_riders', '1692629925771-0')
+console.log(res22); // >>> 1
+
+const res23 = await client.xReadGroup(
+  'italy_riders',
+  'Alice', {
+    key: 'race:italy',
+    id: '0'
+  }, {
+    'COUNT': 1
+  }
+);
+console.log(res23); // >>> [['race:italy', []]]
+// STEP_END
+
+// STEP_START xgroup_read_bob
+const res24 = await client.xReadGroup(
+  'italy_riders',
+  'Bob', {
+    key: 'race:italy',
+    id: '>'
+  }, {
+    'COUNT': 2
+  }
+);
+console.log(res24); // >>> [['race:italy', [('1692629925789-0', {'rider': 'Royce'}), ('1692629925790-0', {'rider': 'Sam-Bodden'})]]]
+// STEP_END
+
+// STEP_START xpending
+const res25 = await client.xPending('race:italy', 'italy_riders');
+console.log(res25); // >>> {'pending': 2, 'min': '1692629925789-0', 'max': '1692629925790-0', 'consumers': [{'name': 'Bob', 'pending': 2}]}
+// STEP_END
+
+// STEP_START xpending_plus_minus
+const res26 = await client.xPendingRange('race:italy', 'italy_riders', '-', '+', 10);
+console.log(res26); // >>> [{'message_id': '1692629925789-0', 'consumer': 'Bob', 'time_since_delivered': 31084, 'times_delivered': 1}, {'message_id': '1692629925790-0', 'consumer': 'Bob', 'time_since_delivered': 31084, 'times_delivered': 1}]
+// STEP_END
+
+// STEP_START xRange_pending
+const res27 = await client.xRange('race:italy', '1692629925789-0', '1692629925789-0');
+console.log(res27); // >>> [('1692629925789-0', {'rider': 'Royce'})]
+// STEP_END
+
+// STEP_START xclaim
+const res28 = await client.xClaim(
+  'race:italy', 'italy_riders', 'Alice', 60000, ['1692629925789-0']
+);
+console.log(res28); // >>> [('1692629925789-0', {'rider': 'Royce'})]
+// STEP_END
+
+// STEP_START xautoclaim
+const res29 = await client.xAutoClaim('race:italy', 'italy_riders', 'Alice', 1, '0-0', 1);
+console.log(res29); // >>> ['1692629925790-0', [('1692629925789-0', {'rider': 'Royce'})]]
+// STEP_END
+
+// STEP_START xautoclaim_cursor
+const res30 = await client.xAutoClaim(
+  'race:italy', 'italy_riders', 'Alice', 1, '(1692629925789-0', 1
+);
+console.log(res30); // >>> ['0-0', [('1692629925790-0', {'rider': 'Sam-Bodden'})]]
+// STEP_END
+
+// STEP_START xinfo
+const res31 = await client.xInfoStream('race:italy');
+console.log(res31); // >>> {'length': 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, 'last-generated-id': '1692629926436-0', 'groups': 1, 'first-entry': ('1692629925771-0', {'rider': 'Castilla'}), 'last-entry': ('1692629926436-0', {'rider': 'Norem'})}
+// STEP_END
+
+// STEP_START xinfo_groups
+const res32 = await client.xInfoGroups('race:italy');
+console.log(res32); // >>> [{'name': 'italy_riders', 'consumers': 2, 'pending': 2, 'last-delivered-id': '1692629925790-0'}]
+// STEP_END
+
+// STEP_START xinfo_consumers
+const res33 = await client.xInfoConsumers('race:italy', 'italy_riders');
+console.log(res33); // >>> [{'name': 'Alice', 'pending': 2, 'idle': 199332}, {'name': 'Bob', 'pending': 0, 'idle': 489170}]
+// STEP_END
+
+// STEP_START maxlen
+await client.xAdd('race:italy', '*', {
+  'rider': 'Jones'
+}, {
+  'MAXLEN': 2
+});
+await client.xAdd('race:italy', '*', {
+  'rider': 'Wood'
+}, {
+  'MAXLEN': 2
+});
+await client.xAdd('race:italy', '*', {
+  'rider': 'Henshaw'
+}, {
+  'MAXLEN': 2
+});
+
+const res34 = await client.xLen('race:italy');
+console.log(res34); // >>> 8
+
+const res35 = await client.xRange('race:italy', '-', '+');
+console.log(res35); // >>> [('1692629925771-0', {'rider': 'Castilla'}), ('1692629925789-0', {'rider': 'Royce'}), ('1692629925790-0', {'rider': 'Sam-Bodden'}), ('1692629925791-0', {'rider': 'Prickett'}), ('1692629926436-0', {'rider': 'Norem'}), ('1692630612602-0', {'rider': 'Jones'}), ('1692630641947-0', {'rider': 'Wood'}), ('1692630648281-0', {'rider': 'Henshaw'})]
+
+await client.xAdd('race:italy', '*', {
+  'rider': 'Smith'
+}, {
+  'MAXLEN': 2,
+  'APPROXIMATE': false
+});
+
+const res36 = await client.xRange('race:italy', '-', '+');
+console.log(res36); // >>> [('1692630648281-0', {'rider': 'Henshaw'}), ('1692631018238-0', {'rider': 'Smith'})]
+// STEP_END
+
+// STEP_START xTrim
+const res37 = await client.xTrim('race:italy', 'MAXLEN', 10, {
+  'APPROXIMATE': false
+});
+console.log(res37); // >>> 0
+// STEP_END
+
+// STEP_START xTrim2
+const res38 = await client.xTrim('race:italy', "MAXLEN", 10);
+console.log(res38); // >>> 0
+// STEP_END
+
+// STEP_START xDel
+const res39 = await client.xRange('race:italy', '-', '+');
+console.log(res39); // >>> [('1692630648281-0', {'rider': 'Henshaw'}), ('1692631018238-0', {'rider': 'Smith'})]
+
+const res40 = await client.xDel('race:italy', '1692631018238-0');
+console.log(res40); // >>> 1
+
+const res41 = await client.xRange('race:italy', '-', '+');
+console.log(res41); // >>> [('1692630648281-0', {'rider': 'Henshaw'})]
+// STEP_END
+
+// REMOVE_START
+await client.quit();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/dt-string.js b/doctests/dt-string.js
new file mode 100644
index 00000000000..69afda59e9e
--- /dev/null
+++ b/doctests/dt-string.js
@@ -0,0 +1,68 @@
+// EXAMPLE: string_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = await createClient();
+await client.connect();
+// HIDE_END
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START set
+const res1 = await client.set("bike:1", "Deimos");
+console.log(res1);  // OK
+const res2 = await client.get("bike:1");
+console.log(res2);  // Deimos
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 'OK');
+assert.equal(res2, 'Deimos');
+// REMOVE_END
+
+// STEP_START set_nx_xx
+const res3 = await client.set("bike:1", "bike", {'NX': true});
+console.log(res3);  // null
+console.log(await client.get("bike:1"));  // Deimos
+const res4 = await client.set("bike:1", "bike", {'XX': true});
+console.log(res4);  // OK
+// STEP_END
+
+// REMOVE_START
+assert.equal(res3, null);
+assert.equal(res4, 'OK');
+// REMOVE_END
+
+// STEP_START mset
+const res5 = await client.mSet([
+  ["bike:1", "Deimos"],
+  ["bike:2", "Ares"],
+  ["bike:3", "Vanth"]
+]);
+
+console.log(res5);  // OK
+const res6 = await client.mGet(["bike:1", "bike:2", "bike:3"]);
+console.log(res6);  // ['Deimos', 'Ares', 'Vanth']
+// STEP_END
+
+// REMOVE_START
+assert.equal(res5, 'OK');
+assert.deepEqual(res6, ["Deimos", "Ares", "Vanth"]);
+// REMOVE_END
+
+// STEP_START incr
+await client.set("total_crashes", 0);
+const res7 = await client.incr("total_crashes");
+console.log(res7); // 1
+const res8 = await client.incrBy("total_crashes", 10);
+console.log(res8); // 11
+// STEP_END
+
+// REMOVE_START
+assert.equal(res7, 1);
+assert.equal(res8, 11);
+
+await client.quit();
+// REMOVE_END
diff --git a/doctests/hash-tutorial.js b/doctests/hash-tutorial.js
deleted file mode 100644
index 12def3f7724..00000000000
--- a/doctests/hash-tutorial.js
+++ /dev/null
@@ -1,120 +0,0 @@
-// EXAMPLE: hash_tutorial
-// REMOVE_START
-import assert from 'assert';
-// REMOVE_END
-
-// HIDE_START
-import { createClient } from 'redis';
-
-const client = createClient();
-
-client.on('error', err => console.log('Redis Client Error', err));
-
-await client.connect();
-// HIDE_END
-
-// STEP_START set_get_all
-const fieldsAdded = await client.hSet(
-    'bike:1',
-    {
-        model: 'Deimos',
-        brand: 'Ergonom',
-        type: 'Enduro bikes',
-        price: 4972,
-    },
-)
-console.log(`Number of fields were added: ${fieldsAdded}`);
-// Number of fields were added: 4
-//REMOVE_START
-assert.equal(fieldsAdded, 4);
-//REMOVE_END
-
-const model = await client.hGet('bike:1', 'model');
-console.log(`Model: ${model}`);
-// Model: Deimos
-// REMOVE_START
-assert.equal(model, 'Deimos');
-// REMOVE_END
-
-const price = await client.hGet('bike:1', 'price');
-console.log(`Price: ${price}`);
-// Price: 4972
-// REMOVE_START
-assert.equal(price, '4972');
-// REMOVE_END
-
-const bike = await client.hGetAll('bike:1');
-console.log(bike);
-// {
-//   model: 'Deimos',
-//   brand: 'Ergonom',
-//   type: 'Enduro bikes',
-//   price: '4972'
-// }
-// REMOVE_START
-assert.equal(Object.keys(bike).length, 4);
-// REMOVE_END
-// STEP_END
-
-// STEP_START hmget
-const fields = await client.hmGet('bike:1', ['model', 'price']);
-console.log(fields);
-// [ 'Deimos', '4972' ]
-// REMOVE_START
-assert.equal(fields.length, 2);
-// REMOVE_END
-// STEP_END
-
-// STEP_START hincrby
-let newPrice = await client.hIncrBy('bike:1', 'price', 100);
-console.log(newPrice);
-// 5072
-// REMOVE_START
-assert.equal(newPrice, 5072);
-// REMOVE_END
-newPrice = await client.hIncrBy('bike:1', 'price', -100);
-console.log(newPrice);
-// 4972
-// REMOVE_START
-assert.equal(newPrice, 4972);
-// REMOVE_END
-// STEP_END
-
-// STEP_START incrby_get_mget
-let rides = await client.hIncrBy('bike:1:stats', 'rides', 1);
-console.log(rides);
-// 1
-
-rides = await client.hIncrBy('bike:1:stats', 'rides', 1);
-console.log(rides);
-// 2
-
-rides = await client.hIncrBy('bike:1:stats', 'rides', 1);
-console.log(rides);
-// 3
-
-let crashes = await client.hIncrBy('bike:1:stats', 'crashes', 1);
-console.log(crashes);
-// 1
-
-let owners = await client.hIncrBy('bike:1:stats', 'owners', 1);
-console.log(owners);
-// 1
-
-rides = await client.hGet('bike:1:stats', 'rides');
-console.log(`Total rides: ${rides}`);
-// Total rides: 3
-// REMOVE_START
-assert.equal(rides, 3);
-// REMOVE_END
-const stats = await client.hmGet('bike:1:stats', ['crashes', 'owners']);
-console.log(`Bike stats: crashes=${stats[0]}, owners=${stats[1]}`);
-// Bike stats: crashes=1, owners=1
-// REMOVE_START
-assert.equal(stats.length, 2);
-// REMOVE_END
-// STEP_END
-
-// HIDE_START
-await client.quit();
-// HIDE_END
\ No newline at end of file
diff --git a/doctests/string-set-get-example.js b/doctests/string-set-get-example.js
deleted file mode 100644
index 0b0c9138f5a..00000000000
--- a/doctests/string-set-get-example.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// EXAMPLE: set_and_get
-// REMOVE_START
-import assert from "assert";
-// REMOVE_END
-
-// HIDE_START
-import { createClient } from 'redis';
-
-const client = createClient();
-
-client.on('error', err => console.log('Redis Client Error', err));
-
-await client.connect();
-
-// HIDE_END
-await client.set('bike:1', 'Process 134');
-const value = await client.get('bike:1');
-console.log(value);
-// returns 'Process 134'
-//REMOVE_START
-assert.equal(value, 'Process 134');
-//REMOVE_END
-
-// HIDE_START
-await client.quit();
-// HIDE_END
\ No newline at end of file

From 0f3d0f3d1ffb9ed59f0d2a47225041d3b0095f0b Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Wed, 3 Jul 2024 12:29:13 -0700
Subject: [PATCH 09/20] DOC-3933: final 8 tabbed code examples (#2784)

---
 doctests/dt-bitfield.js |  76 +++++++++++++++++++
 doctests/dt-bloom.js    |  46 ++++++++++++
 doctests/dt-cms.js      |  50 +++++++++++++
 doctests/dt-cuckoo.js   |  38 ++++++++++
 doctests/dt-hll.js      |  38 ++++++++++
 doctests/dt-ss.js       | 162 ++++++++++++++++++++++++++++++++++++++++
 doctests/dt-tdigest.js  |  85 +++++++++++++++++++++
 doctests/dt-topk.js     |  48 ++++++++++++
 8 files changed, 543 insertions(+)
 create mode 100644 doctests/dt-bitfield.js
 create mode 100644 doctests/dt-bloom.js
 create mode 100644 doctests/dt-cms.js
 create mode 100644 doctests/dt-cuckoo.js
 create mode 100644 doctests/dt-hll.js
 create mode 100644 doctests/dt-ss.js
 create mode 100644 doctests/dt-tdigest.js
 create mode 100644 doctests/dt-topk.js

diff --git a/doctests/dt-bitfield.js b/doctests/dt-bitfield.js
new file mode 100644
index 00000000000..01661aa2737
--- /dev/null
+++ b/doctests/dt-bitfield.js
@@ -0,0 +1,76 @@
+// EXAMPLE: bitfield_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START bf
+let res1 = await client.bitField("bike:1:stats", [{
+  operation: 'SET',
+  encoding: 'u32',
+  offset: '#0',
+  value: 1000
+}]);
+console.log(res1);  // >>> [0]
+
+let res2 = await client.bitField('bike:1:stats', [
+  {
+    operation: 'INCRBY',
+    encoding: 'u32',
+    offset: '#0',
+    increment: -50
+  },
+  {
+    operation: 'INCRBY',
+    encoding: 'u32',
+    offset: '#1',
+    increment: 1
+  }
+]);
+console.log(res2);  // >>> [950, 1]
+
+let res3 = await client.bitField('bike:1:stats', [
+  {
+    operation: 'INCRBY',
+    encoding: 'u32',
+    offset: '#0',
+    increment: 500
+  },
+  {
+    operation: 'INCRBY',
+    encoding: 'u32',
+    offset: '#1',
+    increment: 1
+  }
+]);
+console.log(res3);  // >>> [1450, 2]
+
+let res4 = await client.bitField('bike:1:stats', [
+  {
+    operation: 'GET',
+    encoding: 'u32',
+    offset: '#0'
+  },
+  {
+    operation: 'GET',
+    encoding: 'u32',
+    offset: '#1'
+  }
+]);
+console.log(res4);  // >>> [1450, 2]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res1, [0])
+assert.deepEqual(res2, [950, 1])
+assert.deepEqual(res3, [1450, 2])
+assert.deepEqual(res4, [1450, 2])
+await client.quit();
+// REMOVE_END
diff --git a/doctests/dt-bloom.js b/doctests/dt-bloom.js
new file mode 100644
index 00000000000..917ab26538f
--- /dev/null
+++ b/doctests/dt-bloom.js
@@ -0,0 +1,46 @@
+// EXAMPLE: bf_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START bloom
+const res1 = await client.bf.reserve('bikes:models', 0.01, 1000);
+console.log(res1);  // >>> OK
+
+const res2 = await client.bf.add('bikes:models', 'Smoky Mountain Striker');
+console.log(res2);  // >>> true
+
+const res3 = await client.bf.exists('bikes:models', 'Smoky Mountain Striker');
+console.log(res3);  // >>> true
+
+const res4 = await client.bf.mAdd('bikes:models', [
+  'Rocky Mountain Racer',
+  'Cloudy City Cruiser',
+  'Windy City Wippet'
+]);
+console.log(res4);  // >>> [true, true, true]
+
+const res5 = await client.bf.mExists('bikes:models', [
+  'Rocky Mountain Racer',
+  'Cloudy City Cruiser',
+  'Windy City Wippet'
+]);
+console.log(res5);  // >>> [true, true, true]
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 'OK')
+assert.equal(res2, true)
+assert.equal(res3, true)
+assert.deepEqual(res4, [true, true, true])
+assert.deepEqual(res5, [true, true, true])
+await client.quit();
+// REMOVE_END
diff --git a/doctests/dt-cms.js b/doctests/dt-cms.js
new file mode 100644
index 00000000000..eb8f043642f
--- /dev/null
+++ b/doctests/dt-cms.js
@@ -0,0 +1,50 @@
+// EXAMPLE: cms_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START cms
+const res1 = await client.cms.initByProb('bikes:profit', 0.001, 0.002);
+console.log(res1);  // >>> OK
+
+const res2 = await client.cms.incrBy('bikes:profit', {
+    item: 'Smoky Mountain Striker',
+    incrementBy: 100
+});
+console.log(res2);  // >>> [100]
+
+const res3 = await client.cms.incrBy('bikes:profit', [
+  {
+    item: 'Rocky Mountain Racer',
+    incrementBy: 200
+  },
+  {
+    item: 'Cloudy City Cruiser',
+    incrementBy: 150
+  }
+]);
+console.log(res3);  // >>> [200, 150]
+
+const res4 = await client.cms.query('bikes:profit', 'Smoky Mountain Striker');
+console.log(res4);  // >>> [100]
+
+const res5 = await client.cms.info('bikes:profit');
+console.log(res5.width, res5.depth, res5.count);  // >>> 2000 9 450
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 'OK')
+assert.deepEqual(res2, [100])
+assert.deepEqual(res3, [200, 150])
+assert.deepEqual(res4, [100])
+assert.deepEqual(res5, { width: 2000, depth: 9, count: 450 })
+await client.quit();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/dt-cuckoo.js b/doctests/dt-cuckoo.js
new file mode 100644
index 00000000000..7c76fc8f947
--- /dev/null
+++ b/doctests/dt-cuckoo.js
@@ -0,0 +1,38 @@
+// EXAMPLE: cuckoo_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START cuckoo
+const res1 = await client.cf.reserve('bikes:models', 1000000);
+console.log(res1);  // >>> OK
+
+const res2 = await client.cf.add('bikes:models', 'Smoky Mountain Striker');
+console.log(res2);  // >>> 1
+
+const res3 = await client.cf.exists('bikes:models', 'Smoky Mountain Striker');
+console.log(res3);  // >>> 1
+
+const res4 = await client.cf.exists('bikes:models', 'Terrible Bike Name');
+console.log(res4);  // >>> 0
+
+const res5 = await client.cf.del('bikes:models', 'Smoky Mountain Striker');
+console.log(res5);  // >>> 1
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 'OK')
+assert.equal(res2, true)
+assert.equal(res3, true)
+assert.equal(res4, false)
+assert.equal(res5, true)
+await client.quit();
+// REMOVE_END
diff --git a/doctests/dt-hll.js b/doctests/dt-hll.js
new file mode 100644
index 00000000000..b76ac888278
--- /dev/null
+++ b/doctests/dt-hll.js
@@ -0,0 +1,38 @@
+// EXAMPLE: hll_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START pfadd
+const res1 = await client.pfAdd('bikes', ['Hyperion', 'Deimos', 'Phoebe', 'Quaoar']);
+console.log(res1);  // >>> true
+
+const res2 = await client.pfCount('bikes');
+console.log(res2);  // >>> 4
+
+const res3 = await client.pfAdd('commuter_bikes', ['Salacia', 'Mimas', 'Quaoar']);
+console.log(res3);  // >>> true
+
+const res4 = await client.pfMerge('all_bikes', ['bikes', 'commuter_bikes']);
+console.log(res4);  // >>> OK
+
+const res5 = await client.pfCount('all_bikes');
+console.log(res5);  // >>> 6
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, true)
+assert.equal(res2, 4)
+assert.equal(res3, true)
+assert.equal(res4, 'OK')
+assert.equal(res5, 6)
+await client.quit();
+// REMOVE_END
diff --git a/doctests/dt-ss.js b/doctests/dt-ss.js
new file mode 100644
index 00000000000..54202c36276
--- /dev/null
+++ b/doctests/dt-ss.js
@@ -0,0 +1,162 @@
+// EXAMPLE: ss_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START zadd
+const res1 = await client.zAdd('racer_scores', { score: 10, value: 'Norem' });
+console.log(res1);  // >>> 1
+
+const res2 = await client.zAdd('racer_scores', { score: 12, value: 'Castilla' });
+console.log(res2);  // >>> 1
+
+const res3 = await client.zAdd('racer_scores', [
+  { score: 8, value: 'Sam-Bodden' },
+  { score: 10, value: 'Royce' },
+  { score: 6, value: 'Ford' },
+  { score: 14, value: 'Prickett' },
+  { score: 12, value: 'Castilla' }
+]);
+console.log(res3);  // >>> 4
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 1)
+assert.equal(res2, 1)
+assert.equal(res3, 4)
+// REMOVE_END
+
+// REMOVE_START
+const count = await client.zCard('racer_scores');
+console.assert(count === 6);
+// REMOVE_END
+
+// STEP_START zrange
+const res4 = await client.zRange('racer_scores', 0, -1);
+console.log(res4);  // >>> ['Ford', 'Sam-Bodden', 'Norem', 'Royce', 'Castilla', 'Prickett']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res4, ['Ford', 'Sam-Bodden', 'Norem', 'Royce', 'Castilla', 'Prickett'])
+// REMOVE_END
+
+// STEP_START zrange_withscores
+const res6 = await client.zRangeWithScores('racer_scores', 0, -1);
+console.log(res6);
+// >>> [
+//       { value: 'Ford', score: 6 }, { value: 'Sam-Bodden', score: 8 },
+//       { value: 'Norem', score: 10 }, { value: 'Royce', score: 10 },
+//       { value: 'Castilla', score: 12 }, { value: 'Prickett', score: 14 }
+// ]
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res6, [ { value: 'Ford', score: 6 }, { value: 'Sam-Bodden', score: 8 }, { value: 'Norem', score: 10 }, { value: 'Royce', score: 10 }, { value: 'Castilla', score: 12 }, { value: 'Prickett', score: 14 } ]
+)
+// REMOVE_END
+
+// STEP_START zrangebyscore
+const res7 = await client.zRangeByScore('racer_scores', '-inf', 10);
+console.log(res7);  // >>> ['Ford', 'Sam-Bodden', 'Norem', 'Royce']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res7, ['Ford', 'Sam-Bodden', 'Norem', 'Royce'])
+// REMOVE_END
+
+// STEP_START zremrangebyscore
+const res8 = await client.zRem('racer_scores', 'Castilla');
+console.log(res8);  // >>> 1
+
+const res9 = await client.zRemRangeByScore('racer_scores', '-inf', 9);
+console.log(res9);  // >>> 2
+
+// REMOVE_START
+assert.equal(res8, 1)
+assert.equal(res9, 2)
+// REMOVE_END
+
+const res10 = await client.zRange('racer_scores', 0, -1);
+console.log(res10);  // >>> ['Norem', 'Royce', 'Prickett']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res10, ['Norem', 'Royce', 'Prickett'])
+// REMOVE_END
+
+// REMOVE_START
+const count2 = await client.zCard('racer_scores');
+console.assert(count2 === 3);
+// REMOVE_END
+
+// STEP_START zrank
+const res11 = await client.zRank('racer_scores', 'Norem');
+console.log(res11);  // >>> 0
+
+const res12 = await client.zRevRank('racer_scores', 'Norem');
+console.log(res12);  // >>> 2
+// STEP_END
+
+// STEP_START zadd_lex
+const res13 = await client.zAdd('racer_scores', [
+  { score: 0, value: 'Norem' },
+  { score: 0, value: 'Sam-Bodden' },
+  { score: 0, value: 'Royce' },
+  { score: 0, value: 'Ford' },
+  { score: 0, value: 'Prickett' },
+  { score: 0, value: 'Castilla' }
+]);
+console.log(res13);  // >>> 3
+
+// REMOVE_START
+assert.equal(count2, 3)
+assert.equal(res11, 0)
+assert.equal(res12, 2)
+assert.equal(res13, 3)
+// REMOVE_END
+
+const res14 = await client.zRange('racer_scores', 0, -1);
+console.log(res14);  // >>> ['Castilla', 'Ford', 'Norem', 'Prickett', 'Royce', 'Sam-Bodden']
+
+const res15 = await client.zRangeByLex('racer_scores', '[A', '[L');
+console.log(res15);  // >>> ['Castilla', 'Ford']
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res14, ['Castilla', 'Ford', 'Norem', 'Prickett', 'Royce', 'Sam-Bodden'])
+assert.deepEqual(res15, ['Castilla', 'Ford'])
+// REMOVE_END
+
+// STEP_START leaderboard
+const res16 = await client.zAdd('racer_scores', { score: 100, value: 'Wood' });
+console.log(res16);  // >>> 1
+
+const res17 = await client.zAdd('racer_scores', { score: 100, value: 'Henshaw' });
+console.log(res17);  // >>> 1
+
+const res18 = await client.zAdd('racer_scores', { score: 150, value: 'Henshaw' }, { nx: true });
+console.log(res18);  // >>> 0
+
+const res19 = await client.zIncrBy('racer_scores', 50, 'Wood');
+console.log(res19);  // >>> 150.0
+
+const res20 = await client.zIncrBy('racer_scores', 50, 'Henshaw');
+console.log(res20);  // >>> 200.0
+// STEP_END
+
+// REMOVE_START
+assert.equal(res16, 1)
+assert.equal(res17, 1)
+assert.equal(res18, 0)
+assert.equal(res19, 150.0)
+assert.equal(res20, 200.0)
+await client.quit();
+// REMOVE_END
diff --git a/doctests/dt-tdigest.js b/doctests/dt-tdigest.js
new file mode 100644
index 00000000000..3817d3a8907
--- /dev/null
+++ b/doctests/dt-tdigest.js
@@ -0,0 +1,85 @@
+// EXAMPLE: tdigest_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START tdig_start
+const res1 = await client.tDigest.create('bikes:sales', 100);
+console.log(res1);  // >>> OK
+
+const res2 = await client.tDigest.add('bikes:sales', [21]);
+console.log(res2);  // >>> OK
+
+const res3 = await client.tDigest.add('bikes:sales', [150, 95, 75, 34]);
+console.log(res3);  // >>> OK
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 'OK')
+assert.equal(res2, 'OK')
+assert.equal(res3, 'OK')
+// REMOVE_END
+
+// STEP_START tdig_cdf
+const res4 = await client.tDigest.create('racer_ages');
+console.log(res4);  // >>> OK
+
+const res5 = await client.tDigest.add('racer_ages', [
+  45.88, 44.2, 58.03, 19.76, 39.84, 69.28, 50.97, 25.41, 19.27, 85.71, 42.63
+]);
+console.log(res5);  // >>> OK
+
+const res6 = await client.tDigest.rank('racer_ages', [50]);
+console.log(res6);  // >>> [7]
+
+const res7 = await client.tDigest.rank('racer_ages', [50, 40]);
+console.log(res7);  // >>> [7, 4]
+// STEP_END
+
+// REMOVE_START
+assert.equal(res4, 'OK')
+assert.equal(res5, 'OK')
+assert.deepEqual(res6, [7])
+assert.deepEqual(res7, [7, 4])
+// REMOVE_END
+
+// STEP_START tdig_quant
+const res8 = await client.tDigest.quantile('racer_ages', [0.5]);
+console.log(res8);  // >>> [44.2]
+
+const res9 = await client.tDigest.byRank('racer_ages', [4]);
+console.log(res9);  // >>> [42.63]
+// STEP_END
+
+// STEP_START tdig_min
+const res10 = await client.tDigest.min('racer_ages');
+console.log(res10);  // >>> 19.27
+
+const res11 = await client.tDigest.max('racer_ages');
+console.log(res11);  // >>> 85.71
+// STEP_END
+
+// REMOVE_START
+assert.deepEqual(res8, [44.2])
+assert.deepEqual(res9, [42.63])
+assert.equal(res10, 19.27)
+assert.equal(res11, 85.71)
+// REMOVE_END
+
+// STEP_START tdig_reset
+const res12 = await client.tDigest.reset('racer_ages');
+console.log(res12);  // >>> OK
+// STEP_END
+
+// REMOVE_START
+assert.equal(res12, 'OK')
+await client.quit();
+// REMOVE_END
diff --git a/doctests/dt-topk.js b/doctests/dt-topk.js
new file mode 100644
index 00000000000..97696d97442
--- /dev/null
+++ b/doctests/dt-topk.js
@@ -0,0 +1,48 @@
+// EXAMPLE: topk_tutorial
+// HIDE_START
+import assert from 'assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+// HIDE_END
+
+// REMOVE_START
+await client.flushDb();
+// REMOVE_END
+
+// STEP_START topk
+const res1 = await client.topK.reserve('bikes:keywords', 5, {
+    width: 2000,
+    depth: 7,
+    decay: 0.925
+});
+console.log(res1);  // >>> OK
+
+const res2 = await client.topK.add('bikes:keywords', [
+  'store',
+  'seat',
+  'handlebars',
+  'handles',
+  'pedals',
+  'tires',
+  'store',
+  'seat'
+]);
+console.log(res2);  // >>> [null, null, null, null, null, 'handlebars', null, null]
+
+const res3 = await client.topK.list('bikes:keywords');
+console.log(res3);  // >>> ['store', 'seat', 'pedals', 'tires', 'handles']
+
+const res4 = await client.topK.query('bikes:keywords', ['store', 'handlebars']);
+console.log(res4);  // >>> [1, 0]
+// STEP_END
+
+// REMOVE_START
+assert.equal(res1, 'OK')
+assert.deepEqual(res2, [null, null, null, null, null, 'handlebars', null, null])
+assert.deepEqual(res3, ['store', 'seat', 'pedals', 'tires', 'handles'])
+assert.deepEqual(res4, [1, 0])
+await client.quit();
+// REMOVE_END
+

From 6a3ea590df4ed0e8f9a4ded048cfab1f6598ad2b Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Wed, 17 Jul 2024 09:35:45 -0700
Subject: [PATCH 10/20] doctests: fix step names (#2795)

---
 doctests/dt-string.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doctests/dt-string.js b/doctests/dt-string.js
index 69afda59e9e..7212aff2ac9 100644
--- a/doctests/dt-string.js
+++ b/doctests/dt-string.js
@@ -1,4 +1,4 @@
-// EXAMPLE: string_tutorial
+// EXAMPLE: set_tutorial
 // HIDE_START
 import assert from 'assert';
 import { createClient } from 'redis';
@@ -10,7 +10,7 @@ await client.connect();
 await client.flushDb();
 // REMOVE_END
 
-// STEP_START set
+// STEP_START set_get
 const res1 = await client.set("bike:1", "Deimos");
 console.log(res1);  // OK
 const res2 = await client.get("bike:1");
@@ -22,7 +22,7 @@ assert.equal(res1, 'OK');
 assert.equal(res2, 'Deimos');
 // REMOVE_END
 
-// STEP_START set_nx_xx
+// STEP_START setnx_xx
 const res3 = await client.set("bike:1", "bike", {'NX': true});
 console.log(res3);  // null
 console.log(await client.get("bike:1"));  // Deimos

From 06e91d0623875aa0781c4583a4b85150742dd95d Mon Sep 17 00:00:00 2001
From: 72mask <ljy1017010@163.com>
Date: Wed, 31 Jul 2024 01:25:32 +0800
Subject: [PATCH 11/20] fix: XRangeOptions COUNT (#2791)

Co-authored-by: larry <lijingyuan@teplore.com>
---
 doctests/dt-streams.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/doctests/dt-streams.js b/doctests/dt-streams.js
index b54357ebb67..94e415ea4e7 100644
--- a/doctests/dt-streams.js
+++ b/doctests/dt-streams.js
@@ -49,7 +49,7 @@ assert.equal(await client.xLen('race:france'), 3);
 // REMOVE_END
 
 // STEP_START xRange
-const res4 = await client.xRange('race:france', '1691765278160-0', '+', 2);
+const res4 = await client.xRange('race:france', '1691765278160-0', '+', {COUNT: 2});
 console.log(res4); // >>> [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}), ('1692629594113-0', {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'})]
 // STEP_END
 
@@ -121,22 +121,22 @@ console.log(res12); // >>> [('1692629576966-0', {'rider': 'Castilla', 'speed': '
 // STEP_END
 
 // STEP_START xRange_step_1
-const res13 = await client.xRange('race:france', '-', '+', 2);
+const res13 = await client.xRange('race:france', '-', '+', {COUNT: 2});
 console.log(res13); // >>> [('1692629576966-0', {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}), ('1692629594113-0', {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'})]
 // STEP_END
 
 // STEP_START xRange_step_2
-const res14 = await client.xRange('race:france', '(1692629594113-0', '+', 2);
+const res14 = await client.xRange('race:france', '(1692629594113-0', '+', {COUNT: 2});
 console.log(res14); // >>> [('1692629613374-0', {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}), ('1692629676124-0', {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'})]
 // STEP_END
 
 // STEP_START xRange_empty
-const res15 = await client.xRange('race:france', '(1692629676124-0', '+', 2);
+const res15 = await client.xRange('race:france', '(1692629676124-0', '+', {COUNT: 2});
 console.log(res15); // >>> []
 // STEP_END
 
 // STEP_START xrevrange
-const res16 = await client.xRevRange('race:france', '+', '-', 1);
+const res16 = await client.xRevRange('race:france', '+', '-', {COUNT: 1});
 console.log(
   res16
 ); // >>> [('1692629676124-0', {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'})]

From 9f810c2f858fa37e1f3bbbab1b4280644d82dc48 Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Thu, 26 Sep 2024 04:21:19 -0700
Subject: [PATCH 12/20] Add back accidentally deleted doctests file (#2821)

* Add back accidentally deleted doctest file

* Update string-set-get-example.js
---
 doctests/string-set-get-example.js | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 doctests/string-set-get-example.js

diff --git a/doctests/string-set-get-example.js b/doctests/string-set-get-example.js
new file mode 100644
index 00000000000..9d74c15e058
--- /dev/null
+++ b/doctests/string-set-get-example.js
@@ -0,0 +1,27 @@
+// EXAMPLE: set_and_get
+// REMOVE_START
+import assert from "node:assert";
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+
+client.on('error', err => console.log('Redis Client Error', err));
+
+await client.connect().catch(console.error);
+
+// HIDE_END
+await client.set('bike:1', 'Process 134');
+const value = await client.get('bike:1');
+console.log(value);
+// returns 'Process 134'
+//REMOVE_START
+assert.equal(value, 'Process 134');
+await client.del('bike:1');
+//REMOVE_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END

From ebd2037e4838d92244e076a081753946042fea41 Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Thu, 26 Sep 2024 04:25:31 -0700
Subject: [PATCH 13/20] DOC-4194: add TCEs to the exact match query page
 (COMMIT FIRST!) (#2830)

* DOC-4194: add TCEs to the exact match query page

* Preemptive modifications from previous reviews
---
 doctests/data/query_em.json     |  92 ++++++++++++++++++++++++
 doctests/data/query_vector.json | 123 ++++++++++++++++++++++++++++++++
 doctests/query-em.js            | 121 +++++++++++++++++++++++++++++++
 3 files changed, 336 insertions(+)
 create mode 100644 doctests/data/query_em.json
 create mode 100644 doctests/data/query_vector.json
 create mode 100644 doctests/query-em.js

diff --git a/doctests/data/query_em.json b/doctests/data/query_em.json
new file mode 100644
index 00000000000..bcf908aaf85
--- /dev/null
+++ b/doctests/data/query_em.json
@@ -0,0 +1,92 @@
+[
+  {
+	  "pickup_zone": "POLYGON((-74.0610 40.7578, -73.9510 40.7578, -73.9510 40.6678, -74.0610 40.6678, -74.0610 40.7578))",
+	  "store_location": "-74.0060,40.7128",
+	  "brand": "Velorim",
+	  "model": "Jigger",
+	  "price": 270,
+	  "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.",
+	  "condition": "new"
+  },
+  {
+    "pickup_zone": "POLYGON((-118.2887 34.0972, -118.1987 34.0972, -118.1987 33.9872, -118.2887 33.9872, -118.2887 34.0972))",
+	  "store_location": "-118.2437,34.0522",
+	  "brand": "Bicyk",
+	  "model": "Hillcraft",
+	  "price": 1200,
+	  "description": "Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\" wheel bike is just too clumsy coming off a 24\" bike. The Hillcraft 26 is just the solution they need!",
+	  "condition": "used"
+  },
+  {
+    "pickup_zone": "POLYGON((-87.6848 41.9331, -87.5748 41.9331, -87.5748 41.8231, -87.6848 41.8231, -87.6848 41.9331))",
+	  "store_location": "-87.6298,41.8781",
+  	"brand": "Nord",
+  	"model": "Chook air 5",
+  	"price": 815,
+  	"description": "The Chook Air 5  gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower  top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails.",
+  	"condition": "used"
+  },
+  {
+    "pickup_zone": "POLYGON((-80.2433 25.8067, -80.1333 25.8067, -80.1333 25.6967, -80.2433 25.6967, -80.2433 25.8067))",
+  	"store_location": "-80.1918,25.7617",
+  	"brand": "Eva",
+  	"model": "Eva 291",
+  	"price": 3400,
+  	"description": "The sister company to Nord, Eva launched in 2005 as the first and only women-dedicated bicycle brand. Designed by women for women, allEva bikes are optimized for the feminine physique using analytics from a body metrics database. If you like 29ers, try the Eva 291. It’s a brand new bike for 2022.. This full-suspension, cross-country ride has been designed for velocity. The 291 has 100mm of front and rear travel, a superlight aluminum frame and fast-rolling 29-inch wheels. Yippee!",
+  	"condition": "used"
+  },
+  {
+    "pickup_zone": "POLYGON((-122.4644 37.8199, -122.3544 37.8199, -122.3544 37.7099, -122.4644 37.7099, -122.4644 37.8199))",
+  	"store_location": "-122.4194,37.7749",
+  	"brand": "Noka Bikes",
+  	"model": "Kahuna",
+  	"price": 3200,
+  	"description": "Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway.",
+  	"condition": "used"
+  },
+  {
+    "pickup_zone": "POLYGON((-0.1778 51.5524, 0.0822 51.5524, 0.0822 51.4024, -0.1778 51.4024, -0.1778 51.5524))",
+    "store_location": "-0.1278,51.5074",
+    "brand": "Breakout",
+    "model": "XBN 2.1 Alloy",
+    "price": 810,
+    "description": "The XBN 2.1 Alloy is our entry-level road bike – but that’s not to say that it’s a basic machine. With an internal weld aluminium frame, a full carbon fork, and the slick-shifting Claris gears from Shimano’s, this is a bike which doesn’t break the bank and delivers craved performance.",
+    "condition": "new"
+  },
+  {
+    "pickup_zone": "POLYGON((2.1767 48.9016, 2.5267 48.9016, 2.5267 48.5516, 2.1767 48.5516, 2.1767 48.9016))",
+    "store_location": "2.3522,48.8566",
+    "brand": "ScramBikes",
+    "model": "WattBike",
+    "price": 2300,
+    "description": "The WattBike is the best e-bike for people who still feel young at heart. It has a Bafang 1000W mid-drive system and a 48V 17.5AH Samsung Lithium-Ion battery, allowing you to ride for more than 60 miles on one charge. It’s great for tackling hilly terrain or if you just fancy a more leisurely ride. With three working modes, you can choose between E-bike, assisted bicycle, and normal bike modes.",
+    "condition": "new"
+  },
+  {
+    "pickup_zone": "POLYGON((13.3260 52.5700, 13.6550 52.5700, 13.6550 52.2700, 13.3260 52.2700, 13.3260 52.5700))",
+    "store_location": "13.4050,52.5200",
+    "brand": "Peaknetic",
+    "model": "Secto",
+    "price": 430,
+    "description": "If you struggle with stiff fingers or a kinked neck or back after a few minutes on the road, this lightweight, aluminum bike alleviates those issues and allows you to enjoy the ride. From the ergonomic grips to the lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. The rear-inclined seat tube facilitates stability by allowing you to put a foot on the ground to balance at a stop, and the low step-over frame makes it accessible for all ability and mobility levels. The saddle is very soft, with a wide back to support your hip joints and a cutout in the center to redistribute that pressure. Rim brakes deliver satisfactory braking control, and the wide tires provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts facilitate setting up the Roll Low-Entry as your preferred commuter, and the BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder.",
+    "condition": "new"
+  },
+  {
+    "pickup_zone": "POLYGON((1.9450 41.4301, 2.4018 41.4301, 2.4018 41.1987, 1.9450 41.1987, 1.9450 41.4301))",
+    "store_location": "2.1734, 41.3851",
+    "brand": "nHill",
+    "model": "Summit",
+    "price": 1200,
+    "description": "This budget mountain bike from nHill performs well both on bike paths and on the trail. The fork with 100mm of travel absorbs rough terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. The Shimano Tourney drivetrain offered enough gears for finding a comfortable pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. Whether you want an affordable bike that you can take to work, but also take trail in mountains on the weekends or you’re just after a stable, comfortable ride for the bike path, the Summit gives a good value for money.",
+    "condition": "new"
+  },
+  {
+    "pickup_zone": "POLYGON((12.4464 42.1028, 12.5464 42.1028, 12.5464 41.7028, 12.4464 41.7028, 12.4464 42.1028))",
+    "store_location": "12.4964,41.9028",
+    "model": "ThrillCycle",
+    "brand": "BikeShind",
+    "price": 815,
+    "description": "An artsy,  retro-inspired bicycle that’s as functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn’t suggest taking it to the mountains. Fenders protect you from mud, and a rear basket lets you transport groceries, flowers and books. The ThrillCycle comes with a limited lifetime warranty, so this little guy will last you long past graduation.",
+    "condition": "refurbished"
+  }
+]
diff --git a/doctests/data/query_vector.json b/doctests/data/query_vector.json
new file mode 100644
index 00000000000..0d128bbedb1
--- /dev/null
+++ b/doctests/data/query_vector.json
@@ -0,0 +1,123 @@
+[
+  {
+    "model": "Jigger",
+    "brand": "Velorim",
+    "price": 270,
+    "type": "Kids bikes",
+    "specs": {
+      "material": "aluminium",
+      "weight": "10"
+    },
+    "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go. We say rare because this smokin’ little bike is not ideal for a nervous first-time rider, but it’s a true giddy up for a true speedster. The Jigger is a 12 inch lightweight kids bicycle and it will meet your little one’s need for speed. It’s a single speed bike that makes learning to pump pedals simple and intuitive. It even has  a handle in the bottom of the saddle so you can easily help your child during training!  The Jigger is among the most lightweight children’s bikes on the planet. It is designed so that 2-3 year-olds fit comfortably in a molded ride position that allows for efficient riding, balanced handling and agility. The Jigger’s frame design and gears work together so your buddingbiker can stand up out of the seat, stop rapidly, rip over trails and pump tracks. The Jigger’s is amazing on dirt or pavement. Your tike will speed down the bike path in no time. The Jigger will ship with a coaster brake. A freewheel kit is provided at no cost. "
+  },
+  {
+    "model": "Hillcraft",
+    "brand": "Bicyk",
+    "price": 1200,
+    "type": "Kids Mountain Bikes",
+    "specs": {
+      "material": "carbon",
+      "weight": "11"
+    },
+    "description": "Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\" wheel bike is just too clumsy coming off a 24\" bike. The Hillcraft 26 is just the solution they need! Imagine 120mm travel. Boost front/rear.  You have NOTHING to tweak because it is easy to assemble right out of the box. The Hillcraft 26 is an efficient trail trekking machine. Up or down does not matter - dominate the trails going both down and up with this amazing bike. The name Monarch comes from Monarch trail in Colorado where we love to ride.  It’s a highly technical, steep and rocky trail but the rip on the waydown is so fulfilling.  Don’t ride the trail on a hardtail! It is so much more fun on the full suspension Hillcraft!  Hit your local trail with the Hillcraft Monarch 26 to get to where you want to go.  "
+  },
+  {
+    "model": "Chook air 5",
+    "brand": "Nord",
+    "price": 815,
+    "type": "Kids Mountain Bikes",
+    "specs": {
+      "material": "alloy",
+      "weight": "9.1"
+    },
+    "description": "The Chook Air 5  gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower  top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails. The Chook Air 5 is the perfect intro to mountain biking."
+  },
+  {
+    "model": "Eva 291",
+    "brand": "Eva",
+    "price": 3400,
+    "type": "Mountain Bikes",
+    "specs": {
+      "material": "carbon",
+      "weight": "9.1"
+    },
+    "description": "The sister company to Nord, Eva launched in 2005 as the first and only women-dedicated bicycle brand. Designed by women for women, allEva bikes are optimized for the feminine physique using analytics from a body metrics database. If you like 29ers, try the Eva 291. It’s a brand new bike for 2022.. This full-suspension, cross-country ride has been designed for velocity. The 291 has 100mm of front and rear travel, a superlight aluminum frame and fast-rolling 29-inch wheels. Yippee!"
+  },
+  {
+    "model": "Kahuna",
+    "brand": "Noka Bikes",
+    "price": 3200,
+    "type": "Mountain Bikes",
+    "specs": {
+      "material": "alloy",
+      "weight": "9.8"
+    },
+    "description": "Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway."
+  },
+  {
+    "model": "XBN 2.1 Alloy",
+    "brand": "Breakout",
+    "price": 810,
+    "type": "Road Bikes",
+    "specs": {
+      "material": "alloy",
+      "weight": "7.2"
+    },
+    "description": "The XBN 2.1 Alloy is our entry-level road bike – but that’s not to say that it’s a basic machine. With an internal weld aluminium frame, a full carbon fork, and the slick-shifting Claris gears from Shimano’s, this is a bike which doesn’t break the bank and delivers craved performance. The 6061 alloy frame is triple-butted which ensures a lighter weight and smoother ride. And it’s comfortable with dropped seat stays and the carbon fork. The carefully crafted 50-34 tooth chainset and 11-32 tooth cassette give an easy-on-the-legs bottom gear for climbing, and the high-quality Vittoria Zaffiro tires balance grip, rolling friction and puncture protection when coasting down the other side.  "
+  },
+  {
+    "model": "WattBike",
+    "brand": "ScramBikes",
+    "price": 2300,
+    "type": "eBikes",
+    "specs": {
+      "material": "alloy",
+      "weight": "15"
+    },
+    "description": "The WattBike is the best e-bike for people who still feel young at heart. It has a  Bafang 500 watt geared hub motor that can reach 20 miles per hour on both steep inclines and city streets. The lithium-ion battery, which gets nearly 40 miles per charge, has a lightweight form factor, making it easier for seniors to use. It comes fully assembled (no convoluted instructions!) and includes a sturdy helmet at no cost. The Plush saddle softens over time with use. The included Seatpost, however, is easily adjustable and adds to this bike’s fantastic rating for seniors, as do the hydraulic disc brakes from Tektro.  "
+  },
+  {
+    "model": "Soothe Electric bike",
+    "brand": "Peaknetic",
+    "price": 1950,
+    "type": "eBikes",
+    "specs": {
+      "material": "alloy",
+      "weight": "14.7"
+    },
+    "description": "The Soothe is an everyday electric bike, from the makers of Exercycle  bikes, that conveys style while you get around the city. The Soothe lives up to its name by keeping your posture upright and relaxed for the ride ahead, keeping those aches and pains from riding at bay. It includes a low-step frame , our memory foam seat, bump-resistant shocks and conveniently placed thumb throttle. "
+  },
+  {
+    "model": "Secto",
+    "brand": "Peaknetic",
+    "price": 430,
+    "type": "Commuter bikes",
+    "specs": {
+      "material": "aluminium",
+      "weight": "10.0"
+    },
+    "description": "If you struggle with stiff fingers or a kinked neck or back after a few minutes on the road, this lightweight, aluminum bike alleviates those issues and allows you to enjoy the ride. From the ergonomic grips to the lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. The rear-inclined seat tube facilitates stability by allowing you to put a foot on the ground to balance at a stop, and the low step-over frame makes it accessible for all ability and mobility levels. The saddle is very soft, with a wide back to support your hip joints and a cutout in the center to redistribute that pressure. Rim brakes deliver satisfactory braking control, and the wide tires provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts facilitate setting up the Roll Low-Entry as your preferred commuter, and the BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder."
+  },
+  {
+    "model": "Summit",
+    "brand": "nHill",
+    "price": 1200,
+    "type": "Mountain Bike",
+    "specs": {
+      "material": "alloy",
+      "weight": "11.3"
+    },
+    "description": "This budget mountain bike from nHill performs well both on bike paths and on the trail. The fork with 100mm of travel absorbs rough terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. The Shimano Tourney drivetrain offered enough gears for finding a comfortable pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. Whether you want an affordable bike that you can take to work, but also take trail riding on the weekends or you’re just after a stable, comfortable ride for the bike path, the Summit gives a good value for money."
+  },
+  {
+    "model": "ThrillCycle",
+    "brand": "BikeShind",
+    "price": 815,
+    "type": "Commuter Bikes",
+    "specs": {
+      "material": "alloy",
+      "weight": "12.7"
+    },
+    "description": "An artsy,  retro-inspired bicycle that’s as functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn’t suggest taking it to the mountains. Fenders protect you from mud, and a rear basket lets you transport groceries, flowers and books. The ThrillCycle comes with a limited lifetime warranty, so this little guy will last you long past graduation."
+  }
+]
\ No newline at end of file
diff --git a/doctests/query-em.js b/doctests/query-em.js
new file mode 100644
index 00000000000..a3b8394b133
--- /dev/null
+++ b/doctests/query-em.js
@@ -0,0 +1,121 @@
+// EXAMPLE: query_em
+// HIDE_START
+import assert from 'node:assert';
+import fs from 'node:fs';
+import { createClient, SchemaFieldTypes, AggregateGroupByReducers, AggregateSteps} from 'redis';
+
+const client = createClient();
+
+await client.connect().catch(console.error);
+
+// create index
+await client.ft.create('idx:bicycle', {
+  '$.description': {
+    type: SchemaFieldTypes.TEXT,
+    AS: 'description'
+  },
+  '$.price': {
+    type: SchemaFieldTypes.NUMERIC,
+    AS: 'price'
+  },
+  '$.condition': {
+    type: SchemaFieldTypes.TAG,
+    AS: 'condition'
+  }
+}, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+})
+
+// load data
+const bicycles = JSON.parse(fs.readFileSync('data/query_em.json', 'utf8'));
+
+await Promise.all(
+  bicycles.map((bicycle, bid) => {
+      return client.json.set(`bicycle:${bid}`, '$', bicycle);
+  })
+);
+// HIDE_END
+
+// STEP_START em1
+const res1 = await client.ft.search('idx:bicycle', '@price:[270 270]');
+console.log(res1.total); // >>> 1
+// REMOVE_START
+assert.strictEqual(res1.total, 1);
+// REMOVE_END
+
+try {
+    const res2 = await client.ft.search('idx:bicycle', '@price:[270]');
+    console.log(res2.total); // >>> 1
+    assert.strictEqual(res2.total, 1);
+} catch (err) {
+    console.log("'@price:[270]' syntax not yet supported.");
+}
+
+try {
+    const res3 = await client.ft.search('idx:bicycle', '@price==270');
+    console.log(res3.total); // >>> 1
+    assert.strictEqual(res3.total, 1);
+} catch (err) {
+    console.log("'@price==270' syntax not yet supported.");
+}
+
+// FILTER is not supported
+// const res4 = await client.ft.search('idx:bicycle', '*', {
+//   FILTER: {
+//       field: 'price',
+//       min: 270,
+//       max: 270,
+//   }
+// });
+// console.log(res4.total); // >>> 1
+// REMOVE_START
+// assert.strictEqual(res4.total, 10);
+// REMOVE_END
+// STEP_END
+
+// STEP_START em2
+const res5 = await client.ft.search('idx:bicycle', '@condition:{new}');
+console.log(res5.total); // >>> 5
+// REMOVE_START
+assert.strictEqual(res5.total, 5);
+// REMOVE_END
+// STEP_END
+
+// STEP_START em3
+await client.ft.create('idx:email', {
+  '$.email': {
+    type: SchemaFieldTypes.TAG,
+    AS: 'email'
+  }
+}, {
+  ON: 'JSON',
+  PREFIX: 'key:'
+})
+
+await client.json.set('key:1', '$', { email: 'test@redis.com' });
+
+try {
+    const res6 = await client.ft.search('idx:email', 'test@redis.com', { DIALECT: 2 });
+    console.log(res6);
+} catch (err) {
+    console.log("'test@redis.com' syntax not yet supported.");
+}
+// REMOVE_START
+await client.ft.dropIndex('idx:email', { DD: true });
+// REMOVE_END
+// STEP_END
+
+// STEP_START em4
+const res7 = await client.ft.search('idx:bicycle', '@description:"rough terrain"');
+console.log(res7.total); // >>> 1 (Result{1 total, docs: [Document {'id': 'bicycle:8'...)
+// REMOVE_START
+assert.strictEqual(res7.total, 1);
+// REMOVE_END
+// STEP_END
+
+// REMOVE_START
+// destroy index and data
+await client.ft.dropIndex('idx:bicycle', { DD: true });
+await client.disconnect();
+// REMOVE_END

From fd7b10be6cd20012ceee923c72ddc6db104cdd72 Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Thu, 26 Sep 2024 04:27:12 -0700
Subject: [PATCH 14/20] TCEs for select command pages (#2824)

* TCEs for select command pages

* Preemptive modifications from previous reviews

* Update to previous commit
---
 doctests/cmds-generic.js    | 195 ++++++++++++++++++++++++++++++++++++
 doctests/cmds-hash.js       |  71 +++++++++++++
 doctests/cmds-sorted-set.js | 115 +++++++++++++++++++++
 doctests/cmds-string.js     |  27 +++++
 4 files changed, 408 insertions(+)
 create mode 100644 doctests/cmds-generic.js
 create mode 100644 doctests/cmds-hash.js
 create mode 100644 doctests/cmds-sorted-set.js
 create mode 100644 doctests/cmds-string.js

diff --git a/doctests/cmds-generic.js b/doctests/cmds-generic.js
new file mode 100644
index 00000000000..cfc82fd0187
--- /dev/null
+++ b/doctests/cmds-generic.js
@@ -0,0 +1,195 @@
+// EXAMPLE: cmds_generic
+// REMOVE_START
+import assert from "node:assert";
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START del
+const delRes1 = await client.set('key1', 'Hello');
+console.log(delRes1); // OK
+
+const delRes2 = await client.set('key2', 'World');
+console.log(delRes2); // OK
+
+const delRes3 = await client.del(['key1', 'key2', 'key3']);
+console.log(delRes3); // 2
+// REMOVE_START
+assert.equal(delRes3, 2);
+// REMOVE_END
+// STEP_END
+
+// STEP_START expire
+const expireRes1 = await client.set('mykey', 'Hello');
+console.log(expireRes1); // OK
+
+const expireRes2 = await client.expire('mykey', 10);
+console.log(expireRes2); // true
+
+const expireRes3 = await client.ttl('mykey');
+console.log(expireRes3); // 10
+// REMOVE_START
+assert.equal(expireRes3, 10);
+// REMOVE_END
+
+const expireRes4 = await client.set('mykey', 'Hello World');
+console.log(expireRes4); // OK
+
+const expireRes5 = await client.ttl('mykey');
+console.log(expireRes5); // -1
+// REMOVE_START
+assert.equal(expireRes5, -1);
+// REMOVE_END
+
+const expireRes6 = await client.expire('mykey', 10, "XX");
+console.log(expireRes6); // false
+// REMOVE_START
+assert.equal(expireRes6, false)
+// REMOVE_END
+
+const expireRes7 = await client.ttl('mykey');
+console.log(expireRes7); // -1
+// REMOVE_START
+assert.equal(expireRes7, -1);
+// REMOVE_END
+
+const expireRes8 = await client.expire('mykey', 10, "NX");
+console.log(expireRes8); // true
+// REMOVE_START
+assert.equal(expireRes8, true);
+// REMOVE_END
+
+const expireRes9 = await client.ttl('mykey');
+console.log(expireRes9); // 10
+// REMOVE_START
+assert.equal(expireRes9, 10);
+await client.del('mykey');
+// REMOVE_END
+// STEP_END
+
+// STEP_START ttl
+const ttlRes1 = await client.set('mykey', 'Hello');
+console.log(ttlRes1); // OK
+
+const ttlRes2 = await client.expire('mykey', 10);
+console.log(ttlRes2); // true
+
+const ttlRes3 = await client.ttl('mykey');
+console.log(ttlRes3); // 10
+// REMOVE_START
+assert.equal(ttlRes3, 10);
+await client.del('mykey');
+// REMOVE_END
+// STEP_END
+
+// STEP_START scan1
+const scan1Res1 = await client.sAdd('myset', ['1', '2', '3', 'foo', 'foobar', 'feelsgood']);
+console.log(scan1Res1); // 6
+
+const scan1Res2 = [];
+for await (const value of client.sScanIterator('myset', { MATCH: 'f*' })) {
+    scan1Res2.push(value);
+}
+console.log(scan1Res2); // ['foo', 'foobar', 'feelsgood']
+// REMOVE_START
+console.assert(scan1Res2.sort().toString() === ['foo', 'foobar', 'feelsgood'].sort().toString());
+await client.del('myset');
+// REMOVE_END
+// STEP_END
+
+// STEP_START scan2
+// REMOVE_START
+for (let i = 1; i <= 1000; i++) {
+    await client.set(`key:${i}`, i);
+}
+// REMOVE_END
+let cursor = '0';
+let scanResult;
+
+scanResult = await client.scan(cursor, { MATCH: '*11*' });
+console.log(scanResult.cursor, scanResult.keys);
+
+scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
+console.log(scanResult.cursor, scanResult.keys);
+
+scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
+console.log(scanResult.cursor, scanResult.keys);
+
+scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
+console.log(scanResult.cursor, scanResult.keys);
+
+scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*', COUNT: 1000 });
+console.log(scanResult.cursor, scanResult.keys);
+// REMOVE_START
+console.assert(scanResult.keys.length === 18);
+cursor = '0';
+const prefix = 'key:*';
+while (cursor !== 0) {
+    scanResult = await client.scan(cursor, { MATCH: prefix, COUNT: 1000 });
+    console.log(scanResult.cursor, scanResult.keys);
+    cursor = scanResult.cursor;
+    const keys = scanResult.keys;
+    if (keys.length) {
+        await client.del(keys);
+    }
+}
+// REMOVE_END
+// STEP_END
+
+// STEP_START scan3
+const scan3Res1 = await client.geoAdd('geokey', { longitude: 0, latitude: 0, member: 'value' });
+console.log(scan3Res1); // 1
+
+const scan3Res2 = await client.zAdd('zkey', [{ score: 1000, value: 'value' }]);
+console.log(scan3Res2); // 1
+
+const scan3Res3 = await client.type('geokey');
+console.log(scan3Res3); // zset
+// REMOVE_START
+console.assert(scan3Res3 === 'zset');
+// REMOVE_END
+
+const scan3Res4 = await client.type('zkey');
+console.log(scan3Res4); // zset
+// REMOVE_START
+console.assert(scan3Res4 === 'zset');
+// REMOVE_END
+
+const scan3Res5 = await client.scan('0', { TYPE: 'zset' });
+console.log(scan3Res5.keys); // ['zkey', 'geokey']
+// REMOVE_START
+console.assert(scan3Res5.keys.sort().toString() === ['zkey', 'geokey'].sort().toString());
+await client.del(['geokey', 'zkey']);
+// REMOVE_END
+// STEP_END
+
+// STEP_START scan4
+const scan4Res1 = await client.hSet('myhash', { a: 1, b: 2 });
+console.log(scan4Res1); // 2
+
+const scan4Res2 = await client.hScan('myhash', 0);
+console.log(scan4Res2.tuples); // [{field: 'a', value: '1'}, {field: 'b', value: '2'}]
+// REMOVE_START
+assert.deepEqual(scan4Res2.tuples, [
+  { field: 'a', value: '1' },
+  { field: 'b', value: '2' }
+]);
+// REMOVE_END
+
+const scan4Res3 = await client.hScan('myhash', 0, { COUNT: 10 });
+const items = scan4Res3.tuples.map((item) => item.field)
+console.log(items); // ['a', 'b']
+// REMOVE_START
+assert.deepEqual(items, ['a', 'b'])
+await client.del('myhash');
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-hash.js b/doctests/cmds-hash.js
new file mode 100644
index 00000000000..d47fa1944ae
--- /dev/null
+++ b/doctests/cmds-hash.js
@@ -0,0 +1,71 @@
+// EXAMPLE: cmds_hash
+// HIDE_START
+import assert from 'node:assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START hset
+const res1 = await client.hSet('myhash', 'field1', 'Hello')
+console.log(res1) // 1
+
+const res2 = await client.hGet('myhash', 'field1')
+console.log(res2) // Hello
+
+const res3 = await client.hSet(
+  'myhash',
+  {
+    'field2': 'Hi',
+    'field3': 'World'
+  }
+)
+console.log(res3) // 2
+
+const res4 = await client.hGet('myhash', 'field2')
+console.log(res4) // Hi
+
+const res5 = await client.hGet('myhash', 'field3')
+console.log(res5) // World
+
+const res6 = await client.hGetAll('myhash')
+console.log(res6)  
+
+// REMOVE_START
+assert.equal(res1, 1);
+assert.equal(res2, 'Hello');
+assert.equal(res3, 2);
+assert.equal(res4, 'Hi');
+assert.equal(res5, 'World');
+assert.deepEqual(res6, {
+  field1: 'Hello',
+  field2: 'Hi',
+  field3: 'World'
+});
+await client.del('myhash')
+// REMOVE_END
+// STEP_END
+
+// STEP_START hget
+const res7 = await client.hSet('myhash', 'field1', 'foo')
+console.log(res7) // 1
+
+const res8 = await client.hGet('myhash', 'field1')
+console.log(res8) // foo
+
+const res9 = await client.hGet('myhash', 'field2')
+console.log(res9) // foo
+
+// REMOVE_START
+assert.equal(res7, 1);
+assert.equal(res8, 'foo');
+assert.equal(res9, null);
+await client.del('myhash')
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
+
diff --git a/doctests/cmds-sorted-set.js b/doctests/cmds-sorted-set.js
new file mode 100644
index 00000000000..ee76233cf73
--- /dev/null
+++ b/doctests/cmds-sorted-set.js
@@ -0,0 +1,115 @@
+// EXAMPLE: cmds_sorted_set
+// REMOVE_START
+import assert from "node:assert";
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+client.on('error', err => console.log('Redis Client Error', err));
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START zadd
+const val1 = await client.zAdd("myzset", [{ value: 'one', score: 1 }]);
+console.log(val1);
+// returns 1
+
+const val2 = await client.zAdd("myzset", [{ value: 'uno', score: 1 }]);
+console.log(val2);
+// returns 1
+
+const val3 = await client.zAdd("myzset", [{ value: 'two', score: 2 }, { value: 'three', score: 3 }]);
+console.log(val3);
+// returns 2
+
+const val4 = await client.zRangeWithScores("myzset", 0, -1);
+console.log(val4);
+// returns [{value: 'one', score: 1}, {value: 'uno', score: 1}, {value: 'two', score: 2}, {value: 'three', score: 3} ]
+
+// REMOVE_START
+assert.equal(val1, 1);
+assert.equal(val2, 1);
+assert.equal(val3, 2);
+assert.deepEqual(val4, [
+  { value: 'one', score: 1 },
+  { value: 'uno', score: 1 },
+  { value: 'two', score: 2 },
+  { value: 'three', score: 3 }
+]);
+await client.del('myzset');
+// REMOVE_END
+// STEP_END
+
+// STEP_START zrange1
+const val5 = await client.zAdd("myzset", [
+  { value: 'one', score: 1 },
+  { value: 'two', score: 2 },
+  { value: 'three', score: 3 }
+]);
+console.log(val5);
+// returns 3
+
+const val6 = await client.zRange('myzset', 0, -1);
+console.log(val6);
+// returns ['one', 'two', 'three']
+// REMOVE_START
+console.assert(JSON.stringify(val6) === JSON.stringify(['one', 'two', 'three']));
+// REMOVE_END
+
+const val7 = await client.zRange('myzset', 2, 3);
+console.log(val7);
+// returns ['three']
+// REMOVE_START
+console.assert(JSON.stringify(val7) === JSON.stringify(['three']));
+// REMOVE_END
+
+const val8 = await client.zRange('myzset', -2, -1);
+console.log(val8);
+// returns ['two', 'three']
+// REMOVE_START
+console.assert(JSON.stringify(val8) === JSON.stringify(['two', 'three']));
+await client.del('myzset');
+// REMOVE_END
+// STEP_END
+
+// STEP_START zrange2
+const val9 = await client.zAdd("myzset", [
+  { value: 'one', score: 1 },
+  { value: 'two', score: 2 },
+  { value: 'three', score: 3 }
+]);
+console.log(val9);
+// returns 3
+
+const val10 = await client.zRangeWithScores('myzset', 0, 1);
+console.log(val10);
+// returns [{value: 'one', score: 1}, {value: 'two', score: 2}]
+// REMOVE_START
+console.assert(JSON.stringify(val10) === JSON.stringify([{value: 'one', score: 1}, {value: 'two', score: 2}]));
+await client.del('myzset');
+// REMOVE_END
+// STEP_END
+
+// STEP_START zrange3
+const val11 = await client.zAdd("myzset", [
+  { value: 'one', score: 1 },
+  { value: 'two', score: 2 },
+  { value: 'three', score: 3 }
+]);
+console.log(val11);
+// returns 3
+
+const val12 = await client.zRange('myzset', 2, 3, { BY: 'SCORE', LIMIT: { offset: 1, count: 1 } });
+console.log(val12);
+// >>> ['three']
+// REMOVE_START
+console.assert(JSON.stringify(val12) === JSON.stringify(['three']));
+await client.del('myzset');
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-string.js b/doctests/cmds-string.js
new file mode 100644
index 00000000000..95868711616
--- /dev/null
+++ b/doctests/cmds-string.js
@@ -0,0 +1,27 @@
+// EXAMPLE: cmds_string
+// REMOVE_START
+import assert from "node:assert";
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+client.on('error', err => console.log('Redis Client Error', err));
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START incr
+await client.set("mykey", "10");
+const value1 = await client.incr("mykey");
+console.log(value1);
+// returns 11
+// REMOVE_START
+assert.equal(value1, 11);
+await client.del('mykey');
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END

From 49fdb79897e8732f45b5da6951c26728277ae238 Mon Sep 17 00:00:00 2001
From: Shaya Potter <spotter@gmail.com>
Date: Sun, 29 Sep 2024 13:19:06 +0300
Subject: [PATCH 15/20] Update doctest client with latest v4 release (#2844)

---
 .github/ISSUE_TEMPLATE/BUG-REPORT.yml         |    39 +
 .github/ISSUE_TEMPLATE/DOCUMENTATION.yml      |    11 +
 .github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml    |    19 +
 .github/ISSUE_TEMPLATE/bug-report.md          |    15 -
 .github/ISSUE_TEMPLATE/feature-request.md     |     7 -
 .github/release-drafter/bloom-config.yml      |    50 +
 .github/release-drafter/graph-config.yml      |    49 +
 .../json-config.yml}                          |    13 +-
 .github/release-drafter/search-config.yml     |    50 +
 .../release-drafter/time-series-config.yml    |    49 +
 .github/workflows/codeql.yml                  |     2 +-
 .github/workflows/documentation.yml           |     4 +-
 .github/workflows/release-drafter-bloom.yml   |    24 +
 .github/workflows/release-drafter-graph.yml   |    24 +
 ...e-drafter.yml => release-drafter-json.yml} |     7 +-
 .github/workflows/release-drafter-search.yml  |    24 +
 .../workflows/release-drafter-time-series.yml |    24 +
 .github/workflows/tests.yml                   |     8 +-
 LICENSE                                       |    35 +-
 README.md                                     |    82 +-
 benchmark/package-lock.json                   |   383 +-
 benchmark/package.json                        |     4 +-
 docs/FAQ.md                                   |     2 +-
 docs/client-configuration.md                  |    26 +-
 docs/clustering.md                            |    53 +-
 docs/pub-sub.md                               |    88 +
 examples/README.md                            |     3 +-
 examples/dump-and-restore.js                  |    22 +
 examples/search-hashes.js                     |     2 +-
 examples/search-json.js                       |     2 +-
 package-lock.json                             | 10901 ++++------------
 package.json                                  |    27 +-
 packages/bloom/package.json                   |    24 +-
 packages/client/index.ts                      |     6 +-
 packages/client/lib/client/RESP2/decoder.ts   |    15 +-
 packages/client/lib/client/commands-queue.ts  |   319 +-
 packages/client/lib/client/commands.ts        |    21 +
 packages/client/lib/client/index.spec.ts      |   203 +-
 packages/client/lib/client/index.ts           |   321 +-
 packages/client/lib/client/multi-command.ts   |     9 +-
 packages/client/lib/client/pub-sub.spec.ts    |   151 +
 packages/client/lib/client/pub-sub.ts         |   408 +
 packages/client/lib/client/socket.spec.ts     |    33 +-
 packages/client/lib/client/socket.ts          |    75 +-
 packages/client/lib/cluster/cluster-slots.ts  |   660 +-
 packages/client/lib/cluster/commands.ts       |    36 +
 packages/client/lib/cluster/index.spec.ts     |   348 +-
 packages/client/lib/cluster/index.ts          |   199 +-
 packages/client/lib/cluster/multi-command.ts  |     5 +-
 packages/client/lib/commander.ts              |     2 +
 .../client/lib/commands/ACL_GETUSER.spec.ts   |    34 +-
 .../client/lib/commands/CLIENT_INFO.spec.ts   |    68 +-
 packages/client/lib/commands/CLIENT_INFO.ts   |   123 +-
 .../client/lib/commands/CLIENT_KILL.spec.ts   |    10 +
 packages/client/lib/commands/CLIENT_KILL.ts   |    13 +-
 .../client/lib/commands/CLIENT_LIST.spec.ts   |    78 +
 packages/client/lib/commands/CLIENT_LIST.ts   |    43 +
 .../lib/commands/CLIENT_NO-TOUCH.spec.ts      |    30 +
 .../client/lib/commands/CLIENT_NO-TOUCH.ts    |    11 +
 .../lib/commands/CLUSTER_BUMPEPOCH.spec.ts    |     3 +-
 .../CLUSTER_COUNT-FAILURE-REPORTS.spec.ts     |     2 +-
 .../commands/CLUSTER_COUNTKEYSINSLOT.spec.ts  |     3 +-
 .../commands/CLUSTER_GETKEYSINSLOT.spec.ts    |     3 +-
 .../client/lib/commands/CLUSTER_INFO.spec.ts  |     3 +-
 .../lib/commands/CLUSTER_KEYSLOT.spec.ts      |     3 +-
 .../client/lib/commands/CLUSTER_LINKS.spec.ts |     3 +-
 .../client/lib/commands/CLUSTER_MYID.spec.ts  |     6 +-
 .../lib/commands/CLUSTER_MYSHARDID.spec.ts    |    22 +
 .../client/lib/commands/CLUSTER_MYSHARDID.ts  |     7 +
 .../lib/commands/CLUSTER_SAVECONFIG.spec.ts   |     3 +-
 packages/client/lib/commands/CLUSTER_SLOTS.ts |     2 +-
 packages/client/lib/commands/HEXPIRE.spec.ts  |    40 +
 packages/client/lib/commands/HEXPIRE.ts       |    44 +
 .../client/lib/commands/HEXPIREAT.spec.ts     |    49 +
 packages/client/lib/commands/HEXPIREAT.ts     |    28 +
 .../client/lib/commands/HEXPIRETIME.spec.ts   |    32 +
 packages/client/lib/commands/HEXPIRETIME.ts   |    21 +
 packages/client/lib/commands/HPERSIST.spec.ts |    33 +
 packages/client/lib/commands/HPERSIST.ts      |    10 +
 packages/client/lib/commands/HPEXPIRE.spec.ts |    40 +
 packages/client/lib/commands/HPEXPIRE.ts      |    24 +
 .../client/lib/commands/HPEXPIREAT.spec.ts    |    48 +
 packages/client/lib/commands/HPEXPIREAT.ts    |    25 +
 .../client/lib/commands/HPEXPIRETIME.spec.ts  |    33 +
 packages/client/lib/commands/HPEXPIRETIME.ts  |    11 +
 packages/client/lib/commands/HPTTL.spec.ts    |    33 +
 packages/client/lib/commands/HPTTL.ts         |    11 +
 packages/client/lib/commands/HSCAN.spec.ts    |    13 +
 packages/client/lib/commands/HSCAN.ts         |     2 +-
 .../lib/commands/HSCAN_NOVALUES.spec.ts       |    79 +
 .../client/lib/commands/HSCAN_NOVALUES.ts     |    27 +
 packages/client/lib/commands/HTTL.spec.ts     |    34 +
 packages/client/lib/commands/HTTL.ts          |    11 +
 .../client/lib/commands/LATENCY_GRAPH.spec.ts |     6 +-
 .../lib/commands/LATENCY_HISTORY.spec.ts      |    26 +
 .../client/lib/commands/LATENCY_HISTORY.ts    |    27 +
 .../lib/commands/LATENCY_LATEST.spec.ts       |    27 +
 .../client/lib/commands/LATENCY_LATEST.ts     |    12 +
 packages/client/lib/commands/PING.spec.ts     |    20 +-
 packages/client/lib/commands/PING.ts          |    11 +-
 packages/client/lib/commands/PUBLISH.ts       |     2 +
 .../lib/commands/PUBSUB_SHARDCHANNELS.spec.ts |    30 +
 .../lib/commands/PUBSUB_SHARDCHANNELS.ts      |    13 +
 .../lib/commands/PUBSUB_SHARDNUMSUB.spec.ts   |    48 +
 .../client/lib/commands/PUBSUB_SHARDNUMSUB.ts |    24 +
 packages/client/lib/commands/RESTORE.spec.ts  |    74 +
 packages/client/lib/commands/RESTORE.ts       |    39 +
 packages/client/lib/commands/SPUBLISH.spec.ts |    21 +
 packages/client/lib/commands/SPUBLISH.ts      |    14 +
 .../client/lib/commands/XAUTOCLAIM.spec.ts    |    80 +-
 packages/client/lib/commands/XAUTOCLAIM.ts    |     6 +-
 packages/client/lib/commands/XCLAIM.spec.ts   |    32 +-
 packages/client/lib/commands/XCLAIM.ts        |     2 +-
 .../lib/commands/XINFO_CONSUMERS.spec.ts      |    10 +-
 .../client/lib/commands/XINFO_CONSUMERS.ts    |     4 +-
 .../lib/commands/generic-transformers.spec.ts |    33 +
 .../lib/commands/generic-transformers.ts      |    29 +-
 packages/client/lib/errors.ts                 |    19 +
 packages/client/lib/multi-command.spec.ts     |    21 +-
 packages/client/lib/multi-command.ts          |    34 +-
 packages/client/lib/test-utils.ts             |    30 +-
 packages/client/package.json                  |    27 +-
 packages/client/tsconfig.json                 |     3 +-
 packages/graph/lib/commands/EXPLAIN.spec.ts   |     5 +-
 packages/graph/lib/commands/EXPLAIN.ts        |     2 +-
 packages/graph/lib/commands/PROFILE.ts        |     2 +-
 packages/graph/lib/commands/RO_QUERY.spec.ts  |     5 +-
 packages/graph/lib/graph.spec.ts              |    22 +-
 packages/graph/lib/graph.ts                   |     4 +-
 packages/graph/lib/test-utils.ts              |     3 +-
 packages/graph/package.json                   |    24 +-
 packages/json/README.md                       |    24 +-
 packages/json/lib/commands/MERGE.spec.ts      |    21 +
 packages/json/lib/commands/MERGE.ts           |     9 +
 packages/json/lib/commands/MGET.ts            |     2 +
 packages/json/lib/commands/MSET.spec.ts       |    35 +
 packages/json/lib/commands/MSET.ts            |    28 +
 packages/json/lib/commands/index.ts           |     6 +
 packages/json/lib/test-utils.ts               |     2 +-
 packages/json/package.json                    |    24 +-
 packages/search/README.md                     |     8 +-
 .../search/lib/commands/AGGREGATE.spec.ts     |    14 +
 packages/search/lib/commands/AGGREGATE.ts     |    14 +-
 packages/search/lib/commands/CREATE.spec.ts   |    74 +-
 .../search/lib/commands/CURSOR_READ.spec.ts   |    21 +-
 packages/search/lib/commands/CURSOR_READ.ts   |    15 +-
 .../search/lib/commands/PROFILE_SEARCH.ts     |     6 +-
 packages/search/lib/commands/SEARCH.spec.ts   |    17 +-
 packages/search/lib/commands/SEARCH.ts        |     7 +-
 .../lib/commands/SEARCH_NOCONTENT.spec.ts     |    45 +
 .../search/lib/commands/SEARCH_NOCONTENT.ts   |    30 +
 packages/search/lib/commands/index.ts         |    95 +-
 packages/search/lib/index.ts                  |     4 +-
 packages/search/package.json                  |    24 +-
 packages/test-utils/lib/dockers.ts            |   164 +-
 packages/test-utils/lib/index.ts              |    28 +-
 packages/test-utils/package.json              |    12 +-
 packages/time-series/lib/commands/ADD.spec.ts |    16 +-
 packages/time-series/lib/commands/ADD.ts      |     9 +
 .../time-series/lib/commands/ALTER.spec.ts    |    16 +-
 packages/time-series/lib/commands/ALTER.ts    |     6 +-
 .../time-series/lib/commands/CREATE.spec.ts   |    16 +-
 packages/time-series/lib/commands/CREATE.ts   |     7 +-
 packages/time-series/lib/commands/index.ts    |    14 +-
 packages/time-series/lib/test-utils.ts        |     3 +-
 packages/time-series/package.json             |    24 +-
 tsconfig.base.json                            |     3 +-
 167 files changed, 8132 insertions(+), 9504 deletions(-)
 create mode 100644 .github/ISSUE_TEMPLATE/BUG-REPORT.yml
 create mode 100644 .github/ISSUE_TEMPLATE/DOCUMENTATION.yml
 create mode 100644 .github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml
 delete mode 100644 .github/ISSUE_TEMPLATE/bug-report.md
 delete mode 100644 .github/ISSUE_TEMPLATE/feature-request.md
 create mode 100644 .github/release-drafter/bloom-config.yml
 create mode 100644 .github/release-drafter/graph-config.yml
 rename .github/{release-drafter-config.yml => release-drafter/json-config.yml} (77%)
 create mode 100644 .github/release-drafter/search-config.yml
 create mode 100644 .github/release-drafter/time-series-config.yml
 create mode 100644 .github/workflows/release-drafter-bloom.yml
 create mode 100644 .github/workflows/release-drafter-graph.yml
 rename .github/workflows/{release-drafter.yml => release-drafter-json.yml} (80%)
 create mode 100644 .github/workflows/release-drafter-search.yml
 create mode 100644 .github/workflows/release-drafter-time-series.yml
 create mode 100644 docs/pub-sub.md
 create mode 100644 examples/dump-and-restore.js
 create mode 100644 packages/client/lib/client/pub-sub.spec.ts
 create mode 100644 packages/client/lib/client/pub-sub.ts
 create mode 100644 packages/client/lib/commands/CLIENT_LIST.spec.ts
 create mode 100644 packages/client/lib/commands/CLIENT_LIST.ts
 create mode 100644 packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
 create mode 100644 packages/client/lib/commands/CLIENT_NO-TOUCH.ts
 create mode 100644 packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
 create mode 100644 packages/client/lib/commands/CLUSTER_MYSHARDID.ts
 create mode 100644 packages/client/lib/commands/HEXPIRE.spec.ts
 create mode 100644 packages/client/lib/commands/HEXPIRE.ts
 create mode 100644 packages/client/lib/commands/HEXPIREAT.spec.ts
 create mode 100644 packages/client/lib/commands/HEXPIREAT.ts
 create mode 100644 packages/client/lib/commands/HEXPIRETIME.spec.ts
 create mode 100644 packages/client/lib/commands/HEXPIRETIME.ts
 create mode 100644 packages/client/lib/commands/HPERSIST.spec.ts
 create mode 100644 packages/client/lib/commands/HPERSIST.ts
 create mode 100644 packages/client/lib/commands/HPEXPIRE.spec.ts
 create mode 100644 packages/client/lib/commands/HPEXPIRE.ts
 create mode 100644 packages/client/lib/commands/HPEXPIREAT.spec.ts
 create mode 100644 packages/client/lib/commands/HPEXPIREAT.ts
 create mode 100644 packages/client/lib/commands/HPEXPIRETIME.spec.ts
 create mode 100644 packages/client/lib/commands/HPEXPIRETIME.ts
 create mode 100644 packages/client/lib/commands/HPTTL.spec.ts
 create mode 100644 packages/client/lib/commands/HPTTL.ts
 create mode 100644 packages/client/lib/commands/HSCAN_NOVALUES.spec.ts
 create mode 100644 packages/client/lib/commands/HSCAN_NOVALUES.ts
 create mode 100644 packages/client/lib/commands/HTTL.spec.ts
 create mode 100644 packages/client/lib/commands/HTTL.ts
 create mode 100644 packages/client/lib/commands/LATENCY_HISTORY.spec.ts
 create mode 100644 packages/client/lib/commands/LATENCY_HISTORY.ts
 create mode 100644 packages/client/lib/commands/LATENCY_LATEST.spec.ts
 create mode 100644 packages/client/lib/commands/LATENCY_LATEST.ts
 create mode 100644 packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
 create mode 100644 packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
 create mode 100644 packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
 create mode 100644 packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
 create mode 100644 packages/client/lib/commands/RESTORE.spec.ts
 create mode 100644 packages/client/lib/commands/RESTORE.ts
 create mode 100644 packages/client/lib/commands/SPUBLISH.spec.ts
 create mode 100644 packages/client/lib/commands/SPUBLISH.ts
 create mode 100644 packages/json/lib/commands/MERGE.spec.ts
 create mode 100644 packages/json/lib/commands/MERGE.ts
 create mode 100644 packages/json/lib/commands/MSET.spec.ts
 create mode 100644 packages/json/lib/commands/MSET.ts
 create mode 100644 packages/search/lib/commands/SEARCH_NOCONTENT.spec.ts
 create mode 100644 packages/search/lib/commands/SEARCH_NOCONTENT.ts

diff --git a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml
new file mode 100644
index 00000000000..2e8db33a0c6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml
@@ -0,0 +1,39 @@
+name: Bug Report
+description: Tell us about something that isn't working as expected
+labels: [Bug]
+body:
+  - type: textarea
+    id: description
+    attributes:
+      label: Description
+      description: Please enter a detailed description of your issue. If possible, please provide example code to reproduce the issue.
+    validations:
+      required: true
+  - type: input
+    id: node-js-version
+    attributes:
+      label: Node.js Version
+      description: Please enter your Node.js version `node --version`
+  - type: input
+    id: redis-server-version
+    attributes:
+      label: Redis Server Version
+      description: Please enter your Redis server version ([`INFO server`](https://redis.io/commands/info/))
+  - type: input
+    id: node-redis-version
+    attributes:
+      label: Node Redis Version
+      description: Please enter your node redis version `npm ls redis`
+  - type: input
+    id: platform
+    attributes:
+      label: Platform
+      description: Please enter the platform you are using e.g. Linux, macOS, Windows
+  - type: textarea
+    id: logs
+    attributes:
+      label: Logs
+      description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
+      render: bash
+    validations:
+      required: false
diff --git a/.github/ISSUE_TEMPLATE/DOCUMENTATION.yml b/.github/ISSUE_TEMPLATE/DOCUMENTATION.yml
new file mode 100644
index 00000000000..b5ece5aeca2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/DOCUMENTATION.yml
@@ -0,0 +1,11 @@
+name: Documentation
+description: Any questions or issues relating to the project documentation.
+labels: [Documentation]
+body:
+  - type: textarea
+    id: description
+    attributes:
+      label: Description
+      description: Ask your question or describe your issue here.
+    validations:
+      required: true
diff --git a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml
new file mode 100644
index 00000000000..ae10cbd7b7a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml
@@ -0,0 +1,19 @@
+name: Feature Request
+description: Suggest an idea for this project
+labels: [Feature]
+body:
+  - type: textarea
+    id: motivation
+    attributes:
+      label: Motivation
+      description: How would Node Redis users benefit from this feature?
+    validations:
+      required: true
+  - type: textarea
+    id: basic-code-example
+    attributes:
+      label: Basic Code Example
+      description: Provide examples of how you imagine the API for this feature might be implemented. This will be automatically formatted into code, so no need for backticks.
+      render: JavaScript
+    validations:
+      required: false
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
deleted file mode 100644
index a7fae8eeb11..00000000000
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: Bug
-assignees: ''
----
-
-<!-- Describe your issue here -->
-
-**Environment:**
- - **Node.js Version**: <!-- e.g. "node --version" -->
- - **Redis Server Version**: <!-- e.g. "redis-server --version" -->
- - **Node Redis Version**: <!-- e.g. "npm ls redis" -->
- - **Platform**: <!-- e.g. Ubuntu 20.04.3, Windows 10, Mac OS 11.6 -->
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
deleted file mode 100644
index 0645d6e1a83..00000000000
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: Bug
-assignees: ''
----
diff --git a/.github/release-drafter/bloom-config.yml b/.github/release-drafter/bloom-config.yml
new file mode 100644
index 00000000000..7734330b95c
--- /dev/null
+++ b/.github/release-drafter/bloom-config.yml
@@ -0,0 +1,50 @@
+name-template: 'bloom@$NEXT_PATCH_VERSION'
+tag-template: 'bloom@$NEXT_PATCH_VERSION'
+autolabeler:
+  - label: 'chore'
+    files:
+      - '*.md'
+      - '.github/*'
+  - label: 'bug'
+    branch:
+      - '/bug-.+'
+  - label: 'chore'
+    branch:
+      - '/chore-.+'
+  - label: 'feature'
+    branch:
+      - '/feature-.+'
+categories:
+  - title: 'Breaking Changes'
+    labels:
+      - 'breakingchange'
+  - title: '🚀 New Features'
+    labels:
+      - 'feature'
+      - 'enhancement'
+  - title: '🐛 Bug Fixes'
+    labels:
+      - 'fix'
+      - 'bugfix'
+      - 'bug'
+  - title: '🧰 Maintenance'
+    label:
+      - 'chore'
+      - 'maintenance'
+      - 'documentation'
+      - 'docs'
+
+change-template: '- $TITLE (#$NUMBER)'
+include-paths:
+  - 'packages/bloom'
+exclude-labels:
+  - 'skip-changelog'
+template: |
+  ## Changes
+
+  $CHANGES
+
+  ## Contributors
+  We'd like to thank all the contributors who worked on this release!
+
+  $CONTRIBUTORS
diff --git a/.github/release-drafter/graph-config.yml b/.github/release-drafter/graph-config.yml
new file mode 100644
index 00000000000..88d76b78b55
--- /dev/null
+++ b/.github/release-drafter/graph-config.yml
@@ -0,0 +1,49 @@
+name-template: 'graph@$NEXT_PATCH_VERSION'
+tag-template: 'graph@$NEXT_PATCH_VERSION'
+autolabeler:
+  - label: 'chore'
+    files:
+      - '*.md'
+      - '.github/*'
+  - label: 'bug'
+    branch:
+      - '/bug-.+'
+  - label: 'chore'
+    branch:
+      - '/chore-.+'
+  - label: 'feature'
+    branch:
+      - '/feature-.+'
+categories:
+  - title: 'Breaking Changes'
+    labels:
+      - 'breakingchange'
+  - title: '🚀 New Features'
+    labels:
+      - 'feature'
+      - 'enhancement'
+  - title: '🐛 Bug Fixes'
+    labels:
+      - 'fix'
+      - 'bugfix'
+      - 'bug'
+  - title: '🧰 Maintenance'
+    label:
+      - 'chore'
+      - 'maintenance'
+      - 'documentation'
+      - 'docs'
+change-template: '- $TITLE (#$NUMBER)'
+include-paths:
+  - 'packages/graph'
+exclude-labels:
+  - 'skip-changelog'
+template: |
+  ## Changes
+
+  $CHANGES
+
+  ## Contributors
+  We'd like to thank all the contributors who worked on this release!
+
+  $CONTRIBUTORS
diff --git a/.github/release-drafter-config.yml b/.github/release-drafter/json-config.yml
similarity index 77%
rename from .github/release-drafter-config.yml
rename to .github/release-drafter/json-config.yml
index 9a98b1c08a3..ea259fc0d2d 100644
--- a/.github/release-drafter-config.yml
+++ b/.github/release-drafter/json-config.yml
@@ -1,5 +1,5 @@
-name-template: 'Version $NEXT_PATCH_VERSION'
-tag-template: 'v$NEXT_PATCH_VERSION'
+name-template: 'json@$NEXT_PATCH_VERSION'
+tag-template: 'json@$NEXT_PATCH_VERSION'
 autolabeler:
   - label: 'chore'
     files:
@@ -28,8 +28,15 @@ categories:
       - 'bugfix'
       - 'bug'
   - title: '🧰 Maintenance'
-    label: 'chore'
+    label:
+      - 'chore'
+      - 'maintenance'
+      - 'documentation'
+      - 'docs'
+
 change-template: '- $TITLE (#$NUMBER)'
+include-paths:
+  - 'packages/json'
 exclude-labels:
   - 'skip-changelog'
 template: |
diff --git a/.github/release-drafter/search-config.yml b/.github/release-drafter/search-config.yml
new file mode 100644
index 00000000000..a78070aa59c
--- /dev/null
+++ b/.github/release-drafter/search-config.yml
@@ -0,0 +1,50 @@
+name-template: 'search@$NEXT_PATCH_VERSION'
+tag-template: 'search@$NEXT_PATCH_VERSION'
+autolabeler:
+  - label: 'chore'
+    files:
+      - '*.md'
+      - '.github/*'
+  - label: 'bug'
+    branch:
+      - '/bug-.+'
+  - label: 'chore'
+    branch:
+      - '/chore-.+'
+  - label: 'feature'
+    branch:
+      - '/feature-.+'
+categories:
+  - title: 'Breaking Changes'
+    labels:
+      - 'breakingchange'
+  - title: '🚀 New Features'
+    labels:
+      - 'feature'
+      - 'enhancement'
+  - title: '🐛 Bug Fixes'
+    labels:
+      - 'fix'
+      - 'bugfix'
+      - 'bug'
+  - title: '🧰 Maintenance'
+    label:
+      - 'chore'
+      - 'maintenance'
+      - 'documentation'
+      - 'docs'
+
+change-template: '- $TITLE (#$NUMBER)'
+include-paths:
+  - 'packages/search'
+exclude-labels:
+  - 'skip-changelog'
+template: |
+  ## Changes
+
+  $CHANGES
+
+  ## Contributors
+  We'd like to thank all the contributors who worked on this release!
+
+  $CONTRIBUTORS
diff --git a/.github/release-drafter/time-series-config.yml b/.github/release-drafter/time-series-config.yml
new file mode 100644
index 00000000000..29aee0cbc95
--- /dev/null
+++ b/.github/release-drafter/time-series-config.yml
@@ -0,0 +1,49 @@
+name-template: 'time-series@$NEXT_PATCH_VERSION'
+tag-template: 'time-series@$NEXT_PATCH_VERSION'
+autolabeler:
+  - label: 'chore'
+    files:
+      - '*.md'
+      - '.github/*'
+  - label: 'bug'
+    branch:
+      - '/bug-.+'
+  - label: 'chore'
+    branch:
+      - '/chore-.+'
+  - label: 'feature'
+    branch:
+      - '/feature-.+'
+categories:
+  - title: 'Breaking Changes'
+    labels:
+      - 'breakingchange'
+  - title: '🚀 New Features'
+    labels:
+      - 'feature'
+      - 'enhancement'
+  - title: '🐛 Bug Fixes'
+    labels:
+      - 'fix'
+      - 'bugfix'
+      - 'bug'
+  - title: '🧰 Maintenance'
+    label:
+      - 'chore'
+      - 'maintenance'
+      - 'documentation'
+      - 'docs'
+change-template: '- $TITLE (#$NUMBER)'
+include-paths:
+  - 'packages/time-series'
+exclude-labels:
+  - 'skip-changelog'
+template: |
+  ## Changes
+
+  $CHANGES
+
+  ## Contributors
+  We'd like to thank all the contributors who worked on this release!
+
+  $CONTRIBUTORS
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 3004337c278..47c82baea2c 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -38,7 +38,7 @@ jobs:
 
     steps:
     - name: Checkout repository
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
index 7b3d42bf9f4..e095faf1918 100644
--- a/.github/workflows/documentation.yml
+++ b/.github/workflows/documentation.yml
@@ -10,11 +10,11 @@ jobs:
   documentation:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2.3.4
+      - uses: actions/checkout@v4
         with:
           fetch-depth: 1
       - name: Use Node.js
-        uses: actions/setup-node@v2.3.0
+        uses: actions/setup-node@v3
       - name: Install Packages
         run: npm ci
       - name: Build tests tools
diff --git a/.github/workflows/release-drafter-bloom.yml b/.github/workflows/release-drafter-bloom.yml
new file mode 100644
index 00000000000..4ad525c058f
--- /dev/null
+++ b/.github/workflows/release-drafter-bloom.yml
@@ -0,0 +1,24 @@
+name: Release Drafter
+
+on:
+  push:
+    # branches to consider in the event; optional, defaults to all
+    branches:
+      - master
+
+jobs:
+
+  update_release_draft:
+
+    permissions:
+      contents: write
+      pull-requests: write
+    runs-on: ubuntu-latest
+    steps:
+      # Drafts your next Release notes as Pull Requests are merged into "master"
+      - uses: release-drafter/release-drafter@v5
+        with:
+          # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
+           config-name: release-drafter/bloom-config.yml
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-drafter-graph.yml b/.github/workflows/release-drafter-graph.yml
new file mode 100644
index 00000000000..4d664e5f19e
--- /dev/null
+++ b/.github/workflows/release-drafter-graph.yml
@@ -0,0 +1,24 @@
+name: Release Drafter
+
+on:
+  push:
+    # branches to consider in the event; optional, defaults to all
+    branches:
+      - master
+
+jobs:
+
+  update_release_draft:
+
+    permissions:
+      contents: write
+      pull-requests: write
+    runs-on: ubuntu-latest
+    steps:
+      # Drafts your next Release notes as Pull Requests are merged into "master"
+      - uses: release-drafter/release-drafter@v5
+        with:
+          # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
+           config-name: release-drafter/graph-config.yml
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter-json.yml
similarity index 80%
rename from .github/workflows/release-drafter.yml
rename to .github/workflows/release-drafter-json.yml
index ec2d88bf6e7..a8b3ba4d135 100644
--- a/.github/workflows/release-drafter.yml
+++ b/.github/workflows/release-drafter-json.yml
@@ -7,13 +7,18 @@ on:
       - master
 
 jobs:
+
   update_release_draft:
+
+    permissions:
+      contents: write
+      pull-requests: write
     runs-on: ubuntu-latest
     steps:
       # Drafts your next Release notes as Pull Requests are merged into "master"
       - uses: release-drafter/release-drafter@v5
         with:
           # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
-           config-name: release-drafter-config.yml
+           config-name: release-drafter/json-config.yml
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-drafter-search.yml b/.github/workflows/release-drafter-search.yml
new file mode 100644
index 00000000000..c331430353f
--- /dev/null
+++ b/.github/workflows/release-drafter-search.yml
@@ -0,0 +1,24 @@
+name: Release Drafter
+
+on:
+  push:
+    # branches to consider in the event; optional, defaults to all
+    branches:
+      - master
+
+jobs:
+
+  update_release_draft:
+
+    permissions:
+      contents: write
+      pull-requests: write
+    runs-on: ubuntu-latest
+    steps:
+      # Drafts your next Release notes as Pull Requests are merged into "master"
+      - uses: release-drafter/release-drafter@v5
+        with:
+          # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
+           config-name: release-drafter/search-config.yml
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-drafter-time-series.yml b/.github/workflows/release-drafter-time-series.yml
new file mode 100644
index 00000000000..71e44a70fd3
--- /dev/null
+++ b/.github/workflows/release-drafter-time-series.yml
@@ -0,0 +1,24 @@
+name: Release Drafter
+
+on:
+  push:
+    # branches to consider in the event; optional, defaults to all
+    branches:
+      - master
+
+jobs:
+
+  update_release_draft:
+
+    permissions:
+      contents: write
+      pull-requests: write
+    runs-on: ubuntu-latest
+    steps:
+      # Drafts your next Release notes as Pull Requests are merged into "master"
+      - uses: release-drafter/release-drafter@v5
+        with:
+          # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
+           config-name: release-drafter/time-series-config.yml
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 365e9f31d3c..84d70d6b4c0 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -16,14 +16,14 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        node-version: ['14', '16', '18', '19']
-        redis-version: ['5', '6.0', '6.2', '7.0']
+        node-version: ['18', '20']
+        redis-version: ['5', '6.0', '6.2', '7.0', '7.2', '7.4-rc2']
     steps:
-      - uses: actions/checkout@v2.3.4
+      - uses: actions/checkout@v4
         with:
           fetch-depth: 1
       - name: Use Node.js ${{ matrix.node-version }}
-        uses: actions/setup-node@v2.3.0
+        uses: actions/setup-node@v3
         with:
           node-version: ${{ matrix.node-version }}
       - name: Update npm
diff --git a/LICENSE b/LICENSE
index db86cc4de7f..8509ccd678e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,24 +1,21 @@
 MIT License
 
-Copyright (c) 2016-present Node Redis contributors.
+Copyright (c) 2022-2023, Redis, inc.
 
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 2a894f50c5e..a590372b1b1 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,19 @@
 
 node-redis is a modern, high performance [Redis](https://redis.io) client for Node.js.
 
+## How do I Redis?
+
+[Learn for free at Redis University](https://university.redis.com/)
+
+[Build faster with the Redis Launchpad](https://launchpad.redis.com/)
+
+[Try the Redis Cloud](https://redis.com/try-free/)
+
+[Dive in developer tutorials](https://developer.redis.com/)
+
+[Join the Redis community](https://redis.com/community/)
+
+[Work at Redis](https://redis.com/company/careers/jobs/)
 
 ## Packages
 
@@ -51,11 +64,9 @@ Looking for a high-level library to handle object mapping? See [redis-om-node](h
 ```typescript
 import { createClient } from 'redis';
 
-const client = createClient();
-
-client.on('error', (err) => console.log('Redis Client Error', err));
-
-await client.connect();
+const client = await createClient()
+  .on('error', err => console.log('Redis Client Error', err))
+  .connect();
 
 await client.set('key', 'value');
 const value = await client.get('key');
@@ -166,47 +177,7 @@ To learn more about isolated execution, check out the [guide](./docs/isolated-ex
 
 ### Pub/Sub
 
-Subscribing to a channel requires a dedicated stand-alone connection. You can easily get one by `.duplicate()`ing an existing Redis connection.
-
-```typescript
-const subscriber = client.duplicate();
-
-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.pSubscribe('channe*', (message, channel) => {
-  console.log(message, channel); // 'message', 'channel'
-});
-
-await subscriber.unsubscribe('channel');
-
-await subscriber.pUnsubscribe('channe*');
-```
-
-Publish a message on a channel:
-
-```typescript
-await publisher.publish('channel', 'message');
-```
-
-There is support for buffers as well:
-
-```typescript
-await subscriber.subscribe('channel', (message) => {
-  console.log(message); // <Buffer 6d 65 73 73 61 67 65>
-}, true);
-
-await subscriber.pSubscribe('channe*', (message, channel) => {
-  console.log(message, channel); // <Buffer 6d 65 73 73 61 67 65>, <Buffer 63 68 61 6e 6e 65 6c>
-}, true);
-```
+See the [Pub/Sub overview](./docs/pub-sub.md).
 
 ### Scan Iterator
 
@@ -373,15 +344,18 @@ Check out the [Clustering Guide](./docs/clustering.md) when using Node Redis to
 
 The Node Redis client class is an Nodejs EventEmitter and it emits an event each time the network status changes:
 
-| Event name     | Scenes                                                                                                            | Arguments to be passed to the listener                                                                                                         |
-|----------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|
-| `connect`      | The client is initiating a connection to the server.                                                              | _No argument_                                                                                                                                  |
-| `ready`        | The client successfully initiated the connection to the server.                                                   | _No argument_                                                                                                                                  |
-| `end`          | The client disconnected the connection to the server via `.quit()` or `.disconnect()`.                            | _No argument_                                                                                                                                  |
-| `error`        | When a network error has occurred, such as unable to connect to the server or the connection closed unexpectedly. | 1 argument: The error object, such as `SocketClosedUnexpectedlyError: Socket closed unexpectedly` or `Error: connect ECONNREFUSED [IP]:[PORT]` |
-| `reconnecting` | The client is trying to reconnect to the server.                                                                  | _No argument_                                                                                                                                  |
+| Name                    | When                                                                               | Listener arguments                                         |
+|-------------------------|------------------------------------------------------------------------------------|------------------------------------------------------------|
+| `connect`               | Initiating a connection to the server                                              | *No arguments*                                             |
+| `ready`                 | Client is ready to use                                                             | *No arguments*                                             |
+| `end`                   | Connection has been closed (via `.quit()` or `.disconnect()`)                      | *No arguments*                                             |
+| `error`                 | An error has occurred—usually a network issue such as "Socket closed unexpectedly" | `(error: Error)`                                           |
+| `reconnecting`          | Client is trying to reconnect to the server                                        | *No arguments*                                             |
+| `sharded-channel-moved` | See [here](./docs/pub-sub.md#sharded-channel-moved-event)                          | See  [here](./docs/pub-sub.md#sharded-channel-moved-event) |
+
+> :warning: You **MUST** listen to `error` events. If a client doesn't have at least one `error` listener registered and an `error` occurs, that error will be thrown and the Node.js process will exit. See the [`EventEmitter` docs](https://nodejs.org/api/events.html#events_error_events) for more details.
 
-The client will not emit [any other events](./docs/v3-to-v4.md#all-the-removed-events) beyond those listed above.
+> The client will not emit [any other events](./docs/v3-to-v4.md#all-the-removed-events) beyond those listed above.
 
 ## Supported Redis versions
 
diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json
index 23781c0085c..441c0b07b67 100644
--- a/benchmark/package-lock.json
+++ b/benchmark/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/client-benchmark",
-  "lockfileVersion": 2,
+  "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
@@ -8,39 +8,9 @@
       "dependencies": {
         "@redis/client": "../packages/client",
         "hdr-histogram-js": "3.0.0",
-        "ioredis": "5.2.2",
+        "ioredis": "5.3.2",
         "redis-v3": "npm:redis@3.1.2",
-        "yargs": "17.5.1"
-      }
-    },
-    "../packages/client": {
-      "name": "@redis/client",
-      "version": "1.2.0",
-      "license": "MIT",
-      "dependencies": {
-        "cluster-key-slot": "1.1.0",
-        "generic-pool": "3.8.2",
-        "yallist": "4.0.0"
-      },
-      "devDependencies": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.7.10",
-        "@types/sinon": "^10.0.13",
-        "@types/yallist": "^4.0.1",
-        "@typescript-eslint/eslint-plugin": "^5.34.0",
-        "@typescript-eslint/parser": "^5.34.0",
-        "eslint": "^8.22.0",
-        "nyc": "^15.1.0",
-        "release-it": "^15.3.0",
-        "sinon": "^14.0.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.10",
-        "typescript": "^4.7.4"
-      },
-      "engines": {
-        "node": ">=14"
+        "yargs": "17.7.2"
       }
     },
     "node_modules/@assemblyscript/loader": {
@@ -49,13 +19,22 @@
       "integrity": "sha512-ulkCYfFbYj01ie1MDOyxv2F6SpRN1TOj7fQxbP07D6HmeR+gr2JLSmINKjga2emB+b1L2KGrFKBTc+e00p54nw=="
     },
     "node_modules/@ioredis/commands": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.1.1.tgz",
-      "integrity": "sha512-fsR4P/ROllzf/7lXYyElUJCheWdTJVJvOTps8v9IWKFATxR61ANOlnoPqhH099xYLrJGpc2ZQ28B3rMeUt5VQg=="
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
+      "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
     },
     "node_modules/@redis/client": {
-      "resolved": "../packages/client",
-      "link": true
+      "version": "1.5.7",
+      "resolved": "file:../packages/client",
+      "license": "MIT",
+      "dependencies": {
+        "cluster-key-slot": "1.1.2",
+        "generic-pool": "3.9.0",
+        "yallist": "4.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
     },
     "node_modules/ansi-regex": {
       "version": "5.0.1",
@@ -99,19 +78,22 @@
       ]
     },
     "node_modules/cliui": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
-      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
       "dependencies": {
         "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.0",
+        "strip-ansi": "^6.0.1",
         "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
       }
     },
     "node_modules/cluster-key-slot": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
-      "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
+      "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -149,9 +131,9 @@
       }
     },
     "node_modules/denque": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
-      "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+      "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
       "engines": {
         "node": ">=0.10"
       }
@@ -169,6 +151,14 @@
         "node": ">=6"
       }
     },
+    "node_modules/generic-pool": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
+      "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
     "node_modules/get-caller-file": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -191,14 +181,14 @@
       }
     },
     "node_modules/ioredis": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.2.tgz",
-      "integrity": "sha512-wryKc1ur8PcCmNwfcGkw5evouzpbDXxxkMkzPK8wl4xQfQf7lHe11Jotell5ikMVAtikXJEu/OJVaoV51BggRQ==",
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
+      "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
       "dependencies": {
         "@ioredis/commands": "^1.1.1",
         "cluster-key-slot": "^1.1.0",
         "debug": "^4.3.4",
-        "denque": "^2.0.1",
+        "denque": "^2.1.0",
         "lodash.defaults": "^4.2.0",
         "lodash.isarguments": "^3.1.0",
         "redis-errors": "^1.2.0",
@@ -224,12 +214,12 @@
     "node_modules/lodash.defaults": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
-      "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
+      "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
     },
     "node_modules/lodash.isarguments": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
-      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
+      "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
     },
     "node_modules/ms": {
       "version": "2.1.2",
@@ -249,7 +239,7 @@
     "node_modules/redis-errors": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
-      "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=",
+      "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
       "engines": {
         "node": ">=4"
       }
@@ -257,7 +247,7 @@
     "node_modules/redis-parser": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
-      "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=",
+      "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
       "dependencies": {
         "redis-errors": "^1.0.0"
       },
@@ -295,7 +285,7 @@
     "node_modules/require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -353,288 +343,35 @@
         "node": ">=10"
       }
     },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    },
     "node_modules/yargs": {
-      "version": "17.5.1",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
-      "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==",
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
       "dependencies": {
-        "cliui": "^7.0.2",
+        "cliui": "^8.0.1",
         "escalade": "^3.1.1",
         "get-caller-file": "^2.0.5",
         "require-directory": "^2.1.1",
         "string-width": "^4.2.3",
         "y18n": "^5.0.5",
-        "yargs-parser": "^21.0.0"
+        "yargs-parser": "^21.1.1"
       },
       "engines": {
         "node": ">=12"
       }
     },
     "node_modules/yargs-parser": {
-      "version": "21.0.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
-      "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==",
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
       "engines": {
         "node": ">=12"
       }
     }
-  },
-  "dependencies": {
-    "@assemblyscript/loader": {
-      "version": "0.19.23",
-      "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.19.23.tgz",
-      "integrity": "sha512-ulkCYfFbYj01ie1MDOyxv2F6SpRN1TOj7fQxbP07D6HmeR+gr2JLSmINKjga2emB+b1L2KGrFKBTc+e00p54nw=="
-    },
-    "@ioredis/commands": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.1.1.tgz",
-      "integrity": "sha512-fsR4P/ROllzf/7lXYyElUJCheWdTJVJvOTps8v9IWKFATxR61ANOlnoPqhH099xYLrJGpc2ZQ28B3rMeUt5VQg=="
-    },
-    "@redis/client": {
-      "version": "file:../packages/client",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.7.10",
-        "@types/sinon": "^10.0.13",
-        "@types/yallist": "^4.0.1",
-        "@typescript-eslint/eslint-plugin": "^5.34.0",
-        "@typescript-eslint/parser": "^5.34.0",
-        "cluster-key-slot": "1.1.0",
-        "eslint": "^8.22.0",
-        "generic-pool": "3.8.2",
-        "nyc": "^15.1.0",
-        "release-it": "^15.3.0",
-        "sinon": "^14.0.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.10",
-        "typescript": "^4.7.4",
-        "yallist": "4.0.0"
-      }
-    },
-    "ansi-regex": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
-    },
-    "ansi-styles": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "requires": {
-        "color-convert": "^2.0.1"
-      }
-    },
-    "base64-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
-    },
-    "cliui": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
-      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
-      "requires": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.0",
-        "wrap-ansi": "^7.0.0"
-      }
-    },
-    "cluster-key-slot": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
-      "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw=="
-    },
-    "color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "requires": {
-        "color-name": "~1.1.4"
-      }
-    },
-    "color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
-    },
-    "debug": {
-      "version": "4.3.4",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-      "requires": {
-        "ms": "2.1.2"
-      }
-    },
-    "denque": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
-      "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ=="
-    },
-    "emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
-    },
-    "escalade": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
-    },
-    "get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
-    },
-    "hdr-histogram-js": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-3.0.0.tgz",
-      "integrity": "sha512-/EpvQI2/Z98mNFYEnlqJ8Ogful8OpArLG/6Tf2bPnkutBVLIeMVNHjk1ZDfshF2BUweipzbk+dB1hgSB7SIakw==",
-      "requires": {
-        "@assemblyscript/loader": "^0.19.21",
-        "base64-js": "^1.2.0",
-        "pako": "^1.0.3"
-      }
-    },
-    "ioredis": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.2.tgz",
-      "integrity": "sha512-wryKc1ur8PcCmNwfcGkw5evouzpbDXxxkMkzPK8wl4xQfQf7lHe11Jotell5ikMVAtikXJEu/OJVaoV51BggRQ==",
-      "requires": {
-        "@ioredis/commands": "^1.1.1",
-        "cluster-key-slot": "^1.1.0",
-        "debug": "^4.3.4",
-        "denque": "^2.0.1",
-        "lodash.defaults": "^4.2.0",
-        "lodash.isarguments": "^3.1.0",
-        "redis-errors": "^1.2.0",
-        "redis-parser": "^3.0.0",
-        "standard-as-callback": "^2.1.0"
-      }
-    },
-    "is-fullwidth-code-point": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
-    },
-    "lodash.defaults": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
-      "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
-    },
-    "lodash.isarguments": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
-      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
-    },
-    "ms": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-    },
-    "pako": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
-      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
-    },
-    "redis-commands": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
-      "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
-    },
-    "redis-errors": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
-      "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60="
-    },
-    "redis-parser": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
-      "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=",
-      "requires": {
-        "redis-errors": "^1.0.0"
-      }
-    },
-    "redis-v3": {
-      "version": "npm:redis@3.1.2",
-      "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz",
-      "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==",
-      "requires": {
-        "denque": "^1.5.0",
-        "redis-commands": "^1.7.0",
-        "redis-errors": "^1.2.0",
-        "redis-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "denque": {
-          "version": "1.5.1",
-          "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
-          "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
-        }
-      }
-    },
-    "require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
-    },
-    "standard-as-callback": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
-      "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
-    },
-    "string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "requires": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      }
-    },
-    "strip-ansi": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "requires": {
-        "ansi-regex": "^5.0.1"
-      }
-    },
-    "wrap-ansi": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-      "requires": {
-        "ansi-styles": "^4.0.0",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0"
-      }
-    },
-    "y18n": {
-      "version": "5.0.8",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
-    },
-    "yargs": {
-      "version": "17.5.1",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
-      "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==",
-      "requires": {
-        "cliui": "^7.0.2",
-        "escalade": "^3.1.1",
-        "get-caller-file": "^2.0.5",
-        "require-directory": "^2.1.1",
-        "string-width": "^4.2.3",
-        "y18n": "^5.0.5",
-        "yargs-parser": "^21.0.0"
-      }
-    },
-    "yargs-parser": {
-      "version": "21.0.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
-      "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg=="
-    }
   }
 }
diff --git a/benchmark/package.json b/benchmark/package.json
index d5eac40b1ab..f46f0e00b22 100644
--- a/benchmark/package.json
+++ b/benchmark/package.json
@@ -9,8 +9,8 @@
   "dependencies": {
     "@redis/client": "../packages/client",
     "hdr-histogram-js": "3.0.0",
-    "ioredis": "5.2.2",
+    "ioredis": "5.3.2",
     "redis-v3": "npm:redis@3.1.2",
-    "yargs": "17.5.1"
+    "yargs": "17.7.2"
   }
 }
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 4b7710df3fc..5774213da5b 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -10,7 +10,7 @@ If don't want to queue commands in memory until a new socket is established, set
 
 ## How are commands batched?
 
-Commands are pipelined using [`queueMicrotask`](https://nodejs.org/api/globals.html#globals_queuemicrotask_callback).
+Commands are pipelined using [`setImmediate`](https://nodejs.org/api/timers.html#setimmediatecallback-args).
 
 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 a67cef462ac..1854f07158a 100644
--- a/docs/client-configuration.md
+++ b/docs/client-configuration.md
@@ -15,7 +15,7 @@
 | 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                                                                                                                                                                                                    |
-| name                     |                                          | Connection name ([see `CLIENT SETNAME`](https://redis.io/commands/client-setname))                                                                                                                                                                  |
+| name                     |                                          | Client name ([see `CLIENT SETNAME`](https://redis.io/commands/client-setname))                                                                                                                                                                      |
 | database                 |                                          | Redis database number (see [`SELECT`](https://redis.io/commands/select) command)                                                                                                                                                                    |
 | modules                  |                                          | Included [Redis Modules](../README.md#packages)                                                                                                                                                                                                     |
 | scripts                  |                                          | Script definitions (see [Lua Scripts](../README.md#lua-scripts))                                                                                                                                                                                    |
@@ -25,16 +25,24 @@
 | 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)                                                                                                                                                                                         |
-| pingInterval             |                                          | Send `PING` command at interval (in ms). Useful with "[Azure Cache for Redis](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-best-practices-connection#idle-timeout)"                                                          |
+| pingInterval             |                                          | Send `PING` command at interval (in ms). Useful with ["Azure Cache for Redis"](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-best-practices-connection#idle-timeout)                                                          |
 
 ## Reconnect Strategy
 
-You can implement a custom reconnect strategy as a function:
+When the socket closes unexpectedly (without calling `.quit()`/`.disconnect()`), the client uses `reconnectStrategy` to decide what to do. The following values are supported:
+1. `false` -> do not reconnect, close the client and flush the command queue.
+2. `number` -> wait for `X` milliseconds before reconnecting.
+3. `(retries: number, cause: Error) => false | number | Error` -> `number` is the same as configuring a `number` directly, `Error` is the same as `false`, but with a custom error.
 
-- Receives the number of retries attempted so far.
-- Returns `number | Error`:
-    - `number`: wait time in milliseconds prior to attempting a reconnect.
-    - `Error`: closes the client and flushes internal command queues.
+By default the strategy is `Math.min(retries * 50, 500)`, but it can be overwritten like so:
+
+```javascript
+createClient({
+  socket: {
+    reconnectStrategy: retries => Math.min(retries * 50, 1000)
+  }
+});
+```
 
 ## TLS
 
@@ -44,7 +52,7 @@ To enable TLS, set `socket.tls` to `true`. Below are some basic examples.
 
 ### Create a SSL client
 
-```typescript
+```javascript
 createClient({
   socket: {
     tls: true,
@@ -56,7 +64,7 @@ createClient({
 
 ### Create a SSL client using a self-signed certificate
 
-```typescript
+```javascript
 createClient({
   socket: {
     tls: true,
diff --git a/docs/clustering.md b/docs/clustering.md
index 26acfa0a791..28ea0e2964c 100644
--- a/docs/clustering.md
+++ b/docs/clustering.md
@@ -35,35 +35,70 @@ const value = await cluster.get('key');
 | rootNodes              |         | An array of root nodes that are part of the cluster, which will be used to get the cluster topology. Each element in the array is a client configuration object. There is no need to specify every node in the cluster, 3 should be enough to reliably connect and obtain the cluster configuration from the server |
 | defaults               |         | The default configuration values for every client in the cluster.  Use this for example when specifying an ACL user to connect with                                                                                                                                                                                 |
 | useReplicas            | `false` | When `true`, distribute load by executing readonly commands (such as `GET`, `GEOSEARCH`, etc.) across all cluster nodes. When `false`, only use master nodes                                                                                                                                                        |
+| minimizeConnections    | `false` | When `true`, `.connect()` will only discover the cluster topology, without actually connecting to all the nodes. Useful for short-term or Pub/Sub-only connections.                                                                                                                                                 |
 | maxCommandRedirections | `16`    | The maximum number of times a command will be redirected due to `MOVED` or `ASK` errors                                                                                                                                                                                                                             |
 | nodeAddressMap         |         | Defines the [node address mapping](#node-address-map)                                                                                                                                                                                                                                                               |
 | modules                |         | Included [Redis Modules](../README.md#packages)                                                                                                                                                                                                                                                                     |
 | scripts                |         | Script definitions (see [Lua Scripts](../README.md#lua-scripts))                                                                                                                                                                                                                                                    |
 | functions              |         | Function definitions (see [Functions](../README.md#functions))                                                                                                                                                                                                                                                      |
+## Auth with password and username
 
-## Node Address Map
-
-A node address map is required when a Redis cluster is configured with addresses that are inaccessible by the machine running the Redis client.
-This is a mapping of addresses and ports, with the values being the accessible address/port combination. Example:
-
+Specifying the password in the URL or a root node will only affect the connection to that specific node. In case you want to set the password for all the connections being created from a cluster instance, use the `defaults` option.
 ```javascript
 createCluster({
   rootNodes: [{
-    url: 'external-host-1.io:30001'
+    url: 'redis://10.0.0.1:30001'
   }, {
-    url: 'external-host-2.io:30002'
+    url: 'redis://10.0.0.2:30002'
   }],
+  defaults: {
+    username: 'username',
+    password: 'password'
+  }
+});
+```
+
+## Node Address Map
+
+A mapping between the addresses in the cluster (see `CLUSTER SHARDS`) and the addresses the client should connect to.
+Useful when the cluster is running on a different network to the client.
+
+```javascript
+const rootNodes = [{
+  url: 'external-host-1.io:30001'
+}, {
+  url: 'external-host-2.io:30002'
+}];
+
+// Use either a static mapping:
+createCluster({
+  rootNodes,
   nodeAddressMap: {
     '10.0.0.1:30001': {
-      host: 'external-host-1.io',
+      host: 'external-host.io',
       port: 30001
     },
     '10.0.0.2:30002': {
-      host: 'external-host-2.io',
+      host: 'external-host.io',
       port: 30002
     }
   }
 });
+
+// or create the mapping dynamically, as a function:
+createCluster({
+  rootNodes,
+  nodeAddressMap(address) {
+    const indexOfDash = address.lastIndexOf('-'),
+      indexOfDot = address.indexOf('.', indexOfDash),
+      indexOfColons = address.indexOf(':', indexOfDot);
+    
+    return {
+      host: `external-host-${address.substring(indexOfDash + 1, indexOfDot)}.io`,
+      port: Number(address.substring(indexOfColons + 1))
+    };
+  }
+});
 ```
 
 > This is a common problem when using ElastiCache. See [Accessing ElastiCache from outside AWS](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/accessing-elasticache.html) for more information on that.
diff --git a/docs/pub-sub.md b/docs/pub-sub.md
new file mode 100644
index 00000000000..b319925569d
--- /dev/null
+++ b/docs/pub-sub.md
@@ -0,0 +1,88 @@
+# Pub/Sub
+
+The Pub/Sub API is implemented by `RedisClient` and `RedisCluster`.
+
+## Pub/Sub with `RedisClient`
+
+Pub/Sub requires a dedicated stand-alone client. You can easily get one by `.duplicate()`ing an existing `RedisClient`:
+
+```typescript
+const subscriber = client.duplicate();
+subscriber.on('error', err => console.error(err));
+await subscriber.connect();
+```
+
+When working with a `RedisCluster`, this is handled automatically for you.
+
+### `sharded-channel-moved` event
+
+`RedisClient` emits the `sharded-channel-moved` event when the ["cluster slot"](https://redis.io/docs/reference/cluster-spec/#key-distribution-model) of a subscribed [Sharded Pub/Sub](https://redis.io/docs/manual/pubsub/#sharded-pubsub) channel has been moved to another shard.
+
+The event listener signature is as follows:
+```typescript
+(
+  channel: string,
+  listeners: {
+    buffers: Set<Listener>;
+    strings: Set<Listener>;
+  }
+)
+```
+
+## Subscribing
+
+```javascript
+const listener = (message, channel) => console.log(message, channel);
+await client.subscribe('channel', listener);
+await client.pSubscribe('channe*', listener);
+// Use sSubscribe for sharded Pub/Sub:
+await client.sSubscribe('channel', listener);
+```
+
+> ⚠️ Subscribing to the same channel more than once will create multiple listeners which will each be called when a message is recieved.
+
+## Publishing
+
+```javascript
+await client.publish('channel', 'message');
+// Use sPublish for sharded Pub/Sub:
+await client.sPublish('channel', 'message');
+```
+
+## Unsubscribing
+
+The code below unsubscribes all listeners from all channels.
+
+```javascript
+await client.unsubscribe();
+await client.pUnsubscribe();
+// Use sUnsubscribe for sharded Pub/Sub:
+await client.sUnsubscribe();
+```
+
+To unsubscribe from specific channels:
+
+```javascript
+await client.unsubscribe('channel');
+await client.unsubscribe(['1', '2']);
+```
+
+To unsubscribe a specific listener:
+
+```javascript
+await client.unsubscribe('channel', listener);
+```
+
+## Buffers
+
+Publishing and subscribing using `Buffer`s is also supported:
+
+```javascript
+await subscriber.subscribe('channel', message => {
+  console.log(message); // <Buffer 6d 65 73 73 61 67 65>
+}, true); // true = subscribe in `Buffer` mode.
+
+await subscriber.publish(Buffer.from('channel'), Buffer.from('message'));
+```
+
+> NOTE: Buffers and strings are supported both for the channel name and the message. You can mix and match these as desired.
diff --git a/examples/README.md b/examples/README.md
index 19e9df31f90..4e7655a3519 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -3,7 +3,7 @@
 This folder contains example scripts showing how to use Node Redis in different scenarios.
 
 | File Name                                | Description                                                                                                                                          |
-| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
+|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
 | `blocking-list-pop.js`                   | Block until an element is pushed to a list.                                                                                                          |
 | `bloom-filter.js`                        | Space efficient set membership checks with a [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter) using [RedisBloom](https://redisbloom.io).   |
 | `check-connection-status.js`             | Check the client's connection status.                                                                                                                |
@@ -12,6 +12,7 @@ This folder contains example scripts showing how to use Node Redis in different
 | `connect-to-cluster.js`                  | Connect to a Redis cluster.                                                                                                                          |
 | `count-min-sketch.js`                    | Estimate the frequency of a given event using the [RedisBloom](https://redisbloom.io) Count-Min Sketch.                                              |
 | `cuckoo-filter.js`                       | Space efficient set membership checks with a [Cuckoo Filter](https://en.wikipedia.org/wiki/Cuckoo_filter) using [RedisBloom](https://redisbloom.io). |
+| `dump-and-restore.js`                    | Demonstrates the use of the [`DUMP`](https://redis.io/commands/dump/) and [`RESTORE`](https://redis.io/commands/restore/) commands                   |
 | `get-server-time.js`                     | Get the time from the Redis server.                                                                                                                  |
 | `hyperloglog.js`                         | Showing use of Hyperloglog commands [PFADD, PFCOUNT and PFMERGE](https://redis.io/commands/?group=hyperloglog).                                      |
 | `lua-multi-incr.js`                      | Define a custom lua script that allows you to perform INCRBY on multiple keys.                                                                       |
diff --git a/examples/dump-and-restore.js b/examples/dump-and-restore.js
new file mode 100644
index 00000000000..081e44f9f9a
--- /dev/null
+++ b/examples/dump-and-restore.js
@@ -0,0 +1,22 @@
+// This example demonstrates the use of the DUMP and RESTORE commands
+
+import { commandOptions, createClient } from 'redis';
+
+const client = createClient();
+await client.connect();
+
+// DUMP a specific key into a local variable
+const dump = await client.dump(
+    commandOptions({ returnBuffers: true }),
+    'source'
+);
+
+// RESTORE into a new key
+await client.restore('destination', 0, dump);
+
+// RESTORE and REPLACE an existing key
+await client.restore('destination', 0, dump, {
+    REPLACE: true
+});
+
+await client.quit();
diff --git a/examples/search-hashes.js b/examples/search-hashes.js
index 85e6106a99a..2f8b5fbf7b6 100644
--- a/examples/search-hashes.js
+++ b/examples/search-hashes.js
@@ -13,7 +13,7 @@ try {
   await client.ft.create('idx:animals', {
     name: {
       type: SchemaFieldTypes.TEXT,
-      sortable: true
+      SORTABLE: true
     },
     species: SchemaFieldTypes.TAG,
     age: SchemaFieldTypes.NUMERIC
diff --git a/examples/search-json.js b/examples/search-json.js
index 75de0221a1e..6481889ecfd 100644
--- a/examples/search-json.js
+++ b/examples/search-json.js
@@ -15,7 +15,7 @@ try {
   await client.ft.create('idx:users', {
     '$.name': {
       type: SchemaFieldTypes.TEXT,
-      SORTABLE: 'UNF'
+      SORTABLE: true
     },
     '$.age': {
       type: SchemaFieldTypes.NUMERIC,
diff --git a/package-lock.json b/package-lock.json
index 884a670f840..18a7003947e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,38 +1,47 @@
 {
   "name": "redis",
-  "version": "4.5.1",
-  "lockfileVersion": 2,
+  "version": "4.7.0",
+  "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "redis",
-      "version": "4.5.1",
+      "version": "4.7.0",
       "license": "MIT",
       "workspaces": [
         "./packages/*"
       ],
       "dependencies": {
-        "@redis/bloom": "1.1.0",
-        "@redis/client": "1.4.2",
-        "@redis/graph": "1.1.0",
-        "@redis/json": "1.0.4",
-        "@redis/search": "1.1.0",
-        "@redis/time-series": "1.0.4"
+        "@redis/bloom": "1.2.0",
+        "@redis/client": "1.6.0",
+        "@redis/graph": "1.1.1",
+        "@redis/json": "1.0.7",
+        "@redis/search": "1.2.0",
+        "@redis/time-series": "1.1.0"
       },
       "devDependencies": {
-        "@tsconfig/node14": "^1.0.3",
-        "gh-pages": "^4.0.0",
-        "release-it": "^15.3.0",
-        "typescript": "^4.7.4"
+        "@tsconfig/node14": "^14.1.0",
+        "gh-pages": "^6.0.0",
+        "release-it": "^16.1.5",
+        "typescript": "^5.2.2"
+      }
+    },
+    "node_modules/@aashutoshrathi/word-wrap": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+      "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
       }
     },
     "node_modules/@ampproject/remapping": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
-      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
+      "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/gen-mapping": "^0.3.0",
         "@jridgewell/trace-mapping": "^0.3.9"
       },
       "engines": {
@@ -40,47 +49,98 @@
       }
     },
     "node_modules/@babel/code-frame": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
-      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "version": "7.22.13",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+      "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
       "dev": true,
       "dependencies": {
-        "@babel/highlight": "^7.18.6"
+        "@babel/highlight": "^7.22.13",
+        "chalk": "^2.4.2"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/code-frame/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
     "node_modules/@babel/compat-data": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz",
-      "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz",
+      "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/core": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz",
-      "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==",
-      "dev": true,
-      "dependencies": {
-        "@ampproject/remapping": "^2.1.0",
-        "@babel/code-frame": "^7.18.6",
-        "@babel/generator": "^7.19.6",
-        "@babel/helper-compilation-targets": "^7.19.3",
-        "@babel/helper-module-transforms": "^7.19.6",
-        "@babel/helpers": "^7.19.4",
-        "@babel/parser": "^7.19.6",
-        "@babel/template": "^7.18.10",
-        "@babel/traverse": "^7.19.6",
-        "@babel/types": "^7.19.4",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.20.tgz",
+      "integrity": "sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==",
+      "dev": true,
+      "dependencies": {
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.22.13",
+        "@babel/generator": "^7.22.15",
+        "@babel/helper-compilation-targets": "^7.22.15",
+        "@babel/helper-module-transforms": "^7.22.20",
+        "@babel/helpers": "^7.22.15",
+        "@babel/parser": "^7.22.16",
+        "@babel/template": "^7.22.15",
+        "@babel/traverse": "^7.22.20",
+        "@babel/types": "^7.22.19",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
-        "json5": "^2.2.1",
-        "semver": "^6.3.0"
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -90,208 +150,190 @@
         "url": "https://opencollective.com/babel"
       }
     },
-    "node_modules/@babel/core/node_modules/semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-      "dev": true,
-      "bin": {
-        "semver": "bin/semver.js"
-      }
-    },
     "node_modules/@babel/generator": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz",
-      "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==",
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
+      "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.19.4",
+        "@babel/types": "^7.22.15",
         "@jridgewell/gen-mapping": "^0.3.2",
+        "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
-    "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
-      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
-      "dev": true,
-      "dependencies": {
-        "@jridgewell/set-array": "^1.0.1",
-        "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.9"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
     "node_modules/@babel/helper-compilation-targets": {
-      "version": "7.19.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz",
-      "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==",
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
+      "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
       "dev": true,
       "dependencies": {
-        "@babel/compat-data": "^7.19.3",
-        "@babel/helper-validator-option": "^7.18.6",
-        "browserslist": "^4.21.3",
-        "semver": "^6.3.0"
+        "@babel/compat-data": "^7.22.9",
+        "@babel/helper-validator-option": "^7.22.15",
+        "browserslist": "^4.21.9",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
       },
       "engines": {
         "node": ">=6.9.0"
-      },
-      "peerDependencies": {
-        "@babel/core": "^7.0.0"
       }
     },
-    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+    "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
       "dev": true,
-      "bin": {
-        "semver": "bin/semver.js"
+      "dependencies": {
+        "yallist": "^3.0.2"
       }
     },
+    "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true
+    },
     "node_modules/@babel/helper-environment-visitor": {
-      "version": "7.18.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
-      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+      "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-function-name": {
-      "version": "7.19.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
-      "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
+      "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
       "dev": true,
       "dependencies": {
-        "@babel/template": "^7.18.10",
-        "@babel/types": "^7.19.0"
+        "@babel/template": "^7.22.5",
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-hoist-variables": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
-      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+      "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-module-imports": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
-      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+      "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.22.15"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-module-transforms": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz",
-      "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz",
+      "integrity": "sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-module-imports": "^7.18.6",
-        "@babel/helper-simple-access": "^7.19.4",
-        "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/helper-validator-identifier": "^7.19.1",
-        "@babel/template": "^7.18.10",
-        "@babel/traverse": "^7.19.6",
-        "@babel/types": "^7.19.4"
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-module-imports": "^7.22.15",
+        "@babel/helper-simple-access": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.6",
+        "@babel/helper-validator-identifier": "^7.22.20"
       },
       "engines": {
         "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
       }
     },
     "node_modules/@babel/helper-simple-access": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz",
-      "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==",
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
+      "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.19.4"
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-split-export-declaration": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
-      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+      "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-string-parser": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
-      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+      "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-validator-identifier": {
-      "version": "7.19.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
-      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+      "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-validator-option": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
-      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
+      "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helpers": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz",
-      "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==",
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz",
+      "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==",
       "dev": true,
       "dependencies": {
-        "@babel/template": "^7.18.10",
-        "@babel/traverse": "^7.19.4",
-        "@babel/types": "^7.19.4"
+        "@babel/template": "^7.22.15",
+        "@babel/traverse": "^7.22.15",
+        "@babel/types": "^7.22.15"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/highlight": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
-      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+      "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-validator-identifier": "^7.18.6",
-        "chalk": "^2.0.0",
+        "@babel/helper-validator-identifier": "^7.22.20",
+        "chalk": "^2.4.2",
         "js-tokens": "^4.0.0"
       },
       "engines": {
@@ -348,31 +390,10 @@
         "node": ">=0.8.0"
       }
     },
-    "node_modules/@babel/highlight/node_modules/has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/@babel/highlight/node_modules/supports-color": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dev": true,
-      "dependencies": {
-        "has-flag": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/@babel/parser": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz",
-      "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==",
+      "version": "7.22.16",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
+      "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
       "dev": true,
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -382,33 +403,33 @@
       }
     },
     "node_modules/@babel/template": {
-      "version": "7.18.10",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
-      "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+      "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
       "dev": true,
       "dependencies": {
-        "@babel/code-frame": "^7.18.6",
-        "@babel/parser": "^7.18.10",
-        "@babel/types": "^7.18.10"
+        "@babel/code-frame": "^7.22.13",
+        "@babel/parser": "^7.22.15",
+        "@babel/types": "^7.22.15"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz",
-      "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==",
-      "dev": true,
-      "dependencies": {
-        "@babel/code-frame": "^7.18.6",
-        "@babel/generator": "^7.19.6",
-        "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-function-name": "^7.19.0",
-        "@babel/helper-hoist-variables": "^7.18.6",
-        "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/parser": "^7.19.6",
-        "@babel/types": "^7.19.4",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz",
+      "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.22.13",
+        "@babel/generator": "^7.22.15",
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-function-name": "^7.22.5",
+        "@babel/helper-hoist-variables": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.6",
+        "@babel/parser": "^7.22.16",
+        "@babel/types": "^7.22.19",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
@@ -426,13 +447,13 @@
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz",
-      "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==",
+      "version": "7.22.19",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz",
+      "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-string-parser": "^7.19.4",
-        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/helper-string-parser": "^7.22.5",
+        "@babel/helper-validator-identifier": "^7.22.19",
         "to-fast-properties": "^2.0.0"
       },
       "engines": {
@@ -461,16 +482,40 @@
         "@jridgewell/sourcemap-codec": "^1.4.10"
       }
     },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+      "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+      "dev": true,
+      "dependencies": {
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.8.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz",
+      "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==",
+      "dev": true,
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
     "node_modules/@eslint/eslintrc": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
-      "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+      "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
       "dev": true,
       "dependencies": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
-        "espree": "^9.4.0",
-        "globals": "^13.15.0",
+        "espree": "^9.6.0",
+        "globals": "^13.19.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
         "js-yaml": "^4.1.0",
@@ -484,15 +529,36 @@
         "url": "https://opencollective.com/eslint"
       }
     },
+    "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "8.49.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz",
+      "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
     "node_modules/@humanwhocodes/config-array": {
-      "version": "0.11.6",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz",
-      "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==",
+      "version": "0.11.11",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
+      "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
       "dev": true,
       "dependencies": {
         "@humanwhocodes/object-schema": "^1.2.1",
         "debug": "^4.1.1",
-        "minimatch": "^3.0.4"
+        "minimatch": "^3.0.5"
       },
       "engines": {
         "node": ">=10.10.0"
@@ -548,17 +614,13 @@
         "sprintf-js": "~1.0.2"
       }
     },
-    "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
       "dev": true,
-      "dependencies": {
-        "locate-path": "^5.0.0",
-        "path-exists": "^4.0.0"
-      },
       "engines": {
-        "node": ">=8"
+        "node": ">=6"
       }
     },
     "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
@@ -574,45 +636,6 @@
         "js-yaml": "bin/js-yaml.js"
       }
     },
-    "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-      "dev": true,
-      "dependencies": {
-        "p-locate": "^4.1.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-      "dev": true,
-      "dependencies": {
-        "p-try": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-      "dev": true,
-      "dependencies": {
-        "p-limit": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
@@ -647,22 +670,23 @@
       }
     },
     "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
-      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+      "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/set-array": "^1.0.0",
-        "@jridgewell/sourcemap-codec": "^1.4.10"
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
       },
       "engines": {
         "node": ">=6.0.0"
       }
     },
     "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
-      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
+      "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
       "dev": true,
       "engines": {
         "node": ">=6.0.0"
@@ -678,19 +702,28 @@
       }
     },
     "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.4.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
       "dev": true
     },
     "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.17",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
-      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "version": "0.3.19",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
+      "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/resolve-uri": "3.1.0",
-        "@jridgewell/sourcemap-codec": "1.4.14"
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@ljharb/through": {
+      "version": "2.3.9",
+      "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.9.tgz",
+      "integrity": "sha512-yN599ZBuMPPK4tdoToLlvgJB4CLK8fGl7ntfy0Wn7U6ttNvHYurd81bfUiK/6sMkiIwm65R6ck4L6+Y3DfVbNQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
       }
     },
     "node_modules/@nodelib/fs.scandir": {
@@ -729,28 +762,25 @@
       }
     },
     "node_modules/@octokit/auth-token": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
-      "integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz",
+      "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==",
       "dev": true,
-      "dependencies": {
-        "@octokit/types": "^8.0.0"
-      },
       "engines": {
         "node": ">= 14"
       }
     },
     "node_modules/@octokit/core": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
-      "integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz",
+      "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==",
       "dev": true,
       "dependencies": {
         "@octokit/auth-token": "^3.0.0",
         "@octokit/graphql": "^5.0.0",
         "@octokit/request": "^6.0.0",
         "@octokit/request-error": "^3.0.0",
-        "@octokit/types": "^8.0.0",
+        "@octokit/types": "^9.0.0",
         "before-after-hook": "^2.2.0",
         "universal-user-agent": "^6.0.0"
       },
@@ -759,12 +789,12 @@
       }
     },
     "node_modules/@octokit/endpoint": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
-      "integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz",
+      "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==",
       "dev": true,
       "dependencies": {
-        "@octokit/types": "^8.0.0",
+        "@octokit/types": "^9.0.0",
         "is-plain-object": "^5.0.0",
         "universal-user-agent": "^6.0.0"
       },
@@ -773,13 +803,13 @@
       }
     },
     "node_modules/@octokit/graphql": {
-      "version": "5.0.4",
-      "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
-      "integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
+      "version": "5.0.6",
+      "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz",
+      "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==",
       "dev": true,
       "dependencies": {
         "@octokit/request": "^6.0.0",
-        "@octokit/types": "^8.0.0",
+        "@octokit/types": "^9.0.0",
         "universal-user-agent": "^6.0.0"
       },
       "engines": {
@@ -787,18 +817,19 @@
       }
     },
     "node_modules/@octokit/openapi-types": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
-      "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==",
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz",
+      "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==",
       "dev": true
     },
     "node_modules/@octokit/plugin-paginate-rest": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-4.3.1.tgz",
-      "integrity": "sha512-h8KKxESmSFTcXX409CAxlaOYscEDvN2KGQRsLCGT1NSqRW+D6EXLVQ8vuHhFznS9MuH9QYw1GfsUN30bg8hjVA==",
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz",
+      "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==",
       "dev": true,
       "dependencies": {
-        "@octokit/types": "^7.5.0"
+        "@octokit/tsconfig": "^1.0.2",
+        "@octokit/types": "^9.2.3"
       },
       "engines": {
         "node": ">= 14"
@@ -807,21 +838,6 @@
         "@octokit/core": ">=4"
       }
     },
-    "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
-      "version": "13.13.1",
-      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-13.13.1.tgz",
-      "integrity": "sha512-4EuKSk3N95UBWFau3Bz9b3pheQ8jQYbKmBL5+GSuY8YDPDwu03J4BjI+66yNi8aaX/3h1qDpb0mbBkLdr+cfGQ==",
-      "dev": true
-    },
-    "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
-      "version": "7.5.1",
-      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-7.5.1.tgz",
-      "integrity": "sha512-Zk4OUMLCSpXNI8KZZn47lVLJSsgMyCimsWWQI5hyjZg7hdYm0kjotaIkbG0Pp8SfU2CofMBzonboTqvzn3FrJA==",
-      "dev": true,
-      "dependencies": {
-        "@octokit/openapi-types": "^13.11.0"
-      }
-    },
     "node_modules/@octokit/plugin-request-log": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
@@ -832,13 +848,12 @@
       }
     },
     "node_modules/@octokit/plugin-rest-endpoint-methods": {
-      "version": "6.7.0",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
-      "integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz",
+      "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==",
       "dev": true,
       "dependencies": {
-        "@octokit/types": "^8.0.0",
-        "deprecation": "^2.3.1"
+        "@octokit/types": "^10.0.0"
       },
       "engines": {
         "node": ">= 14"
@@ -847,15 +862,24 @@
         "@octokit/core": ">=3"
       }
     },
+    "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz",
+      "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==",
+      "dev": true,
+      "dependencies": {
+        "@octokit/openapi-types": "^18.0.0"
+      }
+    },
     "node_modules/@octokit/request": {
-      "version": "6.2.2",
-      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
-      "integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
+      "version": "6.2.8",
+      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz",
+      "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==",
       "dev": true,
       "dependencies": {
         "@octokit/endpoint": "^7.0.0",
         "@octokit/request-error": "^3.0.0",
-        "@octokit/types": "^8.0.0",
+        "@octokit/types": "^9.0.0",
         "is-plain-object": "^5.0.0",
         "node-fetch": "^2.6.7",
         "universal-user-agent": "^6.0.0"
@@ -865,12 +889,12 @@
       }
     },
     "node_modules/@octokit/request-error": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
-      "integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz",
+      "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==",
       "dev": true,
       "dependencies": {
-        "@octokit/types": "^8.0.0",
+        "@octokit/types": "^9.0.0",
         "deprecation": "^2.0.0",
         "once": "^1.4.0"
       },
@@ -879,9 +903,9 @@
       }
     },
     "node_modules/@octokit/request/node_modules/node-fetch": {
-      "version": "2.6.7",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
-      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+      "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
       "dev": true,
       "dependencies": {
         "whatwg-url": "^5.0.0"
@@ -899,33 +923,48 @@
       }
     },
     "node_modules/@octokit/rest": {
-      "version": "19.0.4",
-      "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.4.tgz",
-      "integrity": "sha512-LwG668+6lE8zlSYOfwPj4FxWdv/qFXYBpv79TWIQEpBLKA9D/IMcWsF/U9RGpA3YqMVDiTxpgVpEW3zTFfPFTA==",
+      "version": "19.0.13",
+      "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.13.tgz",
+      "integrity": "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==",
       "dev": true,
       "dependencies": {
-        "@octokit/core": "^4.0.0",
-        "@octokit/plugin-paginate-rest": "^4.0.0",
+        "@octokit/core": "^4.2.1",
+        "@octokit/plugin-paginate-rest": "^6.1.2",
         "@octokit/plugin-request-log": "^1.0.4",
-        "@octokit/plugin-rest-endpoint-methods": "^6.0.0"
+        "@octokit/plugin-rest-endpoint-methods": "^7.1.2"
       },
       "engines": {
         "node": ">= 14"
       }
     },
+    "node_modules/@octokit/tsconfig": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz",
+      "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==",
+      "dev": true
+    },
     "node_modules/@octokit/types": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
-      "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
+      "version": "9.3.2",
+      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz",
+      "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==",
       "dev": true,
       "dependencies": {
-        "@octokit/openapi-types": "^14.0.0"
+        "@octokit/openapi-types": "^18.0.0"
+      }
+    },
+    "node_modules/@pnpm/config.env-replace": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
+      "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.22.0"
       }
     },
     "node_modules/@pnpm/network.ca-file": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz",
-      "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz",
+      "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==",
       "dev": true,
       "dependencies": {
         "graceful-fs": "4.2.10"
@@ -934,12 +973,19 @@
         "node": ">=12.22.0"
       }
     },
+    "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+      "dev": true
+    },
     "node_modules/@pnpm/npm-conf": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz",
-      "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==",
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz",
+      "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==",
       "dev": true,
       "dependencies": {
+        "@pnpm/config.env-replace": "^1.1.0",
         "@pnpm/network.ca-file": "^1.0.1",
         "config-chain": "^1.1.11"
       },
@@ -976,9 +1022,9 @@
       "link": true
     },
     "node_modules/@sindresorhus/is": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz",
-      "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==",
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
+      "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==",
       "dev": true,
       "engines": {
         "node": ">=14.16"
@@ -988,34 +1034,43 @@
       }
     },
     "node_modules/@sinonjs/commons": {
-      "version": "1.8.3",
-      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
-      "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
+      "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
       "dev": true,
       "dependencies": {
         "type-detect": "4.0.8"
       }
     },
     "node_modules/@sinonjs/fake-timers": {
-      "version": "9.1.2",
-      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz",
-      "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==",
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+      "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
       "dev": true,
       "dependencies": {
-        "@sinonjs/commons": "^1.7.0"
+        "@sinonjs/commons": "^3.0.0"
       }
     },
     "node_modules/@sinonjs/samsam": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.1.tgz",
-      "integrity": "sha512-cZ7rKJTLiE7u7Wi/v9Hc2fs3Ucc3jrWeMgPHbbTCeVAB2S0wOBbYlkJVeNSL04i7fdhT8wIbDq1zhC/PXTD2SA==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz",
+      "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==",
       "dev": true,
       "dependencies": {
-        "@sinonjs/commons": "^1.6.0",
+        "@sinonjs/commons": "^2.0.0",
         "lodash.get": "^4.4.2",
         "type-detect": "^4.0.8"
       }
     },
+    "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+      "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
+      "dev": true,
+      "dependencies": {
+        "type-detect": "4.0.8"
+      }
+    },
     "node_modules/@sinonjs/text-encoding": {
       "version": "0.7.2",
       "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz",
@@ -1034,14 +1089,11 @@
         "node": ">=14.16"
       }
     },
-    "node_modules/@tootallnate/once": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
-      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
-      "dev": true,
-      "engines": {
-        "node": ">= 6"
-      }
+    "node_modules/@tootallnate/quickjs-emscripten": {
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+      "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+      "dev": true
     },
     "node_modules/@tsconfig/node10": {
       "version": "1.0.9",
@@ -1056,57 +1108,51 @@
       "dev": true
     },
     "node_modules/@tsconfig/node14": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
-      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+      "version": "14.1.0",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-14.1.0.tgz",
+      "integrity": "sha512-VmsCG04YR58ciHBeJKBDNMWWfYbyP8FekWVuTlpstaUPlat1D0x/tXzkWP7yCMU0eSz9V4OZU0LBWTFJ3xZf6w==",
       "dev": true
     },
     "node_modules/@tsconfig/node16": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
-      "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+      "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
       "dev": true
     },
     "node_modules/@types/http-cache-semantics": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
-      "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz",
+      "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==",
       "dev": true
     },
     "node_modules/@types/json-schema": {
-      "version": "7.0.11",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
-      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+      "version": "7.0.13",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz",
+      "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==",
       "dev": true
     },
     "node_modules/@types/mocha": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.0.tgz",
-      "integrity": "sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg==",
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz",
+      "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==",
       "dev": true
     },
     "node_modules/@types/node": {
-      "version": "18.11.6",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.6.tgz",
-      "integrity": "sha512-j3CEDa2vd96K0AXF8Wur7UucACvnjkk8hYyQAHhUNciabZLDl9nfAEVUSwmh245OOZV15bRA3Y590Gi5jUcDJg==",
-      "dev": true
-    },
-    "node_modules/@types/parse-json": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
-      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+      "version": "20.6.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz",
+      "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==",
       "dev": true
     },
     "node_modules/@types/semver": {
-      "version": "7.3.12",
-      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz",
-      "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==",
+      "version": "7.5.2",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz",
+      "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==",
       "dev": true
     },
     "node_modules/@types/sinon": {
-      "version": "10.0.13",
-      "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz",
-      "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==",
+      "version": "10.0.16",
+      "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.16.tgz",
+      "integrity": "sha512-j2Du5SYpXZjJVJtXBokASpPRj+e2z+VUhCPHmM6WMfe3dpHu6iVKJMU6AiBcMp/XTAYnEj6Wc1trJUWwZ0QaAQ==",
       "dev": true,
       "dependencies": {
         "@types/sinonjs__fake-timers": "*"
@@ -1125,9 +1171,9 @@
       "dev": true
     },
     "node_modules/@types/yargs": {
-      "version": "17.0.13",
-      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz",
-      "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==",
+      "version": "17.0.24",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
+      "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
       "dev": true,
       "dependencies": {
         "@types/yargs-parser": "*"
@@ -1140,30 +1186,33 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.41.0.tgz",
-      "integrity": "sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA==",
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz",
+      "integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.41.0",
-        "@typescript-eslint/type-utils": "5.41.0",
-        "@typescript-eslint/utils": "5.41.0",
+        "@eslint-community/regexpp": "^4.5.1",
+        "@typescript-eslint/scope-manager": "6.7.2",
+        "@typescript-eslint/type-utils": "6.7.2",
+        "@typescript-eslint/utils": "6.7.2",
+        "@typescript-eslint/visitor-keys": "6.7.2",
         "debug": "^4.3.4",
-        "ignore": "^5.2.0",
-        "regexpp": "^3.2.0",
-        "semver": "^7.3.7",
-        "tsutils": "^3.21.0"
+        "graphemer": "^1.4.0",
+        "ignore": "^5.2.4",
+        "natural-compare": "^1.4.0",
+        "semver": "^7.5.4",
+        "ts-api-utils": "^1.0.1"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "@typescript-eslint/parser": "^5.0.0",
-        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+        "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
+        "eslint": "^7.0.0 || ^8.0.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -1171,26 +1220,54 @@
         }
       }
     },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/@typescript-eslint/parser": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.41.0.tgz",
-      "integrity": "sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==",
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz",
+      "integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.41.0",
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/typescript-estree": "5.41.0",
+        "@typescript-eslint/scope-manager": "6.7.2",
+        "@typescript-eslint/types": "6.7.2",
+        "@typescript-eslint/typescript-estree": "6.7.2",
+        "@typescript-eslint/visitor-keys": "6.7.2",
         "debug": "^4.3.4"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+        "eslint": "^7.0.0 || ^8.0.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -1199,16 +1276,16 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.41.0.tgz",
-      "integrity": "sha512-xOxPJCnuktUkY2xoEZBKXO5DBCugFzjrVndKdUnyQr3+9aDWZReKq9MhaoVnbL+maVwWJu/N0SEtrtEUNb62QQ==",
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz",
+      "integrity": "sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/visitor-keys": "5.41.0"
+        "@typescript-eslint/types": "6.7.2",
+        "@typescript-eslint/visitor-keys": "6.7.2"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -1216,25 +1293,25 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.41.0.tgz",
-      "integrity": "sha512-L30HNvIG6A1Q0R58e4hu4h+fZqaO909UcnnPbwKiN6Rc3BUEx6ez2wgN7aC0cBfcAjZfwkzE+E2PQQ9nEuoqfA==",
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz",
+      "integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "5.41.0",
-        "@typescript-eslint/utils": "5.41.0",
+        "@typescript-eslint/typescript-estree": "6.7.2",
+        "@typescript-eslint/utils": "6.7.2",
         "debug": "^4.3.4",
-        "tsutils": "^3.21.0"
+        "ts-api-utils": "^1.0.1"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "*"
+        "eslint": "^7.0.0 || ^8.0.0"
       },
       "peerDependenciesMeta": {
         "typescript": {
@@ -1243,12 +1320,12 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.41.0.tgz",
-      "integrity": "sha512-5BejraMXMC+2UjefDvrH0Fo/eLwZRV6859SXRg+FgbhA0R0l6lDqDGAQYhKbXhPN2ofk2kY5sgGyLNL907UXpA==",
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz",
+      "integrity": "sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==",
       "dev": true,
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -1256,21 +1333,21 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.41.0.tgz",
-      "integrity": "sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==",
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz",
+      "integrity": "sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/visitor-keys": "5.41.0",
+        "@typescript-eslint/types": "6.7.2",
+        "@typescript-eslint/visitor-keys": "6.7.2",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
-        "semver": "^7.3.7",
-        "tsutils": "^3.21.0"
+        "semver": "^7.5.4",
+        "ts-api-utils": "^1.0.1"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -1282,43 +1359,134 @@
         }
       }
     },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/@typescript-eslint/utils": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.41.0.tgz",
-      "integrity": "sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==",
-      "dev": true,
-      "dependencies": {
-        "@types/json-schema": "^7.0.9",
-        "@types/semver": "^7.3.12",
-        "@typescript-eslint/scope-manager": "5.41.0",
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/typescript-estree": "5.41.0",
-        "eslint-scope": "^5.1.1",
-        "eslint-utils": "^3.0.0",
-        "semver": "^7.3.7"
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.2.tgz",
+      "integrity": "sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==",
+      "dev": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@types/json-schema": "^7.0.12",
+        "@types/semver": "^7.5.0",
+        "@typescript-eslint/scope-manager": "6.7.2",
+        "@typescript-eslint/types": "6.7.2",
+        "@typescript-eslint/typescript-estree": "6.7.2",
+        "semver": "^7.5.4"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+        "eslint": "^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/utils/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/utils/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.41.0.tgz",
-      "integrity": "sha512-vilqeHj267v8uzzakbm13HkPMl7cbYpKVjgFWZPIOHIJHZtinvypUhJ5xBXfWYg4eFKqztbMMpOgFpT9Gfx4fw==",
+      "version": "6.7.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz",
+      "integrity": "sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.41.0",
-        "eslint-visitor-keys": "^3.3.0"
+        "@typescript-eslint/types": "6.7.2",
+        "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^16.0.0 || >=18.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -1326,9 +1494,9 @@
       }
     },
     "node_modules/acorn": {
-      "version": "8.8.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
-      "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
+      "version": "8.10.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+      "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
       "dev": true,
       "bin": {
         "acorn": "bin/acorn"
@@ -1356,15 +1524,15 @@
       }
     },
     "node_modules/agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
+      "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
       "dev": true,
       "dependencies": {
-        "debug": "4"
+        "debug": "^4.3.4"
       },
       "engines": {
-        "node": ">= 6.0.0"
+        "node": ">= 14"
       }
     },
     "node_modules/aggregate-error": {
@@ -1405,26 +1573,6 @@
         "string-width": "^4.1.0"
       }
     },
-    "node_modules/ansi-align/node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-      "dev": true
-    },
-    "node_modules/ansi-align/node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dev": true,
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/ansi-colors": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@@ -1435,27 +1583,15 @@
       }
     },
     "node_modules/ansi-escapes": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz",
-      "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==",
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+      "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
       "dev": true,
       "dependencies": {
-        "type-fest": "^1.0.2"
-      },
-      "engines": {
-        "node": ">=12"
+        "type-fest": "^0.21.3"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/ansi-escapes/node_modules/type-fest": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
-      "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
-      "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">=8"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -1470,6 +1606,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/ansi-sequence-parser": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
+      "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
+      "dev": true
+    },
     "node_modules/ansi-styles": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -1486,9 +1628,9 @@
       }
     },
     "node_modules/anymatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
-      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
       "dev": true,
       "dependencies": {
         "normalize-path": "^3.0.0",
@@ -1528,13 +1670,29 @@
       "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
       "dev": true
     },
+    "node_modules/array-buffer-byte-length": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
+      "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "is-array-buffer": "^3.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/array-union": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
       "dev": true,
+      "dependencies": {
+        "array-uniq": "^1.0.1"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">=0.10.0"
       }
     },
     "node_modules/array-uniq": {
@@ -1547,14 +1705,14 @@
       }
     },
     "node_modules/array.prototype.map": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz",
-      "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.6.tgz",
+      "integrity": "sha512-nK1psgF2cXqP3wSyCSq0Hc7zwNq3sfljQqaG27r/7a7ooNUnn5nGq6yYWyks9jMO5EoFQ0ax80hSg6oXSRNXaw==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.0",
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
         "es-array-method-boxes-properly": "^1.0.0",
         "is-string": "^1.0.7"
       },
@@ -1565,6 +1723,27 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/arraybuffer.prototype.slice": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz",
+      "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==",
+      "dev": true,
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.0",
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "get-intrinsic": "^1.2.1",
+        "is-array-buffer": "^3.0.2",
+        "is-shared-array-buffer": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/ast-types": {
       "version": "0.13.4",
       "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
@@ -1578,13 +1757,10 @@
       }
     },
     "node_modules/async": {
-      "version": "2.6.4",
-      "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
-      "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
-      "dev": true,
-      "dependencies": {
-        "lodash": "^4.17.14"
-      }
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+      "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+      "dev": true
     },
     "node_modules/async-retry": {
       "version": "1.3.3",
@@ -1595,11 +1771,17 @@
         "retry": "0.13.1"
       }
     },
-    "node_modules/asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-      "dev": true
+    "node_modules/available-typed-arrays": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+      "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
     },
     "node_modules/balanced-match": {
       "version": "1.0.2",
@@ -1627,12 +1809,30 @@
         }
       ]
     },
+    "node_modules/basic-ftp": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz",
+      "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
     "node_modules/before-after-hook": {
       "version": "2.2.3",
       "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
       "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
       "dev": true
     },
+    "node_modules/big-integer": {
+      "version": "1.6.51",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
     "node_modules/binary-extensions": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -1654,19 +1854,19 @@
       }
     },
     "node_modules/boxen": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz",
-      "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz",
+      "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==",
       "dev": true,
       "dependencies": {
         "ansi-align": "^3.0.1",
-        "camelcase": "^7.0.0",
-        "chalk": "^5.0.1",
+        "camelcase": "^7.0.1",
+        "chalk": "^5.2.0",
         "cli-boxes": "^3.0.0",
         "string-width": "^5.1.2",
         "type-fest": "^2.13.0",
         "widest-line": "^4.0.1",
-        "wrap-ansi": "^8.0.1"
+        "wrap-ansi": "^8.1.0"
       },
       "engines": {
         "node": ">=14.16"
@@ -1675,42 +1875,109 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/boxen/node_modules/camelcase": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz",
-      "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==",
+    "node_modules/boxen/node_modules/ansi-regex": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
       "dev": true,
       "engines": {
-        "node": ">=14.16"
+        "node": ">=12"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
       }
     },
-    "node_modules/boxen/node_modules/chalk": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-      "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
+    "node_modules/boxen/node_modules/ansi-styles": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
       "dev": true,
       "engines": {
-        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+        "node": ">=12"
       },
       "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
-    "node_modules/boxen/node_modules/type-fest": {
-      "version": "2.19.0",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
-      "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
-      "dev": true,
-      "engines": {
-        "node": ">=12.20"
-      },
-      "funding": {
+    "node_modules/boxen/node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true
+    },
+    "node_modules/boxen/node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/boxen/node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/boxen/node_modules/type-fest": {
+      "version": "2.19.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+      "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.20"
+      },
+      "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/boxen/node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/bplist-parser": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
+      "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
+      "dev": true,
+      "dependencies": {
+        "big-integer": "^1.6.44"
+      },
+      "engines": {
+        "node": ">= 5.10.0"
+      }
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1740,9 +2007,9 @@
       "dev": true
     },
     "node_modules/browserslist": {
-      "version": "4.21.4",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
-      "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
+      "version": "4.21.10",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+      "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
       "dev": true,
       "funding": [
         {
@@ -1752,13 +2019,17 @@
         {
           "type": "tidelift",
           "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
         }
       ],
       "dependencies": {
-        "caniuse-lite": "^1.0.30001400",
-        "electron-to-chromium": "^1.4.251",
-        "node-releases": "^2.0.6",
-        "update-browserslist-db": "^1.0.9"
+        "caniuse-lite": "^1.0.30001517",
+        "electron-to-chromium": "^1.4.477",
+        "node-releases": "^2.0.13",
+        "update-browserslist-db": "^1.0.11"
       },
       "bin": {
         "browserslist": "cli.js"
@@ -1797,13 +2068,19 @@
       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
       "dev": true
     },
-    "node_modules/bytes": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
-      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+    "node_modules/bundle-name": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
+      "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==",
       "dev": true,
+      "dependencies": {
+        "run-applescript": "^5.0.0"
+      },
       "engines": {
-        "node": ">= 0.8"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/cacheable-lookup": {
@@ -1816,17 +2093,17 @@
       }
     },
     "node_modules/cacheable-request": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.2.tgz",
-      "integrity": "sha512-KxjQZM3UIo7/J6W4sLpwFvu1GB3Whv8NtZ8ZrUL284eiQjiXeeqWTdhixNrp/NLZ/JNuFBo6BD4ZaO8ZJ5BN8Q==",
+      "version": "10.2.13",
+      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.13.tgz",
+      "integrity": "sha512-3SD4rrMu1msNGEtNSt8Od6enwdo//U9s4ykmXfA2TD58kcLkCobtCDiby7kNyj7a/Q7lz/mAesAFI54rTdnvBA==",
       "dev": true,
       "dependencies": {
         "@types/http-cache-semantics": "^4.0.1",
         "get-stream": "^6.0.1",
-        "http-cache-semantics": "^4.1.0",
-        "keyv": "^4.5.0",
+        "http-cache-semantics": "^4.1.1",
+        "keyv": "^4.5.3",
         "mimic-response": "^4.0.0",
-        "normalize-url": "^7.2.0",
+        "normalize-url": "^8.0.0",
         "responselike": "^3.0.0"
       },
       "engines": {
@@ -1871,18 +2148,21 @@
       }
     },
     "node_modules/camelcase": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz",
+      "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==",
       "dev": true,
       "engines": {
-        "node": ">=6"
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001425",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz",
-      "integrity": "sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==",
+      "version": "1.0.30001535",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz",
+      "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==",
       "dev": true,
       "funding": [
         {
@@ -1892,20 +2172,20 @@
         {
           "type": "tidelift",
           "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
         }
       ]
     },
     "node_modules/chalk": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+      "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
       "dev": true,
-      "dependencies": {
-        "ansi-styles": "^4.1.0",
-        "supports-color": "^7.1.0"
-      },
       "engines": {
-        "node": ">=10"
+        "node": "^12.17.0 || ^14.13 || >=16.0.0"
       },
       "funding": {
         "url": "https://github.com/chalk/chalk?sponsor=1"
@@ -1944,24 +2224,21 @@
         "fsevents": "~2.3.2"
       }
     },
-    "node_modules/chokidar/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+    "node_modules/ci-info": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
+      "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
       "dev": true,
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/sibiraj-s"
+        }
+      ],
       "engines": {
-        "node": ">= 6"
+        "node": ">=8"
       }
     },
-    "node_modules/ci-info": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
-      "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==",
-      "dev": true
-    },
     "node_modules/clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -1984,24 +2261,21 @@
       }
     },
     "node_modules/cli-cursor": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
-      "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
       "dev": true,
       "dependencies": {
-        "restore-cursor": "^4.0.0"
+        "restore-cursor": "^3.1.0"
       },
       "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=8"
       }
     },
     "node_modules/cli-spinners": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
-      "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
+      "version": "2.9.1",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz",
+      "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==",
       "dev": true,
       "engines": {
         "node": ">=6"
@@ -2011,9 +2285,9 @@
       }
     },
     "node_modules/cli-width": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz",
-      "integrity": "sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+      "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
       "dev": true,
       "engines": {
         "node": ">= 12"
@@ -2033,26 +2307,6 @@
         "node": ">=12"
       }
     },
-    "node_modules/cliui/node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-      "dev": true
-    },
-    "node_modules/cliui/node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dev": true,
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/cliui/node_modules/wrap-ansi": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -2080,9 +2334,9 @@
       }
     },
     "node_modules/cluster-key-slot": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz",
-      "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
+      "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -2105,24 +2359,15 @@
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
       "dev": true
     },
-    "node_modules/combined-stream": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
-      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+    "node_modules/commander": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz",
+      "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==",
       "dev": true,
-      "dependencies": {
-        "delayed-stream": "~1.0.0"
-      },
       "engines": {
-        "node": ">= 0.8"
+        "node": ">=16"
       }
     },
-    "node_modules/commander": {
-      "version": "2.20.3",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-      "dev": true
-    },
     "node_modules/commondir": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -2176,26 +2421,22 @@
       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
       "dev": true
     },
-    "node_modules/core-util-is": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
-      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
-      "dev": true
-    },
     "node_modules/cosmiconfig": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
-      "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz",
+      "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==",
       "dev": true,
       "dependencies": {
-        "@types/parse-json": "^4.0.0",
         "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
         "parse-json": "^5.0.0",
-        "path-type": "^4.0.0",
-        "yaml": "^1.10.0"
+        "path-type": "^4.0.0"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/d-fischer"
       }
     },
     "node_modules/create-require": {
@@ -2246,9 +2487,9 @@
       }
     },
     "node_modules/data-uri-to-buffer": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
-      "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+      "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
       "dev": true,
       "engines": {
         "node": ">= 12"
@@ -2322,6 +2563,40 @@
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "dev": true
     },
+    "node_modules/default-browser": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz",
+      "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==",
+      "dev": true,
+      "dependencies": {
+        "bundle-name": "^3.0.0",
+        "default-browser-id": "^3.0.0",
+        "execa": "^7.1.1",
+        "titleize": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/default-browser-id": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
+      "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==",
+      "dev": true,
+      "dependencies": {
+        "bplist-parser": "^0.2.0",
+        "untildify": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/default-require-extensions": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz",
@@ -2358,21 +2633,39 @@
         "node": ">=10"
       }
     },
+    "node_modules/define-data-property": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz",
+      "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.2.1",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/define-lazy-prop": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
-      "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
       "dev": true,
       "engines": {
-        "node": ">=8"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/define-properties": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
-      "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
       "dev": true,
       "dependencies": {
+        "define-data-property": "^1.0.1",
         "has-property-descriptors": "^1.0.0",
         "object-keys": "^1.1.1"
       },
@@ -2384,36 +2677,17 @@
       }
     },
     "node_modules/degenerator": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz",
-      "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+      "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
       "dev": true,
       "dependencies": {
-        "ast-types": "^0.13.2",
-        "escodegen": "^1.8.1",
-        "esprima": "^4.0.0",
-        "vm2": "^3.9.8"
+        "ast-types": "^0.13.4",
+        "escodegen": "^2.1.0",
+        "esprima": "^4.0.1"
       },
       "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
-    "node_modules/depd": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
-      "dev": true,
-      "engines": {
-        "node": ">= 0.8"
+        "node": ">= 14"
       }
     },
     "node_modules/deprecation": {
@@ -2477,21 +2751,21 @@
       "dev": true
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.284",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
-      "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
+      "version": "1.4.523",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz",
+      "integrity": "sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg==",
       "dev": true
     },
     "node_modules/email-addresses": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
-      "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz",
+      "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
       "dev": true
     },
     "node_modules/emoji-regex": {
-      "version": "9.2.2",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
-      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
     },
     "node_modules/error-ex": {
@@ -2504,35 +2778,50 @@
       }
     },
     "node_modules/es-abstract": {
-      "version": "1.20.4",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
-      "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
+      "version": "1.22.2",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz",
+      "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==",
       "dev": true,
       "dependencies": {
+        "array-buffer-byte-length": "^1.0.0",
+        "arraybuffer.prototype.slice": "^1.0.2",
+        "available-typed-arrays": "^1.0.5",
         "call-bind": "^1.0.2",
+        "es-set-tostringtag": "^2.0.1",
         "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
-        "function.prototype.name": "^1.1.5",
-        "get-intrinsic": "^1.1.3",
+        "function.prototype.name": "^1.1.6",
+        "get-intrinsic": "^1.2.1",
         "get-symbol-description": "^1.0.0",
+        "globalthis": "^1.0.3",
+        "gopd": "^1.0.1",
         "has": "^1.0.3",
         "has-property-descriptors": "^1.0.0",
+        "has-proto": "^1.0.1",
         "has-symbols": "^1.0.3",
-        "internal-slot": "^1.0.3",
+        "internal-slot": "^1.0.5",
+        "is-array-buffer": "^3.0.2",
         "is-callable": "^1.2.7",
         "is-negative-zero": "^2.0.2",
         "is-regex": "^1.1.4",
         "is-shared-array-buffer": "^1.0.2",
         "is-string": "^1.0.7",
+        "is-typed-array": "^1.1.12",
         "is-weakref": "^1.0.2",
-        "object-inspect": "^1.12.2",
+        "object-inspect": "^1.12.3",
         "object-keys": "^1.1.1",
         "object.assign": "^4.1.4",
-        "regexp.prototype.flags": "^1.4.3",
+        "regexp.prototype.flags": "^1.5.1",
+        "safe-array-concat": "^1.0.1",
         "safe-regex-test": "^1.0.0",
-        "string.prototype.trimend": "^1.0.5",
-        "string.prototype.trimstart": "^1.0.5",
-        "unbox-primitive": "^1.0.2"
+        "string.prototype.trim": "^1.2.8",
+        "string.prototype.trimend": "^1.0.7",
+        "string.prototype.trimstart": "^1.0.7",
+        "typed-array-buffer": "^1.0.0",
+        "typed-array-byte-length": "^1.0.0",
+        "typed-array-byte-offset": "^1.0.0",
+        "typed-array-length": "^1.0.4",
+        "unbox-primitive": "^1.0.2",
+        "which-typed-array": "^1.1.11"
       },
       "engines": {
         "node": ">= 0.4"
@@ -2548,24 +2837,39 @@
       "dev": true
     },
     "node_modules/es-get-iterator": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
-      "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
+      "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.0",
-        "has-symbols": "^1.0.1",
-        "is-arguments": "^1.1.0",
+        "get-intrinsic": "^1.1.3",
+        "has-symbols": "^1.0.3",
+        "is-arguments": "^1.1.1",
         "is-map": "^2.0.2",
         "is-set": "^2.0.2",
-        "is-string": "^1.0.5",
-        "isarray": "^2.0.5"
+        "is-string": "^1.0.7",
+        "isarray": "^2.0.5",
+        "stop-iteration-iterator": "^1.0.0"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
+      "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.3",
+        "has": "^1.0.3",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/es-to-primitive": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
@@ -2611,134 +2915,80 @@
       }
     },
     "node_modules/escape-string-regexp": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+      "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
       "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">=12"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/escodegen": {
-      "version": "1.14.3",
-      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
-      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+      "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
       "dev": true,
       "dependencies": {
         "esprima": "^4.0.1",
-        "estraverse": "^4.2.0",
-        "esutils": "^2.0.2",
-        "optionator": "^0.8.1"
+        "estraverse": "^5.2.0",
+        "esutils": "^2.0.2"
       },
       "bin": {
         "escodegen": "bin/escodegen.js",
         "esgenerate": "bin/esgenerate.js"
       },
       "engines": {
-        "node": ">=4.0"
+        "node": ">=6.0"
       },
       "optionalDependencies": {
         "source-map": "~0.6.1"
       }
     },
-    "node_modules/escodegen/node_modules/levn": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
-      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
-      "dev": true,
-      "dependencies": {
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/escodegen/node_modules/optionator": {
-      "version": "0.8.3",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
-      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
-      "dev": true,
-      "dependencies": {
-        "deep-is": "~0.1.3",
-        "fast-levenshtein": "~2.0.6",
-        "levn": "~0.3.0",
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2",
-        "word-wrap": "~1.2.3"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/escodegen/node_modules/prelude-ls": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
-      "dev": true,
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/escodegen/node_modules/type-check": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
-      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
-      "dev": true,
-      "dependencies": {
-        "prelude-ls": "~1.1.2"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
     "node_modules/eslint": {
-      "version": "8.26.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
-      "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==",
+      "version": "8.49.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz",
+      "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==",
       "dev": true,
       "dependencies": {
-        "@eslint/eslintrc": "^1.3.3",
-        "@humanwhocodes/config-array": "^0.11.6",
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.6.1",
+        "@eslint/eslintrc": "^2.1.2",
+        "@eslint/js": "8.49.0",
+        "@humanwhocodes/config-array": "^0.11.11",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
-        "ajv": "^6.10.0",
+        "ajv": "^6.12.4",
         "chalk": "^4.0.0",
         "cross-spawn": "^7.0.2",
         "debug": "^4.3.2",
         "doctrine": "^3.0.0",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^7.1.1",
-        "eslint-utils": "^3.0.0",
-        "eslint-visitor-keys": "^3.3.0",
-        "espree": "^9.4.0",
-        "esquery": "^1.4.0",
+        "eslint-scope": "^7.2.2",
+        "eslint-visitor-keys": "^3.4.3",
+        "espree": "^9.6.1",
+        "esquery": "^1.4.2",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
         "file-entry-cache": "^6.0.1",
         "find-up": "^5.0.0",
         "glob-parent": "^6.0.2",
-        "globals": "^13.15.0",
-        "grapheme-splitter": "^1.0.4",
+        "globals": "^13.19.0",
+        "graphemer": "^1.4.0",
         "ignore": "^5.2.0",
-        "import-fresh": "^3.0.0",
         "imurmurhash": "^0.1.4",
         "is-glob": "^4.0.0",
         "is-path-inside": "^3.0.3",
-        "js-sdsl": "^4.1.4",
         "js-yaml": "^4.1.0",
         "json-stable-stringify-without-jsonify": "^1.0.1",
         "levn": "^0.4.1",
         "lodash.merge": "^4.6.2",
         "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
-        "optionator": "^0.9.1",
-        "regexpp": "^3.2.0",
+        "optionator": "^0.9.3",
         "strip-ansi": "^6.0.1",
-        "strip-json-comments": "^3.1.0",
         "text-table": "^0.2.0"
       },
       "bin": {
@@ -2752,85 +3002,164 @@
       }
     },
     "node_modules/eslint-scope": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
-      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
       "dev": true,
       "dependencies": {
         "esrecurse": "^4.3.0",
-        "estraverse": "^4.1.1"
+        "estraverse": "^5.2.0"
       },
       "engines": {
-        "node": ">=8.0.0"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/eslint-utils": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
-      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
       "dev": true,
       "dependencies": {
-        "eslint-visitor-keys": "^2.0.0"
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
       },
       "engines": {
-        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+        "node": ">=10"
       },
       "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/eslint/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
       },
-      "peerDependencies": {
-        "eslint": ">=5"
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+    "node_modules/eslint/node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
       "dev": true,
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
       "engines": {
         "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/eslint-visitor-keys": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
-      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+    "node_modules/eslint/node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
       "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": ">=10.13.0"
       }
     },
-    "node_modules/eslint/node_modules/eslint-scope": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
-      "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+    "node_modules/eslint/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/eslint/node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
       "dev": true,
       "dependencies": {
-        "esrecurse": "^4.3.0",
-        "estraverse": "^5.2.0"
+        "p-locate": "^5.0.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/eslint/node_modules/estraverse": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+    "node_modules/eslint/node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
       "dev": true,
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
       "engines": {
-        "node": ">=4.0"
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
       }
     },
     "node_modules/espree": {
-      "version": "9.4.0",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz",
-      "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==",
+      "version": "9.6.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
       "dev": true,
       "dependencies": {
-        "acorn": "^8.8.0",
+        "acorn": "^8.9.0",
         "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^3.3.0"
+        "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -2853,9 +3182,9 @@
       }
     },
     "node_modules/esquery": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
-      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+      "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
       "dev": true,
       "dependencies": {
         "estraverse": "^5.1.0"
@@ -2864,15 +3193,6 @@
         "node": ">=0.10"
       }
     },
-    "node_modules/esquery/node_modules/estraverse": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-      "dev": true,
-      "engines": {
-        "node": ">=4.0"
-      }
-    },
     "node_modules/esrecurse": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -2885,7 +3205,7 @@
         "node": ">=4.0"
       }
     },
-    "node_modules/esrecurse/node_modules/estraverse": {
+    "node_modules/estraverse": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
       "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
@@ -2894,15 +3214,6 @@
         "node": ">=4.0"
       }
     },
-    "node_modules/estraverse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
-      "dev": true,
-      "engines": {
-        "node": ">=4.0"
-      }
-    },
     "node_modules/esutils": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -2913,14 +3224,14 @@
       }
     },
     "node_modules/execa": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz",
-      "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==",
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
+      "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
       "dev": true,
       "dependencies": {
         "cross-spawn": "^7.0.3",
         "get-stream": "^6.0.1",
-        "human-signals": "^3.0.1",
+        "human-signals": "^4.3.0",
         "is-stream": "^3.0.0",
         "merge-stream": "^2.0.0",
         "npm-run-path": "^5.1.0",
@@ -2929,24 +3240,12 @@
         "strip-final-newline": "^3.0.0"
       },
       "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+        "node": "^14.18.0 || ^16.14.0 || >=18.0.0"
       },
       "funding": {
         "url": "https://github.com/sindresorhus/execa?sponsor=1"
       }
     },
-    "node_modules/execa/node_modules/is-stream": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
-      "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
-      "dev": true,
-      "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/external-editor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
@@ -2968,9 +3267,9 @@
       "dev": true
     },
     "node_modules/fast-glob": {
-      "version": "3.2.12",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
-      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
       "dev": true,
       "dependencies": {
         "@nodelib/fs.stat": "^2.0.2",
@@ -2983,18 +3282,6 @@
         "node": ">=8.6.0"
       }
     },
-    "node_modules/fast-glob/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/fast-json-stable-stringify": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -3008,9 +3295,9 @@
       "dev": true
     },
     "node_modules/fastq": {
-      "version": "1.13.0",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
-      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
       "dev": true,
       "dependencies": {
         "reusify": "^1.0.4"
@@ -3055,30 +3342,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/figures/node_modules/escape-string-regexp": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-      "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
-      "dev": true,
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/figures/node_modules/is-unicode-supported": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
-      "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/file-entry-cache": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -3091,15 +3354,6 @@
         "node": "^10.12.0 || >=12.0.0"
       }
     },
-    "node_modules/file-uri-to-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
-      "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==",
-      "dev": true,
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/filename-reserved-regex": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
@@ -3156,19 +3410,16 @@
       }
     },
     "node_modules/find-up": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
       "dev": true,
       "dependencies": {
-        "locate-path": "^6.0.0",
+        "locate-path": "^5.0.0",
         "path-exists": "^4.0.0"
       },
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=8"
       }
     },
     "node_modules/flat": {
@@ -3181,24 +3432,34 @@
       }
     },
     "node_modules/flat-cache": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
-      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz",
+      "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==",
       "dev": true,
       "dependencies": {
-        "flatted": "^3.1.0",
+        "flatted": "^3.2.7",
+        "keyv": "^4.5.3",
         "rimraf": "^3.0.2"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": ">=12.0.0"
       }
     },
     "node_modules/flatted": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
-      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+      "version": "3.2.9",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
+      "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
       "dev": true
     },
+    "node_modules/for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "dependencies": {
+        "is-callable": "^1.1.3"
+      }
+    },
     "node_modules/foreground-child": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
@@ -3212,24 +3473,10 @@
         "node": ">=8.0.0"
       }
     },
-    "node_modules/form-data": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
-      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
-      "dev": true,
-      "dependencies": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.8",
-        "mime-types": "^2.1.12"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/form-data-encoder": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.3.tgz",
-      "integrity": "sha512-KqU0nnPMgIJcCOFTNJFEA8epcseEaoox4XZffTgy8jlI6pL/5EFyR54NRG7CnCJN0biY7q52DO3MH6/sJ/TKlQ==",
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+      "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==",
       "dev": true,
       "engines": {
         "node": ">= 14.17"
@@ -3268,17 +3515,17 @@
       ]
     },
     "node_modules/fs-extra": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
-      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "version": "11.1.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz",
+      "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==",
       "dev": true,
       "dependencies": {
         "graceful-fs": "^4.2.0",
-        "jsonfile": "^4.0.0",
-        "universalify": "^0.1.0"
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
       },
       "engines": {
-        "node": ">=6 <7 || >=8"
+        "node": ">=14.14"
       }
     },
     "node_modules/fs.realpath": {
@@ -3288,9 +3535,9 @@
       "dev": true
     },
     "node_modules/fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
       "dev": true,
       "hasInstallScript": true,
       "optional": true,
@@ -3301,43 +3548,6 @@
         "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
       }
     },
-    "node_modules/ftp": {
-      "version": "0.3.10",
-      "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz",
-      "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==",
-      "dev": true,
-      "dependencies": {
-        "readable-stream": "1.1.x",
-        "xregexp": "2.0.0"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/ftp/node_modules/isarray": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-      "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
-      "dev": true
-    },
-    "node_modules/ftp/node_modules/readable-stream": {
-      "version": "1.1.14",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
-      "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
-      "dev": true,
-      "dependencies": {
-        "core-util-is": "~1.0.0",
-        "inherits": "~2.0.1",
-        "isarray": "0.0.1",
-        "string_decoder": "~0.10.x"
-      }
-    },
-    "node_modules/ftp/node_modules/string_decoder": {
-      "version": "0.10.31",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-      "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
-      "dev": true
-    },
     "node_modules/function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -3345,15 +3555,15 @@
       "dev": true
     },
     "node_modules/function.prototype.name": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
-      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
+      "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.0",
-        "functions-have-names": "^1.2.2"
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1",
+        "functions-have-names": "^1.2.3"
       },
       "engines": {
         "node": ">= 0.4"
@@ -3398,13 +3608,14 @@
       }
     },
     "node_modules/get-intrinsic": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
-      "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
+      "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
       "dev": true,
       "dependencies": {
         "function-bind": "^1.1.1",
         "has": "^1.0.3",
+        "has-proto": "^1.0.1",
         "has-symbols": "^1.0.3"
       },
       "funding": {
@@ -3449,79 +3660,81 @@
       }
     },
     "node_modules/get-uri": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz",
-      "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz",
+      "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==",
       "dev": true,
       "dependencies": {
-        "@tootallnate/once": "1",
-        "data-uri-to-buffer": "3",
-        "debug": "4",
-        "file-uri-to-path": "2",
-        "fs-extra": "^8.1.0",
-        "ftp": "^0.3.10"
+        "basic-ftp": "^5.0.2",
+        "data-uri-to-buffer": "^5.0.1",
+        "debug": "^4.3.4",
+        "fs-extra": "^8.1.0"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 14"
       }
     },
     "node_modules/get-uri/node_modules/data-uri-to-buffer": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
-      "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz",
+      "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==",
       "dev": true,
       "engines": {
-        "node": ">= 6"
+        "node": ">= 14"
       }
     },
-    "node_modules/gh-pages": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-4.0.0.tgz",
-      "integrity": "sha512-p8S0T3aGJc68MtwOcZusul5qPSNZCalap3NWbhRUZYu1YOdp+EjZ+4kPmRM8h3NNRdqw00yuevRjlkuSzCn7iQ==",
+    "node_modules/get-uri/node_modules/fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
       "dev": true,
       "dependencies": {
-        "async": "^2.6.1",
-        "commander": "^2.18.0",
-        "email-addresses": "^3.0.1",
-        "filenamify": "^4.3.0",
-        "find-cache-dir": "^3.3.1",
-        "fs-extra": "^8.1.0",
-        "globby": "^6.1.0"
-      },
-      "bin": {
-        "gh-pages": "bin/gh-pages.js",
-        "gh-pages-clean": "bin/gh-pages-clean.js"
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=6 <7 || >=8"
       }
     },
-    "node_modules/gh-pages/node_modules/array-union": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
-      "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+    "node_modules/get-uri/node_modules/jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "dev": true,
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/get-uri/node_modules/universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
       "dev": true,
-      "dependencies": {
-        "array-uniq": "^1.0.1"
-      },
       "engines": {
-        "node": ">=0.10.0"
+        "node": ">= 4.0.0"
       }
     },
-    "node_modules/gh-pages/node_modules/globby": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
-      "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
+    "node_modules/gh-pages": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.0.0.tgz",
+      "integrity": "sha512-FXZWJRsvP/fK2HJGY+Di6FRNHvqFF6gOIELaopDjXXgjeOYSNURcuYwEO/6bwuq6koP5Lnkvnr5GViXzuOB89g==",
       "dev": true,
       "dependencies": {
-        "array-union": "^1.0.1",
-        "glob": "^7.0.3",
-        "object-assign": "^4.0.1",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
+        "async": "^3.2.4",
+        "commander": "^11.0.0",
+        "email-addresses": "^5.0.0",
+        "filenamify": "^4.3.0",
+        "find-cache-dir": "^3.3.1",
+        "fs-extra": "^11.1.1",
+        "globby": "^6.1.0"
+      },
+      "bin": {
+        "gh-pages": "bin/gh-pages.js",
+        "gh-pages-clean": "bin/gh-pages-clean.js"
       },
       "engines": {
-        "node": ">=0.10.0"
+        "node": ">=10"
       }
     },
     "node_modules/git-up": {
@@ -3544,15 +3757,15 @@
       }
     },
     "node_modules/glob": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
-      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
       "dev": true,
       "dependencies": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
         "inherits": "2",
-        "minimatch": "^3.0.4",
+        "minimatch": "^3.1.1",
         "once": "^1.3.0",
         "path-is-absolute": "^1.0.0"
       },
@@ -3564,21 +3777,21 @@
       }
     },
     "node_modules/glob-parent": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
       "dev": true,
       "dependencies": {
-        "is-glob": "^4.0.3"
+        "is-glob": "^4.0.1"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">= 6"
       }
     },
     "node_modules/global-dirs": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz",
-      "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+      "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
       "dev": true,
       "dependencies": {
         "ini": "2.0.0"
@@ -3591,9 +3804,9 @@
       }
     },
     "node_modules/globals": {
-      "version": "13.17.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
-      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+      "version": "13.21.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+      "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
       "dev": true,
       "dependencies": {
         "type-fest": "^0.20.2"
@@ -3605,36 +3818,71 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/globals/node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
+      "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+      "dev": true,
+      "dependencies": {
+        "define-properties": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/globby": {
-      "version": "11.1.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
-      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+      "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
       "dev": true,
       "dependencies": {
-        "array-union": "^2.1.0",
-        "dir-glob": "^3.0.1",
-        "fast-glob": "^3.2.9",
-        "ignore": "^5.2.0",
-        "merge2": "^1.4.1",
-        "slash": "^3.0.0"
+        "array-union": "^1.0.1",
+        "glob": "^7.0.3",
+        "object-assign": "^4.0.1",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.3"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/got": {
-      "version": "12.5.1",
-      "resolved": "https://registry.npmjs.org/got/-/got-12.5.1.tgz",
-      "integrity": "sha512-sD16AK8cCyUoPtKr/NMvLTFFa+T3i3S+zoiuvhq0HP2YiqBZA9AtlBjAdsQBsLBK7slPuvmfE0OxhGi7N5dD4w==",
+      "version": "13.0.0",
+      "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz",
+      "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==",
       "dev": true,
       "dependencies": {
         "@sindresorhus/is": "^5.2.0",
         "@szmarczak/http-timer": "^5.0.1",
         "cacheable-lookup": "^7.0.0",
-        "cacheable-request": "^10.2.1",
+        "cacheable-request": "^10.2.8",
         "decompress-response": "^6.0.0",
         "form-data-encoder": "^2.1.2",
         "get-stream": "^6.0.1",
@@ -3644,22 +3892,22 @@
         "responselike": "^3.0.0"
       },
       "engines": {
-        "node": ">=14.16"
+        "node": ">=16"
       },
       "funding": {
         "url": "https://github.com/sindresorhus/got?sponsor=1"
       }
     },
     "node_modules/graceful-fs": {
-      "version": "4.2.10",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
-      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
       "dev": true
     },
-    "node_modules/grapheme-splitter": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
-      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
       "dev": true
     },
     "node_modules/has": {
@@ -3684,12 +3932,12 @@
       }
     },
     "node_modules/has-flag": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
       "dev": true,
       "engines": {
-        "node": ">=8"
+        "node": ">=4"
       }
     },
     "node_modules/has-property-descriptors": {
@@ -3704,6 +3952,18 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/has-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/has-symbols": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
@@ -3759,6 +4019,18 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/hasha/node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/hasha/node_modules/type-fest": {
       "version": "0.8.1",
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
@@ -3784,45 +4056,28 @@
       "dev": true
     },
     "node_modules/http-cache-semantics": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
-      "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
       "dev": true
     },
-    "node_modules/http-errors": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
-      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
-      "dev": true,
-      "dependencies": {
-        "depd": "2.0.0",
-        "inherits": "2.0.4",
-        "setprototypeof": "1.2.0",
-        "statuses": "2.0.1",
-        "toidentifier": "1.0.1"
-      },
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/http-proxy-agent": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
-      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz",
+      "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==",
       "dev": true,
       "dependencies": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4"
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 14"
       }
     },
     "node_modules/http2-wrapper": {
-      "version": "2.1.11",
-      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz",
-      "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz",
+      "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==",
       "dev": true,
       "dependencies": {
         "quick-lru": "^5.1.1",
@@ -3833,25 +4088,25 @@
       }
     },
     "node_modules/https-proxy-agent": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
-      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==",
       "dev": true,
       "dependencies": {
-        "agent-base": "6",
+        "agent-base": "^7.0.2",
         "debug": "4"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 14"
       }
     },
     "node_modules/human-signals": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz",
-      "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==",
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
+      "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
       "dev": true,
       "engines": {
-        "node": ">=12.20.0"
+        "node": ">=14.18.0"
       }
     },
     "node_modules/iconv-lite": {
@@ -3887,9 +4142,9 @@
       ]
     },
     "node_modules/ignore": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
-      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "version": "5.2.4",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
       "dev": true,
       "engines": {
         "node": ">= 4"
@@ -3964,77 +4219,186 @@
       }
     },
     "node_modules/inquirer": {
-      "version": "9.1.2",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.1.2.tgz",
-      "integrity": "sha512-Hj2Ml1WpxKJU2npP2Rj0OURGkHV+GtNW2CwFdHDiXlqUBAUrWTcZHxCkFywX/XHzOS7wrG/kExgJFbUkVgyHzg==",
+      "version": "9.2.10",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.10.tgz",
+      "integrity": "sha512-tVVNFIXU8qNHoULiazz612GFl+yqNfjMTbLuViNJE/d860Qxrd3NMrse8dm40VUQLOQeULvaQF8lpAhvysjeyA==",
       "dev": true,
       "dependencies": {
-        "ansi-escapes": "^5.0.0",
-        "chalk": "^5.0.1",
-        "cli-cursor": "^4.0.0",
-        "cli-width": "^4.0.0",
-        "external-editor": "^3.0.3",
+        "@ljharb/through": "^2.3.9",
+        "ansi-escapes": "^4.3.2",
+        "chalk": "^5.3.0",
+        "cli-cursor": "^3.1.0",
+        "cli-width": "^4.1.0",
+        "external-editor": "^3.1.0",
         "figures": "^5.0.0",
         "lodash": "^4.17.21",
-        "mute-stream": "0.0.8",
-        "ora": "^6.1.2",
-        "run-async": "^2.4.0",
-        "rxjs": "^7.5.6",
-        "string-width": "^5.1.2",
-        "strip-ansi": "^7.0.1",
-        "through": "^2.3.6",
-        "wrap-ansi": "^8.0.1"
+        "mute-stream": "1.0.0",
+        "ora": "^5.4.1",
+        "run-async": "^3.0.0",
+        "rxjs": "^7.8.1",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^6.2.0"
       },
       "engines": {
-        "node": ">=12.0.0"
+        "node": ">=14.18.0"
       }
     },
-    "node_modules/inquirer/node_modules/ansi-regex": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+    "node_modules/inquirer/node_modules/bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
       "dev": true,
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      "dependencies": {
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
       }
     },
-    "node_modules/inquirer/node_modules/chalk": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-      "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
+    "node_modules/inquirer/node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
       "dev": true,
-      "engines": {
-        "node": "^12.17.0 || ^14.13 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
       }
     },
-    "node_modules/inquirer/node_modules/strip-ansi": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-      "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+    "node_modules/inquirer/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
       "dev": true,
-      "dependencies": {
-        "ansi-regex": "^6.0.1"
-      },
       "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+        "node": ">=8"
       }
     },
-    "node_modules/internal-slot": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
-      "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+    "node_modules/inquirer/node_modules/is-interactive": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+      "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/inquirer/node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/inquirer/node_modules/log-symbols/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/inquirer/node_modules/ora": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+      "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+      "dev": true,
+      "dependencies": {
+        "bl": "^4.1.0",
+        "chalk": "^4.1.0",
+        "cli-cursor": "^3.1.0",
+        "cli-spinners": "^2.5.0",
+        "is-interactive": "^1.0.0",
+        "is-unicode-supported": "^0.1.0",
+        "log-symbols": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "wcwidth": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/inquirer/node_modules/ora/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
       "dev": true,
       "dependencies": {
-        "get-intrinsic": "^1.1.0",
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/inquirer/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/internal-slot": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
+      "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.2.0",
         "has": "^1.0.3",
         "side-channel": "^1.0.4"
       },
@@ -4073,6 +4437,20 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-array-buffer": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
+      "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.2.0",
+        "is-typed-array": "^1.1.10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-arrayish": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -4144,9 +4522,9 @@
       }
     },
     "node_modules/is-core-module": {
-      "version": "2.11.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
-      "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+      "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
       "dev": true,
       "dependencies": {
         "has": "^1.0.3"
@@ -4171,15 +4549,15 @@
       }
     },
     "node_modules/is-docker": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
-      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
       "dev": true,
       "bin": {
         "is-docker": "cli.js"
       },
       "engines": {
-        "node": ">=8"
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -4215,6 +4593,24 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "dev": true,
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-installed-globally": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
@@ -4383,12 +4779,12 @@
       }
     },
     "node_modules/is-stream": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+      "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
       "dev": true,
       "engines": {
-        "node": ">=8"
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -4424,6 +4820,21 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-typed-array": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
+      "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
+      "dev": true,
+      "dependencies": {
+        "which-typed-array": "^1.1.11"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-typedarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -4431,12 +4842,12 @@
       "dev": true
     },
     "node_modules/is-unicode-supported": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
-      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+      "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
       "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">=12"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -4475,10 +4886,25 @@
         "node": ">=8"
       }
     },
+    "node_modules/is-wsl/node_modules/is-docker": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+      "dev": true,
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-yarn-global": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz",
-      "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz",
+      "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==",
       "dev": true,
       "engines": {
         "node": ">=12"
@@ -4496,6 +4922,22 @@
       "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
       "dev": true
     },
+    "node_modules/issue-parser": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz",
+      "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==",
+      "dev": true,
+      "dependencies": {
+        "lodash.capitalize": "^4.2.1",
+        "lodash.escaperegexp": "^4.1.2",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.isstring": "^4.0.1",
+        "lodash.uniqby": "^4.7.0"
+      },
+      "engines": {
+        "node": ">=10.13"
+      }
+    },
     "node_modules/istanbul-lib-coverage": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
@@ -4532,15 +4974,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/istanbul-lib-instrument/node_modules/semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-      "dev": true,
-      "bin": {
-        "semver": "bin/semver.js"
-      }
-    },
     "node_modules/istanbul-lib-processinfo": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
@@ -4559,15 +4992,78 @@
       }
     },
     "node_modules/istanbul-lib-report": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
-      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+      "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
       "dev": true,
       "dependencies": {
         "istanbul-lib-coverage": "^3.0.0",
-        "make-dir": "^3.0.0",
+        "make-dir": "^4.0.0",
         "supports-color": "^7.1.0"
       },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/make-dir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+      "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^7.5.3"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
       "engines": {
         "node": ">=8"
       }
@@ -4587,9 +5083,9 @@
       }
     },
     "node_modules/istanbul-reports": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
-      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz",
+      "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==",
       "dev": true,
       "dependencies": {
         "html-escaper": "^2.0.0",
@@ -4621,12 +5117,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/js-sdsl": {
-      "version": "4.1.5",
-      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
-      "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
-      "dev": true
-    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -4682,9 +5172,9 @@
       "dev": true
     },
     "node_modules/json5": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
-      "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
       "dev": true,
       "bin": {
         "json5": "lib/cli.js"
@@ -4700,10 +5190,13 @@
       "dev": true
     },
     "node_modules/jsonfile": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
-      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
       "dev": true,
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
       "optionalDependencies": {
         "graceful-fs": "^4.1.6"
       }
@@ -4715,9 +5208,9 @@
       "dev": true
     },
     "node_modules/keyv": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz",
-      "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==",
+      "version": "4.5.3",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
+      "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==",
       "dev": true,
       "dependencies": {
         "json-buffer": "3.0.1"
@@ -4758,18 +5251,15 @@
       "dev": true
     },
     "node_modules/locate-path": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
       "dev": true,
       "dependencies": {
-        "p-locate": "^5.0.0"
+        "p-locate": "^4.1.0"
       },
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=8"
       }
     },
     "node_modules/lodash": {
@@ -4778,10 +5268,22 @@
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
       "dev": true
     },
-    "node_modules/lodash.flattendeep": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
-      "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
+    "node_modules/lodash.capitalize": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz",
+      "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==",
+      "dev": true
+    },
+    "node_modules/lodash.escaperegexp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
+      "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==",
+      "dev": true
+    },
+    "node_modules/lodash.flattendeep": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+      "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
       "dev": true
     },
     "node_modules/lodash.get": {
@@ -4790,23 +5292,41 @@
       "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
       "dev": true
     },
+    "node_modules/lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+      "dev": true
+    },
+    "node_modules/lodash.isstring": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+      "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+      "dev": true
+    },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
+    "node_modules/lodash.uniqby": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
+      "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==",
+      "dev": true
+    },
     "node_modules/log-symbols": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
-      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
+      "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
       "dev": true,
       "dependencies": {
-        "chalk": "^4.1.0",
-        "is-unicode-supported": "^0.1.0"
+        "chalk": "^5.0.0",
+        "is-unicode-supported": "^1.1.0"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=12"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -4825,12 +5345,12 @@
       }
     },
     "node_modules/lru-cache": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "version": "7.18.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+      "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
       "dev": true,
-      "dependencies": {
-        "yallist": "^3.0.2"
+      "engines": {
+        "node": ">=12"
       }
     },
     "node_modules/lunr": {
@@ -4840,9 +5360,9 @@
       "dev": true
     },
     "node_modules/macos-release": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.1.0.tgz",
-      "integrity": "sha512-/M/R0gCDgM+Cv1IuBG1XGdfTFnMEG6PZeT+KGWHO/OG+imqmaD9CH5vHBTycEM3+Kc4uG2Il+tFAuUWLqQOeUA==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.2.0.tgz",
+      "integrity": "sha512-fSErXALFNsnowREYZ49XCdOHF8wOPWuFOGQrAhP7x5J/BqQv+B02cNsTykGpDgRVx43EKg++6ANmTaGTtW+hUA==",
       "dev": true,
       "engines": {
         "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
@@ -4866,15 +5386,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/make-dir/node_modules/semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-      "dev": true,
-      "bin": {
-        "semver": "bin/semver.js"
-      }
-    },
     "node_modules/make-error": {
       "version": "1.3.6",
       "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -4882,9 +5393,9 @@
       "dev": true
     },
     "node_modules/marked": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz",
-      "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==",
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+      "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
       "dev": true,
       "bin": {
         "marked": "bin/marked.js"
@@ -4979,18 +5490,18 @@
       }
     },
     "node_modules/minimist": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
-      "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
       "dev": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/mocha": {
-      "version": "10.1.0",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz",
-      "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==",
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+      "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
       "dev": true,
       "dependencies": {
         "ansi-colors": "4.1.1",
@@ -5027,13 +5538,32 @@
         "url": "https://opencollective.com/mochajs"
       }
     },
-    "node_modules/mocha/node_modules/brace-expansion": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+    "node_modules/mocha/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
       "dev": true,
       "dependencies": {
-        "balanced-match": "^1.0.0"
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/mocha/node_modules/chalk/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
       }
     },
     "node_modules/mocha/node_modules/cliui": {
@@ -5047,11 +5577,117 @@
         "wrap-ansi": "^7.0.0"
       }
     },
-    "node_modules/mocha/node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-      "dev": true
+    "node_modules/mocha/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/glob": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/mocha/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/mocha/node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
     },
     "node_modules/mocha/node_modules/minimatch": {
       "version": "5.0.1",
@@ -5065,24 +5701,61 @@
         "node": ">=10"
       }
     },
+    "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
     "node_modules/mocha/node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
       "dev": true
     },
-    "node_modules/mocha/node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+    "node_modules/mocha/node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
       "dev": true,
       "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
       },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
       "engines": {
         "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/mocha/node_modules/supports-color": {
@@ -5135,6 +5808,15 @@
         "node": ">=10"
       }
     },
+    "node_modules/mocha/node_modules/yargs-parser": {
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -5142,10 +5824,13 @@
       "dev": true
     },
     "node_modules/mute-stream": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
-      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
-      "dev": true
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
+      "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==",
+      "dev": true,
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
     },
     "node_modules/nanoid": {
       "version": "3.3.3",
@@ -5202,18 +5887,27 @@
       }
     },
     "node_modules/nise": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz",
-      "integrity": "sha512-yr5kW2THW1AkxVmCnKEh4nbYkJdB3I7LUkiUgOvEkOp414mc2UMaHMA7pjq1nYowhdoJZGwEKGaQVbxfpWj10A==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz",
+      "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==",
       "dev": true,
       "dependencies": {
-        "@sinonjs/commons": "^1.8.3",
-        "@sinonjs/fake-timers": ">=5",
+        "@sinonjs/commons": "^2.0.0",
+        "@sinonjs/fake-timers": "^10.0.2",
         "@sinonjs/text-encoding": "^0.7.1",
         "just-extend": "^4.0.2",
         "path-to-regexp": "^1.7.0"
       }
     },
+    "node_modules/nise/node_modules/@sinonjs/commons": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+      "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
+      "dev": true,
+      "dependencies": {
+        "type-detect": "4.0.8"
+      }
+    },
     "node_modules/node-domexception": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@@ -5234,9 +5928,9 @@
       }
     },
     "node_modules/node-fetch": {
-      "version": "3.2.10",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz",
-      "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==",
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
+      "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
       "dev": true,
       "dependencies": {
         "data-uri-to-buffer": "^4.0.0",
@@ -5264,9 +5958,9 @@
       }
     },
     "node_modules/node-releases": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
-      "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+      "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
       "dev": true
     },
     "node_modules/normalize-path": {
@@ -5279,12 +5973,12 @@
       }
     },
     "node_modules/normalize-url": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-7.2.0.tgz",
-      "integrity": "sha512-uhXOdZry0L6M2UIo9BTt7FdpBDiAGN/7oItedQwPKh8jh31ZlvC8U9Xl/EJ3aijDHaywXTW3QbZ6LuCocur1YA==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz",
+      "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==",
       "dev": true,
       "engines": {
-        "node": ">=12.20"
+        "node": ">=14.16"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -5358,73 +6052,24 @@
         "node": ">=8.9"
       }
     },
-    "node_modules/nyc/node_modules/cliui": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
-      "dev": true,
-      "dependencies": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.0",
-        "wrap-ansi": "^6.2.0"
-      }
-    },
-    "node_modules/nyc/node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-      "dev": true
-    },
-    "node_modules/nyc/node_modules/find-up": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-      "dev": true,
-      "dependencies": {
-        "locate-path": "^5.0.0",
-        "path-exists": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/nyc/node_modules/locate-path": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-      "dev": true,
-      "dependencies": {
-        "p-locate": "^4.1.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/nyc/node_modules/p-limit": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+    "node_modules/nyc/node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
       "dev": true,
-      "dependencies": {
-        "p-try": "^2.0.0"
-      },
       "engines": {
         "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/nyc/node_modules/p-locate": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+    "node_modules/nyc/node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
       "dev": true,
       "dependencies": {
-        "p-limit": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=8"
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
       }
     },
     "node_modules/nyc/node_modules/resolve-from": {
@@ -5436,34 +6081,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/nyc/node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dev": true,
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/nyc/node_modules/wrap-ansi": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
-      "dev": true,
-      "dependencies": {
-        "ansi-styles": "^4.0.0",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/nyc/node_modules/y18n": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
@@ -5515,9 +6132,9 @@
       }
     },
     "node_modules/object-inspect": {
-      "version": "1.12.2",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
-      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+      "version": "1.12.3",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+      "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
       "dev": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -5575,57 +6192,58 @@
       }
     },
     "node_modules/open": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz",
-      "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==",
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz",
+      "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==",
       "dev": true,
       "dependencies": {
-        "define-lazy-prop": "^2.0.0",
-        "is-docker": "^2.1.1",
+        "default-browser": "^4.0.0",
+        "define-lazy-prop": "^3.0.0",
+        "is-inside-container": "^1.0.0",
         "is-wsl": "^2.2.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=14.16"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/optionator": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
-      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+      "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
       "dev": true,
       "dependencies": {
+        "@aashutoshrathi/word-wrap": "^1.2.3",
         "deep-is": "^0.1.3",
         "fast-levenshtein": "^2.0.6",
         "levn": "^0.4.1",
         "prelude-ls": "^1.2.1",
-        "type-check": "^0.4.0",
-        "word-wrap": "^1.2.3"
+        "type-check": "^0.4.0"
       },
       "engines": {
         "node": ">= 0.8.0"
       }
     },
     "node_modules/ora": {
-      "version": "6.1.2",
-      "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz",
-      "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==",
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz",
+      "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==",
       "dev": true,
       "dependencies": {
-        "bl": "^5.0.0",
-        "chalk": "^5.0.0",
+        "chalk": "^5.3.0",
         "cli-cursor": "^4.0.0",
-        "cli-spinners": "^2.6.1",
+        "cli-spinners": "^2.9.0",
         "is-interactive": "^2.0.0",
-        "is-unicode-supported": "^1.1.0",
+        "is-unicode-supported": "^1.3.0",
         "log-symbols": "^5.1.0",
-        "strip-ansi": "^7.0.1",
-        "wcwidth": "^1.0.1"
+        "stdin-discarder": "^0.1.0",
+        "string-width": "^6.1.0",
+        "strip-ansi": "^7.1.0"
       },
       "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+        "node": ">=16"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -5643,50 +6261,88 @@
         "url": "https://github.com/chalk/ansi-regex?sponsor=1"
       }
     },
-    "node_modules/ora/node_modules/chalk": {
+    "node_modules/ora/node_modules/cli-cursor": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
+      "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
+      "dev": true,
+      "dependencies": {
+        "restore-cursor": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ora/node_modules/emoji-regex": {
+      "version": "10.2.1",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.2.1.tgz",
+      "integrity": "sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==",
+      "dev": true
+    },
+    "node_modules/ora/node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/ora/node_modules/onetime": {
       "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-      "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
       "dev": true,
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
       "engines": {
-        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+        "node": ">=6"
       },
       "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/ora/node_modules/is-unicode-supported": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
-      "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+    "node_modules/ora/node_modules/restore-cursor": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
+      "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
       "dev": true,
+      "dependencies": {
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      },
       "engines": {
-        "node": ">=12"
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/ora/node_modules/log-symbols": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
-      "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
+    "node_modules/ora/node_modules/string-width": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz",
+      "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==",
       "dev": true,
       "dependencies": {
-        "chalk": "^5.0.0",
-        "is-unicode-supported": "^1.1.0"
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^10.2.1",
+        "strip-ansi": "^7.0.1"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=16"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/ora/node_modules/strip-ansi": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-      "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
       "dev": true,
       "dependencies": {
         "ansi-regex": "^6.0.1"
@@ -5699,12 +6355,12 @@
       }
     },
     "node_modules/os-name": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/os-name/-/os-name-5.0.1.tgz",
-      "integrity": "sha512-0EQpaHUHq7olp2/YFUr+0vZi9tMpDTblHGz+Ch5RntKxiRXOAY0JOz1UlxhSjMSksHvkm13eD6elJj3M8Ht/kw==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/os-name/-/os-name-5.1.0.tgz",
+      "integrity": "sha512-YEIoAnM6zFmzw3PQ201gCVCIWbXNyKObGlVvpAVvraAeOHnlYVKFssbA/riRX5R40WA6kKrZ7Dr7dWzO3nKSeQ==",
       "dev": true,
       "dependencies": {
-        "macos-release": "^3.0.1",
+        "macos-release": "^3.1.0",
         "windows-release": "^5.0.1"
       },
       "engines": {
@@ -5733,33 +6389,30 @@
       }
     },
     "node_modules/p-limit": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
       "dev": true,
       "dependencies": {
-        "yocto-queue": "^0.1.0"
+        "p-try": "^2.0.0"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=6"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/p-locate": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
       "dev": true,
       "dependencies": {
-        "p-limit": "^3.0.2"
+        "p-limit": "^2.2.0"
       },
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=8"
       }
     },
     "node_modules/p-map": {
@@ -5784,37 +6437,36 @@
       }
     },
     "node_modules/pac-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==",
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz",
+      "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==",
       "dev": true,
       "dependencies": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4",
-        "get-uri": "3",
-        "http-proxy-agent": "^4.0.1",
-        "https-proxy-agent": "5",
-        "pac-resolver": "^5.0.0",
-        "raw-body": "^2.2.0",
-        "socks-proxy-agent": "5"
+        "@tootallnate/quickjs-emscripten": "^0.23.0",
+        "agent-base": "^7.0.2",
+        "debug": "^4.3.4",
+        "get-uri": "^6.0.1",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.2",
+        "pac-resolver": "^7.0.0",
+        "socks-proxy-agent": "^8.0.2"
       },
       "engines": {
-        "node": ">= 8"
+        "node": ">= 14"
       }
     },
     "node_modules/pac-resolver": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz",
-      "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz",
+      "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==",
       "dev": true,
       "dependencies": {
-        "degenerator": "^3.0.2",
-        "ip": "^1.1.5",
+        "degenerator": "^5.0.0",
+        "ip": "^1.1.8",
         "netmask": "^2.0.2"
       },
       "engines": {
-        "node": ">= 8"
+        "node": ">= 14"
       }
     },
     "node_modules/package-hash": {
@@ -5833,9 +6485,9 @@
       }
     },
     "node_modules/package-json": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz",
-      "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==",
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz",
+      "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==",
       "dev": true,
       "dependencies": {
         "got": "^12.1.0",
@@ -5850,6 +6502,58 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/package-json/node_modules/got": {
+      "version": "12.6.1",
+      "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz",
+      "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==",
+      "dev": true,
+      "dependencies": {
+        "@sindresorhus/is": "^5.2.0",
+        "@szmarczak/http-timer": "^5.0.1",
+        "cacheable-lookup": "^7.0.0",
+        "cacheable-request": "^10.2.8",
+        "decompress-response": "^6.0.0",
+        "form-data-encoder": "^2.1.2",
+        "get-stream": "^6.0.1",
+        "http2-wrapper": "^2.1.10",
+        "lowercase-keys": "^3.0.0",
+        "p-cancelable": "^3.0.0",
+        "responselike": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/got?sponsor=1"
+      }
+    },
+    "node_modules/package-json/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/package-json/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -6015,90 +6719,38 @@
         "node": ">=8"
       }
     },
-    "node_modules/pkg-dir/node_modules/find-up": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
       "dev": true,
-      "dependencies": {
-        "locate-path": "^5.0.0",
-        "path-exists": "^4.0.0"
-      },
       "engines": {
-        "node": ">=8"
+        "node": ">= 0.8.0"
       }
     },
-    "node_modules/pkg-dir/node_modules/locate-path": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+    "node_modules/process-on-spawn": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
+      "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
       "dev": true,
       "dependencies": {
-        "p-locate": "^4.1.0"
+        "fromentries": "^1.2.0"
       },
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/pkg-dir/node_modules/p-limit": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+    "node_modules/promise.allsettled": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.6.tgz",
+      "integrity": "sha512-22wJUOD3zswWFqgwjNHa1965LvqTX87WPu/lreY2KSd7SVcERfuZ4GfUaOnJNnvtoIv2yXT/W00YIGMetXtFXg==",
       "dev": true,
       "dependencies": {
-        "p-try": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/pkg-dir/node_modules/p-locate": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-      "dev": true,
-      "dependencies": {
-        "p-limit": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/prelude-ls": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-      "dev": true,
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/process-on-spawn": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
-      "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
-      "dev": true,
-      "dependencies": {
-        "fromentries": "^1.2.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/promise.allsettled": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.5.tgz",
-      "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==",
-      "dev": true,
-      "dependencies": {
-        "array.prototype.map": "^1.0.4",
+        "array.prototype.map": "^1.0.5",
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1",
-        "get-intrinsic": "^1.1.1",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4",
+        "get-intrinsic": "^1.1.3",
         "iterate-value": "^1.0.2"
       },
       "engines": {
@@ -6121,22 +6773,22 @@
       "dev": true
     },
     "node_modules/proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==",
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz",
+      "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==",
       "dev": true,
       "dependencies": {
-        "agent-base": "^6.0.0",
-        "debug": "4",
-        "http-proxy-agent": "^4.0.0",
-        "https-proxy-agent": "^5.0.0",
-        "lru-cache": "^5.1.1",
-        "pac-proxy-agent": "^5.0.0",
-        "proxy-from-env": "^1.0.0",
-        "socks-proxy-agent": "^5.0.0"
+        "agent-base": "^7.0.2",
+        "debug": "^4.3.4",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.0",
+        "lru-cache": "^7.14.1",
+        "pac-proxy-agent": "^7.0.0",
+        "proxy-from-env": "^1.1.0",
+        "socks-proxy-agent": "^8.0.1"
       },
       "engines": {
-        "node": ">= 8"
+        "node": ">= 14"
       }
     },
     "node_modules/proxy-from-env": {
@@ -6146,9 +6798,9 @@
       "dev": true
     },
     "node_modules/punycode": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+      "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
       "dev": true,
       "engines": {
         "node": ">=6"
@@ -6210,21 +6862,6 @@
         "safe-buffer": "^5.1.0"
       }
     },
-    "node_modules/raw-body": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
-      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
-      "dev": true,
-      "dependencies": {
-        "bytes": "3.1.2",
-        "http-errors": "2.0.0",
-        "iconv-lite": "0.4.24",
-        "unpipe": "1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/rc": {
       "version": "1.2.8",
       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -6246,19 +6883,10 @@
       "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
       "dev": true
     },
-    "node_modules/rc/node_modules/strip-json-comments": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/readable-stream": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
       "dev": true,
       "dependencies": {
         "inherits": "^2.0.3",
@@ -6294,14 +6922,14 @@
       }
     },
     "node_modules/regexp.prototype.flags": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
-      "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz",
+      "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "functions-have-names": "^1.2.2"
+        "define-properties": "^1.2.0",
+        "set-function-name": "^2.0.0"
       },
       "engines": {
         "node": ">= 0.4"
@@ -6310,25 +6938,13 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/regexpp": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
-      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
-      }
-    },
     "node_modules/registry-auth-token": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz",
-      "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==",
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz",
+      "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==",
       "dev": true,
       "dependencies": {
-        "@pnpm/npm-conf": "^1.0.4"
+        "@pnpm/npm-conf": "^2.1.0"
       },
       "engines": {
         "node": ">=14"
@@ -6350,33 +6966,33 @@
       }
     },
     "node_modules/release-it": {
-      "version": "15.5.0",
-      "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.5.0.tgz",
-      "integrity": "sha512-/pQo/PwEXAWRBgVGLE+3IQ3hUoeiDZMGAo/Egin1envCyLyjzrU7+0P2w4iZ1Xv5OxhC2AcaPaN5eY1ql47cBA==",
+      "version": "16.1.5",
+      "resolved": "https://registry.npmjs.org/release-it/-/release-it-16.1.5.tgz",
+      "integrity": "sha512-w/zCljPZBSYcCwR9fjDB1zaYwie1CAQganUrwNqjtXacXhrrsS5E6dDUNLcxm2ypu8GWAgZNMJfuBJqIO2E7fA==",
       "dev": true,
       "dependencies": {
         "@iarna/toml": "2.2.5",
-        "@octokit/rest": "19.0.4",
+        "@octokit/rest": "19.0.13",
         "async-retry": "1.3.3",
-        "chalk": "5.0.1",
-        "cosmiconfig": "7.0.1",
-        "execa": "6.1.0",
-        "form-data": "4.0.0",
+        "chalk": "5.3.0",
+        "cosmiconfig": "8.2.0",
+        "execa": "7.2.0",
         "git-url-parse": "13.1.0",
-        "globby": "13.1.2",
-        "got": "12.5.1",
-        "inquirer": "9.1.2",
+        "globby": "13.2.2",
+        "got": "13.0.0",
+        "inquirer": "9.2.10",
         "is-ci": "3.0.1",
+        "issue-parser": "6.0.0",
         "lodash": "4.17.21",
         "mime-types": "2.1.35",
         "new-github-release-url": "2.0.0",
-        "node-fetch": "3.2.10",
-        "open": "8.4.0",
-        "ora": "6.1.2",
-        "os-name": "5.0.1",
-        "promise.allsettled": "1.0.5",
-        "proxy-agent": "5.0.0",
-        "semver": "7.3.7",
+        "node-fetch": "3.3.2",
+        "open": "9.1.0",
+        "ora": "7.0.1",
+        "os-name": "5.1.0",
+        "promise.allsettled": "1.0.6",
+        "proxy-agent": "6.3.0",
+        "semver": "7.5.4",
         "shelljs": "0.8.5",
         "update-notifier": "6.0.2",
         "url-join": "5.0.0",
@@ -6387,30 +7003,18 @@
         "release-it": "bin/release-it.js"
       },
       "engines": {
-        "node": ">=14.9"
-      }
-    },
-    "node_modules/release-it/node_modules/chalk": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz",
-      "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==",
-      "dev": true,
-      "engines": {
-        "node": "^12.17.0 || ^14.13 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
+        "node": ">=16"
       }
     },
     "node_modules/release-it/node_modules/globby": {
-      "version": "13.1.2",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz",
-      "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==",
+      "version": "13.2.2",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz",
+      "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
       "dev": true,
       "dependencies": {
         "dir-glob": "^3.0.1",
-        "fast-glob": "^3.2.11",
-        "ignore": "^5.2.0",
+        "fast-glob": "^3.3.0",
+        "ignore": "^5.2.4",
         "merge2": "^1.4.1",
         "slash": "^4.0.0"
       },
@@ -6434,9 +7038,9 @@
       }
     },
     "node_modules/release-it/node_modules/semver": {
-      "version": "7.3.7",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
       "dev": true,
       "dependencies": {
         "lru-cache": "^6.0.0"
@@ -6448,33 +7052,6 @@
         "node": ">=10"
       }
     },
-    "node_modules/release-it/node_modules/slash": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
-      "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
-      "dev": true,
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/release-it/node_modules/yallist": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
-    },
-    "node_modules/release-it/node_modules/yargs-parser": {
-      "version": "21.1.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-      "dev": true,
-      "engines": {
-        "node": ">=12"
-      }
-    },
     "node_modules/release-zalgo": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
@@ -6503,12 +7080,12 @@
       "dev": true
     },
     "node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.6",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
+      "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==",
       "dev": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.13.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -6550,19 +7127,16 @@
       }
     },
     "node_modules/restore-cursor": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
-      "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+      "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
       "dev": true,
       "dependencies": {
         "onetime": "^5.1.0",
         "signal-exit": "^3.0.2"
       },
       "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=8"
       }
     },
     "node_modules/restore-cursor/node_modules/mimic-fn": {
@@ -6623,10 +7197,114 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/run-applescript": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
+      "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==",
+      "dev": true,
+      "dependencies": {
+        "execa": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-applescript/node_modules/execa": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/run-applescript/node_modules/human-signals": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.17.0"
+      }
+    },
+    "node_modules/run-applescript/node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-applescript/node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/run-applescript/node_modules/npm-run-path": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/run-applescript/node_modules/onetime": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+      "dev": true,
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-applescript/node_modules/strip-final-newline": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/run-async": {
-      "version": "2.4.1",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
-      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
+      "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==",
       "dev": true,
       "engines": {
         "node": ">=0.12.0"
@@ -6656,14 +7334,32 @@
       }
     },
     "node_modules/rxjs": {
-      "version": "7.5.7",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
-      "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
+      "version": "7.8.1",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+      "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
       "dev": true,
       "dependencies": {
         "tslib": "^2.1.0"
       }
     },
+    "node_modules/safe-array-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz",
+      "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.2.1",
+        "has-symbols": "^1.0.3",
+        "isarray": "^2.0.5"
+      },
+      "engines": {
+        "node": ">=0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/safe-buffer": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -6705,18 +7401,12 @@
       "dev": true
     },
     "node_modules/semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
       "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
       "bin": {
         "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
       }
     },
     "node_modules/semver-diff": {
@@ -6734,7 +7424,7 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/semver/node_modules/lru-cache": {
+    "node_modules/semver-diff/node_modules/lru-cache": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
       "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
@@ -6746,11 +7436,20 @@
         "node": ">=10"
       }
     },
-    "node_modules/semver/node_modules/yallist": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
+    "node_modules/semver-diff/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
     },
     "node_modules/serialize-javascript": {
       "version": "6.0.0",
@@ -6767,11 +7466,19 @@
       "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
       "dev": true
     },
-    "node_modules/setprototypeof": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
-      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
-      "dev": true
+    "node_modules/set-function-name": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz",
+      "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==",
+      "dev": true,
+      "dependencies": {
+        "define-data-property": "^1.0.1",
+        "functions-have-names": "^1.2.3",
+        "has-property-descriptors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
     },
     "node_modules/shebang-command": {
       "version": "2.0.0",
@@ -6812,14 +7519,15 @@
       }
     },
     "node_modules/shiki": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz",
-      "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==",
+      "version": "0.14.4",
+      "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz",
+      "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==",
       "dev": true,
       "dependencies": {
-        "jsonc-parser": "^3.0.0",
-        "vscode-oniguruma": "^1.6.1",
-        "vscode-textmate": "^6.0.0"
+        "ansi-sequence-parser": "^1.1.0",
+        "jsonc-parser": "^3.2.0",
+        "vscode-oniguruma": "^1.7.0",
+        "vscode-textmate": "^8.0.0"
       }
     },
     "node_modules/side-channel": {
@@ -6843,16 +7551,16 @@
       "dev": true
     },
     "node_modules/sinon": {
-      "version": "14.0.1",
-      "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.1.tgz",
-      "integrity": "sha512-JhJ0jCiyBWVAHDS+YSjgEbDn7Wgz9iIjA1/RK+eseJN0vAAWIWiXBdrnb92ELPyjsfreCYntD1ORtLSfIrlvSQ==",
+      "version": "16.0.0",
+      "resolved": "https://registry.npmjs.org/sinon/-/sinon-16.0.0.tgz",
+      "integrity": "sha512-B8AaZZm9CT5pqe4l4uWJztfD/mOTa7dL8Qo0W4+s+t74xECOgSZDDQCBjNgIK3+n4kyxQrSTv2V5ul8K25qkiQ==",
       "dev": true,
       "dependencies": {
-        "@sinonjs/commons": "^1.8.3",
-        "@sinonjs/fake-timers": "^9.1.2",
-        "@sinonjs/samsam": "^6.1.1",
-        "diff": "^5.0.0",
-        "nise": "^5.1.1",
+        "@sinonjs/commons": "^3.0.0",
+        "@sinonjs/fake-timers": "^10.3.0",
+        "@sinonjs/samsam": "^8.0.0",
+        "diff": "^5.1.0",
+        "nise": "^5.1.4",
         "supports-color": "^7.2.0"
       },
       "funding": {
@@ -6860,15 +7568,48 @@
         "url": "https://opencollective.com/sinon"
       }
     },
-    "node_modules/slash": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+    "node_modules/sinon/node_modules/diff": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
+      "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/sinon/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/sinon/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
       "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
       "engines": {
         "node": ">=8"
       }
     },
+    "node_modules/slash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+      "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/smart-buffer": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
@@ -6894,17 +7635,17 @@
       }
     },
     "node_modules/socks-proxy-agent": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz",
-      "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==",
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz",
+      "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==",
       "dev": true,
       "dependencies": {
-        "agent-base": "^6.0.2",
-        "debug": "4",
-        "socks": "^2.3.3"
+        "agent-base": "^7.0.2",
+        "debug": "^4.3.4",
+        "socks": "^2.7.1"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 14"
       }
     },
     "node_modules/socks/node_modules/ip": {
@@ -6955,13 +7696,31 @@
       "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
       "dev": true
     },
-    "node_modules/statuses": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
-      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+    "node_modules/stdin-discarder": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
+      "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==",
+      "dev": true,
+      "dependencies": {
+        "bl": "^5.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/stop-iteration-iterator": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
+      "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
       "dev": true,
+      "dependencies": {
+        "internal-slot": "^1.0.4"
+      },
       "engines": {
-        "node": ">= 0.8"
+        "node": ">= 0.4"
       }
     },
     "node_modules/string_decoder": {
@@ -6974,72 +7733,59 @@
       }
     },
     "node_modules/string-width": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
-      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
       "dev": true,
       "dependencies": {
-        "eastasianwidth": "^0.2.0",
-        "emoji-regex": "^9.2.2",
-        "strip-ansi": "^7.0.1"
-      },
-      "engines": {
-        "node": ">=12"
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/string-width/node_modules/ansi-regex": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-      "dev": true,
       "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+        "node": ">=8"
       }
     },
-    "node_modules/string-width/node_modules/strip-ansi": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-      "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz",
+      "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==",
       "dev": true,
       "dependencies": {
-        "ansi-regex": "^6.0.1"
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">= 0.4"
       },
       "funding": {
-        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/string.prototype.trimend": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
-      "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz",
+      "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.4",
-        "es-abstract": "^1.19.5"
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/string.prototype.trimstart": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
-      "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz",
+      "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.4",
-        "es-abstract": "^1.19.5"
+        "define-properties": "^1.2.0",
+        "es-abstract": "^1.22.1"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -7079,15 +7825,12 @@
       }
     },
     "node_modules/strip-json-comments": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
       "dev": true,
       "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=0.10.0"
       }
     },
     "node_modules/strip-outer": {
@@ -7112,15 +7855,15 @@
       }
     },
     "node_modules/supports-color": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
       "dev": true,
       "dependencies": {
-        "has-flag": "^4.0.0"
+        "has-flag": "^3.0.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=4"
       }
     },
     "node_modules/supports-preserve-symlinks-flag": {
@@ -7155,11 +7898,17 @@
       "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
       "dev": true
     },
-    "node_modules/through": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
-      "dev": true
+    "node_modules/titleize": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
+      "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
     },
     "node_modules/tmp": {
       "version": "0.0.33",
@@ -7194,15 +7943,6 @@
         "node": ">=8.0"
       }
     },
-    "node_modules/toidentifier": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
-      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.6"
-      }
-    },
     "node_modules/tr46": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -7230,6 +7970,18 @@
         "node": ">=0.8.0"
       }
     },
+    "node_modules/ts-api-utils": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
+      "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
+      "dev": true,
+      "engines": {
+        "node": ">=16.13.0"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.2.0"
+      }
+    },
     "node_modules/ts-node": {
       "version": "10.9.1",
       "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
@@ -7273,6 +8025,12 @@
         }
       }
     },
+    "node_modules/ts-node/node_modules/@tsconfig/node14": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+      "dev": true
+    },
     "node_modules/ts-node/node_modules/diff": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@@ -7283,30 +8041,9 @@
       }
     },
     "node_modules/tslib": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
-      "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
-      "dev": true
-    },
-    "node_modules/tsutils": {
-      "version": "3.21.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
-      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
-      "dev": true,
-      "dependencies": {
-        "tslib": "^1.8.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      },
-      "peerDependencies": {
-        "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
-      }
-    },
-    "node_modules/tsutils/node_modules/tslib": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
       "dev": true
     },
     "node_modules/type-check": {
@@ -7331,9 +8068,9 @@
       }
     },
     "node_modules/type-fest": {
-      "version": "0.20.2",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "version": "0.21.3",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+      "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
       "dev": true,
       "engines": {
         "node": ">=10"
@@ -7342,6 +8079,71 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/typed-array-buffer": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz",
+      "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "get-intrinsic": "^1.2.1",
+        "is-typed-array": "^1.1.10"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/typed-array-byte-length": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz",
+      "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "has-proto": "^1.0.1",
+        "is-typed-array": "^1.1.10"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-byte-offset": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz",
+      "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==",
+      "dev": true,
+      "dependencies": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "has-proto": "^1.0.1",
+        "is-typed-array": "^1.1.10"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-length": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
+      "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "is-typed-array": "^1.1.9"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/typedarray-to-buffer": {
       "version": "3.1.5",
       "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -7352,24 +8154,24 @@
       }
     },
     "node_modules/typedoc": {
-      "version": "0.23.18",
-      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.18.tgz",
-      "integrity": "sha512-0Tq/uFkUuWyRYyjOShTkhsOm6u5E8wf0i6L76/k5znEaxvWKHGeT2ywZThGrDrryV/skO/REM824D1gm8ccQuA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.1.tgz",
+      "integrity": "sha512-c2ye3YUtGIadxN2O6YwPEXgrZcvhlZ6HlhWZ8jQRNzwLPn2ylhdGqdR8HbyDRyALP8J6lmSANILCkkIdNPFxqA==",
       "dev": true,
       "dependencies": {
         "lunr": "^2.3.9",
-        "marked": "^4.0.19",
-        "minimatch": "^5.1.0",
-        "shiki": "^0.11.1"
+        "marked": "^4.3.0",
+        "minimatch": "^9.0.3",
+        "shiki": "^0.14.1"
       },
       "bin": {
         "typedoc": "bin/typedoc"
       },
       "engines": {
-        "node": ">= 14.14"
+        "node": ">= 16"
       },
       "peerDependencies": {
-        "typescript": "4.6.x || 4.7.x || 4.8.x"
+        "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x"
       }
     },
     "node_modules/typedoc/node_modules/brace-expansion": {
@@ -7382,28 +8184,31 @@
       }
     },
     "node_modules/typedoc/node_modules/minimatch": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
-      "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
+      "version": "9.0.3",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
       "dev": true,
       "dependencies": {
         "brace-expansion": "^2.0.1"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
       }
     },
     "node_modules/typescript": {
-      "version": "4.8.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
-      "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
+      "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",
         "tsserver": "bin/tsserver"
       },
       "engines": {
-        "node": ">=4.2.0"
+        "node": ">=14.17"
       }
     },
     "node_modules/unbox-primitive": {
@@ -7443,27 +8248,27 @@
       "dev": true
     },
     "node_modules/universalify": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
-      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+      "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
       "dev": true,
       "engines": {
-        "node": ">= 4.0.0"
+        "node": ">= 10.0.0"
       }
     },
-    "node_modules/unpipe": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+    "node_modules/untildify": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
+      "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
       "dev": true,
       "engines": {
-        "node": ">= 0.8"
+        "node": ">=8"
       }
     },
     "node_modules/update-browserslist-db": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
-      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+      "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
       "dev": true,
       "funding": [
         {
@@ -7473,6 +8278,10 @@
         {
           "type": "tidelift",
           "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
         }
       ],
       "dependencies": {
@@ -7480,7 +8289,7 @@
         "picocolors": "^1.0.0"
       },
       "bin": {
-        "browserslist-lint": "cli.js"
+        "update-browserslist-db": "cli.js"
       },
       "peerDependencies": {
         "browserslist": ">= 4.21.0"
@@ -7514,16 +8323,31 @@
         "url": "https://github.com/yeoman/update-notifier?sponsor=1"
       }
     },
-    "node_modules/update-notifier/node_modules/chalk": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-      "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
+    "node_modules/update-notifier/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
       "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
       "engines": {
-        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+        "node": ">=10"
+      }
+    },
+    "node_modules/update-notifier/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
       },
-      "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
       }
     },
     "node_modules/uri-js": {
@@ -7565,32 +8389,16 @@
       "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
       "dev": true
     },
-    "node_modules/vm2": {
-      "version": "3.9.11",
-      "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.11.tgz",
-      "integrity": "sha512-PFG8iJRSjvvBdisowQ7iVF580DXb1uCIiGaXgm7tynMR1uTBlv7UJlB1zdv5KJ+Tmq1f0Upnj3fayoEOPpCBKg==",
-      "dev": true,
-      "dependencies": {
-        "acorn": "^8.7.0",
-        "acorn-walk": "^8.2.0"
-      },
-      "bin": {
-        "vm2": "bin/vm2"
-      },
-      "engines": {
-        "node": ">=6.0"
-      }
-    },
     "node_modules/vscode-oniguruma": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz",
-      "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==",
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
+      "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
       "dev": true
     },
     "node_modules/vscode-textmate": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz",
-      "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
+      "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
       "dev": true
     },
     "node_modules/wcwidth": {
@@ -7659,12 +8467,31 @@
       }
     },
     "node_modules/which-module": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
       "dev": true
     },
-    "node_modules/widest-line": {
+    "node_modules/which-typed-array": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz",
+      "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==",
+      "dev": true,
+      "dependencies": {
+        "available-typed-arrays": "^1.0.5",
+        "call-bind": "^1.0.2",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/widest-line": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz",
       "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==",
@@ -7679,6 +8506,56 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/widest-line/node_modules/ansi-regex": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/widest-line/node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true
+    },
+    "node_modules/widest-line/node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/widest-line/node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
     "node_modules/wildcard-match": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.2.tgz",
@@ -7686,9 +8563,9 @@
       "dev": true
     },
     "node_modules/windows-release": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.0.1.tgz",
-      "integrity": "sha512-y1xFdFvdMiDXI3xiOhMbJwt1Y7dUxidha0CWPs1NgjZIjZANTcX7+7bMqNjuezhzb8s5JGEiBAbQjQQYYy7ulw==",
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.1.1.tgz",
+      "integrity": "sha512-NMD00arvqcq2nwqc5Q6KtrSRHK+fVD31erE5FEMahAw5PmVCgD7MUXodq3pdZSUkqA9Cda2iWx6s1XYwiJWRmw==",
       "dev": true,
       "dependencies": {
         "execa": "^5.1.1"
@@ -7732,6 +8609,18 @@
         "node": ">=10.17.0"
       }
     },
+    "node_modules/windows-release/node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/windows-release/node_modules/mimic-fn": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -7777,15 +8666,6 @@
         "node": ">=6"
       }
     },
-    "node_modules/word-wrap": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
-      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/workerpool": {
       "version": "6.2.1",
       "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
@@ -7793,59 +8673,17 @@
       "dev": true
     },
     "node_modules/wrap-ansi": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz",
-      "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==",
-      "dev": true,
-      "dependencies": {
-        "ansi-styles": "^6.1.0",
-        "string-width": "^5.0.1",
-        "strip-ansi": "^7.0.1"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-      }
-    },
-    "node_modules/wrap-ansi/node_modules/ansi-regex": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-      "dev": true,
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
-      }
-    },
-    "node_modules/wrap-ansi/node_modules/ansi-styles": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
-      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
-      "dev": true,
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-      }
-    },
-    "node_modules/wrap-ansi/node_modules/strip-ansi": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-      "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
       "dev": true,
       "dependencies": {
-        "ansi-regex": "^6.0.1"
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
       },
       "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+        "node": ">=8"
       }
     },
     "node_modules/wrappy": {
@@ -7878,15 +8716,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/xregexp": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
-      "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==",
-      "dev": true,
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/y18n": {
       "version": "5.0.8",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -7897,24 +8726,14 @@
       }
     },
     "node_modules/yallist": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-      "dev": true
-    },
-    "node_modules/yaml": {
-      "version": "1.10.2",
-      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
-      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
-      "dev": true,
-      "engines": {
-        "node": ">= 6"
-      }
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
     },
     "node_modules/yargs": {
-      "version": "17.6.0",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz",
-      "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==",
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
       "dev": true,
       "dependencies": {
         "cliui": "^8.0.1",
@@ -7923,19 +8742,19 @@
         "require-directory": "^2.1.1",
         "string-width": "^4.2.3",
         "y18n": "^5.0.5",
-        "yargs-parser": "^21.0.0"
+        "yargs-parser": "^21.1.1"
       },
       "engines": {
         "node": ">=12"
       }
     },
     "node_modules/yargs-parser": {
-      "version": "20.2.4",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
-      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
       "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">=12"
       }
     },
     "node_modules/yargs-unparser": {
@@ -7977,35 +8796,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/yargs/node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-      "dev": true
-    },
-    "node_modules/yargs/node_modules/string-width": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-      "dev": true,
-      "dependencies": {
-        "emoji-regex": "^8.0.0",
-        "is-fullwidth-code-point": "^3.0.0",
-        "strip-ansi": "^6.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/yargs/node_modules/yargs-parser": {
-      "version": "21.1.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-      "dev": true,
-      "engines": {
-        "node": ">=12"
-      }
-    },
     "node_modules/yn": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
@@ -8029,18 +8819,18 @@
     },
     "packages/bloom": {
       "name": "@redis/bloom",
-      "version": "1.1.0",
+      "version": "1.2.0",
       "license": "MIT",
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
         "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
+        "@types/node": "^20.6.2",
         "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
+        "release-it": "^16.1.5",
         "source-map-support": "^0.5.21",
         "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
+        "typedoc": "^0.25.1",
+        "typescript": "^5.2.2"
       },
       "peerDependencies": {
         "@redis/client": "^1.0.0"
@@ -8048,52 +8838,48 @@
     },
     "packages/client": {
       "name": "@redis/client",
-      "version": "1.4.2",
+      "version": "1.6.0",
       "license": "MIT",
       "dependencies": {
-        "cluster-key-slot": "1.1.1",
+        "cluster-key-slot": "1.1.2",
         "generic-pool": "3.9.0",
         "yallist": "4.0.0"
       },
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
         "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
-        "@types/sinon": "^10.0.13",
+        "@types/node": "^20.6.2",
+        "@types/sinon": "^10.0.16",
         "@types/yallist": "^4.0.1",
-        "@typescript-eslint/eslint-plugin": "^5.41.0",
-        "@typescript-eslint/parser": "^5.41.0",
-        "eslint": "^8.26.0",
+        "@typescript-eslint/eslint-plugin": "^6.7.2",
+        "@typescript-eslint/parser": "^6.7.2",
+        "eslint": "^8.49.0",
         "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
-        "sinon": "^14.0.1",
+        "release-it": "^16.1.5",
+        "sinon": "^16.0.0",
         "source-map-support": "^0.5.21",
         "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
+        "typedoc": "^0.25.1",
+        "typescript": "^5.2.2"
       },
       "engines": {
         "node": ">=14"
       }
     },
-    "packages/client/node_modules/yallist": {
-      "version": "4.0.0",
-      "license": "ISC"
-    },
     "packages/graph": {
       "name": "@redis/graph",
-      "version": "1.1.0",
+      "version": "1.1.1",
       "license": "MIT",
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
         "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
+        "@types/node": "^20.6.2",
         "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
+        "release-it": "^16.1.5",
         "source-map-support": "^0.5.21",
         "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
+        "typedoc": "^0.25.1",
+        "typescript": "^5.2.2"
       },
       "peerDependencies": {
         "@redis/client": "^1.0.0"
@@ -8101,18 +8887,18 @@
     },
     "packages/json": {
       "name": "@redis/json",
-      "version": "1.0.4",
+      "version": "1.0.7",
       "license": "MIT",
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
         "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
+        "@types/node": "^20.6.2",
         "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
+        "release-it": "^16.1.5",
         "source-map-support": "^0.5.21",
         "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
+        "typedoc": "^0.25.1",
+        "typescript": "^5.2.2"
       },
       "peerDependencies": {
         "@redis/client": "^1.0.0"
@@ -8120,18 +8906,18 @@
     },
     "packages/search": {
       "name": "@redis/search",
-      "version": "1.1.0",
+      "version": "1.2.0",
       "license": "MIT",
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
         "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
+        "@types/node": "^20.6.2",
         "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
+        "release-it": "^16.1.5",
         "source-map-support": "^0.5.21",
         "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
+        "typedoc": "^0.25.1",
+        "typescript": "^5.2.2"
       },
       "peerDependencies": {
         "@redis/client": "^1.0.0"
@@ -8141,15 +8927,15 @@
       "name": "@redis/test-utils",
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@types/mocha": "^10.0.0",
-        "@types/node": "^18.11.6",
-        "@types/yargs": "^17.0.13",
-        "mocha": "^10.1.0",
+        "@types/mocha": "^10.0.1",
+        "@types/node": "^20.6.2",
+        "@types/yargs": "^17.0.24",
+        "mocha": "^10.2.0",
         "nyc": "^15.1.0",
         "source-map-support": "^0.5.21",
         "ts-node": "^10.9.1",
-        "typescript": "^4.8.4",
-        "yargs": "^17.6.0"
+        "typescript": "^5.2.2",
+        "yargs": "^17.7.2"
       },
       "peerDependencies": {
         "@redis/client": "^1.0.0"
@@ -8157,5951 +8943,22 @@
     },
     "packages/time-series": {
       "name": "@redis/time-series",
-      "version": "1.0.4",
+      "version": "1.1.0",
       "license": "MIT",
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
         "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
+        "@types/node": "^20.6.2",
         "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
+        "release-it": "^16.1.5",
         "source-map-support": "^0.5.21",
         "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
+        "typedoc": "^0.25.1",
+        "typescript": "^5.2.2"
       },
       "peerDependencies": {
         "@redis/client": "^1.0.0"
       }
     }
-  },
-  "dependencies": {
-    "@ampproject/remapping": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
-      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
-      "dev": true,
-      "requires": {
-        "@jridgewell/gen-mapping": "^0.1.0",
-        "@jridgewell/trace-mapping": "^0.3.9"
-      }
-    },
-    "@babel/code-frame": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
-      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
-      "dev": true,
-      "requires": {
-        "@babel/highlight": "^7.18.6"
-      }
-    },
-    "@babel/compat-data": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz",
-      "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==",
-      "dev": true
-    },
-    "@babel/core": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz",
-      "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==",
-      "dev": true,
-      "requires": {
-        "@ampproject/remapping": "^2.1.0",
-        "@babel/code-frame": "^7.18.6",
-        "@babel/generator": "^7.19.6",
-        "@babel/helper-compilation-targets": "^7.19.3",
-        "@babel/helper-module-transforms": "^7.19.6",
-        "@babel/helpers": "^7.19.4",
-        "@babel/parser": "^7.19.6",
-        "@babel/template": "^7.18.10",
-        "@babel/traverse": "^7.19.6",
-        "@babel/types": "^7.19.4",
-        "convert-source-map": "^1.7.0",
-        "debug": "^4.1.0",
-        "gensync": "^1.0.0-beta.2",
-        "json5": "^2.2.1",
-        "semver": "^6.3.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
-    },
-    "@babel/generator": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz",
-      "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.19.4",
-        "@jridgewell/gen-mapping": "^0.3.2",
-        "jsesc": "^2.5.1"
-      },
-      "dependencies": {
-        "@jridgewell/gen-mapping": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
-          "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
-          "dev": true,
-          "requires": {
-            "@jridgewell/set-array": "^1.0.1",
-            "@jridgewell/sourcemap-codec": "^1.4.10",
-            "@jridgewell/trace-mapping": "^0.3.9"
-          }
-        }
-      }
-    },
-    "@babel/helper-compilation-targets": {
-      "version": "7.19.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz",
-      "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==",
-      "dev": true,
-      "requires": {
-        "@babel/compat-data": "^7.19.3",
-        "@babel/helper-validator-option": "^7.18.6",
-        "browserslist": "^4.21.3",
-        "semver": "^6.3.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
-    },
-    "@babel/helper-environment-visitor": {
-      "version": "7.18.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
-      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
-      "dev": true
-    },
-    "@babel/helper-function-name": {
-      "version": "7.19.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
-      "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
-      "dev": true,
-      "requires": {
-        "@babel/template": "^7.18.10",
-        "@babel/types": "^7.19.0"
-      }
-    },
-    "@babel/helper-hoist-variables": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
-      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.18.6"
-      }
-    },
-    "@babel/helper-module-imports": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
-      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.18.6"
-      }
-    },
-    "@babel/helper-module-transforms": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz",
-      "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-module-imports": "^7.18.6",
-        "@babel/helper-simple-access": "^7.19.4",
-        "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/helper-validator-identifier": "^7.19.1",
-        "@babel/template": "^7.18.10",
-        "@babel/traverse": "^7.19.6",
-        "@babel/types": "^7.19.4"
-      }
-    },
-    "@babel/helper-simple-access": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz",
-      "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.19.4"
-      }
-    },
-    "@babel/helper-split-export-declaration": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
-      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.18.6"
-      }
-    },
-    "@babel/helper-string-parser": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
-      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
-      "dev": true
-    },
-    "@babel/helper-validator-identifier": {
-      "version": "7.19.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
-      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
-      "dev": true
-    },
-    "@babel/helper-validator-option": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
-      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
-      "dev": true
-    },
-    "@babel/helpers": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz",
-      "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==",
-      "dev": true,
-      "requires": {
-        "@babel/template": "^7.18.10",
-        "@babel/traverse": "^7.19.4",
-        "@babel/types": "^7.19.4"
-      }
-    },
-    "@babel/highlight": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
-      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.18.6",
-        "chalk": "^2.0.0",
-        "js-tokens": "^4.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
-          "dev": true
-        },
-        "escape-string-regexp": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "@babel/parser": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz",
-      "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==",
-      "dev": true
-    },
-    "@babel/template": {
-      "version": "7.18.10",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
-      "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.18.6",
-        "@babel/parser": "^7.18.10",
-        "@babel/types": "^7.18.10"
-      }
-    },
-    "@babel/traverse": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz",
-      "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.18.6",
-        "@babel/generator": "^7.19.6",
-        "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-function-name": "^7.19.0",
-        "@babel/helper-hoist-variables": "^7.18.6",
-        "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/parser": "^7.19.6",
-        "@babel/types": "^7.19.4",
-        "debug": "^4.1.0",
-        "globals": "^11.1.0"
-      },
-      "dependencies": {
-        "globals": {
-          "version": "11.12.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-          "dev": true
-        }
-      }
-    },
-    "@babel/types": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz",
-      "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-string-parser": "^7.19.4",
-        "@babel/helper-validator-identifier": "^7.19.1",
-        "to-fast-properties": "^2.0.0"
-      }
-    },
-    "@cspotcode/source-map-support": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
-      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
-      "dev": true,
-      "requires": {
-        "@jridgewell/trace-mapping": "0.3.9"
-      },
-      "dependencies": {
-        "@jridgewell/trace-mapping": {
-          "version": "0.3.9",
-          "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
-          "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
-          "dev": true,
-          "requires": {
-            "@jridgewell/resolve-uri": "^3.0.3",
-            "@jridgewell/sourcemap-codec": "^1.4.10"
-          }
-        }
-      }
-    },
-    "@eslint/eslintrc": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
-      "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==",
-      "dev": true,
-      "requires": {
-        "ajv": "^6.12.4",
-        "debug": "^4.3.2",
-        "espree": "^9.4.0",
-        "globals": "^13.15.0",
-        "ignore": "^5.2.0",
-        "import-fresh": "^3.2.1",
-        "js-yaml": "^4.1.0",
-        "minimatch": "^3.1.2",
-        "strip-json-comments": "^3.1.1"
-      }
-    },
-    "@humanwhocodes/config-array": {
-      "version": "0.11.6",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.6.tgz",
-      "integrity": "sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==",
-      "dev": true,
-      "requires": {
-        "@humanwhocodes/object-schema": "^1.2.1",
-        "debug": "^4.1.1",
-        "minimatch": "^3.0.4"
-      }
-    },
-    "@humanwhocodes/module-importer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
-      "dev": true
-    },
-    "@humanwhocodes/object-schema": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
-      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
-      "dev": true
-    },
-    "@iarna/toml": {
-      "version": "2.2.5",
-      "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
-      "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==",
-      "dev": true
-    },
-    "@istanbuljs/load-nyc-config": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
-      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
-      "dev": true,
-      "requires": {
-        "camelcase": "^5.3.1",
-        "find-up": "^4.1.0",
-        "get-package-type": "^0.1.0",
-        "js-yaml": "^3.13.1",
-        "resolve-from": "^5.0.0"
-      },
-      "dependencies": {
-        "argparse": {
-          "version": "1.0.10",
-          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-          "dev": true,
-          "requires": {
-            "sprintf-js": "~1.0.2"
-          }
-        },
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "js-yaml": {
-          "version": "3.14.1",
-          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
-          "dev": true,
-          "requires": {
-            "argparse": "^1.0.7",
-            "esprima": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-limit": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "resolve-from": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
-          "dev": true
-        }
-      }
-    },
-    "@istanbuljs/nyc-config-typescript": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/@istanbuljs/nyc-config-typescript/-/nyc-config-typescript-1.0.2.tgz",
-      "integrity": "sha512-iKGIyMoyJuFnJRSVTZ78POIRvNnwZaWIf8vG4ZS3rQq58MMDrqEX2nnzx0R28V2X8JvmKYiqY9FP2hlJsm8A0w==",
-      "dev": true,
-      "requires": {
-        "@istanbuljs/schema": "^0.1.2"
-      }
-    },
-    "@istanbuljs/schema": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
-      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
-      "dev": true
-    },
-    "@jridgewell/gen-mapping": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
-      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
-      "dev": true,
-      "requires": {
-        "@jridgewell/set-array": "^1.0.0",
-        "@jridgewell/sourcemap-codec": "^1.4.10"
-      }
-    },
-    "@jridgewell/resolve-uri": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
-      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
-      "dev": true
-    },
-    "@jridgewell/set-array": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
-      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
-      "dev": true
-    },
-    "@jridgewell/sourcemap-codec": {
-      "version": "1.4.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
-      "dev": true
-    },
-    "@jridgewell/trace-mapping": {
-      "version": "0.3.17",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
-      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
-      "dev": true,
-      "requires": {
-        "@jridgewell/resolve-uri": "3.1.0",
-        "@jridgewell/sourcemap-codec": "1.4.14"
-      }
-    },
-    "@nodelib/fs.scandir": {
-      "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
-      "dev": true,
-      "requires": {
-        "@nodelib/fs.stat": "2.0.5",
-        "run-parallel": "^1.1.9"
-      }
-    },
-    "@nodelib/fs.stat": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
-      "dev": true
-    },
-    "@nodelib/fs.walk": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
-      "dev": true,
-      "requires": {
-        "@nodelib/fs.scandir": "2.1.5",
-        "fastq": "^1.6.0"
-      }
-    },
-    "@octokit/auth-token": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
-      "integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
-      "dev": true,
-      "requires": {
-        "@octokit/types": "^8.0.0"
-      }
-    },
-    "@octokit/core": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
-      "integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
-      "dev": true,
-      "requires": {
-        "@octokit/auth-token": "^3.0.0",
-        "@octokit/graphql": "^5.0.0",
-        "@octokit/request": "^6.0.0",
-        "@octokit/request-error": "^3.0.0",
-        "@octokit/types": "^8.0.0",
-        "before-after-hook": "^2.2.0",
-        "universal-user-agent": "^6.0.0"
-      }
-    },
-    "@octokit/endpoint": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
-      "integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
-      "dev": true,
-      "requires": {
-        "@octokit/types": "^8.0.0",
-        "is-plain-object": "^5.0.0",
-        "universal-user-agent": "^6.0.0"
-      }
-    },
-    "@octokit/graphql": {
-      "version": "5.0.4",
-      "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
-      "integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
-      "dev": true,
-      "requires": {
-        "@octokit/request": "^6.0.0",
-        "@octokit/types": "^8.0.0",
-        "universal-user-agent": "^6.0.0"
-      }
-    },
-    "@octokit/openapi-types": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
-      "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==",
-      "dev": true
-    },
-    "@octokit/plugin-paginate-rest": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-4.3.1.tgz",
-      "integrity": "sha512-h8KKxESmSFTcXX409CAxlaOYscEDvN2KGQRsLCGT1NSqRW+D6EXLVQ8vuHhFznS9MuH9QYw1GfsUN30bg8hjVA==",
-      "dev": true,
-      "requires": {
-        "@octokit/types": "^7.5.0"
-      },
-      "dependencies": {
-        "@octokit/openapi-types": {
-          "version": "13.13.1",
-          "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-13.13.1.tgz",
-          "integrity": "sha512-4EuKSk3N95UBWFau3Bz9b3pheQ8jQYbKmBL5+GSuY8YDPDwu03J4BjI+66yNi8aaX/3h1qDpb0mbBkLdr+cfGQ==",
-          "dev": true
-        },
-        "@octokit/types": {
-          "version": "7.5.1",
-          "resolved": "https://registry.npmjs.org/@octokit/types/-/types-7.5.1.tgz",
-          "integrity": "sha512-Zk4OUMLCSpXNI8KZZn47lVLJSsgMyCimsWWQI5hyjZg7hdYm0kjotaIkbG0Pp8SfU2CofMBzonboTqvzn3FrJA==",
-          "dev": true,
-          "requires": {
-            "@octokit/openapi-types": "^13.11.0"
-          }
-        }
-      }
-    },
-    "@octokit/plugin-request-log": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
-      "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
-      "dev": true,
-      "requires": {}
-    },
-    "@octokit/plugin-rest-endpoint-methods": {
-      "version": "6.7.0",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
-      "integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
-      "dev": true,
-      "requires": {
-        "@octokit/types": "^8.0.0",
-        "deprecation": "^2.3.1"
-      }
-    },
-    "@octokit/request": {
-      "version": "6.2.2",
-      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
-      "integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
-      "dev": true,
-      "requires": {
-        "@octokit/endpoint": "^7.0.0",
-        "@octokit/request-error": "^3.0.0",
-        "@octokit/types": "^8.0.0",
-        "is-plain-object": "^5.0.0",
-        "node-fetch": "^2.6.7",
-        "universal-user-agent": "^6.0.0"
-      },
-      "dependencies": {
-        "node-fetch": {
-          "version": "2.6.7",
-          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
-          "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
-          "dev": true,
-          "requires": {
-            "whatwg-url": "^5.0.0"
-          }
-        }
-      }
-    },
-    "@octokit/request-error": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
-      "integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
-      "dev": true,
-      "requires": {
-        "@octokit/types": "^8.0.0",
-        "deprecation": "^2.0.0",
-        "once": "^1.4.0"
-      }
-    },
-    "@octokit/rest": {
-      "version": "19.0.4",
-      "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.4.tgz",
-      "integrity": "sha512-LwG668+6lE8zlSYOfwPj4FxWdv/qFXYBpv79TWIQEpBLKA9D/IMcWsF/U9RGpA3YqMVDiTxpgVpEW3zTFfPFTA==",
-      "dev": true,
-      "requires": {
-        "@octokit/core": "^4.0.0",
-        "@octokit/plugin-paginate-rest": "^4.0.0",
-        "@octokit/plugin-request-log": "^1.0.4",
-        "@octokit/plugin-rest-endpoint-methods": "^6.0.0"
-      }
-    },
-    "@octokit/types": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
-      "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
-      "dev": true,
-      "requires": {
-        "@octokit/openapi-types": "^14.0.0"
-      }
-    },
-    "@pnpm/network.ca-file": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz",
-      "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "4.2.10"
-      }
-    },
-    "@pnpm/npm-conf": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz",
-      "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==",
-      "dev": true,
-      "requires": {
-        "@pnpm/network.ca-file": "^1.0.1",
-        "config-chain": "^1.1.11"
-      }
-    },
-    "@redis/bloom": {
-      "version": "file:packages/bloom",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
-        "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
-      }
-    },
-    "@redis/client": {
-      "version": "file:packages/client",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
-        "@types/sinon": "^10.0.13",
-        "@types/yallist": "^4.0.1",
-        "@typescript-eslint/eslint-plugin": "^5.41.0",
-        "@typescript-eslint/parser": "^5.41.0",
-        "cluster-key-slot": "1.1.1",
-        "eslint": "^8.26.0",
-        "generic-pool": "3.9.0",
-        "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
-        "sinon": "^14.0.1",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4",
-        "yallist": "4.0.0"
-      },
-      "dependencies": {
-        "yallist": {
-          "version": "4.0.0"
-        }
-      }
-    },
-    "@redis/graph": {
-      "version": "file:packages/graph",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
-        "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
-      }
-    },
-    "@redis/json": {
-      "version": "file:packages/json",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
-        "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
-      }
-    },
-    "@redis/search": {
-      "version": "file:packages/search",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
-        "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
-      }
-    },
-    "@redis/test-utils": {
-      "version": "file:packages/test-utils",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@types/mocha": "^10.0.0",
-        "@types/node": "^18.11.6",
-        "@types/yargs": "^17.0.13",
-        "mocha": "^10.1.0",
-        "nyc": "^15.1.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typescript": "^4.8.4",
-        "yargs": "^17.6.0"
-      }
-    },
-    "@redis/time-series": {
-      "version": "file:packages/time-series",
-      "requires": {
-        "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@redis/test-utils": "*",
-        "@types/node": "^18.11.6",
-        "nyc": "^15.1.0",
-        "release-it": "^15.5.0",
-        "source-map-support": "^0.5.21",
-        "ts-node": "^10.9.1",
-        "typedoc": "^0.23.18",
-        "typescript": "^4.8.4"
-      }
-    },
-    "@sindresorhus/is": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz",
-      "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==",
-      "dev": true
-    },
-    "@sinonjs/commons": {
-      "version": "1.8.3",
-      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
-      "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==",
-      "dev": true,
-      "requires": {
-        "type-detect": "4.0.8"
-      }
-    },
-    "@sinonjs/fake-timers": {
-      "version": "9.1.2",
-      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz",
-      "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==",
-      "dev": true,
-      "requires": {
-        "@sinonjs/commons": "^1.7.0"
-      }
-    },
-    "@sinonjs/samsam": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.1.tgz",
-      "integrity": "sha512-cZ7rKJTLiE7u7Wi/v9Hc2fs3Ucc3jrWeMgPHbbTCeVAB2S0wOBbYlkJVeNSL04i7fdhT8wIbDq1zhC/PXTD2SA==",
-      "dev": true,
-      "requires": {
-        "@sinonjs/commons": "^1.6.0",
-        "lodash.get": "^4.4.2",
-        "type-detect": "^4.0.8"
-      }
-    },
-    "@sinonjs/text-encoding": {
-      "version": "0.7.2",
-      "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz",
-      "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==",
-      "dev": true
-    },
-    "@szmarczak/http-timer": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
-      "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
-      "dev": true,
-      "requires": {
-        "defer-to-connect": "^2.0.1"
-      }
-    },
-    "@tootallnate/once": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
-      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
-      "dev": true
-    },
-    "@tsconfig/node10": {
-      "version": "1.0.9",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
-      "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
-      "dev": true
-    },
-    "@tsconfig/node12": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
-      "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
-      "dev": true
-    },
-    "@tsconfig/node14": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
-      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
-      "dev": true
-    },
-    "@tsconfig/node16": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
-      "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
-      "dev": true
-    },
-    "@types/http-cache-semantics": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
-      "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==",
-      "dev": true
-    },
-    "@types/json-schema": {
-      "version": "7.0.11",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
-      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
-      "dev": true
-    },
-    "@types/mocha": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.0.tgz",
-      "integrity": "sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg==",
-      "dev": true
-    },
-    "@types/node": {
-      "version": "18.11.6",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.6.tgz",
-      "integrity": "sha512-j3CEDa2vd96K0AXF8Wur7UucACvnjkk8hYyQAHhUNciabZLDl9nfAEVUSwmh245OOZV15bRA3Y590Gi5jUcDJg==",
-      "dev": true
-    },
-    "@types/parse-json": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
-      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
-      "dev": true
-    },
-    "@types/semver": {
-      "version": "7.3.12",
-      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz",
-      "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==",
-      "dev": true
-    },
-    "@types/sinon": {
-      "version": "10.0.13",
-      "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz",
-      "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==",
-      "dev": true,
-      "requires": {
-        "@types/sinonjs__fake-timers": "*"
-      }
-    },
-    "@types/sinonjs__fake-timers": {
-      "version": "8.1.2",
-      "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz",
-      "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==",
-      "dev": true
-    },
-    "@types/yallist": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/@types/yallist/-/yallist-4.0.1.tgz",
-      "integrity": "sha512-G3FNJfaYtN8URU6wd6+uwFI62KO79j7n3XTYcwcFncP8gkfoi0b821GoVVt0oqKVnCqKYOMNKIGpakPoFhzAGA==",
-      "dev": true
-    },
-    "@types/yargs": {
-      "version": "17.0.13",
-      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz",
-      "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==",
-      "dev": true,
-      "requires": {
-        "@types/yargs-parser": "*"
-      }
-    },
-    "@types/yargs-parser": {
-      "version": "21.0.0",
-      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
-      "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
-      "dev": true
-    },
-    "@typescript-eslint/eslint-plugin": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.41.0.tgz",
-      "integrity": "sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA==",
-      "dev": true,
-      "requires": {
-        "@typescript-eslint/scope-manager": "5.41.0",
-        "@typescript-eslint/type-utils": "5.41.0",
-        "@typescript-eslint/utils": "5.41.0",
-        "debug": "^4.3.4",
-        "ignore": "^5.2.0",
-        "regexpp": "^3.2.0",
-        "semver": "^7.3.7",
-        "tsutils": "^3.21.0"
-      }
-    },
-    "@typescript-eslint/parser": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.41.0.tgz",
-      "integrity": "sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==",
-      "dev": true,
-      "requires": {
-        "@typescript-eslint/scope-manager": "5.41.0",
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/typescript-estree": "5.41.0",
-        "debug": "^4.3.4"
-      }
-    },
-    "@typescript-eslint/scope-manager": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.41.0.tgz",
-      "integrity": "sha512-xOxPJCnuktUkY2xoEZBKXO5DBCugFzjrVndKdUnyQr3+9aDWZReKq9MhaoVnbL+maVwWJu/N0SEtrtEUNb62QQ==",
-      "dev": true,
-      "requires": {
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/visitor-keys": "5.41.0"
-      }
-    },
-    "@typescript-eslint/type-utils": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.41.0.tgz",
-      "integrity": "sha512-L30HNvIG6A1Q0R58e4hu4h+fZqaO909UcnnPbwKiN6Rc3BUEx6ez2wgN7aC0cBfcAjZfwkzE+E2PQQ9nEuoqfA==",
-      "dev": true,
-      "requires": {
-        "@typescript-eslint/typescript-estree": "5.41.0",
-        "@typescript-eslint/utils": "5.41.0",
-        "debug": "^4.3.4",
-        "tsutils": "^3.21.0"
-      }
-    },
-    "@typescript-eslint/types": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.41.0.tgz",
-      "integrity": "sha512-5BejraMXMC+2UjefDvrH0Fo/eLwZRV6859SXRg+FgbhA0R0l6lDqDGAQYhKbXhPN2ofk2kY5sgGyLNL907UXpA==",
-      "dev": true
-    },
-    "@typescript-eslint/typescript-estree": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.41.0.tgz",
-      "integrity": "sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==",
-      "dev": true,
-      "requires": {
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/visitor-keys": "5.41.0",
-        "debug": "^4.3.4",
-        "globby": "^11.1.0",
-        "is-glob": "^4.0.3",
-        "semver": "^7.3.7",
-        "tsutils": "^3.21.0"
-      }
-    },
-    "@typescript-eslint/utils": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.41.0.tgz",
-      "integrity": "sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==",
-      "dev": true,
-      "requires": {
-        "@types/json-schema": "^7.0.9",
-        "@types/semver": "^7.3.12",
-        "@typescript-eslint/scope-manager": "5.41.0",
-        "@typescript-eslint/types": "5.41.0",
-        "@typescript-eslint/typescript-estree": "5.41.0",
-        "eslint-scope": "^5.1.1",
-        "eslint-utils": "^3.0.0",
-        "semver": "^7.3.7"
-      }
-    },
-    "@typescript-eslint/visitor-keys": {
-      "version": "5.41.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.41.0.tgz",
-      "integrity": "sha512-vilqeHj267v8uzzakbm13HkPMl7cbYpKVjgFWZPIOHIJHZtinvypUhJ5xBXfWYg4eFKqztbMMpOgFpT9Gfx4fw==",
-      "dev": true,
-      "requires": {
-        "@typescript-eslint/types": "5.41.0",
-        "eslint-visitor-keys": "^3.3.0"
-      }
-    },
-    "acorn": {
-      "version": "8.8.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
-      "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
-      "dev": true
-    },
-    "acorn-jsx": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
-      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
-      "dev": true,
-      "requires": {}
-    },
-    "acorn-walk": {
-      "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
-    },
-    "agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
-      "dev": true,
-      "requires": {
-        "debug": "4"
-      }
-    },
-    "aggregate-error": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
-      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
-      "dev": true,
-      "requires": {
-        "clean-stack": "^2.0.0",
-        "indent-string": "^4.0.0"
-      }
-    },
-    "ajv": {
-      "version": "6.12.6",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-      "dev": true,
-      "requires": {
-        "fast-deep-equal": "^3.1.1",
-        "fast-json-stable-stringify": "^2.0.0",
-        "json-schema-traverse": "^0.4.1",
-        "uri-js": "^4.2.2"
-      }
-    },
-    "ansi-align": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
-      "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
-      "dev": true,
-      "requires": {
-        "string-width": "^4.1.0"
-      },
-      "dependencies": {
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        }
-      }
-    },
-    "ansi-colors": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
-      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
-      "dev": true
-    },
-    "ansi-escapes": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz",
-      "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==",
-      "dev": true,
-      "requires": {
-        "type-fest": "^1.0.2"
-      },
-      "dependencies": {
-        "type-fest": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
-          "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
-          "dev": true
-        }
-      }
-    },
-    "ansi-regex": {
-      "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": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "dev": true,
-      "requires": {
-        "color-convert": "^2.0.1"
-      }
-    },
-    "anymatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
-      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
-      "dev": true,
-      "requires": {
-        "normalize-path": "^3.0.0",
-        "picomatch": "^2.0.4"
-      }
-    },
-    "append-transform": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
-      "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
-      "dev": true,
-      "requires": {
-        "default-require-extensions": "^3.0.0"
-      }
-    },
-    "archy": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
-      "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==",
-      "dev": true
-    },
-    "arg": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
-      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
-      "dev": true
-    },
-    "argparse": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-      "dev": true
-    },
-    "array-union": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-      "dev": true
-    },
-    "array-uniq": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-      "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
-      "dev": true
-    },
-    "array.prototype.map": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz",
-      "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.0",
-        "es-array-method-boxes-properly": "^1.0.0",
-        "is-string": "^1.0.7"
-      }
-    },
-    "ast-types": {
-      "version": "0.13.4",
-      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
-      "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
-      "dev": true,
-      "requires": {
-        "tslib": "^2.0.1"
-      }
-    },
-    "async": {
-      "version": "2.6.4",
-      "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
-      "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.14"
-      }
-    },
-    "async-retry": {
-      "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.13.1"
-      }
-    },
-    "asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-      "dev": true
-    },
-    "balanced-match": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
-    },
-    "base64-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-      "dev": true
-    },
-    "before-after-hook": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
-      "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
-      "dev": true
-    },
-    "binary-extensions": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-      "dev": true
-    },
-    "bl": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
-      "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
-      "dev": true,
-      "requires": {
-        "buffer": "^6.0.3",
-        "inherits": "^2.0.4",
-        "readable-stream": "^3.4.0"
-      }
-    },
-    "boxen": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz",
-      "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==",
-      "dev": true,
-      "requires": {
-        "ansi-align": "^3.0.1",
-        "camelcase": "^7.0.0",
-        "chalk": "^5.0.1",
-        "cli-boxes": "^3.0.0",
-        "string-width": "^5.1.2",
-        "type-fest": "^2.13.0",
-        "widest-line": "^4.0.1",
-        "wrap-ansi": "^8.0.1"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz",
-          "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==",
-          "dev": true
-        },
-        "chalk": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-          "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
-          "dev": true
-        },
-        "type-fest": {
-          "version": "2.19.0",
-          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
-          "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
-          "dev": true
-        }
-      }
-    },
-    "brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
-      "requires": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
-    "braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-      "dev": true,
-      "requires": {
-        "fill-range": "^7.0.1"
-      }
-    },
-    "browser-stdout": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
-      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
-      "dev": true
-    },
-    "browserslist": {
-      "version": "4.21.4",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
-      "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
-      "dev": true,
-      "requires": {
-        "caniuse-lite": "^1.0.30001400",
-        "electron-to-chromium": "^1.4.251",
-        "node-releases": "^2.0.6",
-        "update-browserslist-db": "^1.0.9"
-      }
-    },
-    "buffer": {
-      "version": "6.0.3",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
-      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
-      "dev": true,
-      "requires": {
-        "base64-js": "^1.3.1",
-        "ieee754": "^1.2.1"
-      }
-    },
-    "buffer-from": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
-      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
-      "dev": true
-    },
-    "bytes": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
-      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
-      "dev": true
-    },
-    "cacheable-lookup": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
-      "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
-      "dev": true
-    },
-    "cacheable-request": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.2.tgz",
-      "integrity": "sha512-KxjQZM3UIo7/J6W4sLpwFvu1GB3Whv8NtZ8ZrUL284eiQjiXeeqWTdhixNrp/NLZ/JNuFBo6BD4ZaO8ZJ5BN8Q==",
-      "dev": true,
-      "requires": {
-        "@types/http-cache-semantics": "^4.0.1",
-        "get-stream": "^6.0.1",
-        "http-cache-semantics": "^4.1.0",
-        "keyv": "^4.5.0",
-        "mimic-response": "^4.0.0",
-        "normalize-url": "^7.2.0",
-        "responselike": "^3.0.0"
-      }
-    },
-    "caching-transform": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
-      "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
-      "dev": true,
-      "requires": {
-        "hasha": "^5.0.0",
-        "make-dir": "^3.0.0",
-        "package-hash": "^4.0.0",
-        "write-file-atomic": "^3.0.0"
-      }
-    },
-    "call-bind": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.2"
-      }
-    },
-    "callsites": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-      "dev": true
-    },
-    "camelcase": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-      "dev": true
-    },
-    "caniuse-lite": {
-      "version": "1.0.30001425",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz",
-      "integrity": "sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==",
-      "dev": true
-    },
-    "chalk": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^4.1.0",
-        "supports-color": "^7.1.0"
-      }
-    },
-    "chardet": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
-      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
-      "dev": true
-    },
-    "chokidar": {
-      "version": "3.5.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
-      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-      "dev": true,
-      "requires": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "fsevents": "~2.3.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
-      },
-      "dependencies": {
-        "glob-parent": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-          "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-          "dev": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        }
-      }
-    },
-    "ci-info": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
-      "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==",
-      "dev": true
-    },
-    "clean-stack": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
-      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
-      "dev": true
-    },
-    "cli-boxes": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
-      "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==",
-      "dev": true
-    },
-    "cli-cursor": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
-      "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
-      "dev": true,
-      "requires": {
-        "restore-cursor": "^4.0.0"
-      }
-    },
-    "cli-spinners": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
-      "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
-      "dev": true
-    },
-    "cli-width": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz",
-      "integrity": "sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==",
-      "dev": true
-    },
-    "cliui": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
-      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
-      "dev": true,
-      "requires": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.1",
-        "wrap-ansi": "^7.0.0"
-      },
-      "dependencies": {
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        },
-        "wrap-ansi": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-          "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-          }
-        }
-      }
-    },
-    "clone": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-      "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
-      "dev": true
-    },
-    "cluster-key-slot": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz",
-      "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw=="
-    },
-    "color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "dev": true,
-      "requires": {
-        "color-name": "~1.1.4"
-      }
-    },
-    "color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "dev": true
-    },
-    "combined-stream": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
-      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-      "dev": true,
-      "requires": {
-        "delayed-stream": "~1.0.0"
-      }
-    },
-    "commander": {
-      "version": "2.20.3",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-      "dev": true
-    },
-    "commondir": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
-      "dev": true
-    },
-    "concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-      "dev": true
-    },
-    "config-chain": {
-      "version": "1.1.13",
-      "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
-      "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
-      "dev": true,
-      "requires": {
-        "ini": "^1.3.4",
-        "proto-list": "~1.2.1"
-      },
-      "dependencies": {
-        "ini": {
-          "version": "1.3.8",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
-          "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
-          "dev": true
-        }
-      }
-    },
-    "configstore": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz",
-      "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==",
-      "dev": true,
-      "requires": {
-        "dot-prop": "^6.0.1",
-        "graceful-fs": "^4.2.6",
-        "unique-string": "^3.0.0",
-        "write-file-atomic": "^3.0.3",
-        "xdg-basedir": "^5.0.1"
-      }
-    },
-    "convert-source-map": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
-      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
-      "dev": true
-    },
-    "core-util-is": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
-      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
-      "dev": true
-    },
-    "cosmiconfig": {
-      "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",
-        "import-fresh": "^3.2.1",
-        "parse-json": "^5.0.0",
-        "path-type": "^4.0.0",
-        "yaml": "^1.10.0"
-      }
-    },
-    "create-require": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
-      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
-      "dev": true
-    },
-    "cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
-      "dev": true,
-      "requires": {
-        "path-key": "^3.1.0",
-        "shebang-command": "^2.0.0",
-        "which": "^2.0.1"
-      }
-    },
-    "crypto-random-string": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz",
-      "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==",
-      "dev": true,
-      "requires": {
-        "type-fest": "^1.0.1"
-      },
-      "dependencies": {
-        "type-fest": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
-          "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
-          "dev": true
-        }
-      }
-    },
-    "data-uri-to-buffer": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
-      "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
-      "dev": true
-    },
-    "debug": {
-      "version": "4.3.4",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-      "dev": true,
-      "requires": {
-        "ms": "2.1.2"
-      }
-    },
-    "decamelize": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
-      "dev": true
-    },
-    "decompress-response": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
-      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
-      "dev": true,
-      "requires": {
-        "mimic-response": "^3.1.0"
-      },
-      "dependencies": {
-        "mimic-response": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
-          "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
-          "dev": true
-        }
-      }
-    },
-    "deep-extend": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
-      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
-      "dev": true
-    },
-    "deep-is": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-      "dev": true
-    },
-    "default-require-extensions": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz",
-      "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==",
-      "dev": true,
-      "requires": {
-        "strip-bom": "^4.0.0"
-      }
-    },
-    "defaults": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
-      "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
-      "dev": true,
-      "requires": {
-        "clone": "^1.0.2"
-      }
-    },
-    "defer-to-connect": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
-      "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
-      "dev": true
-    },
-    "define-lazy-prop": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
-      "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
-      "dev": true
-    },
-    "define-properties": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
-      "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
-      "dev": true,
-      "requires": {
-        "has-property-descriptors": "^1.0.0",
-        "object-keys": "^1.1.1"
-      }
-    },
-    "degenerator": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz",
-      "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==",
-      "dev": true,
-      "requires": {
-        "ast-types": "^0.13.2",
-        "escodegen": "^1.8.1",
-        "esprima": "^4.0.0",
-        "vm2": "^3.9.8"
-      }
-    },
-    "delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
-      "dev": true
-    },
-    "depd": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
-      "dev": true
-    },
-    "deprecation": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
-      "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
-      "dev": true
-    },
-    "diff": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
-      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
-      "dev": true
-    },
-    "dir-glob": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
-      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
-      "dev": true,
-      "requires": {
-        "path-type": "^4.0.0"
-      }
-    },
-    "doctrine": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
-      "dev": true,
-      "requires": {
-        "esutils": "^2.0.2"
-      }
-    },
-    "dot-prop": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
-      "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
-      "dev": true,
-      "requires": {
-        "is-obj": "^2.0.0"
-      }
-    },
-    "eastasianwidth": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
-      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
-      "dev": true
-    },
-    "electron-to-chromium": {
-      "version": "1.4.284",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
-      "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
-      "dev": true
-    },
-    "email-addresses": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
-      "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
-      "dev": true
-    },
-    "emoji-regex": {
-      "version": "9.2.2",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
-      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
-      "dev": true
-    },
-    "error-ex": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
-      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
-      "dev": true,
-      "requires": {
-        "is-arrayish": "^0.2.1"
-      }
-    },
-    "es-abstract": {
-      "version": "1.20.4",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
-      "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
-        "function.prototype.name": "^1.1.5",
-        "get-intrinsic": "^1.1.3",
-        "get-symbol-description": "^1.0.0",
-        "has": "^1.0.3",
-        "has-property-descriptors": "^1.0.0",
-        "has-symbols": "^1.0.3",
-        "internal-slot": "^1.0.3",
-        "is-callable": "^1.2.7",
-        "is-negative-zero": "^2.0.2",
-        "is-regex": "^1.1.4",
-        "is-shared-array-buffer": "^1.0.2",
-        "is-string": "^1.0.7",
-        "is-weakref": "^1.0.2",
-        "object-inspect": "^1.12.2",
-        "object-keys": "^1.1.1",
-        "object.assign": "^4.1.4",
-        "regexp.prototype.flags": "^1.4.3",
-        "safe-regex-test": "^1.0.0",
-        "string.prototype.trimend": "^1.0.5",
-        "string.prototype.trimstart": "^1.0.5",
-        "unbox-primitive": "^1.0.2"
-      }
-    },
-    "es-array-method-boxes-properly": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
-      "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
-      "dev": true
-    },
-    "es-get-iterator": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
-      "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.0",
-        "has-symbols": "^1.0.1",
-        "is-arguments": "^1.1.0",
-        "is-map": "^2.0.2",
-        "is-set": "^2.0.2",
-        "is-string": "^1.0.5",
-        "isarray": "^2.0.5"
-      }
-    },
-    "es-to-primitive": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
-      "dev": true,
-      "requires": {
-        "is-callable": "^1.1.4",
-        "is-date-object": "^1.0.1",
-        "is-symbol": "^1.0.2"
-      }
-    },
-    "es6-error": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
-      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
-      "dev": true
-    },
-    "escalade": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-      "dev": true
-    },
-    "escape-goat": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz",
-      "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==",
-      "dev": true
-    },
-    "escape-string-regexp": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-      "dev": true
-    },
-    "escodegen": {
-      "version": "1.14.3",
-      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
-      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
-      "dev": true,
-      "requires": {
-        "esprima": "^4.0.1",
-        "estraverse": "^4.2.0",
-        "esutils": "^2.0.2",
-        "optionator": "^0.8.1",
-        "source-map": "~0.6.1"
-      },
-      "dependencies": {
-        "levn": {
-          "version": "0.3.0",
-          "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
-          "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
-          "dev": true,
-          "requires": {
-            "prelude-ls": "~1.1.2",
-            "type-check": "~0.3.2"
-          }
-        },
-        "optionator": {
-          "version": "0.8.3",
-          "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
-          "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
-          "dev": true,
-          "requires": {
-            "deep-is": "~0.1.3",
-            "fast-levenshtein": "~2.0.6",
-            "levn": "~0.3.0",
-            "prelude-ls": "~1.1.2",
-            "type-check": "~0.3.2",
-            "word-wrap": "~1.2.3"
-          }
-        },
-        "prelude-ls": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-          "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
-          "dev": true
-        },
-        "type-check": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
-          "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
-          "dev": true,
-          "requires": {
-            "prelude-ls": "~1.1.2"
-          }
-        }
-      }
-    },
-    "eslint": {
-      "version": "8.26.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
-      "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==",
-      "dev": true,
-      "requires": {
-        "@eslint/eslintrc": "^1.3.3",
-        "@humanwhocodes/config-array": "^0.11.6",
-        "@humanwhocodes/module-importer": "^1.0.1",
-        "@nodelib/fs.walk": "^1.2.8",
-        "ajv": "^6.10.0",
-        "chalk": "^4.0.0",
-        "cross-spawn": "^7.0.2",
-        "debug": "^4.3.2",
-        "doctrine": "^3.0.0",
-        "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^7.1.1",
-        "eslint-utils": "^3.0.0",
-        "eslint-visitor-keys": "^3.3.0",
-        "espree": "^9.4.0",
-        "esquery": "^1.4.0",
-        "esutils": "^2.0.2",
-        "fast-deep-equal": "^3.1.3",
-        "file-entry-cache": "^6.0.1",
-        "find-up": "^5.0.0",
-        "glob-parent": "^6.0.2",
-        "globals": "^13.15.0",
-        "grapheme-splitter": "^1.0.4",
-        "ignore": "^5.2.0",
-        "import-fresh": "^3.0.0",
-        "imurmurhash": "^0.1.4",
-        "is-glob": "^4.0.0",
-        "is-path-inside": "^3.0.3",
-        "js-sdsl": "^4.1.4",
-        "js-yaml": "^4.1.0",
-        "json-stable-stringify-without-jsonify": "^1.0.1",
-        "levn": "^0.4.1",
-        "lodash.merge": "^4.6.2",
-        "minimatch": "^3.1.2",
-        "natural-compare": "^1.4.0",
-        "optionator": "^0.9.1",
-        "regexpp": "^3.2.0",
-        "strip-ansi": "^6.0.1",
-        "strip-json-comments": "^3.1.0",
-        "text-table": "^0.2.0"
-      },
-      "dependencies": {
-        "eslint-scope": {
-          "version": "7.1.1",
-          "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
-          "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
-          "dev": true,
-          "requires": {
-            "esrecurse": "^4.3.0",
-            "estraverse": "^5.2.0"
-          }
-        },
-        "estraverse": {
-          "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-          "dev": true
-        }
-      }
-    },
-    "eslint-scope": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
-      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
-      "dev": true,
-      "requires": {
-        "esrecurse": "^4.3.0",
-        "estraverse": "^4.1.1"
-      }
-    },
-    "eslint-utils": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
-      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
-      "dev": true,
-      "requires": {
-        "eslint-visitor-keys": "^2.0.0"
-      },
-      "dependencies": {
-        "eslint-visitor-keys": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-          "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
-          "dev": true
-        }
-      }
-    },
-    "eslint-visitor-keys": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
-      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
-      "dev": true
-    },
-    "espree": {
-      "version": "9.4.0",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz",
-      "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==",
-      "dev": true,
-      "requires": {
-        "acorn": "^8.8.0",
-        "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^3.3.0"
-      }
-    },
-    "esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true
-    },
-    "esquery": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
-      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
-      "dev": true,
-      "requires": {
-        "estraverse": "^5.1.0"
-      },
-      "dependencies": {
-        "estraverse": {
-          "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-          "dev": true
-        }
-      }
-    },
-    "esrecurse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
-      "dev": true,
-      "requires": {
-        "estraverse": "^5.2.0"
-      },
-      "dependencies": {
-        "estraverse": {
-          "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-          "dev": true
-        }
-      }
-    },
-    "estraverse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
-      "dev": true
-    },
-    "esutils": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-      "dev": true
-    },
-    "execa": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz",
-      "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==",
-      "dev": true,
-      "requires": {
-        "cross-spawn": "^7.0.3",
-        "get-stream": "^6.0.1",
-        "human-signals": "^3.0.1",
-        "is-stream": "^3.0.0",
-        "merge-stream": "^2.0.0",
-        "npm-run-path": "^5.1.0",
-        "onetime": "^6.0.0",
-        "signal-exit": "^3.0.7",
-        "strip-final-newline": "^3.0.0"
-      },
-      "dependencies": {
-        "is-stream": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
-          "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
-          "dev": true
-        }
-      }
-    },
-    "external-editor": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
-      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
-      "dev": true,
-      "requires": {
-        "chardet": "^0.7.0",
-        "iconv-lite": "^0.4.24",
-        "tmp": "^0.0.33"
-      }
-    },
-    "fast-deep-equal": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-      "dev": true
-    },
-    "fast-glob": {
-      "version": "3.2.12",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
-      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
-      "dev": true,
-      "requires": {
-        "@nodelib/fs.stat": "^2.0.2",
-        "@nodelib/fs.walk": "^1.2.3",
-        "glob-parent": "^5.1.2",
-        "merge2": "^1.3.0",
-        "micromatch": "^4.0.4"
-      },
-      "dependencies": {
-        "glob-parent": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-          "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-          "dev": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        }
-      }
-    },
-    "fast-json-stable-stringify": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-      "dev": true
-    },
-    "fast-levenshtein": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
-      "dev": true
-    },
-    "fastq": {
-      "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"
-      }
-    },
-    "fetch-blob": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
-      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
-      "dev": true,
-      "requires": {
-        "node-domexception": "^1.0.0",
-        "web-streams-polyfill": "^3.0.3"
-      }
-    },
-    "figures": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz",
-      "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==",
-      "dev": true,
-      "requires": {
-        "escape-string-regexp": "^5.0.0",
-        "is-unicode-supported": "^1.2.0"
-      },
-      "dependencies": {
-        "escape-string-regexp": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-          "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
-          "dev": true
-        },
-        "is-unicode-supported": {
-          "version": "1.3.0",
-          "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
-          "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
-          "dev": true
-        }
-      }
-    },
-    "file-entry-cache": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
-      "dev": true,
-      "requires": {
-        "flat-cache": "^3.0.4"
-      }
-    },
-    "file-uri-to-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
-      "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==",
-      "dev": true
-    },
-    "filename-reserved-regex": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
-      "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
-      "dev": true
-    },
-    "filenamify": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
-      "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
-      "dev": true,
-      "requires": {
-        "filename-reserved-regex": "^2.0.0",
-        "strip-outer": "^1.0.1",
-        "trim-repeated": "^1.0.0"
-      }
-    },
-    "fill-range": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-      "dev": true,
-      "requires": {
-        "to-regex-range": "^5.0.1"
-      }
-    },
-    "find-cache-dir": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
-      "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
-      "dev": true,
-      "requires": {
-        "commondir": "^1.0.1",
-        "make-dir": "^3.0.2",
-        "pkg-dir": "^4.1.0"
-      }
-    },
-    "find-up": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-      "dev": true,
-      "requires": {
-        "locate-path": "^6.0.0",
-        "path-exists": "^4.0.0"
-      }
-    },
-    "flat": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
-      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
-      "dev": true
-    },
-    "flat-cache": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
-      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
-      "dev": true,
-      "requires": {
-        "flatted": "^3.1.0",
-        "rimraf": "^3.0.2"
-      }
-    },
-    "flatted": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
-      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
-      "dev": true
-    },
-    "foreground-child": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
-      "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
-      "dev": true,
-      "requires": {
-        "cross-spawn": "^7.0.0",
-        "signal-exit": "^3.0.2"
-      }
-    },
-    "form-data": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
-      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
-      "dev": true,
-      "requires": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.8",
-        "mime-types": "^2.1.12"
-      }
-    },
-    "form-data-encoder": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.3.tgz",
-      "integrity": "sha512-KqU0nnPMgIJcCOFTNJFEA8epcseEaoox4XZffTgy8jlI6pL/5EFyR54NRG7CnCJN0biY7q52DO3MH6/sJ/TKlQ==",
-      "dev": true
-    },
-    "formdata-polyfill": {
-      "version": "4.0.10",
-      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
-      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
-      "dev": true,
-      "requires": {
-        "fetch-blob": "^3.1.2"
-      }
-    },
-    "fromentries": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
-      "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
-      "dev": true
-    },
-    "fs-extra": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
-      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.2.0",
-        "jsonfile": "^4.0.0",
-        "universalify": "^0.1.0"
-      }
-    },
-    "fs.realpath": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-      "dev": true
-    },
-    "fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-      "dev": true,
-      "optional": true
-    },
-    "ftp": {
-      "version": "0.3.10",
-      "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz",
-      "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==",
-      "dev": true,
-      "requires": {
-        "readable-stream": "1.1.x",
-        "xregexp": "2.0.0"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-          "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "1.1.14",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
-          "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.1",
-            "isarray": "0.0.1",
-            "string_decoder": "~0.10.x"
-          }
-        },
-        "string_decoder": {
-          "version": "0.10.31",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-          "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
-          "dev": true
-        }
-      }
-    },
-    "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
-    },
-    "function.prototype.name": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
-      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.0",
-        "functions-have-names": "^1.2.2"
-      }
-    },
-    "functions-have-names": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
-      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
-      "dev": true
-    },
-    "generic-pool": {
-      "version": "3.9.0",
-      "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
-      "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g=="
-    },
-    "gensync": {
-      "version": "1.0.0-beta.2",
-      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
-      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
-      "dev": true
-    },
-    "get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "dev": true
-    },
-    "get-intrinsic": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
-      "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.3"
-      }
-    },
-    "get-package-type": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
-      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
-      "dev": true
-    },
-    "get-stream": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
-      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
-      "dev": true
-    },
-    "get-symbol-description": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
-      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.1"
-      }
-    },
-    "get-uri": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz",
-      "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==",
-      "dev": true,
-      "requires": {
-        "@tootallnate/once": "1",
-        "data-uri-to-buffer": "3",
-        "debug": "4",
-        "file-uri-to-path": "2",
-        "fs-extra": "^8.1.0",
-        "ftp": "^0.3.10"
-      },
-      "dependencies": {
-        "data-uri-to-buffer": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
-          "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
-          "dev": true
-        }
-      }
-    },
-    "gh-pages": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-4.0.0.tgz",
-      "integrity": "sha512-p8S0T3aGJc68MtwOcZusul5qPSNZCalap3NWbhRUZYu1YOdp+EjZ+4kPmRM8h3NNRdqw00yuevRjlkuSzCn7iQ==",
-      "dev": true,
-      "requires": {
-        "async": "^2.6.1",
-        "commander": "^2.18.0",
-        "email-addresses": "^3.0.1",
-        "filenamify": "^4.3.0",
-        "find-cache-dir": "^3.3.1",
-        "fs-extra": "^8.1.0",
-        "globby": "^6.1.0"
-      },
-      "dependencies": {
-        "array-union": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
-          "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
-          "dev": true,
-          "requires": {
-            "array-uniq": "^1.0.1"
-          }
-        },
-        "globby": {
-          "version": "6.1.0",
-          "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
-          "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
-          "dev": true,
-          "requires": {
-            "array-union": "^1.0.1",
-            "glob": "^7.0.3",
-            "object-assign": "^4.0.1",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          }
-        }
-      }
-    },
-    "git-up": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz",
-      "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==",
-      "dev": true,
-      "requires": {
-        "is-ssh": "^1.4.0",
-        "parse-url": "^8.1.0"
-      }
-    },
-    "git-url-parse": {
-      "version": "13.1.0",
-      "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz",
-      "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==",
-      "dev": true,
-      "requires": {
-        "git-up": "^7.0.0"
-      }
-    },
-    "glob": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
-      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
-      "dev": true,
-      "requires": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
-      }
-    },
-    "glob-parent": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
-      "dev": true,
-      "requires": {
-        "is-glob": "^4.0.3"
-      }
-    },
-    "global-dirs": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz",
-      "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==",
-      "dev": true,
-      "requires": {
-        "ini": "2.0.0"
-      }
-    },
-    "globals": {
-      "version": "13.17.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
-      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
-      "dev": true,
-      "requires": {
-        "type-fest": "^0.20.2"
-      }
-    },
-    "globby": {
-      "version": "11.1.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
-      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
-      "dev": true,
-      "requires": {
-        "array-union": "^2.1.0",
-        "dir-glob": "^3.0.1",
-        "fast-glob": "^3.2.9",
-        "ignore": "^5.2.0",
-        "merge2": "^1.4.1",
-        "slash": "^3.0.0"
-      }
-    },
-    "got": {
-      "version": "12.5.1",
-      "resolved": "https://registry.npmjs.org/got/-/got-12.5.1.tgz",
-      "integrity": "sha512-sD16AK8cCyUoPtKr/NMvLTFFa+T3i3S+zoiuvhq0HP2YiqBZA9AtlBjAdsQBsLBK7slPuvmfE0OxhGi7N5dD4w==",
-      "dev": true,
-      "requires": {
-        "@sindresorhus/is": "^5.2.0",
-        "@szmarczak/http-timer": "^5.0.1",
-        "cacheable-lookup": "^7.0.0",
-        "cacheable-request": "^10.2.1",
-        "decompress-response": "^6.0.0",
-        "form-data-encoder": "^2.1.2",
-        "get-stream": "^6.0.1",
-        "http2-wrapper": "^2.1.10",
-        "lowercase-keys": "^3.0.0",
-        "p-cancelable": "^3.0.0",
-        "responselike": "^3.0.0"
-      }
-    },
-    "graceful-fs": {
-      "version": "4.2.10",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
-      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
-      "dev": true
-    },
-    "grapheme-splitter": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
-      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
-      "dev": true
-    },
-    "has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1"
-      }
-    },
-    "has-bigints": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
-      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
-      "dev": true
-    },
-    "has-flag": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-      "dev": true
-    },
-    "has-property-descriptors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
-      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
-      "dev": true,
-      "requires": {
-        "get-intrinsic": "^1.1.1"
-      }
-    },
-    "has-symbols": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
-      "dev": true
-    },
-    "has-tostringtag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
-      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
-      "dev": true,
-      "requires": {
-        "has-symbols": "^1.0.2"
-      }
-    },
-    "has-yarn": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz",
-      "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==",
-      "dev": true
-    },
-    "hasha": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
-      "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
-      "dev": true,
-      "requires": {
-        "is-stream": "^2.0.0",
-        "type-fest": "^0.8.0"
-      },
-      "dependencies": {
-        "type-fest": {
-          "version": "0.8.1",
-          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
-          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
-          "dev": true
-        }
-      }
-    },
-    "he": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
-      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
-      "dev": true
-    },
-    "html-escaper": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
-      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
-      "dev": true
-    },
-    "http-cache-semantics": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
-      "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
-      "dev": true
-    },
-    "http-errors": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
-      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
-      "dev": true,
-      "requires": {
-        "depd": "2.0.0",
-        "inherits": "2.0.4",
-        "setprototypeof": "1.2.0",
-        "statuses": "2.0.1",
-        "toidentifier": "1.0.1"
-      }
-    },
-    "http-proxy-agent": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
-      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
-      "dev": true,
-      "requires": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4"
-      }
-    },
-    "http2-wrapper": {
-      "version": "2.1.11",
-      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz",
-      "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==",
-      "dev": true,
-      "requires": {
-        "quick-lru": "^5.1.1",
-        "resolve-alpn": "^1.2.0"
-      }
-    },
-    "https-proxy-agent": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
-      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
-      "dev": true,
-      "requires": {
-        "agent-base": "6",
-        "debug": "4"
-      }
-    },
-    "human-signals": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz",
-      "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==",
-      "dev": true
-    },
-    "iconv-lite": {
-      "version": "0.4.24",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-      "dev": true,
-      "requires": {
-        "safer-buffer": ">= 2.1.2 < 3"
-      }
-    },
-    "ieee754": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-      "dev": true
-    },
-    "ignore": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
-      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
-      "dev": true
-    },
-    "import-fresh": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
-      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
-      "dev": true,
-      "requires": {
-        "parent-module": "^1.0.0",
-        "resolve-from": "^4.0.0"
-      }
-    },
-    "import-lazy": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
-      "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
-      "dev": true
-    },
-    "imurmurhash": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
-      "dev": true
-    },
-    "indent-string": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
-      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
-      "dev": true
-    },
-    "inflight": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-      "dev": true,
-      "requires": {
-        "once": "^1.3.0",
-        "wrappy": "1"
-      }
-    },
-    "inherits": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "dev": true
-    },
-    "ini": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
-      "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
-      "dev": true
-    },
-    "inquirer": {
-      "version": "9.1.2",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.1.2.tgz",
-      "integrity": "sha512-Hj2Ml1WpxKJU2npP2Rj0OURGkHV+GtNW2CwFdHDiXlqUBAUrWTcZHxCkFywX/XHzOS7wrG/kExgJFbUkVgyHzg==",
-      "dev": true,
-      "requires": {
-        "ansi-escapes": "^5.0.0",
-        "chalk": "^5.0.1",
-        "cli-cursor": "^4.0.0",
-        "cli-width": "^4.0.0",
-        "external-editor": "^3.0.3",
-        "figures": "^5.0.0",
-        "lodash": "^4.17.21",
-        "mute-stream": "0.0.8",
-        "ora": "^6.1.2",
-        "run-async": "^2.4.0",
-        "rxjs": "^7.5.6",
-        "string-width": "^5.1.2",
-        "strip-ansi": "^7.0.1",
-        "through": "^2.3.6",
-        "wrap-ansi": "^8.0.1"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-          "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-          "dev": true
-        },
-        "chalk": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-          "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
-          "dev": true
-        },
-        "strip-ansi": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-          "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^6.0.1"
-          }
-        }
-      }
-    },
-    "internal-slot": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
-      "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
-      "dev": true,
-      "requires": {
-        "get-intrinsic": "^1.1.0",
-        "has": "^1.0.3",
-        "side-channel": "^1.0.4"
-      }
-    },
-    "interpret": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
-      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
-      "dev": true
-    },
-    "ip": {
-      "version": "1.1.8",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
-      "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==",
-      "dev": true
-    },
-    "is-arguments": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
-      "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "has-tostringtag": "^1.0.0"
-      }
-    },
-    "is-arrayish": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
-      "dev": true
-    },
-    "is-bigint": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
-      "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
-      "dev": true,
-      "requires": {
-        "has-bigints": "^1.0.1"
-      }
-    },
-    "is-binary-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "dev": true,
-      "requires": {
-        "binary-extensions": "^2.0.0"
-      }
-    },
-    "is-boolean-object": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
-      "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "has-tostringtag": "^1.0.0"
-      }
-    },
-    "is-callable": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
-      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
-      "dev": true
-    },
-    "is-ci": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
-      "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
-      "dev": true,
-      "requires": {
-        "ci-info": "^3.2.0"
-      }
-    },
-    "is-core-module": {
-      "version": "2.11.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
-      "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.3"
-      }
-    },
-    "is-date-object": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
-      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
-      "dev": true,
-      "requires": {
-        "has-tostringtag": "^1.0.0"
-      }
-    },
-    "is-docker": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
-      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
-      "dev": true
-    },
-    "is-extglob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-      "dev": true
-    },
-    "is-fullwidth-code-point": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-      "dev": true
-    },
-    "is-glob": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-      "dev": true,
-      "requires": {
-        "is-extglob": "^2.1.1"
-      }
-    },
-    "is-installed-globally": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
-      "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
-      "dev": true,
-      "requires": {
-        "global-dirs": "^3.0.0",
-        "is-path-inside": "^3.0.2"
-      }
-    },
-    "is-interactive": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
-      "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
-      "dev": true
-    },
-    "is-map": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
-      "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
-      "dev": true
-    },
-    "is-negative-zero": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
-      "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
-      "dev": true
-    },
-    "is-npm": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz",
-      "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==",
-      "dev": true
-    },
-    "is-number": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "dev": true
-    },
-    "is-number-object": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
-      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
-      "dev": true,
-      "requires": {
-        "has-tostringtag": "^1.0.0"
-      }
-    },
-    "is-obj": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
-      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
-      "dev": true
-    },
-    "is-path-inside": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-      "dev": true
-    },
-    "is-plain-obj": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
-      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
-      "dev": true
-    },
-    "is-plain-object": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
-      "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
-      "dev": true
-    },
-    "is-regex": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
-      "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "has-tostringtag": "^1.0.0"
-      }
-    },
-    "is-set": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
-      "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
-      "dev": true
-    },
-    "is-shared-array-buffer": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
-      "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2"
-      }
-    },
-    "is-ssh": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz",
-      "integrity": "sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==",
-      "dev": true,
-      "requires": {
-        "protocols": "^2.0.1"
-      }
-    },
-    "is-stream": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
-      "dev": true
-    },
-    "is-string": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
-      "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
-      "dev": true,
-      "requires": {
-        "has-tostringtag": "^1.0.0"
-      }
-    },
-    "is-symbol": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
-      "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
-      "dev": true,
-      "requires": {
-        "has-symbols": "^1.0.2"
-      }
-    },
-    "is-typedarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
-      "dev": true
-    },
-    "is-unicode-supported": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
-      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
-      "dev": true
-    },
-    "is-weakref": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
-      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2"
-      }
-    },
-    "is-windows": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
-      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
-      "dev": true
-    },
-    "is-wsl": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
-      "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
-      "dev": true,
-      "requires": {
-        "is-docker": "^2.0.0"
-      }
-    },
-    "is-yarn-global": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz",
-      "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==",
-      "dev": true
-    },
-    "isarray": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-      "dev": true
-    },
-    "isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
-      "dev": true
-    },
-    "istanbul-lib-coverage": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
-      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
-      "dev": true
-    },
-    "istanbul-lib-hook": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
-      "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
-      "dev": true,
-      "requires": {
-        "append-transform": "^2.0.0"
-      }
-    },
-    "istanbul-lib-instrument": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
-      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
-      "dev": true,
-      "requires": {
-        "@babel/core": "^7.7.5",
-        "@istanbuljs/schema": "^0.1.2",
-        "istanbul-lib-coverage": "^3.0.0",
-        "semver": "^6.3.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
-    },
-    "istanbul-lib-processinfo": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
-      "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
-      "dev": true,
-      "requires": {
-        "archy": "^1.0.0",
-        "cross-spawn": "^7.0.3",
-        "istanbul-lib-coverage": "^3.2.0",
-        "p-map": "^3.0.0",
-        "rimraf": "^3.0.0",
-        "uuid": "^8.3.2"
-      }
-    },
-    "istanbul-lib-report": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
-      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
-      "dev": true,
-      "requires": {
-        "istanbul-lib-coverage": "^3.0.0",
-        "make-dir": "^3.0.0",
-        "supports-color": "^7.1.0"
-      }
-    },
-    "istanbul-lib-source-maps": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
-      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
-      "dev": true,
-      "requires": {
-        "debug": "^4.1.1",
-        "istanbul-lib-coverage": "^3.0.0",
-        "source-map": "^0.6.1"
-      }
-    },
-    "istanbul-reports": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
-      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
-      "dev": true,
-      "requires": {
-        "html-escaper": "^2.0.0",
-        "istanbul-lib-report": "^3.0.0"
-      }
-    },
-    "iterate-iterator": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz",
-      "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==",
-      "dev": true
-    },
-    "iterate-value": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz",
-      "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==",
-      "dev": true,
-      "requires": {
-        "es-get-iterator": "^1.0.2",
-        "iterate-iterator": "^1.0.1"
-      }
-    },
-    "js-sdsl": {
-      "version": "4.1.5",
-      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
-      "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
-      "dev": true
-    },
-    "js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
-    },
-    "js-yaml": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-      "dev": true,
-      "requires": {
-        "argparse": "^2.0.1"
-      }
-    },
-    "jsesc": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-      "dev": true
-    },
-    "json-buffer": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
-      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
-      "dev": true
-    },
-    "json-parse-even-better-errors": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
-      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
-      "dev": true
-    },
-    "json-schema-traverse": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-      "dev": true
-    },
-    "json-stable-stringify-without-jsonify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
-      "dev": true
-    },
-    "json5": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
-      "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
-      "dev": true
-    },
-    "jsonc-parser": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
-      "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
-      "dev": true
-    },
-    "jsonfile": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
-      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.6"
-      }
-    },
-    "just-extend": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
-      "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==",
-      "dev": true
-    },
-    "keyv": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz",
-      "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==",
-      "dev": true,
-      "requires": {
-        "json-buffer": "3.0.1"
-      }
-    },
-    "latest-version": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz",
-      "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==",
-      "dev": true,
-      "requires": {
-        "package-json": "^8.1.0"
-      }
-    },
-    "levn": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
-      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
-      "dev": true,
-      "requires": {
-        "prelude-ls": "^1.2.1",
-        "type-check": "~0.4.0"
-      }
-    },
-    "lines-and-columns": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
-      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
-      "dev": true
-    },
-    "locate-path": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-      "dev": true,
-      "requires": {
-        "p-locate": "^5.0.0"
-      }
-    },
-    "lodash": {
-      "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
-      "dev": true
-    },
-    "lodash.flattendeep": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
-      "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
-      "dev": true
-    },
-    "lodash.get": {
-      "version": "4.4.2",
-      "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
-      "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
-      "dev": true
-    },
-    "lodash.merge": {
-      "version": "4.6.2",
-      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-      "dev": true
-    },
-    "log-symbols": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
-      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
-      "dev": true,
-      "requires": {
-        "chalk": "^4.1.0",
-        "is-unicode-supported": "^0.1.0"
-      }
-    },
-    "lowercase-keys": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
-      "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
-      "dev": true
-    },
-    "lru-cache": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-      "dev": true,
-      "requires": {
-        "yallist": "^3.0.2"
-      }
-    },
-    "lunr": {
-      "version": "2.3.9",
-      "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
-      "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
-      "dev": true
-    },
-    "macos-release": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.1.0.tgz",
-      "integrity": "sha512-/M/R0gCDgM+Cv1IuBG1XGdfTFnMEG6PZeT+KGWHO/OG+imqmaD9CH5vHBTycEM3+Kc4uG2Il+tFAuUWLqQOeUA==",
-      "dev": true
-    },
-    "make-dir": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-      "dev": true,
-      "requires": {
-        "semver": "^6.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
-    },
-    "make-error": {
-      "version": "1.3.6",
-      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
-      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
-      "dev": true
-    },
-    "marked": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz",
-      "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==",
-      "dev": true
-    },
-    "merge-stream": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
-      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
-      "dev": true
-    },
-    "merge2": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-      "dev": true
-    },
-    "micromatch": {
-      "version": "4.0.5",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
-      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
-      "dev": true,
-      "requires": {
-        "braces": "^3.0.2",
-        "picomatch": "^2.3.1"
-      }
-    },
-    "mime-db": {
-      "version": "1.52.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
-      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
-      "dev": true
-    },
-    "mime-types": {
-      "version": "2.1.35",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
-      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-      "dev": true,
-      "requires": {
-        "mime-db": "1.52.0"
-      }
-    },
-    "mimic-fn": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
-      "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
-      "dev": true
-    },
-    "mimic-response": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
-      "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
-      "dev": true
-    },
-    "minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-      "dev": true,
-      "requires": {
-        "brace-expansion": "^1.1.7"
-      }
-    },
-    "minimist": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
-      "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
-      "dev": true
-    },
-    "mocha": {
-      "version": "10.1.0",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz",
-      "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==",
-      "dev": true,
-      "requires": {
-        "ansi-colors": "4.1.1",
-        "browser-stdout": "1.3.1",
-        "chokidar": "3.5.3",
-        "debug": "4.3.4",
-        "diff": "5.0.0",
-        "escape-string-regexp": "4.0.0",
-        "find-up": "5.0.0",
-        "glob": "7.2.0",
-        "he": "1.2.0",
-        "js-yaml": "4.1.0",
-        "log-symbols": "4.1.0",
-        "minimatch": "5.0.1",
-        "ms": "2.1.3",
-        "nanoid": "3.3.3",
-        "serialize-javascript": "6.0.0",
-        "strip-json-comments": "3.1.1",
-        "supports-color": "8.1.1",
-        "workerpool": "6.2.1",
-        "yargs": "16.2.0",
-        "yargs-parser": "20.2.4",
-        "yargs-unparser": "2.0.0"
-      },
-      "dependencies": {
-        "brace-expansion": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-          "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-          "dev": true,
-          "requires": {
-            "balanced-match": "^1.0.0"
-          }
-        },
-        "cliui": {
-          "version": "7.0.4",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
-          "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
-          "dev": true,
-          "requires": {
-            "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.0",
-            "wrap-ansi": "^7.0.0"
-          }
-        },
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "minimatch": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
-          "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^2.0.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        },
-        "supports-color": {
-          "version": "8.1.1",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "wrap-ansi": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-          "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "yargs": {
-          "version": "16.2.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
-          "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
-          "dev": true,
-          "requires": {
-            "cliui": "^7.0.2",
-            "escalade": "^3.1.1",
-            "get-caller-file": "^2.0.5",
-            "require-directory": "^2.1.1",
-            "string-width": "^4.2.0",
-            "y18n": "^5.0.5",
-            "yargs-parser": "^20.2.2"
-          }
-        }
-      }
-    },
-    "ms": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-      "dev": true
-    },
-    "mute-stream": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
-      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
-      "dev": true
-    },
-    "nanoid": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
-      "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
-      "dev": true
-    },
-    "natural-compare": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
-      "dev": true
-    },
-    "netmask": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
-      "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
-      "dev": true
-    },
-    "new-github-release-url": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz",
-      "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==",
-      "dev": true,
-      "requires": {
-        "type-fest": "^2.5.1"
-      },
-      "dependencies": {
-        "type-fest": {
-          "version": "2.19.0",
-          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
-          "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
-          "dev": true
-        }
-      }
-    },
-    "nise": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz",
-      "integrity": "sha512-yr5kW2THW1AkxVmCnKEh4nbYkJdB3I7LUkiUgOvEkOp414mc2UMaHMA7pjq1nYowhdoJZGwEKGaQVbxfpWj10A==",
-      "dev": true,
-      "requires": {
-        "@sinonjs/commons": "^1.8.3",
-        "@sinonjs/fake-timers": ">=5",
-        "@sinonjs/text-encoding": "^0.7.1",
-        "just-extend": "^4.0.2",
-        "path-to-regexp": "^1.7.0"
-      }
-    },
-    "node-domexception": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
-      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
-      "dev": true
-    },
-    "node-fetch": {
-      "version": "3.2.10",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz",
-      "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==",
-      "dev": true,
-      "requires": {
-        "data-uri-to-buffer": "^4.0.0",
-        "fetch-blob": "^3.1.4",
-        "formdata-polyfill": "^4.0.10"
-      }
-    },
-    "node-preload": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
-      "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
-      "dev": true,
-      "requires": {
-        "process-on-spawn": "^1.0.0"
-      }
-    },
-    "node-releases": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
-      "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
-      "dev": true
-    },
-    "normalize-path": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "dev": true
-    },
-    "normalize-url": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-7.2.0.tgz",
-      "integrity": "sha512-uhXOdZry0L6M2UIo9BTt7FdpBDiAGN/7oItedQwPKh8jh31ZlvC8U9Xl/EJ3aijDHaywXTW3QbZ6LuCocur1YA==",
-      "dev": true
-    },
-    "npm-run-path": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
-      "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
-      "dev": true,
-      "requires": {
-        "path-key": "^4.0.0"
-      },
-      "dependencies": {
-        "path-key": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
-          "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
-          "dev": true
-        }
-      }
-    },
-    "nyc": {
-      "version": "15.1.0",
-      "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
-      "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
-      "dev": true,
-      "requires": {
-        "@istanbuljs/load-nyc-config": "^1.0.0",
-        "@istanbuljs/schema": "^0.1.2",
-        "caching-transform": "^4.0.0",
-        "convert-source-map": "^1.7.0",
-        "decamelize": "^1.2.0",
-        "find-cache-dir": "^3.2.0",
-        "find-up": "^4.1.0",
-        "foreground-child": "^2.0.0",
-        "get-package-type": "^0.1.0",
-        "glob": "^7.1.6",
-        "istanbul-lib-coverage": "^3.0.0",
-        "istanbul-lib-hook": "^3.0.0",
-        "istanbul-lib-instrument": "^4.0.0",
-        "istanbul-lib-processinfo": "^2.0.2",
-        "istanbul-lib-report": "^3.0.0",
-        "istanbul-lib-source-maps": "^4.0.0",
-        "istanbul-reports": "^3.0.2",
-        "make-dir": "^3.0.0",
-        "node-preload": "^0.2.1",
-        "p-map": "^3.0.0",
-        "process-on-spawn": "^1.0.0",
-        "resolve-from": "^5.0.0",
-        "rimraf": "^3.0.0",
-        "signal-exit": "^3.0.2",
-        "spawn-wrap": "^2.0.0",
-        "test-exclude": "^6.0.0",
-        "yargs": "^15.0.2"
-      },
-      "dependencies": {
-        "cliui": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
-          "dev": true,
-          "requires": {
-            "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.0",
-            "wrap-ansi": "^6.2.0"
-          }
-        },
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-limit": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "resolve-from": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        },
-        "wrap-ansi": {
-          "version": "6.2.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "y18n": {
-          "version": "4.0.3",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
-          "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
-          "dev": true
-        },
-        "yargs": {
-          "version": "15.4.1",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
-          "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
-          "dev": true,
-          "requires": {
-            "cliui": "^6.0.0",
-            "decamelize": "^1.2.0",
-            "find-up": "^4.1.0",
-            "get-caller-file": "^2.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^4.2.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^18.1.2"
-          }
-        },
-        "yargs-parser": {
-          "version": "18.1.3",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
-          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
-          "dev": true,
-          "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
-          }
-        }
-      }
-    },
-    "object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
-      "dev": true
-    },
-    "object-inspect": {
-      "version": "1.12.2",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
-      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
-      "dev": true
-    },
-    "object-keys": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-      "dev": true
-    },
-    "object.assign": {
-      "version": "4.1.4",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
-      "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.4",
-        "has-symbols": "^1.0.3",
-        "object-keys": "^1.1.1"
-      }
-    },
-    "once": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-      "dev": true,
-      "requires": {
-        "wrappy": "1"
-      }
-    },
-    "onetime": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
-      "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
-      "dev": true,
-      "requires": {
-        "mimic-fn": "^4.0.0"
-      }
-    },
-    "open": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz",
-      "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==",
-      "dev": true,
-      "requires": {
-        "define-lazy-prop": "^2.0.0",
-        "is-docker": "^2.1.1",
-        "is-wsl": "^2.2.0"
-      }
-    },
-    "optionator": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
-      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
-      "dev": true,
-      "requires": {
-        "deep-is": "^0.1.3",
-        "fast-levenshtein": "^2.0.6",
-        "levn": "^0.4.1",
-        "prelude-ls": "^1.2.1",
-        "type-check": "^0.4.0",
-        "word-wrap": "^1.2.3"
-      }
-    },
-    "ora": {
-      "version": "6.1.2",
-      "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz",
-      "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==",
-      "dev": true,
-      "requires": {
-        "bl": "^5.0.0",
-        "chalk": "^5.0.0",
-        "cli-cursor": "^4.0.0",
-        "cli-spinners": "^2.6.1",
-        "is-interactive": "^2.0.0",
-        "is-unicode-supported": "^1.1.0",
-        "log-symbols": "^5.1.0",
-        "strip-ansi": "^7.0.1",
-        "wcwidth": "^1.0.1"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-          "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-          "dev": true
-        },
-        "chalk": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-          "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
-          "dev": true
-        },
-        "is-unicode-supported": {
-          "version": "1.3.0",
-          "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
-          "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
-          "dev": true
-        },
-        "log-symbols": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
-          "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
-          "dev": true,
-          "requires": {
-            "chalk": "^5.0.0",
-            "is-unicode-supported": "^1.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-          "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^6.0.1"
-          }
-        }
-      }
-    },
-    "os-name": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/os-name/-/os-name-5.0.1.tgz",
-      "integrity": "sha512-0EQpaHUHq7olp2/YFUr+0vZi9tMpDTblHGz+Ch5RntKxiRXOAY0JOz1UlxhSjMSksHvkm13eD6elJj3M8Ht/kw==",
-      "dev": true,
-      "requires": {
-        "macos-release": "^3.0.1",
-        "windows-release": "^5.0.1"
-      }
-    },
-    "os-tmpdir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
-      "dev": true
-    },
-    "p-cancelable": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
-      "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
-      "dev": true
-    },
-    "p-limit": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-      "dev": true,
-      "requires": {
-        "yocto-queue": "^0.1.0"
-      }
-    },
-    "p-locate": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-      "dev": true,
-      "requires": {
-        "p-limit": "^3.0.2"
-      }
-    },
-    "p-map": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
-      "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
-      "dev": true,
-      "requires": {
-        "aggregate-error": "^3.0.0"
-      }
-    },
-    "p-try": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "dev": true
-    },
-    "pac-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==",
-      "dev": true,
-      "requires": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4",
-        "get-uri": "3",
-        "http-proxy-agent": "^4.0.1",
-        "https-proxy-agent": "5",
-        "pac-resolver": "^5.0.0",
-        "raw-body": "^2.2.0",
-        "socks-proxy-agent": "5"
-      }
-    },
-    "pac-resolver": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz",
-      "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==",
-      "dev": true,
-      "requires": {
-        "degenerator": "^3.0.2",
-        "ip": "^1.1.5",
-        "netmask": "^2.0.2"
-      }
-    },
-    "package-hash": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
-      "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.15",
-        "hasha": "^5.0.0",
-        "lodash.flattendeep": "^4.4.0",
-        "release-zalgo": "^1.0.0"
-      }
-    },
-    "package-json": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz",
-      "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==",
-      "dev": true,
-      "requires": {
-        "got": "^12.1.0",
-        "registry-auth-token": "^5.0.1",
-        "registry-url": "^6.0.0",
-        "semver": "^7.3.7"
-      }
-    },
-    "parent-module": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-      "dev": true,
-      "requires": {
-        "callsites": "^3.0.0"
-      }
-    },
-    "parse-json": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
-      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.0.0",
-        "error-ex": "^1.3.1",
-        "json-parse-even-better-errors": "^2.3.0",
-        "lines-and-columns": "^1.1.6"
-      }
-    },
-    "parse-path": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz",
-      "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==",
-      "dev": true,
-      "requires": {
-        "protocols": "^2.0.0"
-      }
-    },
-    "parse-url": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz",
-      "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==",
-      "dev": true,
-      "requires": {
-        "parse-path": "^7.0.0"
-      }
-    },
-    "path-exists": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "dev": true
-    },
-    "path-is-absolute": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
-      "dev": true
-    },
-    "path-key": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-      "dev": true
-    },
-    "path-parse": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-      "dev": true
-    },
-    "path-to-regexp": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
-      "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
-      "dev": true,
-      "requires": {
-        "isarray": "0.0.1"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-          "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
-          "dev": true
-        }
-      }
-    },
-    "path-type": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-      "dev": true
-    },
-    "picocolors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-      "dev": true
-    },
-    "picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "dev": true
-    },
-    "pify": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-      "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
-      "dev": true
-    },
-    "pinkie": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
-      "dev": true
-    },
-    "pinkie-promise": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
-      "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
-      "dev": true,
-      "requires": {
-        "pinkie": "^2.0.0"
-      }
-    },
-    "pkg-dir": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
-      "dev": true,
-      "requires": {
-        "find-up": "^4.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-limit": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        }
-      }
-    },
-    "prelude-ls": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-      "dev": true
-    },
-    "process-on-spawn": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
-      "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
-      "dev": true,
-      "requires": {
-        "fromentries": "^1.2.0"
-      }
-    },
-    "promise.allsettled": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.5.tgz",
-      "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==",
-      "dev": true,
-      "requires": {
-        "array.prototype.map": "^1.0.4",
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1",
-        "get-intrinsic": "^1.1.1",
-        "iterate-value": "^1.0.2"
-      }
-    },
-    "proto-list": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
-      "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
-      "dev": true
-    },
-    "protocols": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz",
-      "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==",
-      "dev": true
-    },
-    "proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==",
-      "dev": true,
-      "requires": {
-        "agent-base": "^6.0.0",
-        "debug": "4",
-        "http-proxy-agent": "^4.0.0",
-        "https-proxy-agent": "^5.0.0",
-        "lru-cache": "^5.1.1",
-        "pac-proxy-agent": "^5.0.0",
-        "proxy-from-env": "^1.0.0",
-        "socks-proxy-agent": "^5.0.0"
-      }
-    },
-    "proxy-from-env": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
-      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
-      "dev": true
-    },
-    "punycode": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
-      "dev": true
-    },
-    "pupa": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz",
-      "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==",
-      "dev": true,
-      "requires": {
-        "escape-goat": "^4.0.0"
-      }
-    },
-    "queue-microtask": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-      "dev": true
-    },
-    "quick-lru": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
-      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
-      "dev": true
-    },
-    "randombytes": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
-      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "^5.1.0"
-      }
-    },
-    "raw-body": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
-      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
-      "dev": true,
-      "requires": {
-        "bytes": "3.1.2",
-        "http-errors": "2.0.0",
-        "iconv-lite": "0.4.24",
-        "unpipe": "1.0.0"
-      }
-    },
-    "rc": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
-      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
-      "dev": true,
-      "requires": {
-        "deep-extend": "^0.6.0",
-        "ini": "~1.3.0",
-        "minimist": "^1.2.0",
-        "strip-json-comments": "~2.0.1"
-      },
-      "dependencies": {
-        "ini": {
-          "version": "1.3.8",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
-          "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
-          "dev": true
-        },
-        "strip-json-comments": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-          "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
-          "dev": true
-        }
-      }
-    },
-    "readable-stream": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
-      }
-    },
-    "readdirp": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-      "dev": true,
-      "requires": {
-        "picomatch": "^2.2.1"
-      }
-    },
-    "rechoir": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
-      "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
-      "dev": true,
-      "requires": {
-        "resolve": "^1.1.6"
-      }
-    },
-    "regexp.prototype.flags": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
-      "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "functions-have-names": "^1.2.2"
-      }
-    },
-    "regexpp": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
-      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
-      "dev": true
-    },
-    "registry-auth-token": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz",
-      "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==",
-      "dev": true,
-      "requires": {
-        "@pnpm/npm-conf": "^1.0.4"
-      }
-    },
-    "registry-url": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz",
-      "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==",
-      "dev": true,
-      "requires": {
-        "rc": "1.2.8"
-      }
-    },
-    "release-it": {
-      "version": "15.5.0",
-      "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.5.0.tgz",
-      "integrity": "sha512-/pQo/PwEXAWRBgVGLE+3IQ3hUoeiDZMGAo/Egin1envCyLyjzrU7+0P2w4iZ1Xv5OxhC2AcaPaN5eY1ql47cBA==",
-      "dev": true,
-      "requires": {
-        "@iarna/toml": "2.2.5",
-        "@octokit/rest": "19.0.4",
-        "async-retry": "1.3.3",
-        "chalk": "5.0.1",
-        "cosmiconfig": "7.0.1",
-        "execa": "6.1.0",
-        "form-data": "4.0.0",
-        "git-url-parse": "13.1.0",
-        "globby": "13.1.2",
-        "got": "12.5.1",
-        "inquirer": "9.1.2",
-        "is-ci": "3.0.1",
-        "lodash": "4.17.21",
-        "mime-types": "2.1.35",
-        "new-github-release-url": "2.0.0",
-        "node-fetch": "3.2.10",
-        "open": "8.4.0",
-        "ora": "6.1.2",
-        "os-name": "5.0.1",
-        "promise.allsettled": "1.0.5",
-        "proxy-agent": "5.0.0",
-        "semver": "7.3.7",
-        "shelljs": "0.8.5",
-        "update-notifier": "6.0.2",
-        "url-join": "5.0.0",
-        "wildcard-match": "5.1.2",
-        "yargs-parser": "21.1.1"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz",
-          "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==",
-          "dev": true
-        },
-        "globby": {
-          "version": "13.1.2",
-          "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz",
-          "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==",
-          "dev": true,
-          "requires": {
-            "dir-glob": "^3.0.1",
-            "fast-glob": "^3.2.11",
-            "ignore": "^5.2.0",
-            "merge2": "^1.4.1",
-            "slash": "^4.0.0"
-          }
-        },
-        "lru-cache": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-          "dev": true,
-          "requires": {
-            "yallist": "^4.0.0"
-          }
-        },
-        "semver": {
-          "version": "7.3.7",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        },
-        "slash": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
-          "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
-          "dev": true
-        },
-        "yallist": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-          "dev": true
-        },
-        "yargs-parser": {
-          "version": "21.1.1",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-          "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-          "dev": true
-        }
-      }
-    },
-    "release-zalgo": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
-      "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
-      "dev": true,
-      "requires": {
-        "es6-error": "^4.0.1"
-      }
-    },
-    "require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-      "dev": true
-    },
-    "require-main-filename": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-      "dev": true
-    },
-    "resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
-      "dev": true,
-      "requires": {
-        "is-core-module": "^2.9.0",
-        "path-parse": "^1.0.7",
-        "supports-preserve-symlinks-flag": "^1.0.0"
-      }
-    },
-    "resolve-alpn": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
-      "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
-      "dev": true
-    },
-    "resolve-from": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-      "dev": true
-    },
-    "responselike": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
-      "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
-      "dev": true,
-      "requires": {
-        "lowercase-keys": "^3.0.0"
-      }
-    },
-    "restore-cursor": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
-      "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
-      "dev": true,
-      "requires": {
-        "onetime": "^5.1.0",
-        "signal-exit": "^3.0.2"
-      },
-      "dependencies": {
-        "mimic-fn": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
-          "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
-          "dev": true
-        },
-        "onetime": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
-          "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
-          "dev": true,
-          "requires": {
-            "mimic-fn": "^2.1.0"
-          }
-        }
-      }
-    },
-    "retry": {
-      "version": "0.13.1",
-      "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
-      "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
-      "dev": true
-    },
-    "reusify": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
-      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-      "dev": true
-    },
-    "rimraf": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.1.3"
-      }
-    },
-    "run-async": {
-      "version": "2.4.1",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
-      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
-      "dev": true
-    },
-    "run-parallel": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
-      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
-      "dev": true,
-      "requires": {
-        "queue-microtask": "^1.2.2"
-      }
-    },
-    "rxjs": {
-      "version": "7.5.7",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
-      "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
-      "dev": true,
-      "requires": {
-        "tslib": "^2.1.0"
-      }
-    },
-    "safe-buffer": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-      "dev": true
-    },
-    "safe-regex-test": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
-      "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.3",
-        "is-regex": "^1.1.4"
-      }
-    },
-    "safer-buffer": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true
-    },
-    "semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
-      "dev": true,
-      "requires": {
-        "lru-cache": "^6.0.0"
-      },
-      "dependencies": {
-        "lru-cache": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-          "dev": true,
-          "requires": {
-            "yallist": "^4.0.0"
-          }
-        },
-        "yallist": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-          "dev": true
-        }
-      }
-    },
-    "semver-diff": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz",
-      "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==",
-      "dev": true,
-      "requires": {
-        "semver": "^7.3.5"
-      }
-    },
-    "serialize-javascript": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
-      "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
-      "dev": true,
-      "requires": {
-        "randombytes": "^2.1.0"
-      }
-    },
-    "set-blocking": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
-      "dev": true
-    },
-    "setprototypeof": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
-      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
-      "dev": true
-    },
-    "shebang-command": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-      "dev": true,
-      "requires": {
-        "shebang-regex": "^3.0.0"
-      }
-    },
-    "shebang-regex": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-      "dev": true
-    },
-    "shelljs": {
-      "version": "0.8.5",
-      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
-      "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.0.0",
-        "interpret": "^1.0.0",
-        "rechoir": "^0.6.2"
-      }
-    },
-    "shiki": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz",
-      "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==",
-      "dev": true,
-      "requires": {
-        "jsonc-parser": "^3.0.0",
-        "vscode-oniguruma": "^1.6.1",
-        "vscode-textmate": "^6.0.0"
-      }
-    },
-    "side-channel": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.0",
-        "get-intrinsic": "^1.0.2",
-        "object-inspect": "^1.9.0"
-      }
-    },
-    "signal-exit": {
-      "version": "3.0.7",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
-      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
-      "dev": true
-    },
-    "sinon": {
-      "version": "14.0.1",
-      "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.1.tgz",
-      "integrity": "sha512-JhJ0jCiyBWVAHDS+YSjgEbDn7Wgz9iIjA1/RK+eseJN0vAAWIWiXBdrnb92ELPyjsfreCYntD1ORtLSfIrlvSQ==",
-      "dev": true,
-      "requires": {
-        "@sinonjs/commons": "^1.8.3",
-        "@sinonjs/fake-timers": "^9.1.2",
-        "@sinonjs/samsam": "^6.1.1",
-        "diff": "^5.0.0",
-        "nise": "^5.1.1",
-        "supports-color": "^7.2.0"
-      }
-    },
-    "slash": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
-      "dev": true
-    },
-    "smart-buffer": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
-      "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
-      "dev": true
-    },
-    "socks": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
-      "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
-      "dev": true,
-      "requires": {
-        "ip": "^2.0.0",
-        "smart-buffer": "^4.2.0"
-      },
-      "dependencies": {
-        "ip": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
-          "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
-          "dev": true
-        }
-      }
-    },
-    "socks-proxy-agent": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz",
-      "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==",
-      "dev": true,
-      "requires": {
-        "agent-base": "^6.0.2",
-        "debug": "4",
-        "socks": "^2.3.3"
-      }
-    },
-    "source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-      "dev": true
-    },
-    "source-map-support": {
-      "version": "0.5.21",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
-      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
-      "dev": true,
-      "requires": {
-        "buffer-from": "^1.0.0",
-        "source-map": "^0.6.0"
-      }
-    },
-    "spawn-wrap": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
-      "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
-      "dev": true,
-      "requires": {
-        "foreground-child": "^2.0.0",
-        "is-windows": "^1.0.2",
-        "make-dir": "^3.0.0",
-        "rimraf": "^3.0.0",
-        "signal-exit": "^3.0.2",
-        "which": "^2.0.1"
-      }
-    },
-    "sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
-      "dev": true
-    },
-    "statuses": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
-      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
-      "dev": true
-    },
-    "string_decoder": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
-      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.2.0"
-      }
-    },
-    "string-width": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
-      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
-      "dev": true,
-      "requires": {
-        "eastasianwidth": "^0.2.0",
-        "emoji-regex": "^9.2.2",
-        "strip-ansi": "^7.0.1"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-          "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-          "dev": true
-        },
-        "strip-ansi": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-          "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^6.0.1"
-          }
-        }
-      }
-    },
-    "string.prototype.trimend": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
-      "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.4",
-        "es-abstract": "^1.19.5"
-      }
-    },
-    "string.prototype.trimstart": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
-      "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.4",
-        "es-abstract": "^1.19.5"
-      }
-    },
-    "strip-ansi": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "dev": true,
-      "requires": {
-        "ansi-regex": "^5.0.1"
-      }
-    },
-    "strip-bom": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
-      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
-      "dev": true
-    },
-    "strip-final-newline": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
-      "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
-      "dev": true
-    },
-    "strip-json-comments": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-      "dev": true
-    },
-    "strip-outer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
-      "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
-      "dev": true,
-      "requires": {
-        "escape-string-regexp": "^1.0.2"
-      },
-      "dependencies": {
-        "escape-string-regexp": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-          "dev": true
-        }
-      }
-    },
-    "supports-color": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-      "dev": true,
-      "requires": {
-        "has-flag": "^4.0.0"
-      }
-    },
-    "supports-preserve-symlinks-flag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-      "dev": true
-    },
-    "test-exclude": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
-      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
-      "dev": true,
-      "requires": {
-        "@istanbuljs/schema": "^0.1.2",
-        "glob": "^7.1.4",
-        "minimatch": "^3.0.4"
-      }
-    },
-    "text-table": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-      "dev": true
-    },
-    "through": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
-      "dev": true
-    },
-    "tmp": {
-      "version": "0.0.33",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
-      "dev": true,
-      "requires": {
-        "os-tmpdir": "~1.0.2"
-      }
-    },
-    "to-fast-properties": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
-      "dev": true
-    },
-    "to-regex-range": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "dev": true,
-      "requires": {
-        "is-number": "^7.0.0"
-      }
-    },
-    "toidentifier": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
-      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
-      "dev": true
-    },
-    "tr46": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
-      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
-      "dev": true
-    },
-    "trim-repeated": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
-      "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
-      "dev": true,
-      "requires": {
-        "escape-string-regexp": "^1.0.2"
-      },
-      "dependencies": {
-        "escape-string-regexp": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-          "dev": true
-        }
-      }
-    },
-    "ts-node": {
-      "version": "10.9.1",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
-      "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
-      "dev": true,
-      "requires": {
-        "@cspotcode/source-map-support": "^0.8.0",
-        "@tsconfig/node10": "^1.0.7",
-        "@tsconfig/node12": "^1.0.7",
-        "@tsconfig/node14": "^1.0.0",
-        "@tsconfig/node16": "^1.0.2",
-        "acorn": "^8.4.1",
-        "acorn-walk": "^8.1.1",
-        "arg": "^4.1.0",
-        "create-require": "^1.1.0",
-        "diff": "^4.0.1",
-        "make-error": "^1.1.1",
-        "v8-compile-cache-lib": "^3.0.1",
-        "yn": "3.1.1"
-      },
-      "dependencies": {
-        "diff": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
-          "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
-          "dev": true
-        }
-      }
-    },
-    "tslib": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
-      "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
-      "dev": true
-    },
-    "tsutils": {
-      "version": "3.21.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
-      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.8.1"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "1.14.1",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-          "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
-          "dev": true
-        }
-      }
-    },
-    "type-check": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
-      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
-      "dev": true,
-      "requires": {
-        "prelude-ls": "^1.2.1"
-      }
-    },
-    "type-detect": {
-      "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
-      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
-      "dev": true
-    },
-    "type-fest": {
-      "version": "0.20.2",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-      "dev": true
-    },
-    "typedarray-to-buffer": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
-      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
-      "dev": true,
-      "requires": {
-        "is-typedarray": "^1.0.0"
-      }
-    },
-    "typedoc": {
-      "version": "0.23.18",
-      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.18.tgz",
-      "integrity": "sha512-0Tq/uFkUuWyRYyjOShTkhsOm6u5E8wf0i6L76/k5znEaxvWKHGeT2ywZThGrDrryV/skO/REM824D1gm8ccQuA==",
-      "dev": true,
-      "requires": {
-        "lunr": "^2.3.9",
-        "marked": "^4.0.19",
-        "minimatch": "^5.1.0",
-        "shiki": "^0.11.1"
-      },
-      "dependencies": {
-        "brace-expansion": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-          "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-          "dev": true,
-          "requires": {
-            "balanced-match": "^1.0.0"
-          }
-        },
-        "minimatch": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
-          "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^2.0.1"
-          }
-        }
-      }
-    },
-    "typescript": {
-      "version": "4.8.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
-      "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
-      "dev": true
-    },
-    "unbox-primitive": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
-      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "has-bigints": "^1.0.2",
-        "has-symbols": "^1.0.3",
-        "which-boxed-primitive": "^1.0.2"
-      }
-    },
-    "unique-string": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz",
-      "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==",
-      "dev": true,
-      "requires": {
-        "crypto-random-string": "^4.0.0"
-      }
-    },
-    "universal-user-agent": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
-      "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
-      "dev": true
-    },
-    "universalify": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
-      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
-      "dev": true
-    },
-    "unpipe": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
-      "dev": true
-    },
-    "update-browserslist-db": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
-      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
-      "dev": true,
-      "requires": {
-        "escalade": "^3.1.1",
-        "picocolors": "^1.0.0"
-      }
-    },
-    "update-notifier": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz",
-      "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==",
-      "dev": true,
-      "requires": {
-        "boxen": "^7.0.0",
-        "chalk": "^5.0.1",
-        "configstore": "^6.0.0",
-        "has-yarn": "^3.0.0",
-        "import-lazy": "^4.0.0",
-        "is-ci": "^3.0.1",
-        "is-installed-globally": "^0.4.0",
-        "is-npm": "^6.0.0",
-        "is-yarn-global": "^0.4.0",
-        "latest-version": "^7.0.0",
-        "pupa": "^3.1.0",
-        "semver": "^7.3.7",
-        "semver-diff": "^4.0.0",
-        "xdg-basedir": "^5.1.0"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz",
-          "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
-          "dev": true
-        }
-      }
-    },
-    "uri-js": {
-      "version": "4.4.1",
-      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
-      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
-      "dev": true,
-      "requires": {
-        "punycode": "^2.1.0"
-      }
-    },
-    "url-join": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz",
-      "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==",
-      "dev": true
-    },
-    "util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
-      "dev": true
-    },
-    "uuid": {
-      "version": "8.3.2",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
-      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
-      "dev": true
-    },
-    "v8-compile-cache-lib": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
-      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
-      "dev": true
-    },
-    "vm2": {
-      "version": "3.9.11",
-      "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.11.tgz",
-      "integrity": "sha512-PFG8iJRSjvvBdisowQ7iVF580DXb1uCIiGaXgm7tynMR1uTBlv7UJlB1zdv5KJ+Tmq1f0Upnj3fayoEOPpCBKg==",
-      "dev": true,
-      "requires": {
-        "acorn": "^8.7.0",
-        "acorn-walk": "^8.2.0"
-      }
-    },
-    "vscode-oniguruma": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz",
-      "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==",
-      "dev": true
-    },
-    "vscode-textmate": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz",
-      "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==",
-      "dev": true
-    },
-    "wcwidth": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
-      "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
-      "dev": true,
-      "requires": {
-        "defaults": "^1.0.3"
-      }
-    },
-    "web-streams-polyfill": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
-      "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
-      "dev": true
-    },
-    "webidl-conversions": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
-      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
-      "dev": true
-    },
-    "whatwg-url": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
-      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
-      "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",
-      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dev": true,
-      "requires": {
-        "isexe": "^2.0.0"
-      }
-    },
-    "which-boxed-primitive": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
-      "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
-      "dev": true,
-      "requires": {
-        "is-bigint": "^1.0.1",
-        "is-boolean-object": "^1.1.0",
-        "is-number-object": "^1.0.4",
-        "is-string": "^1.0.5",
-        "is-symbol": "^1.0.3"
-      }
-    },
-    "which-module": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
-      "dev": true
-    },
-    "widest-line": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz",
-      "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==",
-      "dev": true,
-      "requires": {
-        "string-width": "^5.0.1"
-      }
-    },
-    "wildcard-match": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.2.tgz",
-      "integrity": "sha512-qNXwI591Z88c8bWxp+yjV60Ch4F8Riawe3iGxbzquhy8Xs9m+0+SLFBGb/0yCTIDElawtaImC37fYZ+dr32KqQ==",
-      "dev": true
-    },
-    "windows-release": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.0.1.tgz",
-      "integrity": "sha512-y1xFdFvdMiDXI3xiOhMbJwt1Y7dUxidha0CWPs1NgjZIjZANTcX7+7bMqNjuezhzb8s5JGEiBAbQjQQYYy7ulw==",
-      "dev": true,
-      "requires": {
-        "execa": "^5.1.1"
-      },
-      "dependencies": {
-        "execa": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
-          "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
-          "dev": true,
-          "requires": {
-            "cross-spawn": "^7.0.3",
-            "get-stream": "^6.0.0",
-            "human-signals": "^2.1.0",
-            "is-stream": "^2.0.0",
-            "merge-stream": "^2.0.0",
-            "npm-run-path": "^4.0.1",
-            "onetime": "^5.1.2",
-            "signal-exit": "^3.0.3",
-            "strip-final-newline": "^2.0.0"
-          }
-        },
-        "human-signals": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
-          "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
-          "dev": true
-        },
-        "mimic-fn": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
-          "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
-          "dev": true
-        },
-        "npm-run-path": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-          "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
-          "dev": true,
-          "requires": {
-            "path-key": "^3.0.0"
-          }
-        },
-        "onetime": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
-          "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
-          "dev": true,
-          "requires": {
-            "mimic-fn": "^2.1.0"
-          }
-        },
-        "strip-final-newline": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
-          "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
-          "dev": true
-        }
-      }
-    },
-    "word-wrap": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
-      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
-      "dev": true
-    },
-    "workerpool": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
-      "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
-      "dev": true
-    },
-    "wrap-ansi": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz",
-      "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^6.1.0",
-        "string-width": "^5.0.1",
-        "strip-ansi": "^7.0.1"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-          "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "6.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
-          "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
-          "dev": true
-        },
-        "strip-ansi": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
-          "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^6.0.1"
-          }
-        }
-      }
-    },
-    "wrappy": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-      "dev": true
-    },
-    "write-file-atomic": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
-      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
-      "dev": true,
-      "requires": {
-        "imurmurhash": "^0.1.4",
-        "is-typedarray": "^1.0.0",
-        "signal-exit": "^3.0.2",
-        "typedarray-to-buffer": "^3.1.5"
-      }
-    },
-    "xdg-basedir": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz",
-      "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==",
-      "dev": true
-    },
-    "xregexp": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
-      "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==",
-      "dev": true
-    },
-    "y18n": {
-      "version": "5.0.8",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-      "dev": true
-    },
-    "yallist": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-      "dev": true
-    },
-    "yaml": {
-      "version": "1.10.2",
-      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
-      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
-      "dev": true
-    },
-    "yargs": {
-      "version": "17.6.0",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz",
-      "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==",
-      "dev": true,
-      "requires": {
-        "cliui": "^8.0.1",
-        "escalade": "^3.1.1",
-        "get-caller-file": "^2.0.5",
-        "require-directory": "^2.1.1",
-        "string-width": "^4.2.3",
-        "y18n": "^5.0.5",
-        "yargs-parser": "^21.0.0"
-      },
-      "dependencies": {
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        },
-        "yargs-parser": {
-          "version": "21.1.1",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-          "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-          "dev": true
-        }
-      }
-    },
-    "yargs-parser": {
-      "version": "20.2.4",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
-      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
-      "dev": true
-    },
-    "yargs-unparser": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
-      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
-      "dev": true,
-      "requires": {
-        "camelcase": "^6.0.0",
-        "decamelize": "^4.0.0",
-        "flat": "^5.0.2",
-        "is-plain-obj": "^2.1.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
-          "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
-          "dev": true
-        },
-        "decamelize": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
-          "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
-          "dev": true
-        }
-      }
-    },
-    "yn": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
-      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
-      "dev": true
-    },
-    "yocto-queue": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
-      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
-      "dev": true
-    }
   }
 }
diff --git a/package.json b/package.json
index a6f01ce76fb..e8ceef7173d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "redis",
   "description": "A modern, high performance Redis client",
-  "version": "4.5.1",
+  "version": "4.7.0",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -23,18 +23,18 @@
     "gh-pages": "gh-pages -d ./documentation -e ./documentation -u 'documentation-bot <documentation@bot>'"
   },
   "dependencies": {
-    "@redis/bloom": "1.1.0",
-    "@redis/client": "1.4.2",
-    "@redis/graph": "1.1.0",
-    "@redis/json": "1.0.4",
-    "@redis/search": "1.1.0",
-    "@redis/time-series": "1.0.4"
+    "@redis/bloom": "1.2.0",
+    "@redis/client": "1.6.0",
+    "@redis/graph": "1.1.1",
+    "@redis/json": "1.0.7",
+    "@redis/search": "1.2.0",
+    "@redis/time-series": "1.1.0"
   },
   "devDependencies": {
-    "@tsconfig/node14": "^1.0.3",
-    "gh-pages": "^4.0.0",
-    "release-it": "^15.3.0",
-    "typescript": "^4.7.4"
+    "@tsconfig/node14": "^14.1.0",
+    "gh-pages": "^6.0.0",
+    "release-it": "^16.1.5",
+    "typescript": "^5.2.2"
   },
   "repository": {
     "type": "git",
@@ -43,5 +43,8 @@
   "bugs": {
     "url": "https://github.com/redis/node-redis/issues"
   },
-  "homepage": "https://github.com/redis/node-redis"
+  "homepage": "https://github.com/redis/node-redis",
+  "keywords": [
+    "redis"
+  ]
 }
diff --git a/packages/bloom/package.json b/packages/bloom/package.json
index ce79d3ccf7a..8a9d9f7a87a 100644
--- a/packages/bloom/package.json
+++ b/packages/bloom/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/bloom",
-  "version": "1.1.0",
+  "version": "1.2.0",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -18,12 +18,24 @@
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
     "@redis/test-utils": "*",
-    "@types/node": "^18.11.6",
+    "@types/node": "^20.6.2",
     "nyc": "^15.1.0",
-    "release-it": "^15.5.0",
+    "release-it": "^16.1.5",
     "source-map-support": "^0.5.21",
     "ts-node": "^10.9.1",
-    "typedoc": "^0.23.18",
-    "typescript": "^4.8.4"
-  }
+    "typedoc": "^0.25.1",
+    "typescript": "^5.2.2"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/redis/node-redis.git"
+  },
+  "bugs": {
+    "url": "https://github.com/redis/node-redis/issues"
+  },
+  "homepage": "https://github.com/redis/node-redis/tree/master/packages/bloom",
+  "keywords": [
+    "redis",
+    "RedisBloom"
+  ]
 }
diff --git a/packages/client/index.ts b/packages/client/index.ts
index 7e2d25f6d1b..8b21c5d5a32 100644
--- a/packages/client/index.ts
+++ b/packages/client/index.ts
@@ -15,8 +15,10 @@ export const createCluster = RedisCluster.create;
 
 export { defineScript } from './lib/lua-script';
 
+export * from './lib/errors';
+
 export { GeoReplyWith } from './lib/commands/generic-transformers';
 
-export * from './lib/errors';
+export { SetOptions } from './lib/commands/SET';
 
-export { SetOptions } from "./lib/commands/SET";
+export { RedisFlushModes } from './lib/commands/FLUSHALL';
diff --git a/packages/client/lib/client/RESP2/decoder.ts b/packages/client/lib/client/RESP2/decoder.ts
index e9d2317deab..525f118bf30 100644
--- a/packages/client/lib/client/RESP2/decoder.ts
+++ b/packages/client/lib/client/RESP2/decoder.ts
@@ -203,9 +203,9 @@ export default class RESP2Decoder {
             this.arrayItemType = undefined;
 
             if (length === -1) {
-                return this.returnArrayReply(null, arraysToKeep);
+                return this.returnArrayReply(null, arraysToKeep, chunk);
             } else if (length === 0) {
-                return this.returnArrayReply([], arraysToKeep);
+                return this.returnArrayReply([], arraysToKeep, chunk);
             }
 
             this.arraysInProcess.push({
@@ -235,20 +235,23 @@ export default class RESP2Decoder {
         }
     }
 
-    private returnArrayReply(reply: ArrayReply, arraysToKeep: number): ArrayReply | undefined {
+    private returnArrayReply(reply: ArrayReply, arraysToKeep: number, chunk?: Buffer): ArrayReply | undefined {
         if (this.arraysInProcess.length <= arraysToKeep) return reply;
 
-        return this.pushArrayItem(reply, arraysToKeep);
+        return this.pushArrayItem(reply, arraysToKeep, chunk);
     }
 
-    private pushArrayItem(item: Reply, arraysToKeep: number): ArrayReply | undefined {
+    private pushArrayItem(item: Reply, arraysToKeep: number, chunk?: Buffer): ArrayReply | undefined {
         const to = this.arraysInProcess[this.arraysInProcess.length - 1]!;
         to.array[to.pushCounter] = item;
         if (++to.pushCounter === to.array.length) {
             return this.returnArrayReply(
                 this.arraysInProcess.pop()!.array,
-                arraysToKeep
+                arraysToKeep,
+                chunk
             );
+        } else if (chunk && chunk.length > this.cursor) {
+            return this.parseArray(chunk, arraysToKeep);
         }
     }
 }
diff --git a/packages/client/lib/client/commands-queue.ts b/packages/client/lib/client/commands-queue.ts
index f951cd6f845..7fffed86580 100644
--- a/packages/client/lib/client/commands-queue.ts
+++ b/packages/client/lib/client/commands-queue.ts
@@ -1,18 +1,18 @@
 import * as LinkedList from 'yallist';
 import { AbortError, ErrorReply } from '../errors';
-import { RedisCommandArgument, RedisCommandArguments, RedisCommandRawReply } from '../commands';
+import { RedisCommandArguments, RedisCommandRawReply } from '../commands';
 import RESP2Decoder from './RESP2/decoder';
 import encodeCommand from './RESP2/encoder';
+import { ChannelListeners, PubSub, PubSubCommand, PubSubListener, PubSubType, PubSubTypeListeners } from './pub-sub';
 
 export interface QueueCommandOptions {
     asap?: boolean;
     chainId?: symbol;
     signal?: AbortSignal;
     returnBuffers?: boolean;
-    ignorePubSubMode?: boolean;
 }
 
-interface CommandWaitingToBeSent extends CommandWaitingForReply {
+export interface CommandWaitingToBeSent extends CommandWaitingForReply {
     args: RedisCommandArguments;
     chainId?: symbol;
     abort?: {
@@ -28,27 +28,9 @@ interface CommandWaitingForReply {
     returnBuffers?: boolean;
 }
 
-export enum PubSubSubscribeCommands {
-    SUBSCRIBE = 'SUBSCRIBE',
-    PSUBSCRIBE = 'PSUBSCRIBE'
-}
-
-export enum PubSubUnsubscribeCommands {
-    UNSUBSCRIBE = 'UNSUBSCRIBE',
-    PUNSUBSCRIBE = 'PUNSUBSCRIBE'
-}
-
-export type PubSubListener<
-    RETURN_BUFFERS extends boolean = false,
-    T = RETURN_BUFFERS extends true ? Buffer : string
-> = (message: T, channel: T) => unknown;
+const PONG = Buffer.from('pong');
 
-interface PubSubListeners {
-    buffers: Set<PubSubListener<true>>;
-    strings: Set<PubSubListener<false>>;
-}
-
-type PubSubListenersMap = Map<string, PubSubListeners>;
+export type OnShardedChannelMoved = (channel: string, listeners: ChannelListeners) => void;
 
 export default class RedisCommandsQueue {
     static #flushQueue<T extends CommandWaitingForReply>(queue: LinkedList<T>, err: Error): void {
@@ -57,67 +39,54 @@ export default class RedisCommandsQueue {
         }
     }
 
-    static #emitPubSubMessage(listenersMap: PubSubListenersMap, message: Buffer, channel: Buffer, pattern?: Buffer): void {
-        const keyString = (pattern ?? channel).toString(),
-            listeners = listenersMap.get(keyString);
-
-        if (!listeners) return;
-
-        for (const listener of listeners.buffers) {
-            listener(message, channel);
-        }
-
-        if (!listeners.strings.size) return;
-
-        const channelString = pattern ? channel.toString() : keyString,
-            messageString = channelString === '__redis__:invalidate' ?
-                // https://github.com/redis/redis/pull/7469
-                // https://github.com/redis/redis/issues/7463
-                (message === null ? null : (message as any as Array<Buffer>).map(x => x.toString())) as any :
-                message.toString();
-        for (const listener of listeners.strings) {
-            listener(messageString, channelString);
-        }
-    }
-
     readonly #maxLength: number | null | undefined;
     readonly #waitingToBeSent = new LinkedList<CommandWaitingToBeSent>();
     readonly #waitingForReply = new LinkedList<CommandWaitingForReply>();
+    readonly #onShardedChannelMoved: OnShardedChannelMoved;
 
-    readonly #pubSubState = {
-        isActive: false,
-        subscribing: 0,
-        subscribed: 0,
-        unsubscribing: 0,
-        listeners: {
-            channels: new Map(),
-            patterns: new Map()
-        }
-    };
+    readonly #pubSub = new PubSub();
 
-    static readonly #PUB_SUB_MESSAGES = {
-        message: Buffer.from('message'),
-        pMessage: Buffer.from('pmessage'),
-        subscribe: Buffer.from('subscribe'),
-        pSubscribe: Buffer.from('psubscribe'),
-        unsubscribe: Buffer.from('unsubscribe'),
-        pUnsubscribe: Buffer.from('punsubscribe')
-    };
+    get isPubSubActive() {
+        return this.#pubSub.isActive;
+    }
 
     #chainInExecution: symbol | undefined;
 
     #decoder = new RESP2Decoder({
         returnStringsAsBuffers: () => {
             return !!this.#waitingForReply.head?.value.returnBuffers ||
-                this.#pubSubState.isActive;
+                this.#pubSub.isActive;
         },
         onReply: reply => {
-            if (this.#handlePubSubReply(reply)) {
-                return;
-            } else if (!this.#waitingForReply.length) {
-                throw new Error('Got an unexpected reply from Redis');
+            if (this.#pubSub.isActive && Array.isArray(reply)) {
+                if (this.#pubSub.handleMessageReply(reply as Array<Buffer>)) return;
+                
+                const isShardedUnsubscribe = PubSub.isShardedUnsubscribe(reply as Array<Buffer>);
+                if (isShardedUnsubscribe && !this.#waitingForReply.length) {
+                    const channel = (reply[1] as Buffer).toString();
+                    this.#onShardedChannelMoved(
+                        channel,
+                        this.#pubSub.removeShardedListeners(channel)
+                    );
+                    return;
+                } else if (isShardedUnsubscribe || PubSub.isStatusReply(reply as Array<Buffer>)) {
+                    const head = this.#waitingForReply.head!.value;
+                    if (
+                        (Number.isNaN(head.channelsCounter!) && reply[2] === 0) ||
+                        --head.channelsCounter! === 0
+                    ) {
+                        this.#waitingForReply.shift()!.resolve();
+                    }
+                    return;
+                }
+                if (PONG.equals(reply[0] as Buffer)) {
+                    const { resolve, returnBuffers } = this.#waitingForReply.shift()!,
+                        buffer = ((reply[1] as Buffer).length === 0 ? reply[0] : reply[1]) as Buffer;
+                    resolve(returnBuffers ? buffer : buffer.toString());
+                    return;
+                }
             }
-
+            
             const { resolve, reject } = this.#waitingForReply.shift()!;
             if (reply instanceof ErrorReply) {
                 reject(reply);
@@ -127,14 +96,16 @@ export default class RedisCommandsQueue {
         }
     });
 
-    constructor(maxLength: number | null | undefined) {
+    constructor(
+        maxLength: number | null | undefined,
+        onShardedChannelMoved: OnShardedChannelMoved
+    ) {
         this.#maxLength = maxLength;
+        this.#onShardedChannelMoved = onShardedChannelMoved;
     }
 
     addCommand<T = RedisCommandRawReply>(args: RedisCommandArguments, options?: QueueCommandOptions): Promise<T> {
-        if (this.#pubSubState.isActive && !options?.ignorePubSubMode) {
-            return Promise.reject(new Error('Cannot send commands in PubSub mode'));
-        } else if (this.#maxLength && this.#waitingToBeSent.length + this.#waitingForReply.length >= this.#maxLength) {
+        if (this.#maxLength && this.#waitingToBeSent.length + this.#waitingForReply.length >= this.#maxLength) {
             return Promise.reject(new Error('The queue is full'));
         } else if (options?.signal?.aborted) {
             return Promise.reject(new AbortError());
@@ -173,158 +144,76 @@ export default class RedisCommandsQueue {
     }
 
     subscribe<T extends boolean>(
-        command: PubSubSubscribeCommands,
-        channels: RedisCommandArgument | Array<RedisCommandArgument>,
+        type: PubSubType,
+        channels: string | Array<string>,
         listener: PubSubListener<T>,
         returnBuffers?: T
-    ): Promise<void> {
-        const channelsToSubscribe: Array<RedisCommandArgument> = [],
-            listenersMap = command === PubSubSubscribeCommands.SUBSCRIBE ?
-                this.#pubSubState.listeners.channels :
-                this.#pubSubState.listeners.patterns;
-        for (const channel of (Array.isArray(channels) ? channels : [channels])) {
-            const channelString = typeof channel === 'string' ? channel : channel.toString();
-            let listeners = listenersMap.get(channelString);
-            if (!listeners) {
-                listeners = {
-                    buffers: new Set(),
-                    strings: new Set()
-                };
-                listenersMap.set(channelString, listeners);
-                channelsToSubscribe.push(channel);
-            }
-
-            // https://github.com/microsoft/TypeScript/issues/23132
-            (returnBuffers ? listeners.buffers : listeners.strings).add(listener as any);
-        }
-
-        if (!channelsToSubscribe.length) {
-            return Promise.resolve();
-        }
-
-        return this.#pushPubSubCommand(command, channelsToSubscribe);
+    ) {
+        return this.#pushPubSubCommand(
+            this.#pubSub.subscribe(type, channels, listener, returnBuffers)
+        );
     }
 
     unsubscribe<T extends boolean>(
-        command: PubSubUnsubscribeCommands,
+        type: PubSubType,
         channels?: string | Array<string>,
         listener?: PubSubListener<T>,
         returnBuffers?: T
-    ): Promise<void> {
-        const listeners = command === PubSubUnsubscribeCommands.UNSUBSCRIBE ?
-            this.#pubSubState.listeners.channels :
-            this.#pubSubState.listeners.patterns;
-
-        if (!channels) {
-            const size = listeners.size;
-            listeners.clear();
-            return this.#pushPubSubCommand(command, size);
-        }
-
-        const channelsToUnsubscribe = [];
-        for (const channel of (Array.isArray(channels) ? channels : [channels])) {
-            const sets = listeners.get(channel);
-            if (!sets) continue;
-
-            let shouldUnsubscribe;
-            if (listener) {
-                // https://github.com/microsoft/TypeScript/issues/23132
-                (returnBuffers ? sets.buffers : sets.strings).delete(listener as any);
-                shouldUnsubscribe = !sets.buffers.size && !sets.strings.size;
-            } else {
-                shouldUnsubscribe = true;
-            }
+    ) {
+        return this.#pushPubSubCommand(
+            this.#pubSub.unsubscribe(type, channels, listener, returnBuffers)
+        );
+    }
 
-            if (shouldUnsubscribe) {
-                channelsToUnsubscribe.push(channel);
-                listeners.delete(channel);
-            }
-        }
+    resubscribe(): Promise<any> | undefined {
+        const commands = this.#pubSub.resubscribe();
+        if (!commands.length) return;
 
-        if (!channelsToUnsubscribe.length) {
-            return Promise.resolve();
-        }
+        return Promise.all(
+            commands.map(command => this.#pushPubSubCommand(command))
+        );
+    }
 
-        return this.#pushPubSubCommand(command, channelsToUnsubscribe);
+    extendPubSubChannelListeners(
+        type: PubSubType,
+        channel: string,
+        listeners: ChannelListeners
+    ) {
+        return this.#pushPubSubCommand(
+            this.#pubSub.extendChannelListeners(type, channel, listeners)
+        );
     }
 
-    #pushPubSubCommand(command: PubSubSubscribeCommands | PubSubUnsubscribeCommands, channels: number | Array<RedisCommandArgument>): Promise<void> {
-        return new Promise((resolve, reject) => {
-            const isSubscribe = command === PubSubSubscribeCommands.SUBSCRIBE || command === PubSubSubscribeCommands.PSUBSCRIBE,
-                inProgressKey = isSubscribe ? 'subscribing' : 'unsubscribing',
-                commandArgs: Array<RedisCommandArgument> = [command];
+    extendPubSubListeners(type: PubSubType, listeners: PubSubTypeListeners) {
+        return this.#pushPubSubCommand(
+            this.#pubSub.extendTypeListeners(type, listeners)
+        );
+    }
 
-            let channelsCounter: number;
-            if (typeof channels === 'number') { // unsubscribe only
-                channelsCounter = channels;
-            } else {
-                commandArgs.push(...channels);
-                channelsCounter = channels.length;
-            }
+    getPubSubListeners(type: PubSubType) {
+        return this.#pubSub.getTypeListeners(type);
+    }
 
-            this.#pubSubState.isActive = true;
-            this.#pubSubState[inProgressKey] += channelsCounter;
+    #pushPubSubCommand(command: PubSubCommand) {
+        if (command === undefined) return;
 
+        return new Promise<void>((resolve, reject) => {
             this.#waitingToBeSent.push({
-                args: commandArgs,
-                channelsCounter,
+                args: command.args,
+                channelsCounter: command.channelsCounter,
                 returnBuffers: true,
                 resolve: () => {
-                    this.#pubSubState[inProgressKey] -= channelsCounter;
-                    this.#pubSubState.subscribed += channelsCounter * (isSubscribe ? 1 : -1);
-                    this.#updatePubSubActiveState();
+                    command.resolve();
                     resolve();
                 },
                 reject: err => {
-                    this.#pubSubState[inProgressKey] -= channelsCounter * (isSubscribe ? 1 : -1);
-                    this.#updatePubSubActiveState();
+                    command.reject?.();
                     reject(err);
                 }
             });
         });
     }
 
-    #updatePubSubActiveState(): void {
-        if (
-            !this.#pubSubState.subscribed &&
-            !this.#pubSubState.subscribing &&
-            !this.#pubSubState.subscribed
-        ) {
-            this.#pubSubState.isActive = false;
-        }
-    }
-
-    resubscribe(): Promise<any> | undefined {
-        this.#pubSubState.subscribed = 0;
-        this.#pubSubState.subscribing = 0;
-        this.#pubSubState.unsubscribing = 0;
-
-        const promises = [],
-            { channels, patterns } = this.#pubSubState.listeners;
-
-        if (channels.size) {
-            promises.push(
-                this.#pushPubSubCommand(
-                    PubSubSubscribeCommands.SUBSCRIBE,
-                    [...channels.keys()]
-                )
-            );
-        }
-
-        if (patterns.size) {
-            promises.push(
-                this.#pushPubSubCommand(
-                    PubSubSubscribeCommands.PSUBSCRIBE,
-                    [...patterns.keys()]
-                )
-            );
-        }
-
-        if (promises.length) {
-            return Promise.all(promises);
-        }
-    }
-
     getCommandToSend(): RedisCommandArguments | undefined {
         const toSend = this.#waitingToBeSent.shift();
         if (!toSend) return;
@@ -351,39 +240,9 @@ export default class RedisCommandsQueue {
         this.#decoder.write(chunk);
     }
 
-    #handlePubSubReply(reply: any): boolean {
-        if (!this.#pubSubState.isActive || !Array.isArray(reply)) return false;
-
-        if (RedisCommandsQueue.#PUB_SUB_MESSAGES.message.equals(reply[0])) {
-            RedisCommandsQueue.#emitPubSubMessage(
-                this.#pubSubState.listeners.channels,
-                reply[2],
-                reply[1]
-            );
-        } else if (RedisCommandsQueue.#PUB_SUB_MESSAGES.pMessage.equals(reply[0])) {
-            RedisCommandsQueue.#emitPubSubMessage(
-                this.#pubSubState.listeners.patterns,
-                reply[3],
-                reply[2],
-                reply[1]
-            );
-        } else if (
-            RedisCommandsQueue.#PUB_SUB_MESSAGES.subscribe.equals(reply[0]) ||
-            RedisCommandsQueue.#PUB_SUB_MESSAGES.pSubscribe.equals(reply[0]) ||
-            RedisCommandsQueue.#PUB_SUB_MESSAGES.unsubscribe.equals(reply[0]) ||
-            RedisCommandsQueue.#PUB_SUB_MESSAGES.pUnsubscribe.equals(reply[0])
-        ) {
-            if (--this.#waitingForReply.head!.value.channelsCounter! === 0) {
-                this.#waitingForReply.shift()!.resolve();
-            }
-        }
-
-        return true;
-    }
-
     flushWaitingForReply(err: Error): void {
         this.#decoder.reset();
-        this.#pubSubState.isActive = false;
+        this.#pubSub.reset();
         RedisCommandsQueue.#flushQueue(this.#waitingForReply, err);
 
         if (!this.#chainInExecution) return;
@@ -396,6 +255,8 @@ export default class RedisCommandsQueue {
     }
 
     flushAll(err: Error): void {
+        this.#decoder.reset();
+        this.#pubSub.reset();
         RedisCommandsQueue.#flushQueue(this.#waitingForReply, err);
         RedisCommandsQueue.#flushQueue(this.#waitingToBeSent, err);
     }
diff --git a/packages/client/lib/client/commands.ts b/packages/client/lib/client/commands.ts
index f4eb1f1e172..76ae5d73735 100644
--- a/packages/client/lib/client/commands.ts
+++ b/packages/client/lib/client/commands.ts
@@ -21,7 +21,9 @@ import * as CLIENT_GETNAME from '../commands/CLIENT_GETNAME';
 import * as CLIENT_GETREDIR from '../commands/CLIENT_GETREDIR';
 import * as CLIENT_ID from '../commands/CLIENT_ID';
 import * as CLIENT_KILL from '../commands/CLIENT_KILL';
+import * as CLIENT_LIST from '../commands/CLIENT_LIST';
 import * as CLIENT_NO_EVICT from '../commands/CLIENT_NO-EVICT';
+import * as CLIENT_NO_TOUCH from '../commands/CLIENT_NO-TOUCH';
 import * as CLIENT_PAUSE from '../commands/CLIENT_PAUSE';
 import * as CLIENT_SETNAME from '../commands/CLIENT_SETNAME';
 import * as CLIENT_TRACKING from '../commands/CLIENT_TRACKING';
@@ -44,6 +46,7 @@ import * as CLUSTER_KEYSLOT from '../commands/CLUSTER_KEYSLOT';
 import * as CLUSTER_LINKS from '../commands/CLUSTER_LINKS';
 import * as CLUSTER_MEET from '../commands/CLUSTER_MEET';
 import * as CLUSTER_MYID from '../commands/CLUSTER_MYID';
+import * as CLUSTER_MYSHARDID from '../commands/CLUSTER_MYSHARDID';
 import * as CLUSTER_NODES from '../commands/CLUSTER_NODES';
 import * as CLUSTER_REPLICAS from '../commands/CLUSTER_REPLICAS';
 import * as CLUSTER_REPLICATE from '../commands/CLUSTER_REPLICATE';
@@ -83,6 +86,8 @@ import * as KEYS from '../commands/KEYS';
 import * as LASTSAVE from '../commands/LASTSAVE';
 import * as LATENCY_DOCTOR from '../commands/LATENCY_DOCTOR';
 import * as LATENCY_GRAPH from '../commands/LATENCY_GRAPH';
+import * as LATENCY_HISTORY from '../commands/LATENCY_HISTORY';
+import * as LATENCY_LATEST from '../commands/LATENCY_LATEST';
 import * as LOLWUT from '../commands/LOLWUT';
 import * as MEMORY_DOCTOR from '../commands/MEMORY_DOCTOR';
 import * as MEMORY_MALLOC_STATS from '../commands/MEMORY_MALLOC-STATS';
@@ -97,6 +102,8 @@ import * as PING from '../commands/PING';
 import * as PUBSUB_CHANNELS from '../commands/PUBSUB_CHANNELS';
 import * as PUBSUB_NUMPAT from '../commands/PUBSUB_NUMPAT';
 import * as PUBSUB_NUMSUB from '../commands/PUBSUB_NUMSUB';
+import * as PUBSUB_SHARDCHANNELS from '../commands/PUBSUB_SHARDCHANNELS';
+import * as PUBSUB_SHARDNUMSUB from '../commands/PUBSUB_SHARDNUMSUB';
 import * as RANDOMKEY from '../commands/RANDOMKEY';
 import * as READONLY from '../commands/READONLY';
 import * as READWRITE from '../commands/READWRITE';
@@ -164,6 +171,10 @@ export default {
     clientKill: CLIENT_KILL,
     'CLIENT_NO-EVICT': CLIENT_NO_EVICT,
     clientNoEvict: CLIENT_NO_EVICT,
+    'CLIENT_NO-TOUCH': CLIENT_NO_TOUCH,
+    clientNoTouch: CLIENT_NO_TOUCH,
+    CLIENT_LIST,
+    clientList: CLIENT_LIST,
     CLIENT_PAUSE,
     clientPause: CLIENT_PAUSE,
     CLIENT_SETNAME,
@@ -208,6 +219,8 @@ export default {
     clusterMeet: CLUSTER_MEET,
     CLUSTER_MYID,
     clusterMyId: CLUSTER_MYID,
+    CLUSTER_MYSHARDID,
+    clusterMyShardId: CLUSTER_MYSHARDID,
     CLUSTER_NODES,
     clusterNodes: CLUSTER_NODES,
     CLUSTER_REPLICAS,
@@ -286,6 +299,10 @@ export default {
     latencyDoctor: LATENCY_DOCTOR,
     LATENCY_GRAPH,
     latencyGraph: LATENCY_GRAPH,
+    LATENCY_HISTORY,
+    latencyHistory: LATENCY_HISTORY,
+    LATENCY_LATEST,
+    latencyLatest: LATENCY_LATEST,
     LOLWUT,
     lolwut: LOLWUT,
     MEMORY_DOCTOR,
@@ -314,6 +331,10 @@ export default {
     pubSubNumPat: PUBSUB_NUMPAT,
     PUBSUB_NUMSUB,
     pubSubNumSub: PUBSUB_NUMSUB,
+    PUBSUB_SHARDCHANNELS,
+    pubSubShardChannels: PUBSUB_SHARDCHANNELS,
+    PUBSUB_SHARDNUMSUB,
+    pubSubShardNumSub: PUBSUB_SHARDNUMSUB,
     RANDOMKEY,
     randomKey: RANDOMKEY,
     READONLY,
diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts
index 63200bf82d6..7f93efaa1c3 100644
--- a/packages/client/lib/client/index.spec.ts
+++ b/packages/client/lib/client/index.spec.ts
@@ -2,14 +2,16 @@ import { strict as assert } from 'assert';
 import testUtils, { GLOBAL, waitTillBeenCalled } from '../test-utils';
 import RedisClient, { RedisClientType } from '.';
 import { RedisClientMultiCommandType } from './multi-command';
-import { RedisCommandArguments, RedisCommandRawReply, RedisModules, RedisFunctions, RedisScripts } from '../commands';
-import { AbortError, ClientClosedError, ClientOfflineError, ConnectionTimeoutError, DisconnectsClientError, SocketClosedUnexpectedlyError, WatchError } from '../errors';
+import { RedisCommandRawReply, RedisModules, RedisFunctions, RedisScripts } from '../commands';
+import { AbortError, ClientClosedError, ClientOfflineError, ConnectionTimeoutError, DisconnectsClientError, ErrorReply, MultiErrorReply, SocketClosedUnexpectedlyError, WatchError } from '../errors';
 import { defineScript } from '../lua-script';
 import { spy } from 'sinon';
 import { once } from 'events';
 import { ClientKillFilters } from '../commands/CLIENT_KILL';
 import { promisify } from 'util';
 
+import {version} from '../../package.json';
+
 export const SQUARE_SCRIPT = defineScript({
     SCRIPT: 'return ARGV[1] * ARGV[1];',
     NUMBER_OF_KEYS: 0,
@@ -107,6 +109,57 @@ describe('Client', () => {
         });
     });
 
+    describe('connect', () => {
+        testUtils.testWithClient('connect should return the client instance', async client => {
+            try {
+                assert.equal(await client.connect(), client);
+            } finally {
+                if (client.isOpen) await client.disconnect();
+            }
+        }, {
+            ...GLOBAL.SERVERS.PASSWORD,
+            disableClientSetup: true
+        });
+
+        testUtils.testWithClient('should set default lib name and version', async client => {
+            const clientInfo = await client.clientInfo();
+
+            assert.equal(clientInfo.libName, 'node-redis');
+            assert.equal(clientInfo.libVer, version);
+        }, {
+            ...GLOBAL.SERVERS.PASSWORD,
+            minimumDockerVersion: [7, 2]
+        });
+
+        testUtils.testWithClient('disable sending lib name and version', async client => {
+            const clientInfo = await client.clientInfo();
+
+            assert.equal(clientInfo.libName, '');
+            assert.equal(clientInfo.libVer, '');
+        }, {
+            ...GLOBAL.SERVERS.PASSWORD,
+            clientOptions: {
+                ...GLOBAL.SERVERS.PASSWORD.clientOptions,
+                disableClientInfo: true
+            },
+            minimumDockerVersion: [7, 2]
+        });
+
+        testUtils.testWithClient('send client name tag', async client => {
+            const clientInfo = await client.clientInfo();
+
+            assert.equal(clientInfo.libName, 'node-redis(test)');
+            assert.equal(clientInfo.libVer, version);
+        }, {
+            ...GLOBAL.SERVERS.PASSWORD,
+            clientOptions: {
+                ...GLOBAL.SERVERS.PASSWORD.clientOptions,
+                clientInfoTag: "test"
+            },
+            minimumDockerVersion: [7, 2]
+        });
+    });
+
     describe('authentication', () => {
         testUtils.testWithClient('Client should be authenticated', async client => {
             assert.equal(
@@ -165,6 +218,28 @@ describe('Client', () => {
             }
         });
 
+        testUtils.testWithClient('client.sendCommand should reply with error', async client => {
+            await assert.rejects(
+                promisify(client.sendCommand).call(client, '1', '2')
+            );
+        }, {
+            ...GLOBAL.SERVERS.OPEN,
+            clientOptions: {
+                legacyMode: true
+            }
+        });
+
+        testUtils.testWithClient('client.hGetAll should reply with error', async client => {
+            await assert.rejects(
+                promisify(client.hGetAll).call(client)
+            );
+        }, {
+            ...GLOBAL.SERVERS.OPEN,
+            clientOptions: {
+                legacyMode: true
+            }
+        });
+
         testUtils.testWithClient('client.v4.sendCommand should return a promise', async client => {
             assert.equal(
                 await client.v4.sendCommand(['PING']),
@@ -177,6 +252,18 @@ describe('Client', () => {
             }
         });
 
+        testUtils.testWithClient('client.v4.{command} should return a promise', async client => {
+            assert.equal(
+                await client.v4.ping(),
+                'PONG'
+            );
+        }, {
+            ...GLOBAL.SERVERS.OPEN,
+            clientOptions: {
+                legacyMode: true
+            }
+        });
+
         testUtils.testWithClient('client.{command} should accept vardict arguments', async client => {
             assert.equal(
                 await promisify(client.set).call(client, 'a', 'b'),
@@ -484,14 +571,23 @@ describe('Client', () => {
             );
         }, GLOBAL.SERVERS.OPEN);
 
-        testUtils.testWithClient('execAsPipeline', async client => {
-            assert.deepEqual(
-                await client.multi()
-                    .ping()
-                    .exec(true),
-                ['PONG']
-            );
-        }, GLOBAL.SERVERS.OPEN);
+        describe('execAsPipeline', () => {
+            testUtils.testWithClient('exec(true)', async client => {
+                assert.deepEqual(
+                    await client.multi()
+                        .ping()
+                        .exec(true),
+                    ['PONG']
+                );
+            }, GLOBAL.SERVERS.OPEN);
+
+            testUtils.testWithClient('empty execAsPipeline', async client => {
+                assert.deepEqual(
+                    await client.multi().execAsPipeline(),
+                    []
+                );
+            }, GLOBAL.SERVERS.OPEN);
+        });
 
         testUtils.testWithClient('should remember selected db', async client => {
             await client.multi()
@@ -506,6 +602,23 @@ describe('Client', () => {
             ...GLOBAL.SERVERS.OPEN,
             minimumDockerVersion: [6, 2] // CLIENT INFO
         });
+
+        testUtils.testWithClient('should handle error replies (#2665)', async client => {
+            await assert.rejects(
+                client.multi()
+                    .set('key', 'value')
+                    .hGetAll('key')
+                    .exec(),
+                err => {
+                    assert.ok(err instanceof MultiErrorReply);
+                    assert.equal(err.replies.length, 2);
+                    assert.deepEqual(err.errorIndexes, [1]);
+                    assert.ok(err.replies[1] instanceof ErrorReply);
+                    assert.deepEqual([...err.errors()], [err.replies[1]]);
+                    return true;
+                }
+            );
+        }, GLOBAL.SERVERS.OPEN);
     });
 
     testUtils.testWithClient('scripts', async client => {
@@ -564,11 +677,41 @@ describe('Client', () => {
         }
     });
 
-    testUtils.testWithClient('executeIsolated', async client => {
-        const id = await client.clientId(),
-            isolatedId = await client.executeIsolated(isolatedClient => isolatedClient.clientId());
-        assert.ok(id !== isolatedId);
-    }, GLOBAL.SERVERS.OPEN);
+    describe('isolationPool', () => {
+        testUtils.testWithClient('executeIsolated', async client => {
+            const id = await client.clientId(),
+                isolatedId = await client.executeIsolated(isolatedClient => isolatedClient.clientId());
+            assert.ok(id !== isolatedId);
+        }, GLOBAL.SERVERS.OPEN);
+
+        testUtils.testWithClient('should be able to use pool even before connect', async client => {
+            await client.executeIsolated(() => Promise.resolve());
+            // make sure to destroy isolation pool
+            await client.connect();
+            await client.disconnect();
+        }, {
+            ...GLOBAL.SERVERS.OPEN,
+            disableClientSetup: true
+        });
+
+        testUtils.testWithClient('should work after reconnect (#2406)', async client => {
+            await client.disconnect();
+            await client.connect();
+            await client.executeIsolated(() => Promise.resolve());
+        }, GLOBAL.SERVERS.OPEN);
+
+        testUtils.testWithClient('should throw ClientClosedError after disconnect', async client => {
+            await client.connect();
+            await client.disconnect();
+            await assert.rejects(
+                client.executeIsolated(() => Promise.resolve()),
+                ClientClosedError
+            );
+        }, {
+            ...GLOBAL.SERVERS.OPEN,
+            disableClientSetup: true
+        });
+    });
 
     async function killClient<
         M extends RedisModules,
@@ -604,6 +747,9 @@ describe('Client', () => {
     });
 
     testUtils.testWithClient('should propagated errors from "isolated" clients', client => {
+        client.on('error', () => {
+            // ignore errors
+        });
         return client.executeIsolated(isolated => killClient(isolated, client));
     }, GLOBAL.SERVERS.OPEN);
 
@@ -642,6 +788,31 @@ describe('Client', () => {
         assert.deepEqual(hash, results);
     }, GLOBAL.SERVERS.OPEN);
 
+    testUtils.testWithClient('hScanNoValuesIterator', async client => {
+        const hash: Record<string, string> = {};
+        const expectedKeys: Array<string> = [];
+        for (let i = 0; i < 100; i++) {
+            hash[i.toString()] = i.toString();
+            expectedKeys.push(i.toString());
+        }
+
+        await client.hSet('key', hash);
+
+        const keys: Array<string> = [];
+        for await (const key of client.hScanNoValuesIterator('key')) {
+            keys.push(key);
+        }
+
+        function sort(a: string, b: string) {
+            return Number(a) - Number(b);
+        }
+
+        assert.deepEqual(keys.sort(sort), expectedKeys);
+    }, {
+        ...GLOBAL.SERVERS.OPEN,
+        minimumDockerVersion: [7, 4]
+    });
+
     testUtils.testWithClient('sScanIterator', async client => {
         const members = new Set<string>();
         for (let i = 0; i < 100; i++) {
@@ -685,7 +856,7 @@ describe('Client', () => {
             members.map<MemberTuple>(member => [member.value, member.score]).sort(sort)
         );
     }, GLOBAL.SERVERS.OPEN);
-
+    
     describe('PubSub', () => {
         testUtils.testWithClient('should be able to publish and subscribe to messages', async publisher => {
             function assertStringListener(message: string, channel: string) {
diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts
index 8c5a23db448..d7f33e97b16 100644
--- a/packages/client/lib/client/index.ts
+++ b/packages/client/lib/client/index.ts
@@ -1,7 +1,7 @@
 import COMMANDS from './commands';
-import { RedisCommand, RedisCommandArguments, RedisCommandRawReply, RedisCommandReply, RedisFunctions, RedisModules, RedisExtensions, RedisScript, RedisScripts, RedisCommandSignature, ConvertArgumentType, RedisFunction, ExcludeMappedString, RedisCommands } from '../commands';
+import { RedisCommand, RedisCommandArgument, RedisCommandArguments, RedisCommandRawReply, RedisCommandReply, RedisFunctions, RedisModules, RedisExtensions, RedisScript, RedisScripts, RedisCommandSignature, ConvertArgumentType, RedisFunction, ExcludeMappedString, RedisCommands } from '../commands';
 import RedisSocket, { RedisSocketOptions, RedisTlsSocketOptions } from './socket';
-import RedisCommandsQueue, { PubSubListener, PubSubSubscribeCommands, PubSubUnsubscribeCommands, QueueCommandOptions } from './commands-queue';
+import RedisCommandsQueue, { QueueCommandOptions } from './commands-queue';
 import RedisClientMultiCommand, { RedisClientMultiCommandType } from './multi-command';
 import { RedisMultiQueuedCommand } from '../multi-command';
 import { EventEmitter } from 'events';
@@ -11,27 +11,71 @@ import { ScanCommandOptions } from '../commands/SCAN';
 import { HScanTuple } from '../commands/HSCAN';
 import { attachCommands, attachExtensions, fCallArguments, transformCommandArguments, transformCommandReply, transformLegacyCommandArguments } from '../commander';
 import { Pool, Options as PoolOptions, createPool } from 'generic-pool';
-import { ClientClosedError, ClientOfflineError, DisconnectsClientError } from '../errors';
+import { ClientClosedError, ClientOfflineError, DisconnectsClientError, ErrorReply } from '../errors';
 import { URL } from 'url';
 import { TcpSocketConnectOpts } from 'net';
+import { PubSubType, PubSubListener, PubSubTypeListeners, ChannelListeners } from './pub-sub';
+
+import {version} from '../../package.json';
 
 export interface RedisClientOptions<
     M extends RedisModules = RedisModules,
     F extends RedisFunctions = RedisFunctions,
     S extends RedisScripts = RedisScripts
 > extends RedisExtensions<M, F, S> {
+    /**
+     * `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
+     */
     url?: string;
+    /**
+     * Socket connection properties
+     */
     socket?: RedisSocketOptions;
+    /**
+     * ACL username ([see ACL guide](https://redis.io/topics/acl))
+     */
     username?: string;
+    /**
+     * ACL password or the old "--requirepass" password
+     */
     password?: string;
+    /**
+     * Client name ([see `CLIENT SETNAME`](https://redis.io/commands/client-setname))
+     */
     name?: string;
+    /**
+     * Redis database number (see [`SELECT`](https://redis.io/commands/select) command)
+     */
     database?: number;
+    /**
+     * Maximum length of the client's internal command queue
+     */
     commandsQueueMaxLength?: number;
+    /**
+     * When `true`, commands are rejected when the client is reconnecting.
+     * When `false`, commands are queued for execution after reconnection.
+     */
     disableOfflineQueue?: boolean;
+    /**
+     * Connect in [`READONLY`](https://redis.io/commands/readonly) mode
+     */
     readonly?: boolean;
     legacyMode?: boolean;
     isolationPoolOptions?: PoolOptions;
+    /**
+     * Send `PING` command at interval (in ms).
+     * Useful with Redis deployments that do not use TCP Keep-Alive.
+     */
     pingInterval?: number;
+    /**
+     * If set to true, disables sending client identifier (user-agent like message) to the redis server
+     */
+    disableClientInfo?: boolean;
+    /**
+     * Tag to append to library name that is sent to the Redis server
+     */
+    clientInfoTag?: string;
 }
 
 type WithCommands = {
@@ -155,7 +199,7 @@ export default class RedisClient<
     readonly #options?: RedisClientOptions<M, F, S>;
     readonly #socket: RedisSocket;
     readonly #queue: RedisCommandsQueue;
-    readonly #isolationPool: Pool<RedisClientType<M, F, S>>;
+    #isolationPool?: Pool<RedisClientType<M, F, S>>;
     readonly #v4: Record<string, any> = {};
     #selectedDB = 0;
 
@@ -171,6 +215,10 @@ export default class RedisClient<
         return this.#socket.isReady;
     }
 
+    get isPubSubActive() {
+        return this.#queue.isPubSubActive;
+    }
+
     get v4(): Record<string, any> {
         if (!this.#options?.legacyMode) {
             throw new Error('the client is not in "legacy mode"');
@@ -184,16 +232,9 @@ export default class RedisClient<
         this.#options = this.#initiateOptions(options);
         this.#queue = this.#initiateQueue();
         this.#socket = this.#initiateSocket();
-        this.#isolationPool = createPool({
-            create: async () => {
-                const duplicate = this.duplicate({
-                    isolationPoolOptions: undefined
-                }).on('error', err => this.emit('error', err));
-                await duplicate.connect();
-                return duplicate;
-            },
-            destroy: client => client.disconnect()
-        }, options?.isolationPoolOptions);
+        // should be initiated in connect, not here
+        // TODO: consider breaking in v5
+        this.#isolationPool = this.#initiateIsolationPool();
         this.#legacyMode();
     }
 
@@ -215,7 +256,10 @@ export default class RedisClient<
     }
 
     #initiateQueue(): RedisCommandsQueue {
-        return new RedisCommandsQueue(this.#options?.commandsQueueMaxLength);
+        return new RedisCommandsQueue(
+            this.#options?.commandsQueueMaxLength,
+            (channel, listeners) => this.emit('sharded-channel-moved', channel, listeners)
+        );
     }
 
     #initiateSocket(): RedisSocket {
@@ -240,6 +284,33 @@ export default class RedisClient<
                 );
             }
 
+            if (!this.#options?.disableClientInfo) {
+                promises.push(
+                    this.#queue.addCommand(
+                        [  'CLIENT', 'SETINFO', 'LIB-VER', version],
+                        { asap: true }
+                    ).catch(err => {
+                        if (!(err instanceof ErrorReply)) {
+                            throw err;
+                        }
+                    })
+                );
+
+                promises.push(
+                    this.#queue.addCommand(
+                        [
+                           'CLIENT', 'SETINFO', 'LIB-NAME',
+                            this.#options?.clientInfoTag ? `node-redis(${this.#options.clientInfoTag})` : 'node-redis'
+                        ],
+                        { asap: true }
+                    ).catch(err => {
+                        if (!(err instanceof ErrorReply)) {
+                            throw err;
+                        }
+                    })
+                );
+              }
+
             if (this.#options?.name) {
                 promises.push(
                     this.#queue.addCommand(
@@ -295,6 +366,19 @@ export default class RedisClient<
             .on('end', () => this.emit('end'));
     }
 
+    #initiateIsolationPool() {
+        return createPool({
+            create: async () => {
+                const duplicate = this.duplicate({
+                    isolationPoolOptions: undefined
+                }).on('error', err => this.emit('error', err));
+                await duplicate.connect();
+                return duplicate;
+            },
+            destroy: client => client.disconnect()
+        }, this.#options?.isolationPoolOptions);
+    }
+
     #legacyMode(): void {
         if (!this.#options?.legacyMode) return;
 
@@ -302,13 +386,15 @@ export default class RedisClient<
         (this as any).sendCommand = (...args: Array<any>): void => {
             const result = this.#legacySendCommand(...args);
             if (result) {
-                result.promise.then(reply => result.callback(null, reply));
+                result.promise
+                    .then(reply => result.callback(null, reply))
+                    .catch(err => result.callback(err));
             }
         };
 
         for (const [ name, command ] of Object.entries(COMMANDS as RedisCommands)) {
             this.#defineLegacyCommand(name, command);
-            (this as any)[name.toLowerCase()] = (this as any)[name];
+            (this as any)[name.toLowerCase()] ??= (this as any)[name];
         }
 
         // hard coded commands
@@ -339,21 +425,21 @@ export default class RedisClient<
         promise.catch(err => this.emit('error', err));
     }
 
-    #defineLegacyCommand(this: any, name: string, command?: RedisCommand): void {
-        this.#v4[name] = this[name].bind(this);
-        this[name] = command && command.TRANSFORM_LEGACY_REPLY && command.transformReply ?
+    #defineLegacyCommand(name: string, command?: RedisCommand): void {
+        this.#v4[name] = (this as any)[name].bind(this);
+        (this as any)[name] = command && command.TRANSFORM_LEGACY_REPLY && command.transformReply ?
             (...args: Array<unknown>) => {
                 const result = this.#legacySendCommand(name, ...args);
                 if (result) {
-                    result.promise.then((reply: any) => {
-                        result.callback(null, command.transformReply!(reply));
-                    });
+                    result.promise
+                        .then(reply => result.callback(null, command.transformReply!(reply)))
+                        .catch(err => result.callback(err));
                 }
             } :
-            (...args: Array<unknown>) => this.sendCommand(name, ...args);
+            (...args: Array<unknown>) => (this as any).sendCommand(name, ...args);
     }
 
-    #pingTimer?: NodeJS.Timer;
+    #pingTimer?: NodeJS.Timeout;
 
     #setPingTimer(): void {
         if (!this.#options?.pingInterval || !this.#socket.isReady) return;
@@ -362,7 +448,8 @@ export default class RedisClient<
         this.#pingTimer = setTimeout(() => {
             if (!this.#socket.isReady) return;
 
-            (this as unknown as RedisClientType<M, F, S>).ping()
+            // using #sendCommand to support legacy mode
+            this.#sendCommand(['PING'])
                 .then(reply => this.emit('ping-interval', reply))
                 .catch(err => this.emit('error', err))
                 .finally(() => this.#setPingTimer());
@@ -376,8 +463,11 @@ export default class RedisClient<
         });
     }
 
-    async connect(): Promise<void> {
+    async connect() {
+        // see comment in constructor
+        this.#isolationPool ??= this.#initiateIsolationPool();
         await this.#socket.connect();
+        return this as unknown as RedisClientType<M, F, S>;
     }
 
     async commandsExecutor<C extends RedisCommand>(
@@ -415,7 +505,7 @@ export default class RedisClient<
             );
         } else if (!this.#socket.isReady && this.#options?.disableOfflineQueue) {
             return Promise.reject(new ClientOfflineError());
-        } 
+        }
 
         const promise = this.#queue.addCommand<T>(args, options);
         this.#tick();
@@ -499,18 +589,9 @@ export default class RedisClient<
 
     select = this.SELECT;
 
-    #subscribe<T extends boolean>(
-        command: PubSubSubscribeCommands,
-        channels: string | Array<string>,
-        listener: PubSubListener<T>,
-        bufferMode?: T
-    ): Promise<void> {
-        const promise = this.#queue.subscribe(
-            command,
-            channels,
-            listener,
-            bufferMode
-        );
+    #pubSubCommand(promise: Promise<void> | undefined) {
+        if (promise === undefined) return Promise.resolve();
+
         this.#tick();
         return promise;
     }
@@ -520,77 +601,128 @@ export default class RedisClient<
         listener: PubSubListener<T>,
         bufferMode?: T
     ): Promise<void> {
-        return this.#subscribe(
-            PubSubSubscribeCommands.SUBSCRIBE,
-            channels,
-            listener,
-            bufferMode
+        return this.#pubSubCommand(
+            this.#queue.subscribe(
+                PubSubType.CHANNELS,
+                channels,
+                listener,
+                bufferMode
+            )
         );
     }
 
     subscribe = this.SUBSCRIBE;
 
+
+    UNSUBSCRIBE<T extends boolean = false>(
+        channels?: string | Array<string>,
+        listener?: PubSubListener<T>,
+        bufferMode?: T
+    ): Promise<void> {
+        return this.#pubSubCommand(
+            this.#queue.unsubscribe(
+                PubSubType.CHANNELS,
+                channels,
+                listener,
+                bufferMode
+            )
+        );
+    }
+
+    unsubscribe = this.UNSUBSCRIBE;
+
     PSUBSCRIBE<T extends boolean = false>(
         patterns: string | Array<string>,
         listener: PubSubListener<T>,
         bufferMode?: T
     ): Promise<void> {
-        return this.#subscribe(
-            PubSubSubscribeCommands.PSUBSCRIBE,
-            patterns,
-            listener,
-            bufferMode
+        return this.#pubSubCommand(
+            this.#queue.subscribe(
+                PubSubType.PATTERNS,
+                patterns,
+                listener,
+                bufferMode
+            )
         );
     }
 
     pSubscribe = this.PSUBSCRIBE;
 
-    #unsubscribe<T extends boolean>(
-        command: PubSubUnsubscribeCommands,
-        channels?: string | Array<string>,
+    PUNSUBSCRIBE<T extends boolean = false>(
+        patterns?: string | Array<string>,
         listener?: PubSubListener<T>,
         bufferMode?: T
     ): Promise<void> {
-        const promise = this.#queue.unsubscribe(command, channels, listener, bufferMode);
-        this.#tick();
-        return promise;
+        return this.#pubSubCommand(
+            this.#queue.unsubscribe(
+                PubSubType.PATTERNS,
+                patterns,
+                listener,
+                bufferMode
+            )
+        );
     }
 
-    UNSUBSCRIBE<T extends boolean = false>(
-        channels?: string | Array<string>,
-        listener?: PubSubListener<T>,
+    pUnsubscribe = this.PUNSUBSCRIBE;
+
+    SSUBSCRIBE<T extends boolean = false>(
+        channels: string | Array<string>,
+        listener: PubSubListener<T>,
         bufferMode?: T
     ): Promise<void> {
-        return this.#unsubscribe(
-            PubSubUnsubscribeCommands.UNSUBSCRIBE,
-            channels,
-            listener,
-            bufferMode
+        return this.#pubSubCommand(
+            this.#queue.subscribe(
+                PubSubType.SHARDED,
+                channels,
+                listener,
+                bufferMode
+            )
         );
     }
 
-    unsubscribe = this.UNSUBSCRIBE;
+    sSubscribe = this.SSUBSCRIBE;
 
-    PUNSUBSCRIBE<T extends boolean = false>(
-        patterns?: string | Array<string>,
+    SUNSUBSCRIBE<T extends boolean = false>(
+        channels?: string | Array<string>,
         listener?: PubSubListener<T>,
         bufferMode?: T
     ): Promise<void> {
-        return this.#unsubscribe(
-            PubSubUnsubscribeCommands.PUNSUBSCRIBE,
-            patterns,
-            listener,
-            bufferMode
+        return this.#pubSubCommand(
+            this.#queue.unsubscribe(
+                PubSubType.SHARDED,
+                channels,
+                listener,
+                bufferMode
+            )
         );
     }
 
-    pUnsubscribe = this.PUNSUBSCRIBE;
+    sUnsubscribe = this.SUNSUBSCRIBE;
+
+    getPubSubListeners(type: PubSubType) {
+        return this.#queue.getPubSubListeners(type);
+    }
+
+    extendPubSubChannelListeners(
+        type: PubSubType,
+        channel: string,
+        listeners: ChannelListeners
+    ) {
+        return this.#pubSubCommand(
+            this.#queue.extendPubSubChannelListeners(type, channel, listeners)
+        );
+    }
+
+    extendPubSubListeners(type: PubSubType, listeners: PubSubTypeListeners) {
+        return this.#pubSubCommand(
+            this.#queue.extendPubSubListeners(type, listeners)
+        );
+    }
 
     QUIT(): Promise<string> {
         return this.#socket.quit(async () => {
-            const quitPromise = this.#queue.addCommand<string>(['QUIT'], {
-                ignorePubSubMode: true
-            });
+            if (this.#pingTimer) clearTimeout(this.#pingTimer);
+            const quitPromise = this.#queue.addCommand<string>(['QUIT']);
             this.#tick();
             const [reply] = await Promise.all([
                 quitPromise,
@@ -618,6 +750,7 @@ export default class RedisClient<
     }
 
     executeIsolated<T>(fn: (client: RedisClientType<M, F, S>) => T | Promise<T>): Promise<T> {
+        if (!this.#isolationPool) return Promise.reject(new ClientClosedError());
         return this.#isolationPool.use(fn);
     }
 
@@ -639,11 +772,14 @@ export default class RedisClient<
             return Promise.reject(new ClientClosedError());
         }
 
-        const promise = Promise.all(
-            commands.map(({ args }) => {
-                return this.#queue.addCommand(args, { chainId });
-            })
-        );
+        const promise = chainId ?
+            // if `chainId` has a value, it's a `MULTI` (and not "pipeline") - need to add the `MULTI` and `EXEC` commands
+            Promise.all([
+                this.#queue.addCommand(['MULTI'], { chainId }),
+                this.#addMultiCommands(commands, chainId),
+                this.#queue.addCommand(['EXEC'], { chainId })
+            ]) :
+            this.#addMultiCommands(commands);
 
         this.#tick();
 
@@ -656,6 +792,12 @@ export default class RedisClient<
         return results;
     }
 
+    #addMultiCommands(commands: Array<RedisMultiQueuedCommand>, chainId?: symbol) {
+        return Promise.all(
+            commands.map(({ args }) => this.#queue.addCommand(args, { chainId }))
+        );
+    }
+
     async* scanIterator(options?: ScanCommandOptions): AsyncIterable<string> {
         let cursor = 0;
         do {
@@ -678,6 +820,17 @@ export default class RedisClient<
         } while (cursor !== 0);
     }
 
+    async* hScanNoValuesIterator(key: string, options?: ScanOptions): AsyncIterable<ConvertArgumentType<RedisCommandArgument, string>> {
+        let cursor = 0;
+        do {
+            const reply = await (this as any).hScanNoValues(key, cursor, options);
+            cursor = reply.cursor;
+            for (const k of reply.keys) {
+                yield k;
+            }
+        } while (cursor !== 0);
+    }
+
     async* sScanIterator(key: string, options?: ScanOptions): AsyncIterable<string> {
         let cursor = 0;
         do {
@@ -701,14 +854,16 @@ export default class RedisClient<
     }
 
     async disconnect(): Promise<void> {
+        if (this.#pingTimer) clearTimeout(this.#pingTimer);
         this.#queue.flushAll(new DisconnectsClientError());
         this.#socket.disconnect();
         await this.#destroyIsolationPool();
     }
 
     async #destroyIsolationPool(): Promise<void> {
-        await this.#isolationPool.drain();
-        await this.#isolationPool.clear();
+        await this.#isolationPool!.drain();
+        await this.#isolationPool!.clear();
+        this.#isolationPool = undefined;
     }
 
     ref(): void {
diff --git a/packages/client/lib/client/multi-command.ts b/packages/client/lib/client/multi-command.ts
index 4a3b668b758..e347667bf2c 100644
--- a/packages/client/lib/client/multi-command.ts
+++ b/packages/client/lib/client/multi-command.ts
@@ -119,7 +119,7 @@ export default class RedisClientMultiCommand {
 
         for (const [ name, command ] of Object.entries(COMMANDS as RedisCommands)) {
             this.#defineLegacyCommand(name, command);
-            (this as any)[name.toLowerCase()] = (this as any)[name];
+            (this as any)[name.toLowerCase()] ??= (this as any)[name];
         }
     }
 
@@ -170,12 +170,9 @@ export default class RedisClientMultiCommand {
             return this.execAsPipeline();
         }
 
-        const commands = this.#multi.exec();
-        if (!commands) return [];
-
         return this.#multi.handleExecReplies(
             await this.#executor(
-                commands,
+                this.#multi.queue,
                 this.#selectedDB,
                 RedisMultiCommand.generateChainId()
             )
@@ -185,6 +182,8 @@ export default class RedisClientMultiCommand {
     EXEC = this.exec;
 
     async execAsPipeline(): Promise<Array<RedisCommandRawReply>> {
+        if (this.#multi.queue.length === 0) return [];
+        
         return this.#multi.transformReplies(
             await this.#executor(
                 this.#multi.queue,
diff --git a/packages/client/lib/client/pub-sub.spec.ts b/packages/client/lib/client/pub-sub.spec.ts
new file mode 100644
index 00000000000..8b9f16732cb
--- /dev/null
+++ b/packages/client/lib/client/pub-sub.spec.ts
@@ -0,0 +1,151 @@
+import { strict as assert } from 'assert';
+import { PubSub, PubSubType } from './pub-sub';
+
+describe('PubSub', () => {
+    const TYPE = PubSubType.CHANNELS,
+        CHANNEL = 'channel',
+        LISTENER = () => {};
+
+    describe('subscribe to new channel', () => {
+        function createAndSubscribe() {
+            const pubSub = new PubSub(),
+                command = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+    
+            assert.equal(pubSub.isActive, true);
+            assert.ok(command);
+            assert.equal(command.channelsCounter, 1);
+            
+            return {
+                pubSub,
+                command
+            };
+        }
+
+        it('resolve', () => {
+            const { pubSub, command } = createAndSubscribe();
+    
+            command.resolve();
+
+            assert.equal(pubSub.isActive, true);
+        });
+
+        it('reject', () => {
+            const { pubSub, command } = createAndSubscribe();
+    
+            assert.ok(command.reject);
+            command.reject();
+
+            assert.equal(pubSub.isActive, false);
+        });
+    });
+
+    it('subscribe to already subscribed channel', () => {
+        const pubSub = new PubSub(),
+            firstSubscribe = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+        assert.ok(firstSubscribe);
+
+        const secondSubscribe = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+        assert.ok(secondSubscribe);
+
+        firstSubscribe.resolve();
+
+        assert.equal(
+            pubSub.subscribe(TYPE, CHANNEL, LISTENER),
+            undefined
+        );
+    });
+
+    it('unsubscribe all', () => {
+        const pubSub = new PubSub();
+        
+        const subscribe = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+        assert.ok(subscribe);
+        subscribe.resolve();
+        assert.equal(pubSub.isActive, true);
+
+        const unsubscribe = pubSub.unsubscribe(TYPE);
+        assert.equal(pubSub.isActive, true);
+        assert.ok(unsubscribe);
+        unsubscribe.resolve();
+        assert.equal(pubSub.isActive, false);
+    });
+
+    describe('unsubscribe from channel', () => {
+        it('when not subscribed', () => {
+            const pubSub = new PubSub(),
+                unsubscribe = pubSub.unsubscribe(TYPE, CHANNEL);
+            assert.ok(unsubscribe);
+            unsubscribe.resolve();
+            assert.equal(pubSub.isActive, false);
+        });
+
+        it('when already subscribed', () => {
+            const pubSub = new PubSub(),
+                subscribe = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+            assert.ok(subscribe);
+            subscribe.resolve();
+            assert.equal(pubSub.isActive, true);
+    
+            const unsubscribe = pubSub.unsubscribe(TYPE, CHANNEL);
+            assert.equal(pubSub.isActive, true);
+            assert.ok(unsubscribe);
+            unsubscribe.resolve();
+            assert.equal(pubSub.isActive, false);
+        });
+    });
+
+    describe('unsubscribe from listener', () => {
+        it('when it\'s the only listener', () => {
+            const pubSub = new PubSub(),
+                subscribe = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+            assert.ok(subscribe);
+            subscribe.resolve();
+            assert.equal(pubSub.isActive, true);
+
+            const unsubscribe = pubSub.unsubscribe(TYPE, CHANNEL, LISTENER);
+            assert.ok(unsubscribe);
+            unsubscribe.resolve();
+            assert.equal(pubSub.isActive, false);
+        });
+
+        it('when there are more listeners', () => {
+            const pubSub = new PubSub(),
+                subscribe = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+            assert.ok(subscribe);
+            subscribe.resolve();
+            assert.equal(pubSub.isActive, true);
+
+            assert.equal(
+                pubSub.subscribe(TYPE, CHANNEL, () => {}),
+                undefined
+            );
+
+            assert.equal(
+                pubSub.unsubscribe(TYPE, CHANNEL, LISTENER),
+                undefined
+            );
+        });
+
+        describe('non-existing listener', () => {
+            it('on subscribed channel', () => {
+                const pubSub = new PubSub(),
+                    subscribe = pubSub.subscribe(TYPE, CHANNEL, LISTENER);
+                assert.ok(subscribe);
+                subscribe.resolve();
+                assert.equal(pubSub.isActive, true);
+
+                assert.equal(
+                    pubSub.unsubscribe(TYPE, CHANNEL, () => {}),
+                    undefined
+                );
+                assert.equal(pubSub.isActive, true);
+            });
+
+            it('on unsubscribed channel', () => {
+                const pubSub = new PubSub();
+                assert.ok(pubSub.unsubscribe(TYPE, CHANNEL, () => {}));
+                assert.equal(pubSub.isActive, false);
+            });
+        });
+    });
+});
diff --git a/packages/client/lib/client/pub-sub.ts b/packages/client/lib/client/pub-sub.ts
new file mode 100644
index 00000000000..a8a909e0252
--- /dev/null
+++ b/packages/client/lib/client/pub-sub.ts
@@ -0,0 +1,408 @@
+import { RedisCommandArgument } from "../commands";
+
+export enum PubSubType {
+    CHANNELS = 'CHANNELS',
+    PATTERNS = 'PATTERNS',
+    SHARDED = 'SHARDED'
+}
+
+const COMMANDS = {
+    [PubSubType.CHANNELS]: {
+        subscribe: Buffer.from('subscribe'),
+        unsubscribe: Buffer.from('unsubscribe'),
+        message: Buffer.from('message')
+    },
+    [PubSubType.PATTERNS]: {
+        subscribe: Buffer.from('psubscribe'),
+        unsubscribe: Buffer.from('punsubscribe'),
+        message: Buffer.from('pmessage')
+    },
+    [PubSubType.SHARDED]: {
+        subscribe: Buffer.from('ssubscribe'),
+        unsubscribe: Buffer.from('sunsubscribe'),
+        message: Buffer.from('smessage')
+    }
+};
+
+export type PubSubListener<
+    RETURN_BUFFERS extends boolean = false
+> = <T extends RETURN_BUFFERS extends true ? Buffer : string>(message: T, channel: T) => unknown;
+
+export interface ChannelListeners {
+    unsubscribing: boolean;
+    buffers: Set<PubSubListener<true>>;
+    strings: Set<PubSubListener<false>>;
+}
+
+export type PubSubTypeListeners = Map<string, ChannelListeners>;
+
+type Listeners = Record<PubSubType, PubSubTypeListeners>;
+
+export type PubSubCommand = ReturnType<
+    typeof PubSub.prototype.subscribe |
+    typeof PubSub.prototype.unsubscribe | 
+    typeof PubSub.prototype.extendTypeListeners
+>;
+
+export class PubSub {
+    static isStatusReply(reply: Array<Buffer>): boolean {
+        return (
+            COMMANDS[PubSubType.CHANNELS].subscribe.equals(reply[0]) ||
+            COMMANDS[PubSubType.CHANNELS].unsubscribe.equals(reply[0]) ||
+            COMMANDS[PubSubType.PATTERNS].subscribe.equals(reply[0]) ||
+            COMMANDS[PubSubType.PATTERNS].unsubscribe.equals(reply[0]) ||
+            COMMANDS[PubSubType.SHARDED].subscribe.equals(reply[0])
+        );
+    }
+
+    static isShardedUnsubscribe(reply: Array<Buffer>): boolean {
+        return COMMANDS[PubSubType.SHARDED].unsubscribe.equals(reply[0]);
+    }
+    
+    static #channelsArray(channels: string | Array<string>) {
+        return (Array.isArray(channels) ? channels : [channels]);
+    }
+
+    static #listenersSet<T extends boolean>(
+        listeners: ChannelListeners,
+        returnBuffers?: T
+    ) {
+        return (returnBuffers ? listeners.buffers : listeners.strings);
+    }
+
+    #subscribing = 0;
+
+    #isActive = false;
+
+    get isActive() {
+        return this.#isActive;
+    }
+
+    #listeners: Listeners = {
+        [PubSubType.CHANNELS]: new Map(),
+        [PubSubType.PATTERNS]: new Map(),
+        [PubSubType.SHARDED]: new Map()
+    };
+
+    subscribe<T extends boolean>(
+        type: PubSubType,
+        channels: string | Array<string>,
+        listener: PubSubListener<T>,
+        returnBuffers?: T
+    ) {
+        const args: Array<RedisCommandArgument> = [COMMANDS[type].subscribe],
+            channelsArray = PubSub.#channelsArray(channels);
+        for (const channel of channelsArray) {
+            let channelListeners = this.#listeners[type].get(channel);
+            if (!channelListeners || channelListeners.unsubscribing) {
+                args.push(channel);
+            }
+        }
+
+        if (args.length === 1) {
+            // all channels are already subscribed, add listeners without issuing a command
+            for (const channel of channelsArray) {
+                PubSub.#listenersSet(
+                    this.#listeners[type].get(channel)!,
+                    returnBuffers
+                ).add(listener);
+            }
+            return;
+        }
+
+        this.#isActive = true;
+        this.#subscribing++;
+        return {
+            args,
+            channelsCounter: args.length - 1,
+            resolve: () => {
+                this.#subscribing--;
+                for (const channel of channelsArray) {
+                    let listeners = this.#listeners[type].get(channel);
+                    if (!listeners) {
+                        listeners = {
+                            unsubscribing: false,
+                            buffers: new Set(),
+                            strings: new Set()
+                        };
+                        this.#listeners[type].set(channel, listeners);
+                    }
+
+                    PubSub.#listenersSet(listeners, returnBuffers).add(listener);
+                }
+            },
+            reject: () => {
+                this.#subscribing--;
+                this.#updateIsActive();
+            }
+        };
+    }
+
+    extendChannelListeners(
+        type: PubSubType,
+        channel: string,
+        listeners: ChannelListeners
+    ) {
+        if (!this.#extendChannelListeners(type, channel, listeners)) return;
+
+        this.#isActive = true;
+        this.#subscribing++;
+        return {
+            args: [
+                COMMANDS[type].subscribe,
+                channel
+            ],
+            channelsCounter: 1,
+            resolve: () => this.#subscribing--,
+            reject: () => {
+                this.#subscribing--;
+                this.#updateIsActive();
+            }
+        };
+    }
+
+    #extendChannelListeners(
+        type: PubSubType,
+        channel: string,
+        listeners: ChannelListeners
+    ) {
+        const existingListeners = this.#listeners[type].get(channel);
+        if (!existingListeners) {
+            this.#listeners[type].set(channel, listeners);
+            return true;
+        }
+
+        for (const listener of listeners.buffers) {
+            existingListeners.buffers.add(listener);
+        }
+
+        for (const listener of listeners.strings) {
+            existingListeners.strings.add(listener);
+        }
+
+        return false;
+    }
+
+    extendTypeListeners(type: PubSubType, listeners: PubSubTypeListeners) {
+        const args: Array<RedisCommandArgument> = [COMMANDS[type].subscribe];
+        for (const [channel, channelListeners] of listeners) {
+            if (this.#extendChannelListeners(type, channel, channelListeners)) {
+                args.push(channel);
+            }
+        }
+
+        if (args.length === 1) return;
+
+        this.#isActive = true;
+        this.#subscribing++;
+        return {
+            args,
+            channelsCounter: args.length - 1,
+            resolve: () => this.#subscribing--,
+            reject: () => {
+                this.#subscribing--;
+                this.#updateIsActive();
+            }
+        };
+    }
+
+    unsubscribe<T extends boolean>(
+        type: PubSubType,
+        channels?: string | Array<string>,
+        listener?: PubSubListener<T>,
+        returnBuffers?: T
+    ) {
+        const listeners = this.#listeners[type];
+        if (!channels) {
+            return this.#unsubscribeCommand(
+                [COMMANDS[type].unsubscribe],
+                // cannot use `this.#subscribed` because there might be some `SUBSCRIBE` commands in the queue
+                // cannot use `this.#subscribed + this.#subscribing` because some `SUBSCRIBE` commands might fail
+                NaN,
+                () => listeners.clear()
+            );
+        }
+
+        const channelsArray = PubSub.#channelsArray(channels);
+        if (!listener) {
+            return this.#unsubscribeCommand(
+                [COMMANDS[type].unsubscribe, ...channelsArray],
+                channelsArray.length,
+                () => {
+                    for (const channel of channelsArray) {
+                        listeners.delete(channel);
+                    }
+                }
+            );
+        }
+
+        const args: Array<RedisCommandArgument> = [COMMANDS[type].unsubscribe];
+        for (const channel of channelsArray) {
+            const sets = listeners.get(channel);
+            if (sets) {
+                let current,
+                    other;
+                if (returnBuffers) {
+                    current = sets.buffers;
+                    other = sets.strings;
+                } else {
+                    current = sets.strings;
+                    other = sets.buffers;
+                }
+
+                const currentSize = current.has(listener) ? current.size - 1 : current.size;
+                if (currentSize !== 0 || other.size !== 0) continue;
+                sets.unsubscribing = true;
+            }
+
+            args.push(channel);
+        }
+
+        if (args.length === 1) {
+            // all channels has other listeners,
+            // delete the listeners without issuing a command
+            for (const channel of channelsArray) {
+                PubSub.#listenersSet(
+                    listeners.get(channel)!,
+                    returnBuffers
+                ).delete(listener);
+            }
+            return;
+        }
+
+        return this.#unsubscribeCommand(
+            args,
+            args.length - 1,
+            () => {
+                for (const channel of channelsArray) {
+                    const sets = listeners.get(channel);
+                    if (!sets) continue;
+
+                    (returnBuffers ? sets.buffers : sets.strings).delete(listener);
+                    if (sets.buffers.size === 0 && sets.strings.size === 0) {
+                        listeners.delete(channel);
+                    }
+                }
+            }
+        );
+    }
+
+    #unsubscribeCommand(
+        args: Array<RedisCommandArgument>,
+        channelsCounter: number,
+        removeListeners: () => void
+    ) {
+        return {
+            args,
+            channelsCounter,
+            resolve: () => {
+                removeListeners();
+                this.#updateIsActive();
+            },
+            reject: undefined // use the same structure as `subscribe`
+        };
+    }
+
+    #updateIsActive() {
+        this.#isActive = (
+            this.#listeners[PubSubType.CHANNELS].size !== 0 ||
+            this.#listeners[PubSubType.PATTERNS].size !== 0 ||
+            this.#listeners[PubSubType.SHARDED].size !== 0 ||
+            this.#subscribing !== 0
+        );
+    }
+
+    reset() {
+        this.#isActive = false;
+        this.#subscribing = 0;
+    }
+
+    resubscribe(): Array<PubSubCommand> {
+        const commands = [];
+        for (const [type, listeners] of Object.entries(this.#listeners)) {
+            if (!listeners.size) continue;
+
+            this.#isActive = true;
+            this.#subscribing++;
+            const callback = () => this.#subscribing--;
+            commands.push({
+                args: [
+                    COMMANDS[type as PubSubType].subscribe,
+                    ...listeners.keys()
+                ],
+                channelsCounter: listeners.size,
+                resolve: callback,
+                reject: callback
+            });
+        }
+
+        return commands;
+    }
+
+    handleMessageReply(reply: Array<Buffer>): boolean {
+        if (COMMANDS[PubSubType.CHANNELS].message.equals(reply[0])) {
+            this.#emitPubSubMessage(
+                PubSubType.CHANNELS,
+                reply[2],
+                reply[1]
+            );
+            return true;
+        } else if (COMMANDS[PubSubType.PATTERNS].message.equals(reply[0])) {
+            this.#emitPubSubMessage(
+                PubSubType.PATTERNS,
+                reply[3],
+                reply[2],
+                reply[1]
+            );
+            return true;
+        } else if (COMMANDS[PubSubType.SHARDED].message.equals(reply[0])) {
+            this.#emitPubSubMessage(
+                PubSubType.SHARDED,
+                reply[2],
+                reply[1]
+            );
+            return true;
+        }
+
+        return false;
+    }
+
+    removeShardedListeners(channel: string): ChannelListeners {
+        const listeners = this.#listeners[PubSubType.SHARDED].get(channel)!;
+        this.#listeners[PubSubType.SHARDED].delete(channel);
+        this.#updateIsActive();
+        return listeners;
+    }
+    
+    #emitPubSubMessage(
+        type: PubSubType,
+        message: Buffer,
+        channel: Buffer,
+        pattern?: Buffer
+    ): void {
+        const keyString = (pattern ?? channel).toString(),
+            listeners = this.#listeners[type].get(keyString);
+
+        if (!listeners) return;
+
+        for (const listener of listeners.buffers) {
+            listener(message, channel);
+        }
+
+        if (!listeners.strings.size) return;
+
+        const channelString = pattern ? channel.toString() : keyString,
+            messageString = channelString === '__redis__:invalidate' ?
+                // https://github.com/redis/redis/pull/7469
+                // https://github.com/redis/redis/issues/7463
+                (message === null ? null : (message as any as Array<Buffer>).map(x => x.toString())) as any :
+                message.toString();
+        for (const listener of listeners.strings) {
+            listener(messageString, channelString);
+        }
+    }
+
+    getTypeListeners(type: PubSubType): PubSubTypeListeners {
+        return this.#listeners[type];
+    }
+}
diff --git a/packages/client/lib/client/socket.spec.ts b/packages/client/lib/client/socket.spec.ts
index c5862130cf5..eb555351ac4 100644
--- a/packages/client/lib/client/socket.spec.ts
+++ b/packages/client/lib/client/socket.spec.ts
@@ -1,5 +1,6 @@
 import { strict as assert } from 'assert';
 import { spy } from 'sinon';
+import { once } from 'events';
 import RedisSocket, { RedisSocketOptions } from './socket';
 
 describe('Socket', () => {
@@ -17,16 +18,42 @@ describe('Socket', () => {
     }
 
     describe('reconnectStrategy', () => {
+        it('false', async () => {
+            const socket = createSocket({
+                host: 'error',
+                connectTimeout: 1,
+                reconnectStrategy: false
+            });
+
+            await assert.rejects(socket.connect());
+
+            assert.equal(socket.isOpen, false);
+        });
+
+        it('0', async () => {
+            const socket = createSocket({
+                host: 'error',
+                connectTimeout: 1,
+                reconnectStrategy: 0
+            });
+
+            socket.connect();
+            await once(socket, 'error');
+            assert.equal(socket.isOpen, true);
+            assert.equal(socket.isReady, false);
+            socket.disconnect();
+            assert.equal(socket.isOpen, false);
+        });
+
         it('custom strategy', async () => {
-            const numberOfRetries = 10;
+            const numberOfRetries = 3;
 
             const reconnectStrategy = spy((retries: number) => {
                 assert.equal(retries + 1, reconnectStrategy.callCount);
 
                 if (retries === numberOfRetries) return new Error(`${numberOfRetries}`);
 
-                const time = retries * 2;
-                return time;
+                return 0;
             });
 
             const socket = createSocket({
diff --git a/packages/client/lib/client/socket.ts b/packages/client/lib/client/socket.ts
index 345ac1d3e38..b701f6ea979 100644
--- a/packages/client/lib/client/socket.ts
+++ b/packages/client/lib/client/socket.ts
@@ -6,10 +6,26 @@ import { ConnectionTimeoutError, ClientClosedError, SocketClosedUnexpectedlyErro
 import { promiseTimeout } from '../utils';
 
 export interface RedisSocketCommonOptions {
+    /**
+     * Connection Timeout (in milliseconds)
+     */
     connectTimeout?: number;
+    /**
+     * Toggle [`Nagle's algorithm`](https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay)
+     */
     noDelay?: boolean;
+    /**
+     * Toggle [`keep-alive`](https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay)
+     */
     keepAlive?: number | false;
-    reconnectStrategy?(retries: number): number | Error;
+    /**
+     * When the socket closes unexpectedly (without calling `.quit()`/`.disconnect()`), the client uses `reconnectStrategy` to decide what to do. The following values are supported:
+     * 1. `false` -> do not reconnect, close the client and flush the command queue.
+     * 2. `number` -> wait for `X` milliseconds before reconnecting.
+     * 3. `(retries: number, cause: Error) => false | number | Error` -> `number` is the same as configuring a `number` directly, `Error` is the same as `false`, but with a custom error.
+     * Defaults to `retries => Math.min(retries * 50, 500)`
+     */
+    reconnectStrategy?: false | number | ((retries: number, cause: Error) => false | Error | number);
 }
 
 type RedisNetSocketOptions = Partial<net.SocketConnectOpts> & {
@@ -83,23 +99,42 @@ export default class RedisSocket extends EventEmitter {
         this.#options = RedisSocket.#initiateOptions(options);
     }
 
-    reconnectStrategy(retries: number): number | Error {
-        if (this.#options.reconnectStrategy) {
+    #reconnectStrategy(retries: number, cause: Error) {
+        if (this.#options.reconnectStrategy === false) {
+            return false;
+        } else if (typeof this.#options.reconnectStrategy === 'number') {
+            return this.#options.reconnectStrategy;
+        } else if (this.#options.reconnectStrategy) {
             try {
-                const retryIn = this.#options.reconnectStrategy(retries);
-                if (typeof retryIn !== 'number' && !(retryIn instanceof Error)) {
-                    throw new TypeError('Reconnect strategy should return `number | Error`');
+                const retryIn = this.#options.reconnectStrategy(retries, cause);
+                if (retryIn !== false && !(retryIn instanceof Error) && typeof retryIn !== 'number') {
+                    throw new TypeError(`Reconnect strategy should return \`false | Error | number\`, got ${retryIn} instead`);
                 }
 
                 return retryIn;
             } catch (err) {
-                this.emit('error', err);
+                this.emit('error', err);    
             }
         }
 
         return Math.min(retries * 50, 500);
     }
 
+    #shouldReconnect(retries: number, cause: Error) {
+        const retryIn = this.#reconnectStrategy(retries, cause);
+        if (retryIn === false) {
+            this.#isOpen = false;
+            this.emit('error', cause);
+            return cause;
+        } else if (retryIn instanceof Error) {
+            this.#isOpen = false;
+            this.emit('error', cause);
+            return new ReconnectStrategyError(retryIn, cause);
+        }
+
+        return retryIn;
+    }
+
     async connect(): Promise<void> {
         if (this.#isOpen) {
             throw new Error('Socket already opened');
@@ -109,13 +144,9 @@ export default class RedisSocket extends EventEmitter {
         return this.#connect();
     }
 
-    async #connect(hadError?: boolean): Promise<void> {
+    async #connect(): Promise<void> {
         let retries = 0;
         do {
-            if (retries > 0 || hadError) {
-                this.emit('reconnecting');
-            }
-
             try {
                 this.#socket = await this.#createSocket();
                 this.#writableNeedDrain = false;
@@ -131,17 +162,15 @@ export default class RedisSocket extends EventEmitter {
                 this.#isReady = true;
                 this.emit('ready');
             } catch (err) {
-                const retryIn = this.reconnectStrategy(retries);
-                if (retryIn instanceof Error) {
-                    this.#isOpen = false;
-                    this.emit('error', err);
-                    throw new ReconnectStrategyError(retryIn, err);
+                const retryIn = this.#shouldReconnect(retries++, err as Error);
+                if (typeof retryIn !== 'number') {
+                    throw retryIn;
                 }
 
                 this.emit('error', err);
                 await promiseTimeout(retryIn);
+                this.emit('reconnecting');
             }
-            retries++;
         } while (this.#isOpen && !this.#isReady);
     }
 
@@ -200,12 +229,14 @@ export default class RedisSocket extends EventEmitter {
     }
 
     #onSocketError(err: Error): void {
+        const wasReady = this.#isReady;
         this.#isReady = false;
         this.emit('error', err);
 
-        if (!this.#isOpen) return;
-
-        this.#connect(true).catch(() => {
+        if (!wasReady || !this.#isOpen || typeof this.#shouldReconnect(0, err) !== 'number') return;
+        
+        this.emit('reconnecting');
+        this.#connect().catch(() => {
             // the error was already emitted, silently ignore it
         });
     }
@@ -261,7 +292,7 @@ export default class RedisSocket extends EventEmitter {
         this.#socket.cork();
         this.#isCorked = true;
 
-        queueMicrotask(() => {
+        setImmediate(() => {
             this.#socket?.uncork();
             this.#isCorked = false;
         });
diff --git a/packages/client/lib/cluster/cluster-slots.ts b/packages/client/lib/cluster/cluster-slots.ts
index d23ef569f30..45c96a80b50 100644
--- a/packages/client/lib/cluster/cluster-slots.ts
+++ b/packages/client/lib/cluster/cluster-slots.ts
@@ -1,157 +1,254 @@
 import RedisClient, { InstantiableRedisClient, RedisClientType } from '../client';
-import { RedisClusterMasterNode, RedisClusterReplicaNode } from '../commands/CLUSTER_NODES';
 import { RedisClusterClientOptions, RedisClusterOptions } from '.';
 import { RedisCommandArgument, RedisFunctions, RedisModules, RedisScripts } from '../commands';
 import { RootNodesUnavailableError } from '../errors';
+import { ClusterSlotsNode } from '../commands/CLUSTER_SLOTS';
+import { types } from 'util';
+import { ChannelListeners, PubSubType, PubSubTypeListeners } from '../client/pub-sub';
+import { EventEmitter } from 'stream';
 
 // We need to use 'require', because it's not possible with Typescript to import
 // function that are exported as 'module.exports = function`, without esModuleInterop
 // set to true.
 const calculateSlot = require('cluster-key-slot');
 
-export interface ClusterNode<
+interface NodeAddress {
+    host: string;
+    port: number;
+}
+
+export type NodeAddressMap = {
+    [address: string]: NodeAddress;
+} | ((address: string) => NodeAddress | undefined);
+
+type ValueOrPromise<T> = T | Promise<T>;
+
+type ClientOrPromise<
+    M extends RedisModules,
+    F extends RedisFunctions,
+    S extends RedisScripts
+> = ValueOrPromise<RedisClientType<M, F, S>>;
+
+export interface Node<
     M extends RedisModules,
     F extends RedisFunctions,
     S extends RedisScripts
 > {
-    id: string;
-    client: RedisClientType<M, F, S>;
+    address: string;
+    client?: ClientOrPromise<M, F, S>;
 }
 
-interface NodeAddress {
+export interface ShardNode<
+    M extends RedisModules,
+    F extends RedisFunctions,
+    S extends RedisScripts
+> extends Node<M, F, S> {
+    id: string;
     host: string;
     port: number;
+    readonly: boolean;
 }
 
-export type NodeAddressMap = {
-    [address: string]: NodeAddress;
-} | ((address: string) => NodeAddress | undefined);
+export interface MasterNode<
+    M extends RedisModules,
+    F extends RedisFunctions,
+    S extends RedisScripts
+> extends ShardNode<M, F, S> {
+    pubSubClient?: ClientOrPromise<M, F, S>;
+}
 
-interface SlotNodes<
+export interface Shard<
     M extends RedisModules,
     F extends RedisFunctions,
     S extends RedisScripts
 > {
-    master: ClusterNode<M, F, S>;
-    replicas: Array<ClusterNode<M, F, S>>;
-    clientIterator: IterableIterator<RedisClientType<M, F, S>> | undefined;
+    master: MasterNode<M, F, S>;
+    replicas?: Array<ShardNode<M, F, S>>;
+    nodesIterator?: IterableIterator<ShardNode<M, F, S>>;
 }
 
-type OnError = (err: unknown) => void;
+type ShardWithReplicas<
+    M extends RedisModules,
+    F extends RedisFunctions,
+    S extends RedisScripts
+> = Shard<M, F, S> & Required<Pick<Shard<M, F, S>, 'replicas'>>;
+
+export type PubSubNode<
+    M extends RedisModules,
+    F extends RedisFunctions,
+    S extends RedisScripts
+> = Required<Node<M, F, S>>;
+
+type PubSubToResubscribe = Record<
+    PubSubType.CHANNELS | PubSubType.PATTERNS,
+    PubSubTypeListeners
+>;
+
+export type OnShardedChannelMovedError = (
+    err: unknown,
+    channel: string,
+    listeners?: ChannelListeners
+) => void;
 
 export default class RedisClusterSlots<
     M extends RedisModules,
     F extends RedisFunctions,
     S extends RedisScripts
 > {
+    static #SLOTS = 16384;
+
     readonly #options: RedisClusterOptions<M, F, S>;
     readonly #Client: InstantiableRedisClient<M, F, S>;
-    readonly #onError: OnError;
-    readonly #nodeByAddress = new Map<string, ClusterNode<M, F, S>>();
-    readonly #slots: Array<SlotNodes<M, F, S>> = [];
+    readonly #emit: EventEmitter['emit'];
+    slots = new Array<Shard<M, F, S>>(RedisClusterSlots.#SLOTS);
+    shards = new Array<Shard<M, F, S>>();
+    masters = new Array<ShardNode<M, F, S>>();
+    replicas = new Array<ShardNode<M, F, S>>();
+    readonly nodeByAddress = new Map<string, MasterNode<M, F, S> | ShardNode<M, F, S>>();
+    pubSubNode?: PubSubNode<M, F, S>;
+
+    #isOpen = false;
+
+    get isOpen() {
+        return this.#isOpen;
+    }
 
-    constructor(options: RedisClusterOptions<M, F, S>, onError: OnError) {
+    constructor(
+        options: RedisClusterOptions<M, F, S>,
+        emit: EventEmitter['emit']
+    ) {
         this.#options = options;
         this.#Client = RedisClient.extend(options);
-        this.#onError = onError;
+        this.#emit = emit;
     }
 
-    async connect(): Promise<void> {
-        for (const rootNode of this.#options.rootNodes) {
-            if (await this.#discoverNodes(rootNode)) return;
+    async connect() {
+        if (this.#isOpen) {
+            throw new Error('Cluster already open');
         }
 
-        throw new RootNodesUnavailableError();
-    }
-
-    async #discoverNodes(clientOptions?: RedisClusterClientOptions): Promise<boolean> {
-        const client = this.#initiateClient(clientOptions);
-
-        await client.connect();
-
+        this.#isOpen = true;
         try {
-            await this.#reset(await client.clusterNodes());
-            return true;
+            await this.#discoverWithRootNodes();
         } catch (err) {
-            this.#onError(err);
-            return false;
-        } finally {
-            if (client.isOpen) {
-                await client.disconnect();
-            }
+            this.#isOpen = false;
+            throw err;
         }
     }
 
-    #runningRediscoverPromise?: Promise<void>;
+    async #discoverWithRootNodes() {
+        let start = Math.floor(Math.random() * this.#options.rootNodes.length);
+        for (let i = start; i < this.#options.rootNodes.length; i++) {    
+            if (await this.#discover(this.#options.rootNodes[i])) return;
+        }
 
-    async rediscover(startWith: RedisClientType<M, F, S>): Promise<void> {
-        if (!this.#runningRediscoverPromise) {
-            this.#runningRediscoverPromise = this.#rediscover(startWith)
-                .finally(() => this.#runningRediscoverPromise = undefined);
+        for (let i = 0; i < start; i++) {
+            if (await this.#discover(this.#options.rootNodes[i])) return;
         }
 
-        return this.#runningRediscoverPromise;
+        throw new RootNodesUnavailableError();
     }
 
-    async #rediscover(startWith: RedisClientType<M, F, S>): Promise<void> {
-        if (await this.#discoverNodes(startWith.options)) return;
+    #resetSlots() {
+        this.slots = new Array(RedisClusterSlots.#SLOTS);
+        this.shards = [];
+        this.masters = [];
+        this.replicas = [];
+        this.#randomNodeIterator = undefined;
+    }
 
-        for (const { client } of this.#nodeByAddress.values()) {
-            if (client === startWith) continue;
+    async #discover(rootNode?: RedisClusterClientOptions) {
+        const addressesInUse = new Set<string>();
 
-            if (await this.#discoverNodes(client.options)) return;
-        }
-
-        throw new Error('None of the cluster nodes is available');
-    }
+        try {
+            const shards = await this.#getShards(rootNode),
+                promises: Array<Promise<unknown>> = [],
+                eagerConnect = this.#options.minimizeConnections !== true;
+            this.#resetSlots();
+            for (const { from, to, master, replicas } of shards) {
+                const shard: Shard<M, F, S> = {
+                    master: this.#initiateSlotNode(master, false, eagerConnect, addressesInUse, promises)
+                };
+
+                if (this.#options.useReplicas) {
+                    shard.replicas = replicas.map(replica =>
+                        this.#initiateSlotNode(replica, true, eagerConnect, addressesInUse, promises)
+                    );
+                }
 
-    async #reset(masters: Array<RedisClusterMasterNode>): Promise<void> {
-        // Override this.#slots and add not existing clients to this.#nodeByAddress
-        const promises: Array<Promise<void>> = [],
-            clientsInUse = new Set<string>();
-        for (const master of masters) {
-            const slot = {
-                master: this.#initiateClientForNode(master, false, clientsInUse, promises),
-                replicas: this.#options.useReplicas ?
-                    master.replicas.map(replica => this.#initiateClientForNode(replica, true, clientsInUse, promises)) :
-                    [],
-                clientIterator: undefined // will be initiated in use
-            };
+                this.shards.push(shard);
 
-            for (const { from, to } of master.slots) {
                 for (let i = from; i <= to; i++) {
-                    this.#slots[i] = slot;
+                    this.slots[i] = shard;
                 }
             }
-        }
 
-        // Remove unused clients from this.#nodeByAddress using clientsInUse
-        for (const [address, { client }] of this.#nodeByAddress.entries()) {
-            if (clientsInUse.has(address)) continue;
+            if (this.pubSubNode && !addressesInUse.has(this.pubSubNode.address)) {
+                if (types.isPromise(this.pubSubNode.client)) {
+                    promises.push(
+                        this.pubSubNode.client.then(client => client.disconnect())
+                    );
+                    this.pubSubNode = undefined;
+                } else {
+                    promises.push(this.pubSubNode.client.disconnect());
+                    
+                    const channelsListeners = this.pubSubNode.client.getPubSubListeners(PubSubType.CHANNELS),
+                        patternsListeners = this.pubSubNode.client.getPubSubListeners(PubSubType.PATTERNS);
+
+                    if (channelsListeners.size || patternsListeners.size) {
+                        promises.push(
+                            this.#initiatePubSubClient({
+                                [PubSubType.CHANNELS]: channelsListeners,
+                                [PubSubType.PATTERNS]: patternsListeners
+                            })
+                        );
+                    }
+                }
+            }
 
-            promises.push(client.disconnect());
-            this.#nodeByAddress.delete(address);
-        }
+            for (const [address, node] of this.nodeByAddress.entries()) {
+                if (addressesInUse.has(address)) continue;
 
-        await Promise.all(promises);
-    }
+                if (node.client) {
+                    promises.push(
+                        this.#execOnNodeClient(node.client, client => client.disconnect())
+                    );
+                }
+
+                const { pubSubClient } = node as MasterNode<M, F, S>;
+                if (pubSubClient) {
+                    promises.push(
+                        this.#execOnNodeClient(pubSubClient, client => client.disconnect())
+                    );
+                }
 
-    #clientOptionsDefaults(options?: RedisClusterClientOptions): RedisClusterClientOptions | undefined {
-        if (!this.#options.defaults) return options;
+                this.nodeByAddress.delete(address);
+            }
 
-        return {
-            ...this.#options.defaults,
-            ...options,
-            socket: this.#options.defaults.socket && options?.socket ? {
-                ...this.#options.defaults.socket,
-                ...options.socket
-            } : this.#options.defaults.socket ?? options?.socket
-        };
+            await Promise.all(promises);
+
+            return true;
+        } catch (err) {
+            this.#emit('error', err);
+            return false;
+        }
     }
 
-    #initiateClient(options?: RedisClusterClientOptions): RedisClientType<M, F, S> {
-        return new this.#Client(this.#clientOptionsDefaults(options))
-            .on('error', this.#onError);
+    async #getShards(rootNode?: RedisClusterClientOptions) {
+        const client = new this.#Client(
+            this.#clientOptionsDefaults(rootNode, true)
+        );
+
+        client.on('error', err => this.#emit('error', err));
+
+        await client.connect();
+
+        try {
+            // using `CLUSTER SLOTS` and not `CLUSTER SHARDS` to support older versions
+            return await client.clusterSlots();
+        } finally {
+            await client.disconnect();
+        }
     }
 
     #getNodeAddress(address: string): NodeAddress | undefined {
@@ -164,130 +261,361 @@ export default class RedisClusterSlots<
         }
     }
 
-    #initiateClientForNode(
-        nodeData: RedisClusterMasterNode | RedisClusterReplicaNode,
-        readonly: boolean,
-        clientsInUse: Set<string>,
-        promises: Array<Promise<void>>
-    ): ClusterNode<M, F, S> {
-        const address = `${nodeData.host}:${nodeData.port}`;
-        clientsInUse.add(address);
+    #clientOptionsDefaults(
+        options?: RedisClusterClientOptions,
+        disableReconnect?: boolean
+    ): RedisClusterClientOptions | undefined {
+        let result: RedisClusterClientOptions | undefined;
+        if (this.#options.defaults) {
+            let socket;
+            if (this.#options.defaults.socket) {
+                socket = {
+                    ...this.#options.defaults.socket,
+                    ...options?.socket
+                };
+            } else {
+                socket = options?.socket;
+            }
 
-        let node = this.#nodeByAddress.get(address);
+            result = {
+                ...this.#options.defaults,
+                ...options,
+                socket
+            };
+        } else {
+            result = options;
+        }
+        
+        if (disableReconnect) {
+            result ??= {};
+            result.socket ??= {};
+            result.socket.reconnectStrategy = false;
+        }
+
+        return result;
+    }
+
+    #initiateSlotNode(
+        { id, ip, port }: ClusterSlotsNode,
+        readonly: boolean,
+        eagerConnent: boolean,
+        addressesInUse: Set<string>,
+        promises: Array<Promise<unknown>>
+    ) {
+        const address = `${ip}:${port}`;
+        addressesInUse.add(address);
+
+        let node = this.nodeByAddress.get(address);
         if (!node) {
             node = {
-                id: nodeData.id,
-                client: this.#initiateClient({
-                    socket: this.#getNodeAddress(address) ?? {
-                        host: nodeData.host,
-                        port: nodeData.port
-                    },
-                    readonly
-                })
+                id,
+                host: ip,
+                port,
+                address,
+                readonly,
+                client: undefined
             };
-            promises.push(node.client.connect());
-            this.#nodeByAddress.set(address, node);
+            
+            if (eagerConnent) {
+                promises.push(this.#createNodeClient(node));
+            }
+            
+            this.nodeByAddress.set(address, node);
         }
 
+        (readonly ? this.replicas : this.masters).push(node);
+
         return node;
     }
 
-    getSlotMaster(slot: number): ClusterNode<M, F, S> {
-        return this.#slots[slot].master;
+    async #createClient(
+        node: ShardNode<M, F, S>,
+        readonly = node.readonly
+    ) {
+        const client = new this.#Client(
+            this.#clientOptionsDefaults({
+                socket: this.#getNodeAddress(node.address) ?? {
+                    host: node.host,
+                    port: node.port
+                },
+                readonly
+            })
+        );
+        client.on('error', err => this.#emit('error', err));
+
+        await client.connect();
+
+        return client;
     }
 
-    *#slotClientIterator(slotNumber: number): IterableIterator<RedisClientType<M, F, S>> {
-        const slot = this.#slots[slotNumber];
-        yield slot.master.client;
+    #createNodeClient(node: ShardNode<M, F, S>) {
+        const promise = this.#createClient(node)
+            .then(client => {
+                node.client = client;
+                return client;
+            })
+            .catch(err => {
+                node.client = undefined;
+                throw err;
+            });
+        node.client = promise;
+        return promise;
+    }
 
-        for (const replica of slot.replicas) {
-            yield replica.client;
-        }
+    nodeClient(node: ShardNode<M, F, S>) {
+        return node.client ?? this.#createNodeClient(node);
     }
 
-    #getSlotClient(slotNumber: number): RedisClientType<M, F, S> {
-        const slot = this.#slots[slotNumber];
-        if (!slot.clientIterator) {
-            slot.clientIterator = this.#slotClientIterator(slotNumber);
-        }
+    #runningRediscoverPromise?: Promise<void>;
 
-        const {done, value} = slot.clientIterator.next();
-        if (done) {
-            slot.clientIterator = undefined;
-            return this.#getSlotClient(slotNumber);
-        }
+    async rediscover(startWith: RedisClientType<M, F, S>): Promise<void> {
+        this.#runningRediscoverPromise ??= this.#rediscover(startWith)
+            .finally(() => this.#runningRediscoverPromise = undefined);
+        return this.#runningRediscoverPromise;
+    }
+
+    async #rediscover(startWith: RedisClientType<M, F, S>): Promise<void> {
+        if (await this.#discover(startWith.options)) return;
 
-        return value;
+        return this.#discoverWithRootNodes();
     }
 
-    #randomClientIterator?: IterableIterator<ClusterNode<M, F, S>>;
+    quit(): Promise<void> {
+        return this.#destroy(client => client.quit());
+    }
 
-    #getRandomClient(): RedisClientType<M, F, S> {
-        if (!this.#nodeByAddress.size) {
-            throw new Error('Cluster is not connected');
-        }
+    disconnect(): Promise<void> {
+        return this.#destroy(client => client.disconnect());
+    }
+
+    async #destroy(fn: (client: RedisClientType<M, F, S>) => Promise<unknown>): Promise<void> {
+        this.#isOpen = false;
+
+        const promises = [];
+        for (const { master, replicas } of this.shards) {
+            if (master.client) {
+                promises.push(
+                    this.#execOnNodeClient(master.client, fn)
+                );
+            }
 
-        if (!this.#randomClientIterator) {
-            this.#randomClientIterator = this.#nodeByAddress.values();
+            if (master.pubSubClient) {
+                promises.push(
+                    this.#execOnNodeClient(master.pubSubClient, fn)
+                );
+            }
+
+            if (replicas) {
+                for (const { client } of replicas) {
+                    if (client) {
+                        promises.push(
+                            this.#execOnNodeClient(client, fn)
+                        );
+                    }
+                }
+            }
         }
 
-        const {done, value} = this.#randomClientIterator.next();
-        if (done) {
-            this.#randomClientIterator = undefined;
-            return this.#getRandomClient();
+        if (this.pubSubNode) {
+            promises.push(this.#execOnNodeClient(this.pubSubNode.client, fn));
+            this.pubSubNode = undefined;
         }
 
-        return value.client;
+        this.#resetSlots();
+        this.nodeByAddress.clear();
+
+        await Promise.allSettled(promises);
+    }
+
+    #execOnNodeClient(
+        client: ClientOrPromise<M, F, S>,
+        fn: (client: RedisClientType<M, F, S>) => Promise<unknown>
+    ) {
+        return types.isPromise(client) ?
+            client.then(fn) :
+            fn(client);
     }
 
-    getClient(firstKey?: RedisCommandArgument, isReadonly?: boolean): RedisClientType<M, F, S> {
+    getClient(
+        firstKey: RedisCommandArgument | undefined,
+        isReadonly: boolean | undefined
+    ): ClientOrPromise<M, F, S> {
         if (!firstKey) {
-            return this.#getRandomClient();
+            return this.nodeClient(this.getRandomNode());
         }
 
-        const slot = calculateSlot(firstKey);
-        if (!isReadonly || !this.#options.useReplicas) {
-            return this.getSlotMaster(slot).client;
+        const slotNumber = calculateSlot(firstKey);
+        if (!isReadonly) {
+            return this.nodeClient(this.slots[slotNumber].master);
         }
 
-        return this.#getSlotClient(slot);
+        return this.nodeClient(this.getSlotRandomNode(slotNumber));
     }
 
-    getMasters(): Array<ClusterNode<M, F, S>> {
-        const masters = [];
-        for (const node of this.#nodeByAddress.values()) {
-            if (node.client.options?.readonly) continue;
+    *#iterateAllNodes() {
+        let i = Math.floor(Math.random() * (this.masters.length + this.replicas.length));
+        if (i < this.masters.length) {
+            do {
+                yield this.masters[i];
+            } while (++i < this.masters.length);
 
-            masters.push(node);
+            for (const replica of this.replicas) {
+                yield replica;
+            }
+        } else {
+            i -= this.masters.length;
+            do {
+                yield this.replicas[i];
+            } while (++i < this.replicas.length);
         }
 
-        return masters;
+        while (true) {
+            for (const master of this.masters) {
+                yield master;
+            }
+
+            for (const replica of this.replicas) {
+                yield replica;
+            }
+        }
     }
 
-    getNodeByAddress(address: string): ClusterNode<M, F, S> | undefined {
-        const mappedAddress = this.#getNodeAddress(address);
-        return this.#nodeByAddress.get(
-            mappedAddress ? `${mappedAddress.host}:${mappedAddress.port}` : address
-        );
+    #randomNodeIterator?: IterableIterator<ShardNode<M, F, S>>;
+
+    getRandomNode() {
+        this.#randomNodeIterator ??= this.#iterateAllNodes();
+        return this.#randomNodeIterator.next().value as ShardNode<M, F, S>;
     }
 
-    quit(): Promise<void> {
-        return this.#destroy(client => client.quit());
+    *#slotNodesIterator(slot: ShardWithReplicas<M, F, S>) {
+        let i = Math.floor(Math.random() * (1 + slot.replicas.length));
+        if (i < slot.replicas.length) {
+            do {
+                yield slot.replicas[i];
+            } while (++i < slot.replicas.length);
+        }
+
+        while (true) {
+            yield slot.master;
+            
+            for (const replica of slot.replicas) {
+                yield replica;
+            }
+        }
     }
 
-    disconnect(): Promise<void> {
-        return this.#destroy(client => client.disconnect());
+    getSlotRandomNode(slotNumber: number) {
+        const slot = this.slots[slotNumber];
+        if (!slot.replicas?.length) {
+            return slot.master;
+        }
+
+        slot.nodesIterator ??= this.#slotNodesIterator(slot as ShardWithReplicas<M, F, S>);
+        return slot.nodesIterator.next().value as ShardNode<M, F, S>;
     }
 
-    async #destroy(fn: (client: RedisClientType<M, F, S>) => Promise<unknown>): Promise<void> {
-        const promises = [];
-        for (const { client } of this.#nodeByAddress.values()) {
-            promises.push(fn(client));
+    getMasterByAddress(address: string) {
+        const master = this.nodeByAddress.get(address);
+        if (!master) return;
+
+        return this.nodeClient(master);
+    }
+
+    getPubSubClient() {
+        return this.pubSubNode ?
+            this.pubSubNode.client :
+            this.#initiatePubSubClient();
+    }
+
+    async #initiatePubSubClient(toResubscribe?: PubSubToResubscribe) {
+        const index = Math.floor(Math.random() * (this.masters.length + this.replicas.length)),
+            node = index < this.masters.length ?
+                this.masters[index] :
+                this.replicas[index - this.masters.length];
+    
+        this.pubSubNode = {
+            address: node.address,
+            client: this.#createClient(node, true)
+                .then(async client => {
+                    if (toResubscribe) {
+                        await Promise.all([
+                            client.extendPubSubListeners(PubSubType.CHANNELS, toResubscribe[PubSubType.CHANNELS]),
+                            client.extendPubSubListeners(PubSubType.PATTERNS, toResubscribe[PubSubType.PATTERNS])
+                        ]);
+                    }
+                    
+                    this.pubSubNode!.client = client;
+                    return client;
+                })
+                .catch(err => {
+                    this.pubSubNode = undefined;
+                    throw err;
+                })
+        };
+        
+        return this.pubSubNode.client as Promise<RedisClientType<M, F, S>>;
+    }
+
+    async executeUnsubscribeCommand(
+        unsubscribe: (client: RedisClientType<M, F, S>) => Promise<void>
+    ): Promise<void> {
+        const client = await this.getPubSubClient();
+        await unsubscribe(client);
+
+        if (!client.isPubSubActive && client.isOpen) {
+            await client.disconnect();
+            this.pubSubNode = undefined;
         }
+    }
+
+    getShardedPubSubClient(channel: string) {
+        const { master } = this.slots[calculateSlot(channel)];
+        return master.pubSubClient ?? this.#initiateShardedPubSubClient(master);
+    }
+
+    #initiateShardedPubSubClient(master: MasterNode<M, F, S>) {
+        const promise = this.#createClient(master, true)
+            .then(client => {
+                client.on('server-sunsubscribe', async (channel, listeners) => {
+                    try {
+                        await this.rediscover(client);
+                        const redirectTo = await this.getShardedPubSubClient(channel);
+                        redirectTo.extendPubSubChannelListeners(
+                            PubSubType.SHARDED,
+                            channel,
+                            listeners
+                        );
+                    } catch (err) {
+                        this.#emit('sharded-shannel-moved-error', err, channel, listeners);
+                    }
+                });
+
+                master.pubSubClient = client;
+                return client;
+            })
+            .catch(err => {
+                master.pubSubClient = undefined;
+                throw err;
+            });
+
+        master.pubSubClient = promise;
+
+        return promise;
+    }
 
-        await Promise.all(promises);
+    async executeShardedUnsubscribeCommand(
+        channel: string,
+        unsubscribe: (client: RedisClientType<M, F, S>) => Promise<void>
+    ): Promise<void> {
+        const { master } = this.slots[calculateSlot(channel)];
+        if (!master.pubSubClient) return Promise.resolve();
 
-        this.#nodeByAddress.clear();
-        this.#slots.splice(0);
+        const client = await master.pubSubClient;
+        await unsubscribe(client);
+
+        if (!client.isPubSubActive && client.isOpen) {
+            await client.disconnect();
+            master.pubSubClient = undefined;
+        }
     }
 }
diff --git a/packages/client/lib/cluster/commands.ts b/packages/client/lib/cluster/commands.ts
index 8edbd1e3891..9027c5c0b5e 100644
--- a/packages/client/lib/cluster/commands.ts
+++ b/packages/client/lib/cluster/commands.ts
@@ -53,6 +53,9 @@ import * as GETRANGE from '../commands/GETRANGE';
 import * as GETSET from '../commands/GETSET';
 import * as HDEL from '../commands/HDEL';
 import * as HEXISTS from '../commands/HEXISTS';
+import * as HEXPIRE from '../commands/HEXPIRE';
+import * as HEXPIREAT from '../commands/HEXPIREAT';
+import * as HEXPIRETIME from '../commands/HEXPIRETIME';
 import * as HGET from '../commands/HGET';
 import * as HGETALL from '../commands/HGETALL';
 import * as HINCRBY from '../commands/HINCRBY';
@@ -60,13 +63,20 @@ import * as HINCRBYFLOAT from '../commands/HINCRBYFLOAT';
 import * as HKEYS from '../commands/HKEYS';
 import * as HLEN from '../commands/HLEN';
 import * as HMGET from '../commands/HMGET';
+import * as HPERSIST from '../commands/HPERSIST';
+import * as HPEXPIRE from '../commands/HPEXPIRE';
+import * as HPEXPIREAT from '../commands/HPEXPIREAT';
+import * as HPEXPIRETIME from '../commands/HPEXPIRETIME';
+import * as HPTTL from '../commands/HPTTL';
 import * as HRANDFIELD_COUNT_WITHVALUES from '../commands/HRANDFIELD_COUNT_WITHVALUES';
 import * as HRANDFIELD_COUNT from '../commands/HRANDFIELD_COUNT';
 import * as HRANDFIELD from '../commands/HRANDFIELD';
 import * as HSCAN from '../commands/HSCAN';
+import * as HSCAN_NOVALUES from '../commands/HSCAN_NOVALUES';
 import * as HSET from '../commands/HSET';
 import * as HSETNX from '../commands/HSETNX';
 import * as HSTRLEN from '../commands/HSTRLEN';
+import * as HTTL from '../commands/HTTL';
 import * as HVALS from '../commands/HVALS';
 import * as INCR from '../commands/INCR';
 import * as INCRBY from '../commands/INCRBY';
@@ -110,6 +120,7 @@ import * as PTTL from '../commands/PTTL';
 import * as PUBLISH from '../commands/PUBLISH';
 import * as RENAME from '../commands/RENAME';
 import * as RENAMENX from '../commands/RENAMENX';
+import * as RESTORE from '../commands/RESTORE';
 import * as RPOP_COUNT from '../commands/RPOP_COUNT';
 import * as RPOP from '../commands/RPOP';
 import * as RPOPLPUSH from '../commands/RPOPLPUSH';
@@ -135,6 +146,7 @@ import * as SORT_RO from '../commands/SORT_RO';
 import * as SORT_STORE from '../commands/SORT_STORE';
 import * as SORT from '../commands/SORT';
 import * as SPOP from '../commands/SPOP';
+import * as SPUBLISH from '../commands/SPUBLISH';
 import * as SRANDMEMBER_COUNT from '../commands/SRANDMEMBER_COUNT';
 import * as SRANDMEMBER from '../commands/SRANDMEMBER';
 import * as SREM from '../commands/SREM';
@@ -319,6 +331,12 @@ export default {
     hDel: HDEL,
     HEXISTS,
     hExists: HEXISTS,
+    HEXPIRE,
+    hExpire: HEXPIRE,
+    HEXPIREAT,
+    hExpireAt: HEXPIREAT,
+    HEXPIRETIME,
+    hExpireTime: HEXPIRETIME,
     HGET,
     hGet: HGET,
     HGETALL,
@@ -333,6 +351,16 @@ export default {
     hLen: HLEN,
     HMGET,
     hmGet: HMGET,
+    HPERSIST,
+    hPersist: HPERSIST,
+    HPEXPIRE,
+    hpExpire: HPEXPIRE,
+    HPEXPIREAT,
+    hpExpireAt: HPEXPIREAT,
+    HPEXPIRETIME,
+    hpExpireTime: HPEXPIRETIME,
+    HPTTL,
+    hpTTL: HPTTL,
     HRANDFIELD_COUNT_WITHVALUES,
     hRandFieldCountWithValues: HRANDFIELD_COUNT_WITHVALUES,
     HRANDFIELD_COUNT,
@@ -341,12 +369,16 @@ export default {
     hRandField: HRANDFIELD,
     HSCAN,
     hScan: HSCAN,
+    HSCAN_NOVALUES,
+    hScanNoValues: HSCAN_NOVALUES,
     HSET,
     hSet: HSET,
     HSETNX,
     hSetNX: HSETNX,
     HSTRLEN,
     hStrLen: HSTRLEN,
+    HTTL,
+    hTTL: HTTL,
     HVALS,
     hVals: HVALS,
     INCR,
@@ -433,6 +465,8 @@ export default {
     rename: RENAME,
     RENAMENX,
     renameNX: RENAMENX,
+    RESTORE,
+    restore: RESTORE,
     RPOP_COUNT,
     rPopCount: RPOP_COUNT,
     RPOP,
@@ -483,6 +517,8 @@ export default {
     sort: SORT,
     SPOP,
     sPop: SPOP,
+    SPUBLISH,
+    sPublish: SPUBLISH,
     SRANDMEMBER_COUNT,
     sRandMemberCount: SRANDMEMBER_COUNT,
     SRANDMEMBER,
diff --git a/packages/client/lib/cluster/index.spec.ts b/packages/client/lib/cluster/index.spec.ts
index a2981d824e3..569d716272a 100644
--- a/packages/client/lib/cluster/index.spec.ts
+++ b/packages/client/lib/cluster/index.spec.ts
@@ -1,25 +1,30 @@
 import { strict as assert } from 'assert';
-import testUtils, { GLOBAL } from '../test-utils';
+import testUtils, { GLOBAL, waitTillBeenCalled } from '../test-utils';
 import RedisCluster from '.';
 import { ClusterSlotStates } from '../commands/CLUSTER_SETSLOT';
+import { commandOptions } from '../command-options';
 import { SQUARE_SCRIPT } from '../client/index.spec';
 import { RootNodesUnavailableError } from '../errors';
-
-// We need to use 'require', because it's not possible with Typescript to import
-// function that are exported as 'module.exports = function`, without esModuleInterop
-// set to true.
-const calculateSlot = require('cluster-key-slot');
+import { spy } from 'sinon';
+import { promiseTimeout } from '../utils';
+import RedisClient from '../client';
 
 describe('Cluster', () => {
     testUtils.testWithCluster('sendCommand', async cluster => {
-        await cluster.publish('channel', 'message');
-        await cluster.set('a', 'b');
-        await cluster.set('a{a}', 'bb');
-        await cluster.set('aa', 'bb');
-        await cluster.get('aa');
-        await cluster.get('aa');
-        await cluster.get('aa');
-        await cluster.get('aa');
+        assert.equal(
+            await cluster.sendCommand(undefined, true, ['PING']),
+            'PONG'
+        );
+    }, GLOBAL.CLUSTERS.OPEN);
+
+    testUtils.testWithCluster('isOpen', async cluster => {
+        assert.equal(cluster.isOpen, true);
+        await cluster.disconnect();
+        assert.equal(cluster.isOpen, false);
+    }, GLOBAL.CLUSTERS.OPEN);
+
+    testUtils.testWithCluster('connect should throw if already connected', async cluster => {
+        await assert.rejects(cluster.connect());
     }, GLOBAL.CLUSTERS.OPEN);
 
     testUtils.testWithCluster('multi', async cluster => {
@@ -64,54 +69,321 @@ describe('Cluster', () => {
     });
 
     testUtils.testWithCluster('should handle live resharding', async cluster => {
-        const key = 'key',
+        const slot = 12539,
+            key = 'key',
             value = 'value';
         await cluster.set(key, value);
 
-        const slot = calculateSlot(key),
-            source = cluster.getSlotMaster(slot),
-            destination = cluster.getMasters().find(node => node.id !== source.id)!;
+        const importing = cluster.slots[0].master,
+            migrating = cluster.slots[slot].master,
+            [ importingClient, migratingClient ] = await Promise.all([
+                cluster.nodeClient(importing),
+                cluster.nodeClient(migrating)
+            ]);
 
         await Promise.all([
-            source.client.clusterSetSlot(slot, ClusterSlotStates.MIGRATING, destination.id),
-            destination.client.clusterSetSlot(slot, ClusterSlotStates.IMPORTING, destination.id)
+            importingClient.clusterSetSlot(slot, ClusterSlotStates.IMPORTING, migrating.id),
+            migratingClient.clusterSetSlot(slot, ClusterSlotStates.MIGRATING, importing.id)
         ]);
 
-        // should be able to get the key from the source node using "ASKING"
+        // should be able to get the key from the migrating node
         assert.equal(
             await cluster.get(key),
             value
         );
 
-        await Promise.all([
-            source.client.migrate(
-                '127.0.0.1',
-                (<any>destination.client.options).socket.port,
-                key,
-                0,
-                10
-            )
-        ]);
+        await migratingClient.migrate(
+            importing.host,
+            importing.port,
+            key,
+            0,
+            10
+        );
 
-        // should be able to get the key from the destination node using the "ASKING" command
+        // should be able to get the key from the importing node using `ASKING`
         assert.equal(
             await cluster.get(key),
             value
         );
 
-        await Promise.all(
-            cluster.getMasters().map(({ client }) => {
-                return client.clusterSetSlot(slot, ClusterSlotStates.NODE, destination.id);
-            })
-        );
+        await Promise.all([
+            importingClient.clusterSetSlot(slot, ClusterSlotStates.NODE, importing.id),
+            migratingClient.clusterSetSlot(slot, ClusterSlotStates.NODE, importing.id),
+        ]);
 
-        // should handle "MOVED" errors
+        // should handle `MOVED` errors
         assert.equal(
             await cluster.get(key),
             value
         );
     }, {
         serverArguments: [],
-        numberOfNodes: 2
+        numberOfMasters: 2
+    });
+
+    testUtils.testWithCluster('getRandomNode should spread the the load evenly', async cluster => {
+        const totalNodes = cluster.masters.length + cluster.replicas.length,
+            ids = new Set<string>();
+        for (let i = 0; i < totalNodes; i++) {
+            ids.add(cluster.getRandomNode().id);
+        }
+        
+        assert.equal(ids.size, totalNodes);
+    }, GLOBAL.CLUSTERS.WITH_REPLICAS);
+
+    testUtils.testWithCluster('getSlotRandomNode should spread the the load evenly', async cluster => {
+        const totalNodes = 1 + cluster.slots[0].replicas!.length,
+            ids = new Set<string>();
+        for (let i = 0; i < totalNodes; i++) {
+            ids.add(cluster.getSlotRandomNode(0).id);
+        }
+        
+        assert.equal(ids.size, totalNodes);
+    }, GLOBAL.CLUSTERS.WITH_REPLICAS);
+
+    testUtils.testWithCluster('cluster topology', async cluster => {
+        assert.equal(cluster.slots.length, 16384);
+        const { numberOfMasters, numberOfReplicas } = GLOBAL.CLUSTERS.WITH_REPLICAS;
+        assert.equal(cluster.shards.length, numberOfMasters);
+        assert.equal(cluster.masters.length, numberOfMasters);
+        assert.equal(cluster.replicas.length, numberOfReplicas * numberOfMasters);
+        assert.equal(cluster.nodeByAddress.size, numberOfMasters + numberOfMasters * numberOfReplicas);
+    }, GLOBAL.CLUSTERS.WITH_REPLICAS);
+
+    testUtils.testWithCluster('getMasters should be backwards competiable (without `minimizeConnections`)', async cluster => {
+        const masters = cluster.getMasters();
+        assert.ok(Array.isArray(masters));
+        for (const master of masters) {
+            assert.equal(typeof master.id, 'string');
+            assert.ok(master.client instanceof RedisClient);
+        }
+    }, {
+        ...GLOBAL.CLUSTERS.OPEN,
+        clusterConfiguration: {
+            minimizeConnections: undefined // reset to default
+        }
+    });
+
+    testUtils.testWithCluster('getSlotMaster should be backwards competiable (without `minimizeConnections`)', async cluster => {
+        const master = cluster.getSlotMaster(0);
+        assert.equal(typeof master.id, 'string');
+        assert.ok(master.client instanceof RedisClient);
+    }, {
+        ...GLOBAL.CLUSTERS.OPEN,
+        clusterConfiguration: {
+            minimizeConnections: undefined // reset to default
+        }
+    });
+
+    testUtils.testWithCluster('should throw CROSSSLOT error', async cluster => {
+        await assert.rejects(cluster.mGet(['a', 'b']));
+    }, GLOBAL.CLUSTERS.OPEN);
+
+    testUtils.testWithCluster('should send commands with commandOptions to correct cluster slot (without redirections)', async cluster => {
+        // 'a' and 'b' hash to different cluster slots (see previous unit test)
+        // -> maxCommandRedirections 0: rejects on MOVED/ASK reply
+        await cluster.set(commandOptions({ isolated: true }), 'a', '1'),
+        await cluster.set(commandOptions({ isolated: true }), 'b', '2'),
+
+        assert.equal(await cluster.get('a'), '1');
+        assert.equal(await cluster.get('b'), '2');
+    }, {
+        ...GLOBAL.CLUSTERS.OPEN,
+        clusterConfiguration: {
+            maxCommandRedirections: 0
+        }
+    });
+
+    describe('minimizeConnections', () => {
+        testUtils.testWithCluster('false', async cluster => {
+            for (const master of cluster.masters) {
+                assert.ok(master.client instanceof RedisClient);
+            }
+        }, {
+            ...GLOBAL.CLUSTERS.OPEN,
+            clusterConfiguration: {
+                minimizeConnections: false
+            }
+        });
+
+        testUtils.testWithCluster('true', async cluster => {
+            for (const master of cluster.masters) {
+                assert.equal(master.client, undefined);
+            }
+        }, {
+            ...GLOBAL.CLUSTERS.OPEN,
+            clusterConfiguration: {
+                minimizeConnections: true
+            }
+        });
+    });
+
+    describe('PubSub', () => {
+        testUtils.testWithCluster('subscribe & unsubscribe', async cluster => {
+            const listener = spy();
+
+            await cluster.subscribe('channel', listener);
+
+            await Promise.all([
+                waitTillBeenCalled(listener),
+                cluster.publish('channel', 'message')
+            ]);
+            
+            assert.ok(listener.calledOnceWithExactly('message', 'channel'));
+
+            await cluster.unsubscribe('channel', listener);
+
+            assert.equal(cluster.pubSubNode, undefined);
+        }, GLOBAL.CLUSTERS.OPEN);
+        
+        testUtils.testWithCluster('concurrent UNSUBSCRIBE does not throw an error (#2685)', async cluster => {
+            const listener = spy();
+            await Promise.all([
+                cluster.subscribe('1', listener),
+                cluster.subscribe('2', listener)
+            ]);
+            await Promise.all([
+                cluster.unsubscribe('1', listener),
+                cluster.unsubscribe('2', listener)
+            ]);
+        }, GLOBAL.CLUSTERS.OPEN);
+
+        testUtils.testWithCluster('psubscribe & punsubscribe', async cluster => {
+            const listener = spy();
+
+            await cluster.pSubscribe('channe*', listener);
+
+            await Promise.all([
+                waitTillBeenCalled(listener),
+                cluster.publish('channel', 'message')
+            ]);
+            
+            assert.ok(listener.calledOnceWithExactly('message', 'channel'));
+
+            await cluster.pUnsubscribe('channe*', listener);
+
+            assert.equal(cluster.pubSubNode, undefined);
+        }, GLOBAL.CLUSTERS.OPEN);        
+
+        testUtils.testWithCluster('should move listeners when PubSub node disconnects from the cluster', async cluster => {
+            const listener = spy();
+            await cluster.subscribe('channel', listener);
+
+            assert.ok(cluster.pubSubNode);
+            const [ migrating, importing ] = cluster.masters[0].address === cluster.pubSubNode.address ?
+                    cluster.masters :
+                    [cluster.masters[1], cluster.masters[0]],
+                [ migratingClient, importingClient ] = await Promise.all([
+                    cluster.nodeClient(migrating),
+                    cluster.nodeClient(importing)
+                ]);
+
+            const range = cluster.slots[0].master === migrating ? {
+                key: 'bar', // 5061
+                start: 0,
+                end: 8191
+            } : {
+                key: 'foo', // 12182
+                start: 8192,
+                end: 16383
+            };
+
+            await Promise.all([
+                migratingClient.clusterDelSlotsRange(range),
+                importingClient.clusterDelSlotsRange(range),
+                importingClient.clusterAddSlotsRange(range)
+            ]);
+
+            // wait for migrating node to be notified about the new topology
+            while ((await migratingClient.clusterInfo()).state !== 'ok') {
+                await promiseTimeout(50);
+            }
+
+            // make sure to cause `MOVED` error
+            await cluster.get(range.key);
+
+            await Promise.all([
+                cluster.publish('channel', 'message'),
+                waitTillBeenCalled(listener)
+            ]);
+            
+            assert.ok(listener.calledOnceWithExactly('message', 'channel'));
+        }, {
+            serverArguments: [],
+            numberOfMasters: 2,
+            minimumDockerVersion: [7]
+        });
+
+        testUtils.testWithCluster('ssubscribe & sunsubscribe', async cluster => {
+            const listener = spy();
+
+            await cluster.sSubscribe('channel', listener);
+
+            await Promise.all([
+                waitTillBeenCalled(listener),
+                cluster.sPublish('channel', 'message')
+            ]);
+            
+            assert.ok(listener.calledOnceWithExactly('message', 'channel'));
+
+            await cluster.sUnsubscribe('channel', listener);
+
+            // 10328 is the slot of `channel`
+            assert.equal(cluster.slots[10328].master.pubSubClient, undefined);
+        }, {
+            ...GLOBAL.CLUSTERS.OPEN,
+            minimumDockerVersion: [7]
+        });
+
+        testUtils.testWithCluster('concurrent SUNSUBCRIBE does not throw an error (#2685)', async cluster => {
+            const listener = spy();
+            await Promise.all([
+                await cluster.sSubscribe('1', listener),
+                await cluster.sSubscribe('2', listener)
+            ]);
+            await Promise.all([
+                cluster.sUnsubscribe('1', listener),
+                cluster.sUnsubscribe('2', listener)
+            ]);
+        }, {
+            ...GLOBAL.CLUSTERS.OPEN,
+            minimumDockerVersion: [7]
+        });
+
+        testUtils.testWithCluster('should handle sharded-channel-moved events', async cluster => {
+            const SLOT = 10328,
+                migrating = cluster.slots[SLOT].master,
+                importing = cluster.masters.find(master => master !== migrating)!,
+                [ migratingClient, importingClient ] = await Promise.all([
+                    cluster.nodeClient(migrating),
+                    cluster.nodeClient(importing)
+                ]);
+
+            await Promise.all([
+                migratingClient.clusterDelSlots(SLOT),
+                importingClient.clusterDelSlots(SLOT),
+                importingClient.clusterAddSlots(SLOT)
+            ]);
+
+            // wait for migrating node to be notified about the new topology
+            while ((await migratingClient.clusterInfo()).state !== 'ok') {
+                await promiseTimeout(50);
+            }
+
+            const listener = spy();
+
+            // will trigger `MOVED` error
+            await cluster.sSubscribe('channel', listener);
+
+            await Promise.all([
+                waitTillBeenCalled(listener),
+                cluster.sPublish('channel', 'message')
+            ]);
+            
+            assert.ok(listener.calledOnceWithExactly('message', 'channel'));
+        }, {
+            serverArguments: [],
+            minimumDockerVersion: [7]
+        });
     });
 });
diff --git a/packages/client/lib/cluster/index.ts b/packages/client/lib/cluster/index.ts
index 6eafdda86ce..49ac293d6cf 100644
--- a/packages/client/lib/cluster/index.ts
+++ b/packages/client/lib/cluster/index.ts
@@ -1,11 +1,13 @@
 import COMMANDS from './commands';
 import { RedisCommand, RedisCommandArgument, RedisCommandArguments, RedisCommandRawReply, RedisCommandReply, RedisFunctions, RedisModules, RedisExtensions, RedisScript, RedisScripts, RedisCommandSignature, RedisFunction } from '../commands';
 import { ClientCommandOptions, RedisClientOptions, RedisClientType, WithFunctions, WithModules, WithScripts } from '../client';
-import RedisClusterSlots, { ClusterNode, NodeAddressMap } from './cluster-slots';
+import RedisClusterSlots, { NodeAddressMap, ShardNode } from './cluster-slots';
 import { attachExtensions, transformCommandReply, attachCommands, transformCommandArguments } from '../commander';
 import { EventEmitter } from 'events';
 import RedisClusterMultiCommand, { InstantiableRedisClusterMultiCommandType, RedisClusterMultiCommandType } from './multi-command';
 import { RedisMultiQueuedCommand } from '../multi-command';
+import { PubSubListener } from '../client/pub-sub';
+import { ErrorReply } from '../errors';
 
 export type RedisClusterClientOptions = Omit<
     RedisClientOptions,
@@ -17,10 +19,34 @@ export interface RedisClusterOptions<
     F extends RedisFunctions = Record<string, never>,
     S extends RedisScripts = Record<string, never>
 > extends RedisExtensions<M, F, S> {
+    /**
+     * Should contain details for some of the cluster nodes that the client will use to discover
+     * the "cluster topology". We recommend including details for at least 3 nodes here.
+     */
     rootNodes: Array<RedisClusterClientOptions>;
+    /**
+     * Default values used for every client in the cluster. Use this to specify global values,
+     * for example: ACL credentials, timeouts, TLS configuration etc.
+     */
     defaults?: Partial<RedisClusterClientOptions>;
+    /**
+     * When `true`, `.connect()` will only discover the cluster topology, without actually connecting to all the nodes.
+     * Useful for short-term or PubSub-only connections.
+     */
+    minimizeConnections?: boolean;
+    /**
+     * When `true`, distribute load by executing readonly commands (such as `GET`, `GEOSEARCH`, etc.) across all cluster nodes. When `false`, only use master nodes.
+     */
     useReplicas?: boolean;
+    /**
+     * The maximum number of times a command will be redirected due to `MOVED` or `ASK` errors.
+     */
     maxCommandRedirections?: number;
+    /**
+     * Mapping between the addresses in the cluster (see `CLUSTER SHARDS`) and the addresses the client should connect to
+     * Useful when the cluster is running on another network
+     *
+     */
     nodeAddressMap?: NodeAddressMap;
 }
 
@@ -70,14 +96,44 @@ export default class RedisCluster<
     }
 
     readonly #options: RedisClusterOptions<M, F, S>;
+
     readonly #slots: RedisClusterSlots<M, F, S>;
+
+    get slots() {
+        return this.#slots.slots;
+    }
+
+    get shards() {
+        return this.#slots.shards;
+    }
+
+    get masters() {
+        return this.#slots.masters;
+    }
+
+    get replicas() {
+        return this.#slots.replicas;
+    }
+
+    get nodeByAddress() {
+        return this.#slots.nodeByAddress;
+    }
+
+    get pubSubNode() {
+        return this.#slots.pubSubNode;
+    }
+
     readonly #Multi: InstantiableRedisClusterMultiCommandType<M, F, S>;
 
+    get isOpen() {
+        return this.#slots.isOpen;
+    }
+
     constructor(options: RedisClusterOptions<M, F, S>) {
         super();
 
         this.#options = options;
-        this.#slots = new RedisClusterSlots(options, err => this.emit('error', err));
+        this.#slots = new RedisClusterSlots(options, this.emit.bind(this));
         this.#Multi = RedisClusterMultiCommand.extend(options);
     }
 
@@ -88,7 +144,7 @@ export default class RedisCluster<
         });
     }
 
-    async connect(): Promise<void> {
+    connect() {
         return this.#slots.connect();
     }
 
@@ -96,11 +152,11 @@ export default class RedisCluster<
         command: C,
         args: Array<unknown>
     ): Promise<RedisCommandReply<C>> {
-        const { args: redisArgs, options } = transformCommandArguments(command, args);
+        const { jsArgs, args: redisArgs, options } = transformCommandArguments(command, args);
         return transformCommandReply(
             command,
             await this.sendCommand(
-                RedisCluster.extractFirstKey(command, args, redisArgs),
+                RedisCluster.extractFirstKey(command, jsArgs, redisArgs),
                 command.IS_READ_ONLY,
                 redisArgs,
                 options
@@ -188,34 +244,33 @@ export default class RedisCluster<
         executor: (client: RedisClientType<M, F, S>) => Promise<Reply>
     ): Promise<Reply> {
         const maxCommandRedirections = this.#options.maxCommandRedirections ?? 16;
-        let client = this.#slots.getClient(firstKey, isReadonly);
+        let client = await this.#slots.getClient(firstKey, isReadonly);
         for (let i = 0;; i++) {
             try {
                 return await executor(client);
             } catch (err) {
-                if (++i > maxCommandRedirections || !(err instanceof Error)) {
+                if (++i > maxCommandRedirections || !(err instanceof ErrorReply)) {
                     throw err;
                 }
 
                 if (err.message.startsWith('ASK')) {
                     const address = err.message.substring(err.message.lastIndexOf(' ') + 1);
-                    if (this.#slots.getNodeByAddress(address)?.client === client) {
-                        await client.asking();
-                        continue;
+                    let redirectTo = await this.#slots.getMasterByAddress(address);
+                    if (!redirectTo) {
+                        await this.#slots.rediscover(client);
+                        redirectTo = await this.#slots.getMasterByAddress(address);
                     }
 
-                    await this.#slots.rediscover(client);
-                    const redirectTo = this.#slots.getNodeByAddress(address);
                     if (!redirectTo) {
                         throw new Error(`Cannot find node ${address}`);
                     }
 
-                    await redirectTo.client.asking();
-                    client = redirectTo.client;
+                    await redirectTo.asking();
+                    client = redirectTo;
                     continue;
                 } else if (err.message.startsWith('MOVED')) {
                     await this.#slots.rediscover(client);
-                    client = this.#slots.getClient(firstKey, isReadonly);
+                    client = await this.#slots.getClient(firstKey, isReadonly);
                     continue;
                 }
 
@@ -239,14 +294,94 @@ export default class RedisCluster<
 
     multi = this.MULTI;
 
-    getMasters(): Array<ClusterNode<M, F, S>> {
-        return this.#slots.getMasters();
+    async SUBSCRIBE<T extends boolean = false>(
+        channels: string | Array<string>,
+        listener: PubSubListener<T>,
+        bufferMode?: T
+    ) {
+        return (await this.#slots.getPubSubClient())
+            .SUBSCRIBE(channels, listener, bufferMode);
+    }
+
+    subscribe = this.SUBSCRIBE;
+
+    async UNSUBSCRIBE<T extends boolean = false>(
+        channels?: string | Array<string>,
+        listener?: PubSubListener<boolean>,
+        bufferMode?: T
+    ) {
+        return this.#slots.executeUnsubscribeCommand(client =>
+            client.UNSUBSCRIBE(channels, listener, bufferMode)
+        );
+    }
+
+    unsubscribe = this.UNSUBSCRIBE;
+
+    async PSUBSCRIBE<T extends boolean = false>(
+        patterns: string | Array<string>,
+        listener: PubSubListener<T>,
+        bufferMode?: T
+    ) {
+        return (await this.#slots.getPubSubClient())
+            .PSUBSCRIBE(patterns, listener, bufferMode);
+    }
+
+    pSubscribe = this.PSUBSCRIBE;
+
+    async PUNSUBSCRIBE<T extends boolean = false>(
+        patterns?: string | Array<string>,
+        listener?: PubSubListener<T>,
+        bufferMode?: T
+    ) {
+        return this.#slots.executeUnsubscribeCommand(client =>
+            client.PUNSUBSCRIBE(patterns, listener, bufferMode)
+        );
+    }
+
+    pUnsubscribe = this.PUNSUBSCRIBE;
+
+    async SSUBSCRIBE<T extends boolean = false>(
+        channels: string | Array<string>,
+        listener: PubSubListener<T>,
+        bufferMode?: T
+    ) {
+        const maxCommandRedirections = this.#options.maxCommandRedirections ?? 16,
+            firstChannel = Array.isArray(channels) ? channels[0] : channels;
+        let client = await this.#slots.getShardedPubSubClient(firstChannel);
+        for (let i = 0;; i++) {
+            try {
+                return await client.SSUBSCRIBE(channels, listener, bufferMode);
+            } catch (err) {
+                if (++i > maxCommandRedirections || !(err instanceof ErrorReply)) {
+                    throw err;
+                }
+
+                if (err.message.startsWith('MOVED')) {
+                    await this.#slots.rediscover(client);
+                    client = await this.#slots.getShardedPubSubClient(firstChannel);
+                    continue;
+                }
+
+                throw err;
+            }
+        }
     }
 
-    getSlotMaster(slot: number): ClusterNode<M, F, S> {
-        return this.#slots.getSlotMaster(slot);
+    sSubscribe = this.SSUBSCRIBE;
+
+    SUNSUBSCRIBE<T extends boolean = false>(
+        channels: string | Array<string>,
+        listener?: PubSubListener<T>,
+        bufferMode?: T
+    ) {
+        return this.#slots.executeShardedUnsubscribeCommand(
+            Array.isArray(channels) ? channels[0] : channels,
+            client => client.SUNSUBSCRIBE(channels, listener, bufferMode)
+        );
     }
 
+    sUnsubscribe = this.SUNSUBSCRIBE;
+
     quit(): Promise<void> {
         return this.#slots.quit();
     }
@@ -254,6 +389,32 @@ export default class RedisCluster<
     disconnect(): Promise<void> {
         return this.#slots.disconnect();
     }
+
+    nodeClient(node: ShardNode<M, F, S>) {
+        return this.#slots.nodeClient(node);
+    }
+
+    getRandomNode() {
+        return this.#slots.getRandomNode();
+    }
+
+    getSlotRandomNode(slot: number) {
+        return this.#slots.getSlotRandomNode(slot);
+    }
+
+    /**
+     * @deprecated use `.masters` instead
+     */
+    getMasters() {
+        return this.masters;
+    }
+
+    /**
+     * @deprecated use `.slots[<SLOT>]` instead
+     */
+    getSlotMaster(slot: number) {
+        return this.slots[slot].master;
+    }
 }
 
 attachCommands({
diff --git a/packages/client/lib/cluster/multi-command.ts b/packages/client/lib/cluster/multi-command.ts
index 52ab6eb0e23..ef3c7590ec7 100644
--- a/packages/client/lib/cluster/multi-command.ts
+++ b/packages/client/lib/cluster/multi-command.ts
@@ -120,11 +120,8 @@ export default class RedisClusterMultiCommand {
             return this.execAsPipeline();
         }
 
-        const commands = this.#multi.exec();
-        if (!commands) return [];
-
         return this.#multi.handleExecReplies(
-            await this.#executor(commands, this.#firstKey, RedisMultiCommand.generateChainId())
+            await this.#executor(this.#multi.queue, this.#firstKey, RedisMultiCommand.generateChainId())
         );
     }
 
diff --git a/packages/client/lib/commander.ts b/packages/client/lib/commander.ts
index 1407a80344c..c04f41e1eb0 100644
--- a/packages/client/lib/commander.ts
+++ b/packages/client/lib/commander.ts
@@ -108,6 +108,7 @@ export function transformCommandArguments<T = ClientCommandOptions>(
     command: RedisCommand,
     args: Array<unknown>
 ): {
+    jsArgs: Array<unknown>;
     args: RedisCommandArguments;
     options: CommandOptions<T> | undefined;
 } {
@@ -118,6 +119,7 @@ export function transformCommandArguments<T = ClientCommandOptions>(
     }
 
     return {
+        jsArgs: args,
         args: command.transformArguments(...args),
         options
     };
diff --git a/packages/client/lib/commands/ACL_GETUSER.spec.ts b/packages/client/lib/commands/ACL_GETUSER.spec.ts
index f91f2ff9e5c..4cd693db9ce 100644
--- a/packages/client/lib/commands/ACL_GETUSER.spec.ts
+++ b/packages/client/lib/commands/ACL_GETUSER.spec.ts
@@ -13,32 +13,22 @@ describe('ACL GETUSER', () => {
     });
 
     testUtils.testWithClient('client.aclGetUser', async client => {
-        const expectedReply: any = {
-            passwords: [],
-            commands: '+@all',
-        };
+        const reply = await client.aclGetUser('default');
+
+        assert.ok(Array.isArray(reply.passwords));
+        assert.equal(typeof reply.commands, 'string');
+        assert.ok(Array.isArray(reply.flags));
 
         if (testUtils.isVersionGreaterThan([7])) {
-            expectedReply.flags = ['on', 'nopass'];
-            expectedReply.keys = '~*';
-            expectedReply.channels = '&*';
-            expectedReply.selectors = [];
+        assert.equal(typeof reply.keys, 'string');
+        assert.equal(typeof reply.channels, 'string');
+        assert.ok(Array.isArray(reply.selectors));
         } else {
-            expectedReply.keys = ['*'];
-            expectedReply.selectors = undefined;
+        assert.ok(Array.isArray(reply.keys));
 
-            if (testUtils.isVersionGreaterThan([6, 2])) {
-                expectedReply.flags = ['on', 'allkeys', 'allchannels', 'allcommands', 'nopass'];
-                expectedReply.channels = ['*'];
-            } else {
-                expectedReply.flags = ['on', 'allkeys', 'allcommands', 'nopass'];
-                expectedReply.channels = undefined;
-            }
+        if (testUtils.isVersionGreaterThan([6, 2])) {
+            assert.ok(Array.isArray(reply.channels));
+        }
         }
-
-        assert.deepEqual(
-            await client.aclGetUser('default'),
-            expectedReply
-        );
     }, GLOBAL.SERVERS.OPEN);
 });
diff --git a/packages/client/lib/commands/CLIENT_INFO.spec.ts b/packages/client/lib/commands/CLIENT_INFO.spec.ts
index ee87df4a199..ccb99017cf3 100644
--- a/packages/client/lib/commands/CLIENT_INFO.spec.ts
+++ b/packages/client/lib/commands/CLIENT_INFO.spec.ts
@@ -1,7 +1,10 @@
 import { strict as assert } from 'assert';
 import { transformArguments, transformReply } from './CLIENT_INFO';
+import testUtils, { GLOBAL } from '../test-utils';
 
 describe('CLIENT INFO', () => {
+    testUtils.isVersionGreaterThanHook([6, 2]);
+
     it('transformArguments', () => {
         assert.deepEqual(
             transformArguments(),
@@ -9,34 +12,39 @@ describe('CLIENT INFO', () => {
         );
     });
 
-    it('transformReply', () => {
-        assert.deepEqual(
-            transformReply('id=526512 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1\n'),
-            {
-                id: 526512,
-                addr: '127.0.0.1:36244',
-                laddr: '127.0.0.1:6379',
-                fd: 8,
-                name: '',
-                age: 11213,
-                idle: 0,
-                flags: 'N',
-                db: 0,
-                sub: 0,
-                psub: 0,
-                multi: -1,
-                qbuf: 26,
-                qbufFree: 40928,
-                argvMem: 10,
-                obl: 0,
-                oll: 0,
-                omem: 0,
-                totMem: 61466,
-                events: 'r',
-                cmd: 'client',
-                user: 'default',
-                redir: -1
-            }
-        );
-    });
+    testUtils.testWithClient('client.clientInfo', async client => {
+        const reply = await client.clientInfo();
+        assert.equal(typeof reply.id, 'number');
+        assert.equal(typeof reply.addr, 'string');
+        assert.equal(typeof reply.laddr, 'string');
+        assert.equal(typeof reply.fd, 'number');
+        assert.equal(typeof reply.name, 'string');
+        assert.equal(typeof reply.age, 'number');
+        assert.equal(typeof reply.idle, 'number');
+        assert.equal(typeof reply.flags, 'string');
+        assert.equal(typeof reply.db, 'number');
+        assert.equal(typeof reply.sub, 'number');
+        assert.equal(typeof reply.psub, 'number');
+        assert.equal(typeof reply.multi, 'number');
+        assert.equal(typeof reply.qbuf, 'number');
+        assert.equal(typeof reply.qbufFree, 'number');
+        assert.equal(typeof reply.argvMem, 'number');
+        assert.equal(typeof reply.obl, 'number');
+        assert.equal(typeof reply.oll, 'number');
+        assert.equal(typeof reply.omem, 'number');
+        assert.equal(typeof reply.totMem, 'number');
+        assert.equal(typeof reply.events, 'string');
+        assert.equal(typeof reply.cmd, 'string');
+        assert.equal(typeof reply.user, 'string');
+        assert.equal(typeof reply.redir, 'number');
+
+        if (testUtils.isVersionGreaterThan([7, 0])) {
+            assert.equal(typeof reply.multiMem, 'number');
+            assert.equal(typeof reply.resp, 'number');
+        }
+
+        if (testUtils.isVersionGreaterThan([7, 0, 3])) {
+            assert.equal(typeof reply.ssub, 'number');
+        }
+    }, GLOBAL.SERVERS.OPEN);
 });
diff --git a/packages/client/lib/commands/CLIENT_INFO.ts b/packages/client/lib/commands/CLIENT_INFO.ts
index 8dd30b70590..fd823542f86 100644
--- a/packages/client/lib/commands/CLIENT_INFO.ts
+++ b/packages/client/lib/commands/CLIENT_INFO.ts
@@ -1,11 +1,13 @@
+export const IS_READ_ONLY = true;
+
 export function transformArguments(): Array<string> {
     return ['CLIENT', 'INFO'];
 }
 
-interface ClientInfoReply {
+export interface ClientInfoReply {
     id: number;
     addr: string;
-    laddr: string;
+    laddr?: string; // 6.2
     fd: number;
     name: string;
     age: number;
@@ -14,72 +16,79 @@ interface ClientInfoReply {
     db: number;
     sub: number;
     psub: number;
+    ssub?: number; // 7.0.3
     multi: number;
     qbuf: number;
     qbufFree: number;
-    argvMem: number;
+    argvMem?: number; // 6.0
+    multiMem?: number; // 7.0
     obl: number;
     oll: number;
     omem: number;
-    totMem: number;
+    totMem?: number; // 6.0
     events: string;
     cmd: string;
-    user: string;
-    redir: number;
+    user?: string; // 6.0
+    redir?: number; // 6.2
+    resp?: number; // 7.0
+    // 7.2
+    libName?: string;
+    libVer?: string;
 }
 
-const REGEX = /=([^\s]*)/g;
+const CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g;
 
-export function transformReply(reply: string): ClientInfoReply {
-    const [
-        [, id],
-        [, addr],
-        [, laddr],
-        [, fd],
-        [, name],
-        [, age],
-        [, idle],
-        [, flags],
-        [, db],
-        [, sub],
-        [, psub],
-        [, multi],
-        [, qbuf],
-        [, qbufFree],
-        [, argvMem],
-        [, obl],
-        [, oll],
-        [, omem],
-        [, totMem],
-        [, events],
-        [, cmd],
-        [, user],
-        [, redir]
-    ] = [...reply.matchAll(REGEX)];
+export function transformReply(rawReply: string): ClientInfoReply {
+    const map: Record<string, string> = {};
+    for (const item of rawReply.matchAll(CLIENT_INFO_REGEX)) {
+        map[item[1]] = item[2];
+    }
 
-    return {
-        id: Number(id),
-        addr,
-        laddr,
-        fd: Number(fd),
-        name,
-        age: Number(age),
-        idle: Number(idle),
-        flags,
-        db: Number(db),
-        sub: Number(sub),
-        psub: Number(psub),
-        multi: Number(multi),
-        qbuf: Number(qbuf),
-        qbufFree: Number(qbufFree),
-        argvMem: Number(argvMem),
-        obl: Number(obl),
-        oll: Number(oll),
-        omem: Number(omem),
-        totMem: Number(totMem),
-        events,
-        cmd,
-        user,
-        redir: Number(redir)
+    const reply: ClientInfoReply = {
+        id: Number(map.id),
+        addr: map.addr,
+        fd: Number(map.fd),
+        name: map.name,
+        age: Number(map.age),
+        idle: Number(map.idle),
+        flags: map.flags,
+        db: Number(map.db),
+        sub: Number(map.sub),
+        psub: Number(map.psub),
+        multi: Number(map.multi),
+        qbuf: Number(map.qbuf),
+        qbufFree: Number(map['qbuf-free']),
+        argvMem: Number(map['argv-mem']),
+        obl: Number(map.obl),
+        oll: Number(map.oll),
+        omem: Number(map.omem),
+        totMem: Number(map['tot-mem']),
+        events: map.events,
+        cmd: map.cmd,
+        user: map.user,
+        libName: map['lib-name'],
+        libVer: map['lib-ver'],
     };
+
+    if (map.laddr !== undefined) {
+        reply.laddr = map.laddr;
+    }
+
+    if (map.redir !== undefined) {
+        reply.redir = Number(map.redir);
+    }
+
+    if (map.ssub !== undefined) {
+        reply.ssub = Number(map.ssub);
+    }
+
+    if (map['multi-mem'] !== undefined) {
+        reply.multiMem = Number(map['multi-mem']);
+    }
+
+    if (map.resp !== undefined) {
+        reply.resp = Number(map.resp);
+    }
+
+    return reply;
 }
diff --git a/packages/client/lib/commands/CLIENT_KILL.spec.ts b/packages/client/lib/commands/CLIENT_KILL.spec.ts
index 2fe894f3610..733aaca858b 100644
--- a/packages/client/lib/commands/CLIENT_KILL.spec.ts
+++ b/packages/client/lib/commands/CLIENT_KILL.spec.ts
@@ -65,6 +65,16 @@ describe('CLIENT KILL', () => {
             );
         });
 
+        it('MAXAGE', () => {
+            assert.deepEqual(
+                transformArguments({
+                    filter: ClientKillFilters.MAXAGE,
+                    maxAge: 10
+                }),
+                ['CLIENT', 'KILL', 'MAXAGE', '10']
+            );
+        });
+
         describe('SKIP_ME', () => {
             it('undefined', () => {
                 assert.deepEqual(
diff --git a/packages/client/lib/commands/CLIENT_KILL.ts b/packages/client/lib/commands/CLIENT_KILL.ts
index adb2a5a6569..b1a53df64d8 100644
--- a/packages/client/lib/commands/CLIENT_KILL.ts
+++ b/packages/client/lib/commands/CLIENT_KILL.ts
@@ -6,7 +6,8 @@ export enum ClientKillFilters {
     ID = 'ID',
     TYPE = 'TYPE',
     USER = 'USER',
-    SKIP_ME = 'SKIPME'
+    SKIP_ME = 'SKIPME',
+    MAXAGE = 'MAXAGE'
 }
 
 interface KillFilter<T extends ClientKillFilters> {
@@ -37,7 +38,11 @@ type KillSkipMe = ClientKillFilters.SKIP_ME | (KillFilter<ClientKillFilters.SKIP
     skipMe: boolean;
 });
 
-type KillFilters = KillAddress | KillLocalAddress | KillId | KillType | KillUser | KillSkipMe;
+interface KillMaxAge extends KillFilter<ClientKillFilters.MAXAGE> {
+    maxAge: number;
+}
+
+type KillFilters = KillAddress | KillLocalAddress | KillId | KillType | KillUser | KillSkipMe | KillMaxAge;
 
 export function transformArguments(filters: KillFilters | Array<KillFilters>): RedisCommandArguments {
     const args = ['CLIENT', 'KILL'];
@@ -89,6 +94,10 @@ function pushFilter(args: RedisCommandArguments, filter: KillFilters): void {
         case ClientKillFilters.SKIP_ME:
             args.push(filter.skipMe ? 'yes' : 'no');
             break;
+
+        case ClientKillFilters.MAXAGE:
+            args.push(filter.maxAge.toString());
+            break;
     }
 }
 
diff --git a/packages/client/lib/commands/CLIENT_LIST.spec.ts b/packages/client/lib/commands/CLIENT_LIST.spec.ts
new file mode 100644
index 00000000000..c9c720e12ef
--- /dev/null
+++ b/packages/client/lib/commands/CLIENT_LIST.spec.ts
@@ -0,0 +1,78 @@
+import { strict as assert } from 'assert';
+import { transformArguments, transformReply } from './CLIENT_LIST';
+import testUtils, { GLOBAL } from '../test-utils';
+
+describe('CLIENT LIST', () => {
+    describe('transformArguments', () => {
+        it('simple', () => {
+            assert.deepEqual(
+                transformArguments(),
+                ['CLIENT', 'LIST']
+            );
+        });
+
+        it('with TYPE', () => {
+            assert.deepEqual(
+                transformArguments({
+                    TYPE: 'NORMAL' 
+                }),
+                ['CLIENT', 'LIST', 'TYPE', 'NORMAL']
+            );
+        });
+
+        it('with ID', () => {
+            assert.deepEqual(
+                transformArguments({
+                    ID: ['1', '2']
+                }),
+                ['CLIENT', 'LIST', 'ID', '1', '2']
+            );
+        });
+    });
+
+    testUtils.testWithClient('client.clientList', async client => {
+        const reply = await client.clientList();
+        assert.ok(Array.isArray(reply));
+
+        for (const item of reply) {
+            assert.equal(typeof item.id, 'number');
+            assert.equal(typeof item.addr, 'string');
+            assert.equal(typeof item.fd, 'number');
+            assert.equal(typeof item.name, 'string');
+            assert.equal(typeof item.age, 'number');
+            assert.equal(typeof item.idle, 'number');
+            assert.equal(typeof item.flags, 'string');
+            assert.equal(typeof item.db, 'number');
+            assert.equal(typeof item.sub, 'number');
+            assert.equal(typeof item.psub, 'number');
+            assert.equal(typeof item.multi, 'number');
+            assert.equal(typeof item.qbuf, 'number');
+            assert.equal(typeof item.qbufFree, 'number');
+            assert.equal(typeof item.obl, 'number');
+            assert.equal(typeof item.oll, 'number');
+            assert.equal(typeof item.omem, 'number');
+            assert.equal(typeof item.events, 'string');
+            assert.equal(typeof item.cmd, 'string');
+
+            if (testUtils.isVersionGreaterThan([6, 0])) {
+                assert.equal(typeof item.argvMem, 'number');
+                assert.equal(typeof item.totMem, 'number');
+                assert.equal(typeof item.user, 'string');
+            }
+
+            if (testUtils.isVersionGreaterThan([6, 2])) {
+                assert.equal(typeof item.redir, 'number');
+                assert.equal(typeof item.laddr, 'string');
+            }
+
+            if (testUtils.isVersionGreaterThan([7, 0])) {
+                assert.equal(typeof item.multiMem, 'number');
+                assert.equal(typeof item.resp, 'number');
+            }
+
+            if (testUtils.isVersionGreaterThan([7, 0, 3])) {
+                assert.equal(typeof item.ssub, 'number');
+            }
+        }
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/CLIENT_LIST.ts b/packages/client/lib/commands/CLIENT_LIST.ts
new file mode 100644
index 00000000000..6f71dc7d999
--- /dev/null
+++ b/packages/client/lib/commands/CLIENT_LIST.ts
@@ -0,0 +1,43 @@
+import { RedisCommandArguments, RedisCommandArgument } from '.';
+import { pushVerdictArguments } from './generic-transformers';
+import { transformReply as transformClientInfoReply, ClientInfoReply } from './CLIENT_INFO';
+
+interface ListFilterType {
+    TYPE: 'NORMAL' | 'MASTER' | 'REPLICA' | 'PUBSUB';
+    ID?: never;
+}
+
+interface ListFilterId {
+    ID: Array<RedisCommandArgument>;
+    TYPE?: never;
+}
+
+export type ListFilter = ListFilterType | ListFilterId;
+
+export const IS_READ_ONLY = true;
+
+export function transformArguments(filter?: ListFilter): RedisCommandArguments {
+    let args: RedisCommandArguments = ['CLIENT', 'LIST'];
+
+    if (filter) {
+        if (filter.TYPE !== undefined) {
+            args.push('TYPE', filter.TYPE);
+        } else  {
+            args.push('ID');
+            args = pushVerdictArguments(args, filter.ID);
+        }
+    }
+
+    return args;
+}
+
+export function transformReply(rawReply: string): Array<ClientInfoReply> {
+    const split = rawReply.split('\n'),
+        length = split.length - 1,
+        reply: Array<ClientInfoReply> = [];
+    for (let i = 0; i < length; i++) {
+        reply.push(transformClientInfoReply(split[i]));
+    }
+    
+    return reply;
+}
diff --git a/packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts b/packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
new file mode 100644
index 00000000000..80ee0ada1fd
--- /dev/null
+++ b/packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
@@ -0,0 +1,30 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './CLIENT_NO-TOUCH';
+
+describe('CLIENT NO-TOUCH', () => {
+    testUtils.isVersionGreaterThanHook([7, 2]);
+
+    describe('transformArguments', () => {
+        it('true', () => {
+            assert.deepEqual(
+                transformArguments(true),
+                ['CLIENT', 'NO-TOUCH', 'ON']
+            );
+        });
+
+        it('false', () => {
+            assert.deepEqual(
+                transformArguments(false),
+                ['CLIENT', 'NO-TOUCH', 'OFF']
+            );
+        });
+    });
+
+    testUtils.testWithClient('client.clientNoTouch', async client => {
+        assert.equal(
+            await client.clientNoTouch(true),
+            'OK'
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/CLIENT_NO-TOUCH.ts b/packages/client/lib/commands/CLIENT_NO-TOUCH.ts
new file mode 100644
index 00000000000..d11f693dbab
--- /dev/null
+++ b/packages/client/lib/commands/CLIENT_NO-TOUCH.ts
@@ -0,0 +1,11 @@
+import { RedisCommandArguments } from '.';
+
+export function transformArguments(value: boolean): RedisCommandArguments {
+    return [
+        'CLIENT',
+        'NO-TOUCH',
+        value ? 'ON' : 'OFF'
+    ];
+}
+
+export declare function transformReply(): 'OK' | Buffer;
diff --git a/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts b/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts
index f9d2f5437b2..edb68b3b3b0 100644
--- a/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_BUMPEPOCH.spec.ts
@@ -11,8 +11,9 @@ describe('CLUSTER BUMPEPOCH', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterBumpEpoch', async cluster => {
+        const client = await cluster.nodeClient(cluster.masters[0]);
         assert.equal(
-            typeof await cluster.getSlotMaster(0).client.clusterBumpEpoch(),
+            typeof await client.clusterBumpEpoch(),
             'string'
         );
     }, GLOBAL.SERVERS.OPEN);
diff --git a/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts b/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts
index d84687631bc..558110d0a28 100644
--- a/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.spec.ts
@@ -11,7 +11,7 @@ describe('CLUSTER COUNT-FAILURE-REPORTS', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterCountFailureReports', async cluster => {
-        const { client } = cluster.getSlotMaster(0);
+        const client = await cluster.nodeClient(cluster.masters[0]);
         assert.equal(
             typeof await client.clusterCountFailureReports(
                 await client.clusterMyId()
diff --git a/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts b/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts
index ecaed428cb7..27ecbcfffa3 100644
--- a/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_COUNTKEYSINSLOT.spec.ts
@@ -11,8 +11,9 @@ describe('CLUSTER COUNTKEYSINSLOT', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterCountKeysInSlot', async cluster => {
+        const client = await cluster.nodeClient(cluster.masters[0]);
         assert.equal(
-            typeof await cluster.getSlotMaster(0).client.clusterCountKeysInSlot(0),
+            typeof await client.clusterCountKeysInSlot(0),
             'number'
         );
     }, GLOBAL.CLUSTERS.OPEN);
diff --git a/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts b/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
index 7c156341301..957b7de20cb 100644
--- a/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
@@ -11,7 +11,8 @@ describe('CLUSTER GETKEYSINSLOT', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterGetKeysInSlot', async cluster => {
-        const reply = await cluster.getSlotMaster(0).client.clusterGetKeysInSlot(0, 1);
+        const client = await cluster.nodeClient(cluster.masters[0]),
+            reply = await client.clusterGetKeysInSlot(0, 1);
         assert.ok(Array.isArray(reply));
         for (const item of reply) {
             assert.equal(typeof item, 'string');
diff --git a/packages/client/lib/commands/CLUSTER_INFO.spec.ts b/packages/client/lib/commands/CLUSTER_INFO.spec.ts
index b770ed33616..69d5c4a8c56 100644
--- a/packages/client/lib/commands/CLUSTER_INFO.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_INFO.spec.ts
@@ -46,8 +46,9 @@ describe('CLUSTER INFO', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterInfo', async cluster => {
+        const client = await cluster.nodeClient(cluster.masters[0]);
         assert.notEqual(
-            await cluster.getSlotMaster(0).client.clusterInfo(),
+            await client.clusterInfo(),
             null
         );
     }, GLOBAL.CLUSTERS.OPEN);
diff --git a/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts b/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts
index a7a5ab9472f..3bbc9f9cb2d 100644
--- a/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_KEYSLOT.spec.ts
@@ -11,8 +11,9 @@ describe('CLUSTER KEYSLOT', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterKeySlot', async cluster => {
+        const client = await cluster.nodeClient(cluster.masters[0]);
         assert.equal(
-            typeof await cluster.getSlotMaster(0).client.clusterKeySlot('key'),
+            typeof await client.clusterKeySlot('key'),
             'number'
         );
     }, GLOBAL.CLUSTERS.OPEN);
diff --git a/packages/client/lib/commands/CLUSTER_LINKS.spec.ts b/packages/client/lib/commands/CLUSTER_LINKS.spec.ts
index a8b1663c3af..982973e8ea5 100644
--- a/packages/client/lib/commands/CLUSTER_LINKS.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_LINKS.spec.ts
@@ -13,7 +13,8 @@ describe('CLUSTER LINKS', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterLinks', async cluster => {
-        const links = await cluster.getSlotMaster(0).client.clusterLinks();
+        const client = await cluster.nodeClient(cluster.masters[0]),
+            links = await client.clusterLinks();
         assert.ok(Array.isArray(links));
         for (const link of links) {
             assert.equal(typeof link.direction, 'string');
diff --git a/packages/client/lib/commands/CLUSTER_MYID.spec.ts b/packages/client/lib/commands/CLUSTER_MYID.spec.ts
index 7781c374526..f427d7058e2 100644
--- a/packages/client/lib/commands/CLUSTER_MYID.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_MYID.spec.ts
@@ -11,9 +11,11 @@ describe('CLUSTER MYID', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterMyId', async cluster => {
+        const [master] = cluster.masters,
+            client = await cluster.nodeClient(master);
         assert.equal(
-            typeof await cluster.getSlotMaster(0).client.clusterMyId(),
-            'string'
+            await client.clusterMyId(),
+            master.id
         );
     }, GLOBAL.CLUSTERS.OPEN);
 });
diff --git a/packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts b/packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
new file mode 100644
index 00000000000..180289870ca
--- /dev/null
+++ b/packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
@@ -0,0 +1,22 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './CLUSTER_MYSHARDID';
+
+describe('CLUSTER MYSHARDID', () => {
+    testUtils.isVersionGreaterThanHook([7, 2]);
+
+    it('transformArguments', () => {
+        assert.deepEqual(
+            transformArguments(),
+            ['CLUSTER', 'MYSHARDID']
+        );
+    });
+
+    testUtils.testWithCluster('clusterNode.clusterMyShardId', async cluster => {
+        const client = await cluster.nodeClient(cluster.masters[0]);
+        assert.equal(
+            typeof await client.clusterMyShardId(),
+            'string'
+        );
+    }, GLOBAL.CLUSTERS.OPEN);
+});
diff --git a/packages/client/lib/commands/CLUSTER_MYSHARDID.ts b/packages/client/lib/commands/CLUSTER_MYSHARDID.ts
new file mode 100644
index 00000000000..1c4f8b82f56
--- /dev/null
+++ b/packages/client/lib/commands/CLUSTER_MYSHARDID.ts
@@ -0,0 +1,7 @@
+export const IS_READ_ONLY = true;
+
+export function transformArguments() {
+    return ['CLUSTER', 'MYSHARDID'];
+}
+
+export declare function transformReply(): string | Buffer;
diff --git a/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts b/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts
index bcdccd90919..81ba4aa2509 100644
--- a/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts
+++ b/packages/client/lib/commands/CLUSTER_SAVECONFIG.spec.ts
@@ -11,8 +11,9 @@ describe('CLUSTER SAVECONFIG', () => {
     });
 
     testUtils.testWithCluster('clusterNode.clusterSaveConfig', async cluster => {
+        const client = await cluster.nodeClient(cluster.masters[0]);
         assert.equal(
-            await cluster.getSlotMaster(0).client.clusterSaveConfig(),
+            await client.clusterSaveConfig(),
             'OK'
         );
     }, GLOBAL.CLUSTERS.OPEN);
diff --git a/packages/client/lib/commands/CLUSTER_SLOTS.ts b/packages/client/lib/commands/CLUSTER_SLOTS.ts
index 7e1f5dcc964..20d9782dd9e 100644
--- a/packages/client/lib/commands/CLUSTER_SLOTS.ts
+++ b/packages/client/lib/commands/CLUSTER_SLOTS.ts
@@ -13,7 +13,7 @@ type ClusterSlotsRawReply = Array<[
     ...replicas: Array<ClusterSlotsRawNode>
 ]>;
 
-type ClusterSlotsNode = {
+export interface ClusterSlotsNode {
     ip: string;
     port: number;
     id: string;
diff --git a/packages/client/lib/commands/HEXPIRE.spec.ts b/packages/client/lib/commands/HEXPIRE.spec.ts
new file mode 100644
index 00000000000..3714f617f58
--- /dev/null
+++ b/packages/client/lib/commands/HEXPIRE.spec.ts
@@ -0,0 +1,40 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HEXPIRE';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HEXPIRE', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field', 1),
+        ['HEXPIRE', 'key', '1', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2'], 1),
+        ['HEXPIRE', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+
+    it('with set option', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1'], 1, 'NX'),
+        ['HEXPIRE', 'key', '1', 'NX', 'FIELDS', '1', 'field1']
+      );
+    });
+  });
+
+  testUtils.testWithClient('hexpire', async client => {
+    assert.deepEqual(
+      await client.hExpire('key', ['field1'], 0),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN
+  });
+});
diff --git a/packages/client/lib/commands/HEXPIRE.ts b/packages/client/lib/commands/HEXPIRE.ts
new file mode 100644
index 00000000000..938f9039939
--- /dev/null
+++ b/packages/client/lib/commands/HEXPIRE.ts
@@ -0,0 +1,44 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument } from './generic-transformers';
+
+/**
+ * @readonly
+ * @enum {number}
+ */
+export const HASH_EXPIRATION = {
+  /** @property {number} */
+  /** The field does not exist */
+  FIELD_NOT_EXISTS: -2,
+  /** @property {number} */
+  /** Specified NX | XX | GT | LT condition not met */
+  CONDITION_NOT_MET: 0,
+  /** @property {number} */
+  /** Expiration time was set or updated */
+  UPDATED: 1,
+  /** @property {number} */
+  /** Field deleted because the specified expiration time is in the past */
+  DELETED: 2
+} as const;
+  
+export type HashExpiration = typeof HASH_EXPIRATION[keyof typeof HASH_EXPIRATION];
+
+export const FIRST_KEY_INDEX = 1;
+
+export function transformArguments(
+  key: RedisCommandArgument, 
+  fields: RedisCommandArgument| Array<RedisCommandArgument>,
+  seconds: number,
+  mode?: 'NX' | 'XX' | 'GT' | 'LT',
+) {
+  const args = ['HEXPIRE', key, seconds.toString()];
+
+  if (mode) {
+    args.push(mode);
+  }
+
+  args.push('FIELDS');
+
+  return pushVerdictArgument(args, fields);
+}
+
+export declare function transformReply(): Array<HashExpiration>;
\ No newline at end of file
diff --git a/packages/client/lib/commands/HEXPIREAT.spec.ts b/packages/client/lib/commands/HEXPIREAT.spec.ts
new file mode 100644
index 00000000000..1c65fb61773
--- /dev/null
+++ b/packages/client/lib/commands/HEXPIREAT.spec.ts
@@ -0,0 +1,49 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HEXPIREAT';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HEXPIREAT', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string + number', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field', 1),
+        ['HEXPIREAT', 'key', '1', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array + number', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2'], 1),
+        ['HEXPIREAT', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+
+    it('date', () => {
+      const d = new Date();
+
+      assert.deepEqual(
+        transformArguments('key', ['field1'], d),
+        ['HEXPIREAT', 'key', Math.floor(d.getTime() / 1000).toString(), 'FIELDS', '1', 'field1']
+      );
+    });
+
+    it('with set option', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field1', 1, 'GT'),
+        ['HEXPIREAT', 'key', '1', 'GT', 'FIELDS', '1', 'field1']
+      );
+    });
+  });
+
+  testUtils.testWithClient('expireAt', async client => {
+    assert.deepEqual(
+      await client.hExpireAt('key', 'field1', 1),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN,
+  });
+});
diff --git a/packages/client/lib/commands/HEXPIREAT.ts b/packages/client/lib/commands/HEXPIREAT.ts
new file mode 100644
index 00000000000..58c52d3a1f6
--- /dev/null
+++ b/packages/client/lib/commands/HEXPIREAT.ts
@@ -0,0 +1,28 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument, transformEXAT } from './generic-transformers';
+import { HashExpiration } from './HEXPIRE';
+
+export const FIRST_KEY_INDEX = 1;
+
+export function transformArguments(
+  key: RedisCommandArgument,
+  fields: RedisCommandArgument | Array<RedisCommandArgument>,
+  timestamp: number | Date,
+  mode?: 'NX' | 'XX' | 'GT' | 'LT'
+) {
+  const args = [
+    'HEXPIREAT',
+    key,
+    transformEXAT(timestamp)
+  ];
+
+  if (mode) {
+    args.push(mode);
+  }
+
+  args.push('FIELDS')
+
+  return pushVerdictArgument(args, fields);
+}
+
+export declare function transformReply(): Array<HashExpiration>;
\ No newline at end of file
diff --git a/packages/client/lib/commands/HEXPIRETIME.spec.ts b/packages/client/lib/commands/HEXPIRETIME.spec.ts
new file mode 100644
index 00000000000..9c3eb024bed
--- /dev/null
+++ b/packages/client/lib/commands/HEXPIRETIME.spec.ts
@@ -0,0 +1,32 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { HASH_EXPIRATION_TIME, transformArguments } from './HEXPIRETIME';
+
+describe('HEXPIRETIME', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field'),
+        ['HEXPIRETIME', 'key', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2']),
+        ['HEXPIRETIME', 'key', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+  })
+
+  testUtils.testWithClient('hExpireTime', async client => {
+    assert.deepEqual(
+      await client.hExpireTime('key', 'field1'),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN,
+  });
+});
diff --git a/packages/client/lib/commands/HEXPIRETIME.ts b/packages/client/lib/commands/HEXPIRETIME.ts
new file mode 100644
index 00000000000..01764b1032d
--- /dev/null
+++ b/packages/client/lib/commands/HEXPIRETIME.ts
@@ -0,0 +1,21 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument } from './generic-transformers';
+
+export const HASH_EXPIRATION_TIME = {
+  /** @property {number} */
+  /** The field does not exist */
+  FIELD_NOT_EXISTS: -2,
+  /** @property {number} */
+  /** The field exists but has no associated expire */
+  NO_EXPIRATION: -1,
+} as const;
+
+export const FIRST_KEY_INDEX = 1
+
+export const IS_READ_ONLY = true;
+
+export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
+  return pushVerdictArgument(['HEXPIRETIME', key, 'FIELDS'], fields);
+}
+
+export declare function transformReply(): Array<number>;
\ No newline at end of file
diff --git a/packages/client/lib/commands/HPERSIST.spec.ts b/packages/client/lib/commands/HPERSIST.spec.ts
new file mode 100644
index 00000000000..8cf3f1fe221
--- /dev/null
+++ b/packages/client/lib/commands/HPERSIST.spec.ts
@@ -0,0 +1,33 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HPERSIST';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HPERSIST', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+  
+  describe('transformArguments', () => {
+    it('string', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field'),
+        ['HPERSIST', 'key', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2']),
+        ['HPERSIST', 'key', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+  })
+
+  testUtils.testWithClient('hPersist', async client => {
+    assert.deepEqual(
+      await client.hPersist('key', 'field1'),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN,
+  });
+});
diff --git a/packages/client/lib/commands/HPERSIST.ts b/packages/client/lib/commands/HPERSIST.ts
new file mode 100644
index 00000000000..862a7548ac1
--- /dev/null
+++ b/packages/client/lib/commands/HPERSIST.ts
@@ -0,0 +1,10 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument } from './generic-transformers';
+
+export const FIRST_KEY_INDEX = 1;
+
+export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
+  return pushVerdictArgument(['HPERSIST', key, 'FIELDS'], fields);
+}
+
+export declare function transformReply(): Array<number> | null;
\ No newline at end of file
diff --git a/packages/client/lib/commands/HPEXPIRE.spec.ts b/packages/client/lib/commands/HPEXPIRE.spec.ts
new file mode 100644
index 00000000000..852d9f5bd21
--- /dev/null
+++ b/packages/client/lib/commands/HPEXPIRE.spec.ts
@@ -0,0 +1,40 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HPEXPIRE';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HEXPIRE', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field', 1),
+        ['HPEXPIRE', 'key', '1', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2'], 1),
+        ['HPEXPIRE', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+
+    it('with set option', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1'], 1, 'NX'),
+        ['HPEXPIRE', 'key', '1', 'NX', 'FIELDS', '1', 'field1']
+      );
+    });
+  });
+
+  testUtils.testWithClient('hexpire', async client => {
+    assert.deepEqual(
+      await client.hpExpire('key', ['field1'], 0),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN
+  });
+});
diff --git a/packages/client/lib/commands/HPEXPIRE.ts b/packages/client/lib/commands/HPEXPIRE.ts
new file mode 100644
index 00000000000..afbb056ed4e
--- /dev/null
+++ b/packages/client/lib/commands/HPEXPIRE.ts
@@ -0,0 +1,24 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument } from './generic-transformers';
+import { HashExpiration } from "./HEXPIRE";
+
+export const FIRST_KEY_INDEX = 1;
+
+export function transformArguments(
+  key: RedisCommandArgument, 
+  fields: RedisCommandArgument | Array<RedisCommandArgument>,
+  ms: number,
+  mode?: 'NX' | 'XX' | 'GT' | 'LT',
+) {
+  const args = ['HPEXPIRE', key, ms.toString()];
+
+  if (mode) {
+    args.push(mode);
+  }
+
+  args.push('FIELDS')
+
+  return pushVerdictArgument(args, fields);
+}
+
+export declare function transformReply(): Array<HashExpiration> | null;
\ No newline at end of file
diff --git a/packages/client/lib/commands/HPEXPIREAT.spec.ts b/packages/client/lib/commands/HPEXPIREAT.spec.ts
new file mode 100644
index 00000000000..9747cca1a2d
--- /dev/null
+++ b/packages/client/lib/commands/HPEXPIREAT.spec.ts
@@ -0,0 +1,48 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HPEXPIREAT';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HPEXPIREAT', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string + number', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field', 1),
+        ['HPEXPIREAT', 'key', '1', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array + number', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2'], 1),
+        ['HPEXPIREAT', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+
+    it('date', () => {
+      const d = new Date();
+      assert.deepEqual(
+        transformArguments('key', ['field1'], d),
+        ['HPEXPIREAT', 'key', d.getTime().toString(), 'FIELDS', '1', 'field1']
+      );
+    });
+
+    it('with set option', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1'], 1, 'XX'),
+        ['HPEXPIREAT', 'key', '1', 'XX', 'FIELDS', '1', 'field1']
+      );
+    });
+  });
+
+  testUtils.testWithClient('hpExpireAt', async client => {
+    assert.deepEqual(
+      await client.hpExpireAt('key', ['field1'], 1),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN,
+  });
+});
diff --git a/packages/client/lib/commands/HPEXPIREAT.ts b/packages/client/lib/commands/HPEXPIREAT.ts
new file mode 100644
index 00000000000..b6e01d8ee5c
--- /dev/null
+++ b/packages/client/lib/commands/HPEXPIREAT.ts
@@ -0,0 +1,25 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument, transformEXAT, transformPXAT } from './generic-transformers';
+import { HashExpiration } from './HEXPIRE';
+
+export const FIRST_KEY_INDEX = 1;
+export const IS_READ_ONLY = true;
+
+export function transformArguments(
+  key: RedisCommandArgument,
+  fields: RedisCommandArgument | Array<RedisCommandArgument>,
+  timestamp: number | Date,
+  mode?: 'NX' | 'XX' | 'GT' | 'LT'
+) {
+  const args = ['HPEXPIREAT', key, transformPXAT(timestamp)];
+
+  if (mode) {
+    args.push(mode);
+  }
+
+  args.push('FIELDS')
+
+  return pushVerdictArgument(args, fields);
+}
+
+export declare function transformReply(): Array<HashExpiration> | null;
\ No newline at end of file
diff --git a/packages/client/lib/commands/HPEXPIRETIME.spec.ts b/packages/client/lib/commands/HPEXPIRETIME.spec.ts
new file mode 100644
index 00000000000..ff03b73c71d
--- /dev/null
+++ b/packages/client/lib/commands/HPEXPIRETIME.spec.ts
@@ -0,0 +1,33 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HPEXPIRETIME';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HPEXPIRETIME', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field'),
+        ['HPEXPIRETIME', 'key', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2']),
+        ['HPEXPIRETIME', 'key', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+  });
+
+  testUtils.testWithClient('hpExpireTime', async client => {
+    assert.deepEqual(
+      await client.hpExpireTime('key', 'field1'),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN
+  });
+});
diff --git a/packages/client/lib/commands/HPEXPIRETIME.ts b/packages/client/lib/commands/HPEXPIRETIME.ts
new file mode 100644
index 00000000000..22a794ccefa
--- /dev/null
+++ b/packages/client/lib/commands/HPEXPIRETIME.ts
@@ -0,0 +1,11 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument } from './generic-transformers';
+
+export const FIRST_KEY_INDEX = 1;
+export const IS_READ_ONLY = true;
+
+export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
+  return pushVerdictArgument(['HPEXPIRETIME', key, 'FIELDS'], fields);
+}
+
+export declare function transformReply(): Array<number> | null;
\ No newline at end of file
diff --git a/packages/client/lib/commands/HPTTL.spec.ts b/packages/client/lib/commands/HPTTL.spec.ts
new file mode 100644
index 00000000000..ddca26ea85b
--- /dev/null
+++ b/packages/client/lib/commands/HPTTL.spec.ts
@@ -0,0 +1,33 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HPTTL';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HPTTL', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field'),
+        ['HPTTL', 'key', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2']),
+        ['HPTTL', 'key', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+  });
+
+  testUtils.testWithClient('hpTTL', async client => {
+    assert.deepEqual(
+      await client.hpTTL('key', 'field1'),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN
+  });
+});
diff --git a/packages/client/lib/commands/HPTTL.ts b/packages/client/lib/commands/HPTTL.ts
new file mode 100644
index 00000000000..988b805c0c9
--- /dev/null
+++ b/packages/client/lib/commands/HPTTL.ts
@@ -0,0 +1,11 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument } from './generic-transformers';
+
+export const FIRST_KEY_INDEX = 1;
+export const IS_READ_ONLY =  true;
+
+export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
+  return pushVerdictArgument(['HPTTL', key, 'FIELDS'], fields);
+}
+
+export declare function transformReply(): Array<number> | null;
diff --git a/packages/client/lib/commands/HSCAN.spec.ts b/packages/client/lib/commands/HSCAN.spec.ts
index b426763b99b..6757888a875 100644
--- a/packages/client/lib/commands/HSCAN.spec.ts
+++ b/packages/client/lib/commands/HSCAN.spec.ts
@@ -73,5 +73,18 @@ describe('HSCAN', () => {
                 tuples: []
             }
         );
+
+        await Promise.all([
+            client.hSet('key', 'a', '1'),
+            client.hSet('key', 'b', '2')
+        ]);
+
+        assert.deepEqual(
+            await client.hScan('key', 0),
+            {
+                cursor: 0,
+                tuples: [{field: 'a', value: '1'}, {field: 'b', value: '2'}]
+            }
+        );
     }, GLOBAL.SERVERS.OPEN);
 });
diff --git a/packages/client/lib/commands/HSCAN.ts b/packages/client/lib/commands/HSCAN.ts
index ba18fb986bc..5167693b604 100644
--- a/packages/client/lib/commands/HSCAN.ts
+++ b/packages/client/lib/commands/HSCAN.ts
@@ -16,7 +16,7 @@ export function transformArguments(
     ], cursor, options);
 }
 
-type HScanRawReply = [RedisCommandArgument, Array<RedisCommandArgument>];
+export type HScanRawReply = [RedisCommandArgument, Array<RedisCommandArgument>];
 
 export interface HScanTuple {
     field: RedisCommandArgument;
diff --git a/packages/client/lib/commands/HSCAN_NOVALUES.spec.ts b/packages/client/lib/commands/HSCAN_NOVALUES.spec.ts
new file mode 100644
index 00000000000..7e05b841e43
--- /dev/null
+++ b/packages/client/lib/commands/HSCAN_NOVALUES.spec.ts
@@ -0,0 +1,79 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments, transformReply } from './HSCAN_NOVALUES';
+
+describe('HSCAN_NOVALUES', () => {
+    testUtils.isVersionGreaterThanHook([7, 4]);
+    
+    describe('transformArguments', () => {
+        it('cusror only', () => {
+            assert.deepEqual(
+                transformArguments('key', 0),
+                ['HSCAN', 'key', '0', 'NOVALUES']
+            );
+        });
+
+        it('with MATCH', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, {
+                    MATCH: 'pattern'
+                }),
+                ['HSCAN', 'key', '0', 'MATCH', 'pattern', 'NOVALUES']
+            );
+        });
+
+        it('with COUNT', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, {
+                    COUNT: 1
+                }),
+                ['HSCAN', 'key', '0', 'COUNT', '1', 'NOVALUES']
+            );
+        });
+    });
+
+    describe('transformReply', () => {
+        it('without keys', () => {
+            assert.deepEqual(
+                transformReply(['0', []]),
+                {
+                    cursor: 0,
+                    keys: []
+                }
+            );
+        });
+
+        it('with keys', () => {
+            assert.deepEqual(
+                transformReply(['0', ['key1', 'key2']]),
+                {
+                    cursor: 0,
+                    keys: ['key1', 'key2']
+                }
+            );
+        });
+    });
+
+    testUtils.testWithClient('client.hScanNoValues', async client => {
+        assert.deepEqual(
+            await client.hScanNoValues('key', 0),
+            {
+                cursor: 0,
+                keys: []
+            }
+        );
+
+        await Promise.all([
+            client.hSet('key', 'a', '1'),
+            client.hSet('key', 'b', '2')
+        ]);
+
+        assert.deepEqual(
+            await client.hScanNoValues('key', 0),
+            {
+                cursor: 0,
+                keys: ['a', 'b']
+            }
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/HSCAN_NOVALUES.ts b/packages/client/lib/commands/HSCAN_NOVALUES.ts
new file mode 100644
index 00000000000..37a929754c6
--- /dev/null
+++ b/packages/client/lib/commands/HSCAN_NOVALUES.ts
@@ -0,0 +1,27 @@
+import { RedisCommandArgument, RedisCommandArguments } from '.';
+import { ScanOptions } from './generic-transformers';
+import { HScanRawReply, transformArguments as transformHScanArguments } from './HSCAN';
+
+export { FIRST_KEY_INDEX, IS_READ_ONLY } from './HSCAN';
+
+export function transformArguments(
+    key: RedisCommandArgument,
+    cursor: number,
+    options?: ScanOptions
+): RedisCommandArguments {
+    const args = transformHScanArguments(key, cursor, options);
+    args.push('NOVALUES');
+    return args;
+}
+
+interface HScanNoValuesReply {
+    cursor: number;
+    keys: Array<RedisCommandArgument>;
+}
+
+export function transformReply([cursor, rawData]: HScanRawReply): HScanNoValuesReply {
+    return {
+        cursor: Number(cursor),
+        keys: rawData
+    };
+}
diff --git a/packages/client/lib/commands/HTTL.spec.ts b/packages/client/lib/commands/HTTL.spec.ts
new file mode 100644
index 00000000000..21b8b329a5d
--- /dev/null
+++ b/packages/client/lib/commands/HTTL.spec.ts
@@ -0,0 +1,34 @@
+import { strict as assert } from 'node:assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './HTTL';
+import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
+
+describe('HTTL', () => {
+  testUtils.isVersionGreaterThanHook([7, 4]);
+
+  describe('transformArguments', () => {
+    it('string', () => {
+      assert.deepEqual(
+        transformArguments('key', 'field'),
+        ['HTTL', 'key', 'FIELDS', '1', 'field']
+      );
+    });
+
+    it('array', () => {
+      assert.deepEqual(
+        transformArguments('key', ['field1', 'field2']),
+        ['HTTL', 'key', 'FIELDS', '2', 'field1', 'field2']
+      );
+    });
+  
+  });
+
+  testUtils.testWithClient('hTTL', async client => {
+    assert.deepEqual(
+      await client.hTTL('key', 'field1'),
+      [HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
+    );
+  }, {
+    ...GLOBAL.SERVERS.OPEN
+  });
+});
diff --git a/packages/client/lib/commands/HTTL.ts b/packages/client/lib/commands/HTTL.ts
new file mode 100644
index 00000000000..d3eedd0db0e
--- /dev/null
+++ b/packages/client/lib/commands/HTTL.ts
@@ -0,0 +1,11 @@
+import { RedisCommandArgument } from '.';
+import { pushVerdictArgument } from './generic-transformers';
+
+export const FIRST_KEY_INDEX = 1;
+export const IS_READ_ONLY = true;
+
+export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
+  return pushVerdictArgument(['HTTL', key, 'FIELDS'], fields);
+}
+
+export declare function transformReply(): Array<number> | null;
diff --git a/packages/client/lib/commands/LATENCY_GRAPH.spec.ts b/packages/client/lib/commands/LATENCY_GRAPH.spec.ts
index df4d5d466ab..21755a253b3 100644
--- a/packages/client/lib/commands/LATENCY_GRAPH.spec.ts
+++ b/packages/client/lib/commands/LATENCY_GRAPH.spec.ts
@@ -24,9 +24,5 @@ describe('LATENCY GRAPH', () => {
             typeof await client.latencyGraph('command'),
             'string'
         );
-    }, {
-        serverArguments: testUtils.isVersionGreaterThan([7]) ?
-            ['--enable-debug-command', 'yes'] :
-            GLOBAL.SERVERS.OPEN.serverArguments
-    });
+    }, GLOBAL.SERVERS.OPEN);
 });
diff --git a/packages/client/lib/commands/LATENCY_HISTORY.spec.ts b/packages/client/lib/commands/LATENCY_HISTORY.spec.ts
new file mode 100644
index 00000000000..e79e969b261
--- /dev/null
+++ b/packages/client/lib/commands/LATENCY_HISTORY.spec.ts
@@ -0,0 +1,26 @@
+import {strict as assert} from 'assert';
+import testUtils, {GLOBAL} from '../test-utils';
+import { transformArguments } from './LATENCY_HISTORY';
+
+describe('LATENCY HISTORY', () => {
+    it('transformArguments', () => {
+        assert.deepEqual(
+            transformArguments('command'),
+            ['LATENCY', 'HISTORY', 'command']
+        );
+    });
+
+    testUtils.testWithClient('client.latencyHistory', async client => {
+        await Promise.all([
+            client.configSet('latency-monitor-threshold', '100'),
+            client.sendCommand(['DEBUG', 'SLEEP', '1'])
+        ]);
+        
+        const latencyHisRes = await client.latencyHistory('command');
+        assert.ok(Array.isArray(latencyHisRes));
+        for (const [timestamp, latency] of latencyHisRes) {
+            assert.equal(typeof timestamp, 'number');
+            assert.equal(typeof latency, 'number');
+        }
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/LATENCY_HISTORY.ts b/packages/client/lib/commands/LATENCY_HISTORY.ts
new file mode 100644
index 00000000000..c0b1964553e
--- /dev/null
+++ b/packages/client/lib/commands/LATENCY_HISTORY.ts
@@ -0,0 +1,27 @@
+export type EventType = (
+    'active-defrag-cycle' |
+    'aof-fsync-always' |
+    'aof-stat' |
+    'aof-rewrite-diff-write' |
+    'aof-rename' |
+    'aof-write' |
+    'aof-write-active-child' |
+    'aof-write-alone' |
+    'aof-write-pending-fsync' |
+    'command' |
+    'expire-cycle' |
+    'eviction-cycle' |
+    'eviction-del' |
+    'fast-command' |
+    'fork' |
+    'rdb-unlink-temp-file'
+);
+
+export function transformArguments(event: EventType) {
+    return ['LATENCY', 'HISTORY', event];
+}
+
+export declare function transformReply(): Array<[
+    timestamp: number,
+    latency: number,
+]>;
diff --git a/packages/client/lib/commands/LATENCY_LATEST.spec.ts b/packages/client/lib/commands/LATENCY_LATEST.spec.ts
new file mode 100644
index 00000000000..4087f212139
--- /dev/null
+++ b/packages/client/lib/commands/LATENCY_LATEST.spec.ts
@@ -0,0 +1,27 @@
+import {strict as assert} from 'assert';
+import testUtils, {GLOBAL} from '../test-utils';
+import { transformArguments } from './LATENCY_LATEST';
+
+describe('LATENCY LATEST', () => {
+    it('transformArguments', () => {
+        assert.deepEqual(
+            transformArguments(),
+            ['LATENCY', 'LATEST']
+        );
+    });
+
+    testUtils.testWithClient('client.latencyLatest', async client => {
+        await Promise.all([
+            client.configSet('latency-monitor-threshold', '100'),
+            client.sendCommand(['DEBUG', 'SLEEP', '1'])
+        ]);
+        const latency = await client.latencyLatest();
+        assert.ok(Array.isArray(latency));
+        for (const [name, timestamp, latestLatency, allTimeLatency] of latency) {
+            assert.equal(typeof name, 'string');
+            assert.equal(typeof timestamp, 'number');
+            assert.equal(typeof latestLatency, 'number');
+            assert.equal(typeof allTimeLatency, 'number');
+        }
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/LATENCY_LATEST.ts b/packages/client/lib/commands/LATENCY_LATEST.ts
new file mode 100644
index 00000000000..3e4dd6236c6
--- /dev/null
+++ b/packages/client/lib/commands/LATENCY_LATEST.ts
@@ -0,0 +1,12 @@
+import { RedisCommandArguments } from '.';
+
+export function transformArguments(): RedisCommandArguments {
+    return ['LATENCY', 'LATEST'];
+}
+
+export declare function transformReply(): Array<[
+    name: string,
+    timestamp: number,
+    latestLatency: number,
+    allTimeLatency: number
+]>;
diff --git a/packages/client/lib/commands/PING.spec.ts b/packages/client/lib/commands/PING.spec.ts
index fae349176d7..06cbae43a13 100644
--- a/packages/client/lib/commands/PING.spec.ts
+++ b/packages/client/lib/commands/PING.spec.ts
@@ -1,8 +1,24 @@
 import { strict as assert } from 'assert';
 import testUtils, { GLOBAL } from '../test-utils';
-import RedisClient from '../client';
+import { transformArguments } from './PING';
 
 describe('PING', () => {
+    describe('transformArguments', () => {
+        it('default', () => {
+            assert.deepEqual(
+                transformArguments(),
+                ['PING']
+            );
+        });
+
+        it('with message', () => {
+            assert.deepEqual(
+                transformArguments('message'),
+                ['PING', 'message']
+            );
+        });
+    });
+
     describe('client.ping', () => {
         testUtils.testWithClient('string', async client => {
             assert.equal(
@@ -13,7 +29,7 @@ describe('PING', () => {
 
         testUtils.testWithClient('buffer', async client => {
             assert.deepEqual(
-                await client.ping(RedisClient.commandOptions({ returnBuffers: true })),
+                await client.ping(client.commandOptions({ returnBuffers: true })),
                 Buffer.from('PONG')
             );
         }, GLOBAL.SERVERS.OPEN);
diff --git a/packages/client/lib/commands/PING.ts b/packages/client/lib/commands/PING.ts
index 10ab01f7bdf..95fa006122d 100644
--- a/packages/client/lib/commands/PING.ts
+++ b/packages/client/lib/commands/PING.ts
@@ -1,7 +1,12 @@
-import { RedisCommandArgument } from '.';
+import { RedisCommandArgument, RedisCommandArguments } from '.';
 
-export function transformArguments(): Array<string> {
-    return ['PING'];
+export function transformArguments(message?: RedisCommandArgument): RedisCommandArguments {
+    const args: RedisCommandArguments = ['PING'];
+    if (message) {
+        args.push(message);
+    }
+
+    return args;
 }
 
 export declare function transformReply(): RedisCommandArgument;
diff --git a/packages/client/lib/commands/PUBLISH.ts b/packages/client/lib/commands/PUBLISH.ts
index 93a8016900e..7862a0936cb 100644
--- a/packages/client/lib/commands/PUBLISH.ts
+++ b/packages/client/lib/commands/PUBLISH.ts
@@ -1,5 +1,7 @@
 import { RedisCommandArgument, RedisCommandArguments } from '.';
 
+export const IS_READ_ONLY = true;
+
 export function transformArguments(
     channel: RedisCommandArgument,
     message: RedisCommandArgument
diff --git a/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
new file mode 100644
index 00000000000..1e5f2292b39
--- /dev/null
+++ b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
@@ -0,0 +1,30 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './PUBSUB_SHARDCHANNELS';
+
+describe('PUBSUB SHARDCHANNELS', () => {
+    testUtils.isVersionGreaterThanHook([7]);
+    
+    describe('transformArguments', () => {
+        it('without pattern', () => {
+            assert.deepEqual(
+                transformArguments(),
+                ['PUBSUB', 'SHARDCHANNELS']
+            );
+        });
+
+        it('with pattern', () => {
+            assert.deepEqual(
+                transformArguments('patter*'),
+                ['PUBSUB', 'SHARDCHANNELS', 'patter*']
+            );
+        });
+    });
+
+    testUtils.testWithClient('client.pubSubShardChannels', async client => {
+        assert.deepEqual(
+            await client.pubSubShardChannels(),
+            []
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
new file mode 100644
index 00000000000..e998677848a
--- /dev/null
+++ b/packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
@@ -0,0 +1,13 @@
+import { RedisCommandArgument, RedisCommandArguments } from '.';
+
+export const IS_READ_ONLY = true;
+
+export function transformArguments(
+    pattern?: RedisCommandArgument
+): RedisCommandArguments {
+    const args: RedisCommandArguments = ['PUBSUB', 'SHARDCHANNELS'];
+    if (pattern) args.push(pattern);
+    return args;
+}
+
+export declare function transformReply(): Array<RedisCommandArgument>;
diff --git a/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
new file mode 100644
index 00000000000..fea1373b55d
--- /dev/null
+++ b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
@@ -0,0 +1,48 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './PUBSUB_SHARDNUMSUB';
+
+describe('PUBSUB SHARDNUMSUB', () => {
+    testUtils.isVersionGreaterThanHook([7]);
+
+    describe('transformArguments', () => {
+        it('simple', () => {
+            assert.deepEqual(
+                transformArguments(),
+                ['PUBSUB', 'SHARDNUMSUB']
+            );
+        });
+
+        it('string', () => {
+            assert.deepEqual(
+                transformArguments('channel'),
+                ['PUBSUB', 'SHARDNUMSUB', 'channel']
+            );
+        });
+
+        it('array', () => {
+            assert.deepEqual(
+                transformArguments(['1', '2']),
+                ['PUBSUB', 'SHARDNUMSUB', '1', '2']
+            );
+        });
+    });
+
+    testUtils.testWithClient('client.pubSubShardNumSub', async client => {
+        assert.deepEqual(
+            await client.pubSubShardNumSub(['foo', 'bar']),
+            Object.create(null, {
+                foo: {
+                    value: 0,
+                    configurable: true,
+                    enumerable: true
+                },
+                bar: {
+                    value: 0,
+                    configurable: true,
+                    enumerable: true
+                }
+            })
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
new file mode 100644
index 00000000000..4d7f4d8a71e
--- /dev/null
+++ b/packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
@@ -0,0 +1,24 @@
+import { pushVerdictArguments } from './generic-transformers';
+import { RedisCommandArgument, RedisCommandArguments } from '.';
+
+export const IS_READ_ONLY = true;
+
+export function transformArguments(
+    channels?: Array<RedisCommandArgument> | RedisCommandArgument
+): RedisCommandArguments {
+    const args = ['PUBSUB', 'SHARDNUMSUB'];
+
+    if (channels) return pushVerdictArguments(args, channels);
+
+    return args;
+}
+
+export function transformReply(rawReply: Array<string | number>): Record<string, number> {
+    const transformedReply = Object.create(null);
+
+    for (let i = 0; i < rawReply.length; i += 2) {
+        transformedReply[rawReply[i]] = rawReply[i + 1];
+    }
+
+    return transformedReply;
+}
diff --git a/packages/client/lib/commands/RESTORE.spec.ts b/packages/client/lib/commands/RESTORE.spec.ts
new file mode 100644
index 00000000000..89d42f3d4de
--- /dev/null
+++ b/packages/client/lib/commands/RESTORE.spec.ts
@@ -0,0 +1,74 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './RESTORE';
+
+describe('RESTORE', () => {
+    describe('transformArguments', () => {
+        it('simple', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, 'value'),
+                ['RESTORE', 'key', '0', 'value']
+            );
+        });
+
+        it('with REPLACE', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, 'value', {
+                    REPLACE: true
+                }),
+                ['RESTORE', 'key', '0', 'value', 'REPLACE']
+            );
+        });
+
+        it('with ABSTTL', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, 'value', {
+                    ABSTTL: true
+                }),
+                ['RESTORE', 'key', '0', 'value', 'ABSTTL']
+            );
+        });
+
+        it('with IDLETIME', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, 'value', {
+                    IDLETIME: 1
+                }),
+                ['RESTORE', 'key', '0', 'value', 'IDLETIME', '1']
+            );
+        });
+
+        it('with FREQ', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, 'value', {
+                    FREQ: 1
+                }),
+                ['RESTORE', 'key', '0', 'value', 'FREQ', '1']
+            );
+        });
+
+        it('with REPLACE, ABSTTL, IDLETIME and FREQ', () => {
+            assert.deepEqual(
+                transformArguments('key', 0, 'value', {
+                    REPLACE: true,
+                    ABSTTL: true,
+                    IDLETIME: 1,
+                    FREQ: 2
+                }),
+                ['RESTORE', 'key', '0', 'value', 'REPLACE', 'ABSTTL', 'IDLETIME', '1', 'FREQ', '2']
+            );
+        });
+    });
+
+    testUtils.testWithClient('client.restore', async client => {
+        const [, dump] = await Promise.all([
+            client.set('source', 'value'),
+            client.dump(client.commandOptions({ returnBuffers: true }), 'source')
+        ]);
+
+        assert.equal(
+            await client.restore('destination', 0, dump),
+            'OK'
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/RESTORE.ts b/packages/client/lib/commands/RESTORE.ts
new file mode 100644
index 00000000000..d9ac11c424b
--- /dev/null
+++ b/packages/client/lib/commands/RESTORE.ts
@@ -0,0 +1,39 @@
+import { RedisCommandArgument, RedisCommandArguments } from '.';
+
+export const FIRST_KEY_INDEX = 1;
+
+interface RestoreOptions {
+    REPLACE?: true;
+    ABSTTL?: true;
+    IDLETIME?: number;
+    FREQ?: number;
+}
+
+export function transformArguments(
+    key: RedisCommandArgument,
+    ttl: number,
+    serializedValue: RedisCommandArgument,
+    options?: RestoreOptions
+): RedisCommandArguments {
+    const args =  ['RESTORE', key, ttl.toString(), serializedValue];
+
+    if (options?.REPLACE) {
+        args.push('REPLACE');
+    }
+
+    if (options?.ABSTTL) {
+        args.push('ABSTTL');
+    }
+
+    if (options?.IDLETIME) {
+        args.push('IDLETIME', options.IDLETIME.toString());
+    }
+
+    if (options?.FREQ) {
+        args.push('FREQ', options.FREQ.toString());
+    }
+
+    return args;
+}
+
+export declare function transformReply(): 'OK';
diff --git a/packages/client/lib/commands/SPUBLISH.spec.ts b/packages/client/lib/commands/SPUBLISH.spec.ts
new file mode 100644
index 00000000000..60b6ce2dad0
--- /dev/null
+++ b/packages/client/lib/commands/SPUBLISH.spec.ts
@@ -0,0 +1,21 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './SPUBLISH';
+
+describe('SPUBLISH', () => {
+    testUtils.isVersionGreaterThanHook([7]);
+    
+    it('transformArguments', () => {
+        assert.deepEqual(
+            transformArguments('channel', 'message'),
+            ['SPUBLISH', 'channel', 'message']
+        );
+    });
+
+    testUtils.testWithClient('client.sPublish', async client => {
+        assert.equal(
+            await client.sPublish('channel', 'message'),
+            0
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/client/lib/commands/SPUBLISH.ts b/packages/client/lib/commands/SPUBLISH.ts
new file mode 100644
index 00000000000..42a7ab49072
--- /dev/null
+++ b/packages/client/lib/commands/SPUBLISH.ts
@@ -0,0 +1,14 @@
+import { RedisCommandArgument, RedisCommandArguments } from '.';
+
+export const IS_READ_ONLY = true;
+
+export const FIRST_KEY_INDEX = 1;
+
+export function transformArguments(
+    channel: RedisCommandArgument,
+    message: RedisCommandArgument
+): RedisCommandArguments {
+    return ['SPUBLISH', channel, message];
+}
+
+export declare function transformReply(): number;
diff --git a/packages/client/lib/commands/XAUTOCLAIM.spec.ts b/packages/client/lib/commands/XAUTOCLAIM.spec.ts
index 4447a06d773..bae914bda05 100644
--- a/packages/client/lib/commands/XAUTOCLAIM.spec.ts
+++ b/packages/client/lib/commands/XAUTOCLAIM.spec.ts
@@ -23,20 +23,76 @@ describe('XAUTOCLAIM', () => {
         });
     });
 
-    testUtils.testWithClient('client.xAutoClaim', async client => {
-        await Promise.all([
-            client.xGroupCreate('key', 'group', '$', {
-                MKSTREAM: true
-            }),
+    testUtils.testWithClient('client.xAutoClaim without messages', async client => {
+        const [,, reply] = await Promise.all([
+            client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }),
             client.xGroupCreateConsumer('key', 'group', 'consumer'),
+            client.xAutoClaim('key', 'group', 'consumer', 1, '0-0')
         ]);
 
-        assert.deepEqual(
-            await client.xAutoClaim('key', 'group', 'consumer', 1, '0-0'),
-            {
-                nextId: '0-0',
-                messages: []
-            }
-        );
+        assert.deepEqual(reply, {
+            nextId: '0-0',
+            messages: []
+        });
+    }, GLOBAL.SERVERS.OPEN);
+
+    testUtils.testWithClient('client.xAutoClaim with messages', async client => {
+        const [,, id,, reply] = await Promise.all([
+            client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }),
+            client.xGroupCreateConsumer('key', 'group', 'consumer'),
+            client.xAdd('key', '*', { foo: 'bar' }),
+            client.xReadGroup('group', 'consumer', { key: 'key', id: '>' }),
+            client.xAutoClaim('key', 'group', 'consumer', 0, '0-0')
+        ]);
+
+        assert.deepEqual(reply, {
+            nextId: '0-0',
+            messages: [{
+                id,
+                message: Object.create(null, {
+                    foo: {
+                        value: 'bar',
+                        configurable: true,
+                        enumerable: true
+                    }
+                })
+            }]
+        });
+    }, GLOBAL.SERVERS.OPEN);
+
+    testUtils.testWithClient('client.xAutoClaim with trimmed messages', async client => {
+        const [,,,,, id,, reply] = await Promise.all([
+            client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }),
+            client.xGroupCreateConsumer('key', 'group', 'consumer'),
+            client.xAdd('key', '*', { foo: 'bar' }),
+            client.xReadGroup('group', 'consumer', { key: 'key', id: '>' }),
+            client.xTrim('key', 'MAXLEN', 0),
+            client.xAdd('key', '*', { bar: 'baz' }),
+            client.xReadGroup('group', 'consumer', { key: 'key', id: '>' }),
+            client.xAutoClaim('key', 'group', 'consumer', 0, '0-0')
+        ]);
+
+        assert.deepEqual(reply, {
+            nextId: '0-0',
+            messages: testUtils.isVersionGreaterThan([7, 0]) ? [{
+                id,
+                message: Object.create(null, {
+                    bar: {
+                        value: 'baz',
+                        configurable: true,
+                        enumerable: true
+                    }
+                })
+            }] : [null, {
+                id,
+                message: Object.create(null, {
+                    bar: {
+                        value: 'baz',
+                        configurable: true,
+                        enumerable: true
+                    }
+                })
+            }]
+        });
     }, GLOBAL.SERVERS.OPEN);
 });
diff --git a/packages/client/lib/commands/XAUTOCLAIM.ts b/packages/client/lib/commands/XAUTOCLAIM.ts
index 4bf46057bac..831563981a6 100644
--- a/packages/client/lib/commands/XAUTOCLAIM.ts
+++ b/packages/client/lib/commands/XAUTOCLAIM.ts
@@ -1,5 +1,5 @@
 import { RedisCommandArgument, RedisCommandArguments } from '.';
-import { StreamMessagesReply, transformStreamMessagesReply } from './generic-transformers';
+import { StreamMessagesNullReply, transformStreamMessagesNullReply } from './generic-transformers';
 
 export const FIRST_KEY_INDEX = 1;
 
@@ -28,12 +28,12 @@ type XAutoClaimRawReply = [RedisCommandArgument, Array<any>];
 
 interface XAutoClaimReply {
     nextId: RedisCommandArgument;
-    messages: StreamMessagesReply;
+    messages: StreamMessagesNullReply;
 }
 
 export function transformReply(reply: XAutoClaimRawReply): XAutoClaimReply {
     return {
         nextId: reply[0],
-        messages: transformStreamMessagesReply(reply[1])
+        messages: transformStreamMessagesNullReply(reply[1])
     };
 }
diff --git a/packages/client/lib/commands/XCLAIM.spec.ts b/packages/client/lib/commands/XCLAIM.spec.ts
index 141a62ab77a..6626e84c731 100644
--- a/packages/client/lib/commands/XCLAIM.spec.ts
+++ b/packages/client/lib/commands/XCLAIM.spec.ts
@@ -83,8 +83,38 @@ describe('XCLAIM', () => {
         });
 
         assert.deepEqual(
-            await client.xClaim('key', 'group', 'consumer', 1, '0-0'),
+            await client.xClaim('key', 'group', 'consumer', 0, '0-0'),
             []
         );
     }, GLOBAL.SERVERS.OPEN);
+
+    testUtils.testWithClient('client.xClaim with a message', async client => {
+        await client.xGroupCreate('key', 'group', '$', { MKSTREAM: true });
+        const id = await client.xAdd('key', '*', { foo: 'bar' });
+        await client.xReadGroup('group', 'consumer', { key: 'key', id: '>' });
+
+        assert.deepEqual(
+            await client.xClaim('key', 'group', 'consumer', 0, id),
+            [{
+                id,
+                message: Object.create(null, { 'foo': {
+                    value: 'bar',
+                    configurable: true,
+                    enumerable: true
+                } })
+            }]
+        );
+    }, GLOBAL.SERVERS.OPEN);
+
+    testUtils.testWithClient('client.xClaim with a trimmed message', async client => {
+        await client.xGroupCreate('key', 'group', '$', { MKSTREAM: true });
+        const id = await client.xAdd('key', '*', { foo: 'bar' });
+        await client.xReadGroup('group', 'consumer', { key: 'key', id: '>' });
+        await client.xTrim('key', 'MAXLEN', 0);
+
+        assert.deepEqual(
+            await client.xClaim('key', 'group', 'consumer', 0, id),
+            testUtils.isVersionGreaterThan([7, 0]) ? []: [null]
+        );
+    }, GLOBAL.SERVERS.OPEN);
 });
diff --git a/packages/client/lib/commands/XCLAIM.ts b/packages/client/lib/commands/XCLAIM.ts
index bc38f9b9e95..e7b458e2376 100644
--- a/packages/client/lib/commands/XCLAIM.ts
+++ b/packages/client/lib/commands/XCLAIM.ts
@@ -45,4 +45,4 @@ export function transformArguments(
     return args;
 }
 
-export { transformStreamMessagesReply as transformReply } from './generic-transformers';
+export { transformStreamMessagesNullReply as transformReply } from './generic-transformers';
diff --git a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts
index 87c82b34f29..a2c58999773 100644
--- a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts
+++ b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts
@@ -13,17 +13,19 @@ describe('XINFO CONSUMERS', () => {
     it('transformReply', () => {
         assert.deepEqual(
             transformReply([
-                ['name', 'Alice', 'pending', 1, 'idle', 9104628],
-                ['name', 'Bob', 'pending', 1, 'idle', 83841983]
+                ['name', 'Alice', 'pending', 1, 'idle', 9104628, 'inactive', 9281221],
+                ['name', 'Bob', 'pending', 1, 'idle', 83841983, 'inactive', 7213871]
             ]),
             [{
                 name: 'Alice',
                 pending: 1,
-                idle: 9104628
+                idle: 9104628,
+                inactive: 9281221,
             }, {
                 name: 'Bob',
                 pending: 1,
-                idle: 83841983
+                idle: 83841983,
+                inactive: 7213871,
             }]
         );
     });
diff --git a/packages/client/lib/commands/XINFO_CONSUMERS.ts b/packages/client/lib/commands/XINFO_CONSUMERS.ts
index 05e3a26b172..9b3893cc93c 100644
--- a/packages/client/lib/commands/XINFO_CONSUMERS.ts
+++ b/packages/client/lib/commands/XINFO_CONSUMERS.ts
@@ -15,12 +15,14 @@ type XInfoConsumersReply = Array<{
     name: RedisCommandArgument;
     pending: number;
     idle: number;
+    inactive: number;
 }>;
 
 export function transformReply(rawReply: Array<any>): XInfoConsumersReply {
     return rawReply.map(consumer => ({
         name: consumer[1],
         pending: consumer[3],
-        idle: consumer[5]
+        idle: consumer[5],
+        inactive: consumer[7]
     }));
 }
diff --git a/packages/client/lib/commands/generic-transformers.spec.ts b/packages/client/lib/commands/generic-transformers.spec.ts
index 301cab0a75c..60caf26eaad 100644
--- a/packages/client/lib/commands/generic-transformers.spec.ts
+++ b/packages/client/lib/commands/generic-transformers.spec.ts
@@ -9,6 +9,7 @@ import {
     transformStringNumberInfinityArgument,
     transformTuplesReply,
     transformStreamMessagesReply,
+    transformStreamMessagesNullReply,
     transformStreamsMessagesReply,
     transformSortedSetWithScoresReply,
     pushGeoCountArgument,
@@ -219,6 +220,38 @@ describe('Generic Transformers', () => {
         );
     });
 
+    it('transformStreamMessagesNullReply', () => {
+        assert.deepEqual(
+            transformStreamMessagesNullReply([null, ['0-0', ['0key', '0value']]]),
+            [null, {
+                id: '0-0',
+                message: Object.create(null, {
+                    '0key': {
+                        value: '0value',
+                        configurable: true,
+                        enumerable: true
+                    }
+                })
+            }]
+        );
+    });
+
+    it('transformStreamMessagesNullReply', () => {
+        assert.deepEqual(
+            transformStreamMessagesNullReply([null, ['0-1', ['11key', '11value']]]),
+            [null, {
+                id: '0-1',
+                message: Object.create(null, {
+                    '11key': {
+                        value: '11value',
+                        configurable: true,
+                        enumerable: true
+                    }
+                })
+            }]
+        );
+    });
+
     describe('transformStreamsMessagesReply', () => {
         it('null', () => {
             assert.equal(
diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts
index d3a57a9346b..4cf610a036e 100644
--- a/packages/client/lib/commands/generic-transformers.ts
+++ b/packages/client/lib/commands/generic-transformers.ts
@@ -92,19 +92,27 @@ export interface StreamMessageReply {
     message: Record<string, RedisCommandArgument>;
 }
 
-export type StreamMessagesReply = Array<StreamMessageReply>;
+export function transformStreamMessageReply([id, message]: Array<any>): StreamMessageReply {
+    return {
+        id,
+        message: transformTuplesReply(message)
+    };
+}
 
-export function transformStreamMessagesReply(reply: Array<any>): StreamMessagesReply {
-    const messages = [];
+export function transformStreamMessageNullReply(reply: Array<any>): StreamMessageReply | null {
+    if (reply === null) return null;
+    return transformStreamMessageReply(reply);
+}
 
-    for (const [id, message] of reply) {
-        messages.push({
-            id,
-            message: transformTuplesReply(message)
-        });
-    }
 
-    return messages;
+export type StreamMessagesReply = Array<StreamMessageReply>;
+export function transformStreamMessagesReply(reply: Array<any>): StreamMessagesReply {
+    return reply.map(transformStreamMessageReply);
+}
+
+export type StreamMessagesNullReply = Array<StreamMessageReply | null>;
+export function transformStreamMessagesNullReply(reply: Array<any>): StreamMessagesNullReply {
+    return reply.map(transformStreamMessageNullReply);
 }
 
 export type StreamsMessagesReply = Array<{
@@ -137,7 +145,6 @@ export function transformSortedSetMemberNullReply(
 export function transformSortedSetMemberReply(
     reply: [RedisCommandArgument, RedisCommandArgument]
 ): ZMember {
-
     return {
         value: reply[0],
         score: transformNumberInfinityReply(reply[1])
diff --git a/packages/client/lib/errors.ts b/packages/client/lib/errors.ts
index 30709703153..aa97d9cf26d 100644
--- a/packages/client/lib/errors.ts
+++ b/packages/client/lib/errors.ts
@@ -1,3 +1,5 @@
+import { RedisCommandRawReply } from './commands';
+
 export class AbortError extends Error {
     constructor() {
         super('The command was aborted');
@@ -63,3 +65,20 @@ export class ErrorReply extends Error {
         this.stack = undefined;
     }
 }
+
+export class MultiErrorReply extends ErrorReply {
+    replies;
+    errorIndexes;
+
+    constructor(replies: Array<RedisCommandRawReply | ErrorReply>, errorIndexes: Array<number>) {
+        super(`${errorIndexes.length} commands failed, see .replies and .errorIndexes for more information`);
+        this.replies = replies;
+        this.errorIndexes = errorIndexes;
+    }
+
+    *errors() {
+        for (const index of this.errorIndexes) {
+            yield this.replies[index];
+        }
+    }
+}
diff --git a/packages/client/lib/multi-command.spec.ts b/packages/client/lib/multi-command.spec.ts
index 7e9667cd518..b0f79c6e157 100644
--- a/packages/client/lib/multi-command.spec.ts
+++ b/packages/client/lib/multi-command.spec.ts
@@ -46,24 +46,23 @@ describe('Multi Command', () => {
     });
 
     describe('exec', () => {
-        it('undefined', () => {
-            assert.equal(
-                new RedisMultiCommand().exec(),
-                undefined
+        it('without commands', () => {
+            assert.deepEqual(
+                new RedisMultiCommand().queue,
+                []
             );
         });
 
-        it('Array', () => {
+        it('with commands', () => {
             const multi = new RedisMultiCommand();
             multi.addCommand(['PING']);
 
             assert.deepEqual(
-                multi.exec(),
-                [
-                    { args: ['MULTI'] },
-                    { args: ['PING'], transformReply: undefined },
-                    { args: ['EXEC'] }
-                ]
+                multi.queue,
+                [{
+                    args: ['PING'],
+                    transformReply: undefined
+                }]
             );
         });
     });
diff --git a/packages/client/lib/multi-command.ts b/packages/client/lib/multi-command.ts
index 8865cc8e002..642c2ea36c0 100644
--- a/packages/client/lib/multi-command.ts
+++ b/packages/client/lib/multi-command.ts
@@ -1,6 +1,6 @@
 import { fCallArguments } from './commander';
 import { RedisCommand, RedisCommandArguments, RedisCommandRawReply, RedisFunction, RedisScript } from './commands';
-import { WatchError } from './errors';
+import { ErrorReply, MultiErrorReply, WatchError } from './errors';
 
 export interface RedisMultiQueuedCommand {
     args: RedisCommandArguments;
@@ -69,19 +69,7 @@ export default class RedisMultiCommand {
         return transformedArguments;
     }
 
-    exec(): undefined | Array<RedisMultiQueuedCommand> {
-        if (!this.queue.length) {
-            return;
-        }
-
-        return [
-            { args: ['MULTI'] },
-            ...this.queue,
-            { args: ['EXEC'] }
-        ];
-    }
-
-    handleExecReplies(rawReplies: Array<RedisCommandRawReply>): Array<RedisCommandRawReply> {
+    handleExecReplies(rawReplies: Array<RedisCommandRawReply | ErrorReply>): Array<RedisCommandRawReply> {
         const execReply = rawReplies[rawReplies.length - 1] as (null | Array<RedisCommandRawReply>);
         if (execReply === null) {
             throw new WatchError();
@@ -90,10 +78,18 @@ export default class RedisMultiCommand {
         return this.transformReplies(execReply);
     }
 
-    transformReplies(rawReplies: Array<RedisCommandRawReply>): Array<RedisCommandRawReply> {
-        return rawReplies.map((reply, i) => {
-            const { transformReply, args } = this.queue[i];
-            return transformReply ? transformReply(reply, args.preserve) : reply;
-        });
+    transformReplies(rawReplies: Array<RedisCommandRawReply | ErrorReply>): Array<RedisCommandRawReply> {
+        const errorIndexes: Array<number> = [],
+            replies = rawReplies.map((reply, i) => {
+                if (reply instanceof ErrorReply) {
+                    errorIndexes.push(i);
+                    return reply;
+                }
+                const { transformReply, args } = this.queue[i];
+                return transformReply ? transformReply(reply, args.preserve) : reply;
+            });
+
+        if (errorIndexes.length) throw new MultiErrorReply(replies, errorIndexes);
+        return replies;
     }
 }
diff --git a/packages/client/lib/test-utils.ts b/packages/client/lib/test-utils.ts
index d2e33b4abf3..fbbac3e0b71 100644
--- a/packages/client/lib/test-utils.ts
+++ b/packages/client/lib/test-utils.ts
@@ -2,19 +2,25 @@ import TestUtils from '@redis/test-utils';
 import { SinonSpy } from 'sinon';
 import { promiseTimeout } from './utils';
 
-export default new TestUtils({
-    defaultDockerVersion: '7.0.2',
-    dockerImageName: 'redis',
-    dockerImageVersionArgument: 'redis-version'
+const utils = new TestUtils({
+  dockerImageName: 'redis',
+  dockerImageVersionArgument: 'redis-version',
+  defaultDockerVersion: '7.4-rc2'
 });
 
+export default utils;
+
+const DEBUG_MODE_ARGS = utils.isVersionGreaterThan([7]) ?
+  ['--enable-debug-command', 'yes'] :
+  [];
+
 export const GLOBAL = {
     SERVERS: {
         OPEN: {
-            serverArguments: []
+            serverArguments: [...DEBUG_MODE_ARGS]
         },
         PASSWORD: {
-            serverArguments: ['--requirepass', 'password'],
+            serverArguments: ['--requirepass', 'password', ...DEBUG_MODE_ARGS],
             clientOptions: {
                 password: 'password'
             }
@@ -22,15 +28,23 @@ export const GLOBAL = {
     },
     CLUSTERS: {
         OPEN: {
-            serverArguments: []
+            serverArguments: [...DEBUG_MODE_ARGS]
         },
         PASSWORD: {
-            serverArguments: ['--requirepass', 'password'],
+            serverArguments: ['--requirepass', 'password', ...DEBUG_MODE_ARGS],
             clusterConfiguration: {
                 defaults: {
                     password: 'password'
                 }
             }
+        },
+        WITH_REPLICAS: {
+            serverArguments: [...DEBUG_MODE_ARGS],
+            numberOfMasters: 2,
+            numberOfReplicas: 1,
+            clusterConfiguration: {
+                useReplicas: true
+            }
         }
     }
 };
diff --git a/packages/client/package.json b/packages/client/package.json
index 43e70381361..e344edd52c3 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/client",
-  "version": "1.4.2",
+  "version": "1.6.0",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -14,26 +14,26 @@
     "documentation": "typedoc"
   },
   "dependencies": {
-    "cluster-key-slot": "1.1.1",
+    "cluster-key-slot": "1.1.2",
     "generic-pool": "3.9.0",
     "yallist": "4.0.0"
   },
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
     "@redis/test-utils": "*",
-    "@types/node": "^18.11.6",
-    "@types/sinon": "^10.0.13",
+    "@types/node": "^20.6.2",
+    "@types/sinon": "^10.0.16",
     "@types/yallist": "^4.0.1",
-    "@typescript-eslint/eslint-plugin": "^5.41.0",
-    "@typescript-eslint/parser": "^5.41.0",
-    "eslint": "^8.26.0",
+    "@typescript-eslint/eslint-plugin": "^6.7.2",
+    "@typescript-eslint/parser": "^6.7.2",
+    "eslint": "^8.49.0",
     "nyc": "^15.1.0",
-    "release-it": "^15.5.0",
-    "sinon": "^14.0.1",
+    "release-it": "^16.1.5",
+    "sinon": "^16.0.0",
     "source-map-support": "^0.5.21",
     "ts-node": "^10.9.1",
-    "typedoc": "^0.23.18",
-    "typescript": "^4.8.4"
+    "typedoc": "^0.25.1",
+    "typescript": "^5.2.2"
   },
   "engines": {
     "node": ">=14"
@@ -45,5 +45,8 @@
   "bugs": {
     "url": "https://github.com/redis/node-redis/issues"
   },
-  "homepage": "https://github.com/redis/node-redis/tree/master/packages/client"
+  "homepage": "https://github.com/redis/node-redis/tree/master/packages/client",
+  "keywords": [
+    "redis"
+  ]
 }
diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json
index 3271cf400a2..c71595c5702 100644
--- a/packages/client/tsconfig.json
+++ b/packages/client/tsconfig.json
@@ -5,7 +5,8 @@
   },
   "include": [
     "./index.ts",
-    "./lib/**/*.ts"
+    "./lib/**/*.ts",
+    "./package.json"
   ],
   "exclude": [
     "./lib/test-utils.ts",
diff --git a/packages/graph/lib/commands/EXPLAIN.spec.ts b/packages/graph/lib/commands/EXPLAIN.spec.ts
index 2919a211631..86d89b212cb 100644
--- a/packages/graph/lib/commands/EXPLAIN.spec.ts
+++ b/packages/graph/lib/commands/EXPLAIN.spec.ts
@@ -11,7 +11,10 @@ describe('EXPLAIN', () => {
     });
 
     testUtils.testWithClient('client.graph.explain', async client => {
-        const reply = await client.graph.explain('key', 'RETURN 0');
+        const [, reply] = await Promise.all([
+            client.graph.query('key', 'RETURN 0'), // make sure to create a graph first
+            client.graph.explain('key', 'RETURN 0')
+        ]);
         assert.ok(Array.isArray(reply));
         assert.ok(!reply.find(x => typeof x !== 'string'));
     }, GLOBAL.SERVERS.OPEN);
diff --git a/packages/graph/lib/commands/EXPLAIN.ts b/packages/graph/lib/commands/EXPLAIN.ts
index 419ff62b112..ebea9ca900d 100644
--- a/packages/graph/lib/commands/EXPLAIN.ts
+++ b/packages/graph/lib/commands/EXPLAIN.ts
@@ -6,4 +6,4 @@ export function transformArguments(key: string, query: string): Array<string> {
     return ['GRAPH.EXPLAIN', key, query];
 }
 
-export declare function transfromReply(): Array<string>;
+export declare function transformReply(): Array<string>;
diff --git a/packages/graph/lib/commands/PROFILE.ts b/packages/graph/lib/commands/PROFILE.ts
index 473c526e679..c964452f497 100644
--- a/packages/graph/lib/commands/PROFILE.ts
+++ b/packages/graph/lib/commands/PROFILE.ts
@@ -6,4 +6,4 @@ export function transformArguments(key: string, query: string): Array<string> {
     return ['GRAPH.PROFILE', key, query];
 }
 
-export declare function transfromReply(): Array<string>;
+export declare function transformReply(): Array<string>;
diff --git a/packages/graph/lib/commands/RO_QUERY.spec.ts b/packages/graph/lib/commands/RO_QUERY.spec.ts
index 0fbaeb69537..1d76b1bd652 100644
--- a/packages/graph/lib/commands/RO_QUERY.spec.ts
+++ b/packages/graph/lib/commands/RO_QUERY.spec.ts
@@ -11,7 +11,10 @@ describe('RO_QUERY', () => {
     });
 
     testUtils.testWithClient('client.graph.roQuery', async client => {
-        const { data } = await client.graph.roQuery('key', 'RETURN 0');
+        const [, { data }] = await Promise.all([
+            client.graph.query('key', 'RETURN 0'), // make sure to create a graph first
+            client.graph.roQuery('key', 'RETURN 0')
+        ]);
         assert.deepEqual(data, [[0]]);
     }, GLOBAL.SERVERS.OPEN);
 });
\ No newline at end of file
diff --git a/packages/graph/lib/graph.spec.ts b/packages/graph/lib/graph.spec.ts
index 51912356d3a..495c6d17a8a 100644
--- a/packages/graph/lib/graph.spec.ts
+++ b/packages/graph/lib/graph.spec.ts
@@ -5,7 +5,7 @@ import Graph from './graph';
 describe('Graph', () => {
     testUtils.testWithClient('null', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN null AS key');
+            { data } = await graph.query('RETURN null AS key');
 
         assert.deepEqual(
             data,
@@ -15,7 +15,7 @@ describe('Graph', () => {
 
     testUtils.testWithClient('string', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN "string" AS key');
+            { data } = await graph.query('RETURN "string" AS key');
 
         assert.deepEqual(
             data,
@@ -25,7 +25,7 @@ describe('Graph', () => {
 
     testUtils.testWithClient('integer', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN 0 AS key');
+            { data } = await graph.query('RETURN 0 AS key');
 
         assert.deepEqual(
             data,
@@ -35,7 +35,7 @@ describe('Graph', () => {
 
     testUtils.testWithClient('boolean', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN false AS key');
+            { data } = await graph.query('RETURN false AS key');
 
         assert.deepEqual(
             data,
@@ -45,7 +45,7 @@ describe('Graph', () => {
 
     testUtils.testWithClient('double', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN 0.1 AS key');
+            { data } = await graph.query('RETURN 0.1 AS key');
 
         assert.deepEqual(
             data,
@@ -55,7 +55,7 @@ describe('Graph', () => {
 
     testUtils.testWithClient('array', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN [null] AS key');
+            { data } = await graph.query('RETURN [null] AS key');
 
         assert.deepEqual(
             data,
@@ -68,7 +68,7 @@ describe('Graph', () => {
 
         // check with and without metadata cache
         for (let i = 0; i < 2; i++) {
-            const { data } = await graph.query('CREATE ()-[edge :edge]->() RETURN edge');
+            const { data } = await graph.query<any>('CREATE ()-[edge :edge]->() RETURN edge');
             assert.ok(Array.isArray(data));
             assert.equal(data.length, 1);
             assert.equal(typeof data[0].edge.id, 'number');
@@ -85,7 +85,7 @@ describe('Graph', () => {
 
         // check with and without metadata cache
         for (let i = 0; i < 2; i++) {
-            const { data } = await graph.query('CREATE (node :node { p: 0 }) RETURN node');
+            const { data } = await graph.query<any>('CREATE (node :node { p: 0 }) RETURN node');
             assert.ok(Array.isArray(data));
             assert.equal(data.length, 1);
             assert.equal(typeof data[0].node.id, 'number');
@@ -98,7 +98,7 @@ describe('Graph', () => {
         const graph = new Graph(client as any, 'graph'),
             [, { data }] = await Promise.all([
                 await graph.query('CREATE ()-[:edge]->()'),
-                await graph.roQuery('MATCH path = ()-[:edge]->() RETURN path')
+                await graph.roQuery<any>('MATCH path = ()-[:edge]->() RETURN path')
             ]);
 
         assert.ok(Array.isArray(data));
@@ -125,7 +125,7 @@ describe('Graph', () => {
 
     testUtils.testWithClient('map', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN { key: "value" } AS map');
+            { data } = await graph.query('RETURN { key: "value" } AS map');
 
         assert.deepEqual(data, [{
             map: {
@@ -136,7 +136,7 @@ describe('Graph', () => {
 
     testUtils.testWithClient('point', async client => {
         const graph = new Graph(client as any, 'graph'),
-            { data } = await graph.roQuery('RETURN point({ latitude: 1, longitude: 2 }) AS point');
+            { data } = await graph.query('RETURN point({ latitude: 1, longitude: 2 }) AS point');
 
         assert.deepEqual(data, [{
             point: {
diff --git a/packages/graph/lib/graph.ts b/packages/graph/lib/graph.ts
index 5baff1dae29..a95338bd8f3 100644
--- a/packages/graph/lib/graph.ts
+++ b/packages/graph/lib/graph.ts
@@ -126,11 +126,11 @@ type GraphValue = null | string | number | boolean | Array<GraphValue> | {
     longitude: string;
 };
 
-type GraphReply<T> = Omit<QueryReply, 'headers' | 'data'> & {
+export type GraphReply<T> = Omit<QueryReply, 'headers' | 'data'> & {
     data?: Array<T>;
 };
 
-type GraphClientType = RedisClientType<{
+export type GraphClientType = RedisClientType<{
     graph: {
         query: typeof import('./commands/QUERY'),
         roQuery: typeof import('./commands/RO_QUERY')
diff --git a/packages/graph/lib/test-utils.ts b/packages/graph/lib/test-utils.ts
index 4ae0e0a2695..56c0af56a2e 100644
--- a/packages/graph/lib/test-utils.ts
+++ b/packages/graph/lib/test-utils.ts
@@ -3,8 +3,7 @@ import RedisGraph from '.';
 
 export default new TestUtils({
     dockerImageName: 'redislabs/redisgraph',
-    dockerImageVersionArgument: 'redisgraph-version',
-    defaultDockerVersion: '2.8.15'
+    dockerImageVersionArgument: 'redisgraph-version'
 });
 
 export const GLOBAL = {
diff --git a/packages/graph/package.json b/packages/graph/package.json
index 36697ec3c84..95cce6b8a86 100644
--- a/packages/graph/package.json
+++ b/packages/graph/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/graph",
-  "version": "1.1.0",
+  "version": "1.1.1",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -18,12 +18,24 @@
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
     "@redis/test-utils": "*",
-    "@types/node": "^18.11.6",
+    "@types/node": "^20.6.2",
     "nyc": "^15.1.0",
-    "release-it": "^15.5.0",
+    "release-it": "^16.1.5",
     "source-map-support": "^0.5.21",
     "ts-node": "^10.9.1",
-    "typedoc": "^0.23.18",
-    "typescript": "^4.8.4"
-  }
+    "typedoc": "^0.25.1",
+    "typescript": "^5.2.2"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/redis/node-redis.git"
+  },
+  "bugs": {
+    "url": "https://github.com/redis/node-redis/issues"
+  },
+  "homepage": "https://github.com/redis/node-redis/tree/master/packages/graph",
+  "keywords": [
+    "redis",
+    "RedisGraph"
+  ]
 }
diff --git a/packages/json/README.md b/packages/json/README.md
index adc125eb980..e7f70174116 100644
--- a/packages/json/README.md
+++ b/packages/json/README.md
@@ -1,6 +1,6 @@
 # @redis/json
 
-This package provides support for the [RedisJSON](https://redisjson.io) module, which adds JSON as a native data type to Redis.  It extends the [Node Redis client](https://github.com/redis/node-redis) to include functions for each of the RedisJSON commands.
+This package provides support for the [RedisJSON](https://redis.io/docs/stack/json/) module, which adds JSON as a native data type to Redis.  It extends the [Node Redis client](https://github.com/redis/node-redis) to include functions for each of the RedisJSON commands.
 
 To use these extra commands, your Redis server must have the RedisJSON module installed.
 
@@ -10,7 +10,7 @@ For a complete example, see [`managing-json.js`](https://github.com/redis/node-r
 
 ### Storing JSON Documents in Redis
 
-The [`JSON.SET`](https://oss.redis.com/redisjson/commands/#jsonset) command stores a JSON value at a given JSON Path in a Redis key.
+The [`JSON.SET`](https://redis.io/commands/json.set/) command stores a JSON value at a given JSON Path in a Redis key.
 
 Here, we'll store a JSON document in the root of the Redis key "`mydoc`":
 
@@ -37,11 +37,11 @@ await client.json.set('noderedis:jsondata', '$', {
 });
 ```
 
-For more information about RedisJSON's path syntax, [check out the documentation](https://oss.redis.com/redisjson/path/).
+For more information about RedisJSON's path syntax, [check out the documentation](https://redis.io/docs/stack/json/path/).
 
 ### Retrieving JSON Documents from Redis
 
-With RedisJSON, we can retrieve all or part(s) of a JSON document using the [`JSON.GET`]() command and one or more JSON Paths.  Let's get the name and age of one of the pets:
+With RedisJSON, we can retrieve all or part(s) of a JSON document using the [`JSON.GET`](https://redis.io/commands/json.get/) command and one or more JSON Paths.  Let's get the name and age of one of the pets:
 
 ```javascript
 const results = await client.json.get('noderedis:jsondata', {
@@ -62,19 +62,19 @@ const results = await client.json.get('noderedis:jsondata', {
 
 RedisJSON includes commands that can atomically update values in a JSON document, in place in Redis without having to first retrieve the entire document.
 
-Using the [`JSON.NUMINCRBY`](https://oss.redis.com/redisjson/commands/#jsonnumincrby) command, we can update the age of one of the pets like this:
+Using the [`JSON.NUMINCRBY`](https://redis.io/commands/json.numincrby/) command, we can update the age of one of the pets like this:
 
 ```javascript
 await client.json.numIncrBy('noderedis:jsondata', '.pets[1].age', 1);
 ```
 
-And we can add a new object to the pets array with the [`JSON.ARRAPPEND`](https://oss.redis.com/redisjson/commands/#jsonarrappend) command:
+And we can add a new object to the pets array with the [`JSON.ARRAPPEND`](https://redis.io/commands/json.arrappend/) command:
 
 ```javascript
- await client.json.arrAppend('noderedis:jsondata', '.pets', {
-    name: 'Robin',
-    species: 'bird',
-    age: 1,
-    isMammal: false
-  });
+await client.json.arrAppend('noderedis:jsondata', '.pets', {
+  name: 'Robin',
+  species: 'bird',
+  age: 1,
+  isMammal: false
+});
 ```
diff --git a/packages/json/lib/commands/MERGE.spec.ts b/packages/json/lib/commands/MERGE.spec.ts
new file mode 100644
index 00000000000..ee5e6fff86d
--- /dev/null
+++ b/packages/json/lib/commands/MERGE.spec.ts
@@ -0,0 +1,21 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './MERGE';
+
+describe('MERGE', () => {
+    testUtils.isVersionGreaterThanHook([2, 6]);
+
+    it('transformArguments', () => {
+        assert.deepEqual(
+            transformArguments('key', '$', 1),
+            ['JSON.MERGE', 'key', '$', '1']
+        );
+    });
+
+    testUtils.testWithClient('client.json.merge', async client => {
+        assert.equal(
+            await client.json.merge('key', '$', 'json'),
+            'OK'
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/json/lib/commands/MERGE.ts b/packages/json/lib/commands/MERGE.ts
new file mode 100644
index 00000000000..81cce7f006b
--- /dev/null
+++ b/packages/json/lib/commands/MERGE.ts
@@ -0,0 +1,9 @@
+import { RedisJSON, transformRedisJsonArgument } from '.';
+
+export const FIRST_KEY_INDEX = 1;
+
+export function transformArguments(key: string, path: string, json: RedisJSON): Array<string> {
+    return ['JSON.MERGE', key, path, transformRedisJsonArgument(json)];
+}
+
+export declare function transformReply(): 'OK';
diff --git a/packages/json/lib/commands/MGET.ts b/packages/json/lib/commands/MGET.ts
index 582b73bf85a..34ca8da289f 100644
--- a/packages/json/lib/commands/MGET.ts
+++ b/packages/json/lib/commands/MGET.ts
@@ -2,6 +2,8 @@ import { RedisJSON, transformRedisJsonNullReply } from '.';
 
 export const FIRST_KEY_INDEX = 1;
 
+export const IS_READ_ONLY = true;
+
 export function transformArguments(keys: Array<string>, path: string): Array<string> {
     return [
         'JSON.MGET',
diff --git a/packages/json/lib/commands/MSET.spec.ts b/packages/json/lib/commands/MSET.spec.ts
new file mode 100644
index 00000000000..53d4d822505
--- /dev/null
+++ b/packages/json/lib/commands/MSET.spec.ts
@@ -0,0 +1,35 @@
+import { strict as assert } from 'assert';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments } from './MSET';
+
+describe('MSET', () => {
+    it('transformArguments', () => {
+        assert.deepEqual(
+            transformArguments([{
+                key: '1',
+                path: '$',
+                value: 1
+            }, {
+                key: '2',
+                path: '$',
+                value: '2'
+            }]),
+            ['JSON.MSET', '1', '$', '1', '2', '$', '"2"']
+        );
+    });
+
+    testUtils.testWithClient('client.json.mSet', async client => {
+        assert.deepEqual(
+            await client.json.mSet([{
+                key: '1',
+                path: '$',
+                value: 1
+            }, {
+                key: '2',
+                path: '$',
+                value: '2'
+            }]),
+            'OK'
+        );
+    }, GLOBAL.SERVERS.OPEN);
+});
diff --git a/packages/json/lib/commands/MSET.ts b/packages/json/lib/commands/MSET.ts
new file mode 100644
index 00000000000..67228f264d2
--- /dev/null
+++ b/packages/json/lib/commands/MSET.ts
@@ -0,0 +1,28 @@
+import { RedisJSON, transformRedisJsonArgument } from '.';
+import { RedisCommandArgument } from '@redis/client/dist/lib/commands';
+
+export const FIRST_KEY_INDEX = 1;
+
+interface JsonMSetItem {
+    key: RedisCommandArgument;
+    path: RedisCommandArgument;
+    value: RedisJSON;
+}
+
+export function transformArguments(items: Array<JsonMSetItem>): Array<string> {
+  
+    const args = new Array(1 + items.length * 3);
+    args[0] = 'JSON.MSET';
+
+    let argsIndex = 1;
+    for (let i = 0; i < items.length; i++) {
+        const item = items[i];
+        args[argsIndex++] = item.key;
+        args[argsIndex++] = item.path;
+        args[argsIndex++] = transformRedisJsonArgument(item.value);
+    }
+
+    return args;
+}
+
+export declare function transformReply(): 'OK';
diff --git a/packages/json/lib/commands/index.ts b/packages/json/lib/commands/index.ts
index efcf156b84d..9d0a82ec271 100644
--- a/packages/json/lib/commands/index.ts
+++ b/packages/json/lib/commands/index.ts
@@ -8,7 +8,9 @@ import * as DEBUG_MEMORY from './DEBUG_MEMORY';
 import * as DEL from './DEL';
 import * as FORGET from './FORGET';
 import * as GET from './GET';
+import * as MERGE from './MERGE';
 import * as MGET from './MGET';
+import * as MSET from './MSET';
 import * as NUMINCRBY from './NUMINCRBY';
 import * as NUMMULTBY from './NUMMULTBY';
 import * as OBJKEYS from './OBJKEYS';
@@ -40,8 +42,12 @@ export default {
     forget: FORGET,
     GET,
     get: GET,
+    MERGE,
+    merge: MERGE,
     MGET,
     mGet: MGET,
+    MSET,
+    mSet: MSET,
     NUMINCRBY,
     numIncrBy: NUMINCRBY,
     NUMMULTBY,
diff --git a/packages/json/lib/test-utils.ts b/packages/json/lib/test-utils.ts
index fa150e4b7db..55426890e00 100644
--- a/packages/json/lib/test-utils.ts
+++ b/packages/json/lib/test-utils.ts
@@ -4,7 +4,7 @@ import RedisJSON from '.';
 export default new TestUtils({
     dockerImageName: 'redislabs/rejson',
     dockerImageVersionArgument: 'rejson-version',
-    defaultDockerVersion: '2.0.9'
+    defaultDockerVersion: '2.6.9'
 });
 
 export const GLOBAL = {
diff --git a/packages/json/package.json b/packages/json/package.json
index 11dd7cae780..ad60cc13c26 100644
--- a/packages/json/package.json
+++ b/packages/json/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/json",
-  "version": "1.0.4",
+  "version": "1.0.7",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -18,12 +18,24 @@
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
     "@redis/test-utils": "*",
-    "@types/node": "^18.11.6",
+    "@types/node": "^20.6.2",
     "nyc": "^15.1.0",
-    "release-it": "^15.5.0",
+    "release-it": "^16.1.5",
     "source-map-support": "^0.5.21",
     "ts-node": "^10.9.1",
-    "typedoc": "^0.23.18",
-    "typescript": "^4.8.4"
-  }
+    "typedoc": "^0.25.1",
+    "typescript": "^5.2.2"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/redis/node-redis.git"
+  },
+  "bugs": {
+    "url": "https://github.com/redis/node-redis/issues"
+  },
+  "homepage": "https://github.com/redis/node-redis/tree/master/packages/json",
+  "keywords": [
+    "redis",
+    "RedisJSON"
+  ]
 }
diff --git a/packages/search/README.md b/packages/search/README.md
index e7d99cf75e1..60186ba7f92 100644
--- a/packages/search/README.md
+++ b/packages/search/README.md
@@ -12,7 +12,7 @@ For complete examples, see [`search-hashes.js`](https://github.com/redis/node-re
 
 #### Creating an Index
 
-Before we can perform any searches, we need to tell RediSearch how to index our data, and which Redis keys to find that data in.  The [FT.CREATE](https://oss.redis.com/redisearch/Commands/#ftcreate) command creates a RediSearch index.  Here's how to use it to create an index we'll call `idx:animals` where we want to index hashes containing `name`, `species` and `age` fields, and whose key names in Redis begin with the prefix `noderedis:animals`:
+Before we can perform any searches, we need to tell RediSearch how to index our data, and which Redis keys to find that data in.  The [FT.CREATE](https://redis.io/commands/ft.create) command creates a RediSearch index.  Here's how to use it to create an index we'll call `idx:animals` where we want to index hashes containing `name`, `species` and `age` fields, and whose key names in Redis begin with the prefix `noderedis:animals`:
 
 ```javascript
 await client.ft.create('idx:animals', {
@@ -28,11 +28,11 @@ await client.ft.create('idx:animals', {
 });
 ```
 
-See the [`FT.CREATE` documentation](https://oss.redis.com/redisearch/Commands/#ftcreate) for information about the different field types and additional options.
+See the [`FT.CREATE` documentation](https://redis.io/commands/ft.create/#description) for information about the different field types and additional options.
 
 #### Querying the Index
 
-Once we've created an index, and added some data to Redis hashes whose keys begin with the prefix `noderedis:animals`, we can start writing some search queries.  RediSearch supports a rich query syntax for full-text search, faceted search, aggregation and more.  Check out the [`FT.SEARCH` documentation](https://oss.redis.com/redisearch/Commands/#ftsearch) and the [query syntax reference](https://oss.redis.com/redisearch/Query_Syntax/) for more information.
+Once we've created an index, and added some data to Redis hashes whose keys begin with the prefix `noderedis:animals`, we can start writing some search queries.  RediSearch supports a rich query syntax for full-text search, faceted search, aggregation and more.  Check out the [`FT.SEARCH` documentation](https://redis.io/commands/ft.search) and the [query syntax reference](https://redis.io/docs/interact/search-and-query/query) for more information.
 
 Let's write a query to find all the animals where the `species` field has the value `dog`:
 
@@ -112,7 +112,7 @@ Note that we're using JSON Path to specify where the fields to index are in our
 
 Now we have an index and some data stored as JSON documents in Redis (see the [JSON package documentation](https://github.com/redis/node-redis/tree/master/packages/json) for examples of how to store JSON), we can write some queries...
 
-We'll use the [RediSearch query language](https://oss.redis.com/redisearch/Query_Syntax/) and [`FT.SEARCH`](https://oss.redis.com/redisearch/Commands/#ftsearch) command.  Here's a query to find users under the age of 30:
+We'll use the [RediSearch query language](https://redis.io/docs/interact/search-and-query/query) and [`FT.SEARCH`](https://redis.io/commands/ft.search) command.  Here's a query to find users under the age of 30:
 
 ```javascript
 await client.ft.search('idx:users', '@age:[0 30]');
diff --git a/packages/search/lib/commands/AGGREGATE.spec.ts b/packages/search/lib/commands/AGGREGATE.spec.ts
index a2330076438..5b34d7dc16f 100644
--- a/packages/search/lib/commands/AGGREGATE.spec.ts
+++ b/packages/search/lib/commands/AGGREGATE.spec.ts
@@ -19,6 +19,13 @@ describe('AGGREGATE', () => {
             );
         });
 
+        it('with ADDSCORES', () => {
+            assert.deepEqual(
+                transformArguments('index', '*', { ADDSCORES: true }),
+                ['FT.AGGREGATE', 'index', '*', 'ADDSCORES']
+            );
+        });
+
         describe('with LOAD', () => {
             describe('single', () => {
                 describe('without alias', () => {
@@ -454,6 +461,13 @@ describe('AGGREGATE', () => {
                 ['FT.AGGREGATE', 'index', '*', 'DIALECT', '1']
             );
         });
+
+        it('with TIMEOUT', () => {
+            assert.deepEqual(
+                transformArguments('index', '*', { TIMEOUT: 10 }),
+                ['FT.AGGREGATE', 'index', '*', 'TIMEOUT', '10']
+            );
+        });
     });
 
     testUtils.testWithClient('client.ft.aggregate', async client => {
diff --git a/packages/search/lib/commands/AGGREGATE.ts b/packages/search/lib/commands/AGGREGATE.ts
index c32d20b0b1c..0cab9b25d48 100644
--- a/packages/search/lib/commands/AGGREGATE.ts
+++ b/packages/search/lib/commands/AGGREGATE.ts
@@ -119,11 +119,13 @@ type LoadField = PropertyName | {
 }
 
 export interface AggregateOptions {
-    VERBATIM?: true;
+    VERBATIM?: boolean;
+    ADDSCORES?: boolean;
     LOAD?: LoadField | Array<LoadField>;
     STEPS?: Array<GroupByStep | SortStep | ApplyStep | LimitStep | FilterStep>;
     PARAMS?: Params;
     DIALECT?: number;
+    TIMEOUT?: number;
 }
 
 export const FIRST_KEY_INDEX = 1;
@@ -149,6 +151,10 @@ export function pushAggregatehOptions(
         args.push('VERBATIM');
     }
 
+    if (options?.ADDSCORES) {
+        args.push('ADDSCORES');
+    }
+
     if (options?.LOAD) {
         args.push('LOAD');
         pushArgumentsWithLength(args, () => {
@@ -213,6 +219,10 @@ export function pushAggregatehOptions(
         args.push('DIALECT', options.DIALECT.toString());
     }
 
+    if (options?.TIMEOUT !== undefined) {
+        args.push('TIMEOUT', options.TIMEOUT.toString());
+    }
+
     return args;
 }
 
@@ -303,4 +313,4 @@ export function transformReply(rawReply: AggregateRawReply): AggregateReply {
         total: rawReply[0],
         results
     };
-}
\ No newline at end of file
+}
diff --git a/packages/search/lib/commands/CREATE.spec.ts b/packages/search/lib/commands/CREATE.spec.ts
index 1a0a4f244bd..50c5c011c89 100644
--- a/packages/search/lib/commands/CREATE.spec.ts
+++ b/packages/search/lib/commands/CREATE.spec.ts
@@ -1,7 +1,7 @@
 import { strict as assert } from 'assert';
 import testUtils, { GLOBAL } from '../test-utils';
 import { transformArguments } from './CREATE';
-import { SchemaFieldTypes, SchemaTextFieldPhonetics, RedisSearchLanguages, VectorAlgorithms } from '.';
+import { SchemaFieldTypes, SchemaTextFieldPhonetics, RedisSearchLanguages, VectorAlgorithms, SCHEMA_GEO_SHAPE_COORD_SYSTEM } from '.';
 
 describe('CREATE', () => {
     describe('transformArguments', () => {
@@ -70,6 +70,18 @@ describe('CREATE', () => {
                         ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'WITHSUFFIXTRIE']
                     );
                 });
+
+                it('with INDEXEMPTY', () => {
+                    assert.deepEqual(
+                        transformArguments('index', {
+                            field: {
+                                type: SchemaFieldTypes.TEXT,
+                                INDEXEMPTY: true
+                            }
+                        }),
+                        ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'INDEXEMPTY']
+                    );
+                });
             });
 
             it('NUMERIC', () => {
@@ -148,6 +160,18 @@ describe('CREATE', () => {
                         ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'WITHSUFFIXTRIE']
                     );
                 });
+
+                it('with INDEXEMPTY', () => {
+                    assert.deepEqual(
+                        transformArguments('index', {
+                            field: {
+                                type: SchemaFieldTypes.TAG,
+                                INDEXEMPTY: true
+                            }
+                        }),
+                        ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'INDEXEMPTY']
+                    );
+                });
             });
 
             describe('VECTOR', () => {
@@ -196,6 +220,42 @@ describe('CREATE', () => {
                 });
             });
 
+            describe('GEOSHAPE', () => {
+                describe('without options', () => {
+                    it('SCHEMA_FIELD_TYPE.GEOSHAPE', () => {
+                        assert.deepEqual(
+                            transformArguments('index', {
+                                field: SchemaFieldTypes.GEOSHAPE
+                            }),
+                            ['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEOSHAPE']
+                        );
+                    });
+
+                    it('{ type: SCHEMA_FIELD_TYPE.GEOSHAPE }', () => {
+                        assert.deepEqual(
+                            transformArguments('index', {
+                                field: {
+                                    type: SchemaFieldTypes.GEOSHAPE
+                                }
+                            }),
+                            ['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEOSHAPE']
+                        );
+                    });
+                });
+
+                it('with COORD_SYSTEM', () => {
+                    assert.deepEqual(
+                        transformArguments('index', {
+                            field: {
+                                type: SchemaFieldTypes.GEOSHAPE,
+                                COORD_SYSTEM: SCHEMA_GEO_SHAPE_COORD_SYSTEM.SPHERICAL
+                            }
+                        }),
+                        ['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEOSHAPE', 'COORD_SYSTEM', 'SPHERICAL']
+                    );
+                });
+            });
+
             describe('with generic options', () => {
                 it('with AS', () => {
                     assert.deepEqual(
@@ -246,6 +306,18 @@ describe('CREATE', () => {
                         ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'NOINDEX']
                     );
                 });
+
+                it('with INDEXMISSING', () => {
+                    assert.deepEqual(
+                        transformArguments('index', {
+                            field: {
+                                type: SchemaFieldTypes.TEXT,
+                                INDEXMISSING: true
+                            }
+                        }),
+                        ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'INDEXMISSING']
+                    );
+                });
             });
         });
 
diff --git a/packages/search/lib/commands/CURSOR_READ.spec.ts b/packages/search/lib/commands/CURSOR_READ.spec.ts
index 5b4f4122d49..bb68e2b6396 100644
--- a/packages/search/lib/commands/CURSOR_READ.spec.ts
+++ b/packages/search/lib/commands/CURSOR_READ.spec.ts
@@ -4,15 +4,24 @@ import testUtils, { GLOBAL } from '../test-utils';
 import { transformArguments } from './CURSOR_READ';
 
 describe('CURSOR READ', () => {
-    it('transformArguments', () => {
-        assert.deepEqual(
-            transformArguments('index', 0),
-            ['FT.CURSOR', 'READ', 'index', '0']
-        );
+    describe('transformArguments', () => {
+        it('without options', () => {
+            assert.deepEqual(
+                transformArguments('index', 0),
+                ['FT.CURSOR', 'READ', 'index', '0']
+            );
+        });
+
+        it('with COUNT', () => {
+            assert.deepEqual(
+                transformArguments('index', 0, { COUNT: 1 }),
+                ['FT.CURSOR', 'READ', 'index', '0', 'COUNT', '1']
+            );
+        });
     });
 
     testUtils.testWithClient('client.ft.cursorRead', async client => {
-        const [ ,, { cursor } ] = await Promise.all([
+        const [, , { cursor }] = await Promise.all([
             client.ft.create('idx', {
                 field: {
                     type: SchemaFieldTypes.TEXT
diff --git a/packages/search/lib/commands/CURSOR_READ.ts b/packages/search/lib/commands/CURSOR_READ.ts
index 1e828cc3e46..35cf1bc4f06 100644
--- a/packages/search/lib/commands/CURSOR_READ.ts
+++ b/packages/search/lib/commands/CURSOR_READ.ts
@@ -4,16 +4,27 @@ export const FIRST_KEY_INDEX = 1;
 
 export const IS_READ_ONLY = true;
 
+interface CursorReadOptions {
+    COUNT?: number;
+}
+
 export function transformArguments(
     index: RedisCommandArgument,
-    cursor: number
+    cursor: number,
+    options?: CursorReadOptions
 ): RedisCommandArguments {
-    return [
+    const args = [
         'FT.CURSOR',
         'READ',
         index,
         cursor.toString()
     ];
+
+    if (options?.COUNT) {
+        args.push('COUNT', options.COUNT.toString());
+    }
+
+    return args;
 }
 
 export { transformReply } from './AGGREGATE_WITHCURSOR';
diff --git a/packages/search/lib/commands/PROFILE_SEARCH.ts b/packages/search/lib/commands/PROFILE_SEARCH.ts
index 8040ccb5e05..94fba8a6a54 100644
--- a/packages/search/lib/commands/PROFILE_SEARCH.ts
+++ b/packages/search/lib/commands/PROFILE_SEARCH.ts
@@ -9,7 +9,7 @@ export function transformArguments(
     query: string,
     options?: ProfileOptions & SearchOptions
 ): RedisCommandArguments {
-    const args = ['FT.PROFILE', index, 'SEARCH'];
+    let args: RedisCommandArguments = ['FT.PROFILE', index, 'SEARCH'];
 
     if (options?.LIMITED) {
         args.push('LIMITED');
@@ -21,9 +21,9 @@ export function transformArguments(
 
 type ProfileSearchRawReply = ProfileRawReply<SearchRawReply>;
 
-export function transformReply(reply: ProfileSearchRawReply): ProfileReply {
+export function transformReply(reply: ProfileSearchRawReply, withoutDocuments: boolean): ProfileReply {
     return {
-        results: transformSearchReply(reply[0]),
+        results: transformSearchReply(reply[0], withoutDocuments),
         profile: transformProfile(reply[1])
     };
 }
diff --git a/packages/search/lib/commands/SEARCH.spec.ts b/packages/search/lib/commands/SEARCH.spec.ts
index a5d8ae9e6c4..931458b3a25 100644
--- a/packages/search/lib/commands/SEARCH.spec.ts
+++ b/packages/search/lib/commands/SEARCH.spec.ts
@@ -233,6 +233,15 @@ describe('SEARCH', () => {
                 ['FT.SEARCH', 'index', 'query', 'DIALECT', '1']
             );
         });
+
+        it('with TIMEOUT', () => {
+            assert.deepEqual(
+                transformArguments('index', 'query', {
+                    TIMEOUT: 5
+                }),
+                ['FT.SEARCH', 'index', 'query', 'TIMEOUT', '5']
+            );
+        });
     });
 
     describe('client.ft.search', () => {
@@ -267,7 +276,8 @@ describe('SEARCH', () => {
                 client.ft.create('index', {
                     field: SchemaFieldTypes.NUMERIC
                 }),
-                client.hSet('1', 'field', '1')
+                client.hSet('1', 'field', '1'),
+                client.hSet('2', 'field', '2')
             ]);
 
             assert.deepEqual(
@@ -275,10 +285,13 @@ describe('SEARCH', () => {
                     RETURN: []
                 }),
                 {
-                    total: 1,
+                    total: 2,
                     documents: [{
                         id: '1',
                         value: Object.create(null)
+                    }, {
+                        id: '2',
+                        value: Object.create(null)
                     }]
                 }
             );
diff --git a/packages/search/lib/commands/SEARCH.ts b/packages/search/lib/commands/SEARCH.ts
index bed06e22c36..ff7ab7e201d 100644
--- a/packages/search/lib/commands/SEARCH.ts
+++ b/packages/search/lib/commands/SEARCH.ts
@@ -6,7 +6,6 @@ export const FIRST_KEY_INDEX = 1;
 export const IS_READ_ONLY = true;
 
 export interface SearchOptions {
-    // NOCONTENT?: true; TODO
     VERBATIM?: true;
     NOSTOPWORDS?: true;
     // WITHSCORES?: true;
@@ -55,6 +54,7 @@ export interface SearchOptions {
     };
     PARAMS?: Params;
     DIALECT?: number;
+    TIMEOUT?: number;
 }
 
 export function transformArguments(
@@ -70,13 +70,13 @@ export function transformArguments(
 
 export type SearchRawReply = Array<any>;
 
-export function transformReply(reply: SearchRawReply): SearchReply {
+export function transformReply(reply: SearchRawReply, withoutDocuments: boolean): SearchReply {
     const documents = [];
     let i = 1;
     while (i < reply.length) {
         documents.push({
             id: reply[i++],
-            value: documentValue(reply[i++])
+            value: withoutDocuments ? Object.create(null) : documentValue(reply[i++])
         });
     }
 
@@ -88,7 +88,6 @@ export function transformReply(reply: SearchRawReply): SearchReply {
 
 function documentValue(tuples: any) {
     const message = Object.create(null);
-    if (tuples === undefined) return message;
 
     let i = 0;
     while (i < tuples.length) {
diff --git a/packages/search/lib/commands/SEARCH_NOCONTENT.spec.ts b/packages/search/lib/commands/SEARCH_NOCONTENT.spec.ts
new file mode 100644
index 00000000000..da5a6feaba7
--- /dev/null
+++ b/packages/search/lib/commands/SEARCH_NOCONTENT.spec.ts
@@ -0,0 +1,45 @@
+import { strict as assert } from 'assert';
+import { SchemaFieldTypes } from '.';
+import testUtils, { GLOBAL } from '../test-utils';
+import { transformArguments, transformReply } from './SEARCH_NOCONTENT';
+
+describe('SEARCH_NOCONTENT', () => {
+    describe('transformArguments', () => {
+        it('without options', () => {
+            assert.deepEqual(
+                transformArguments('index', 'query'),
+                ['FT.SEARCH', 'index', 'query', 'NOCONTENT']
+            );
+        });
+    });
+
+    describe('transformReply', () => {
+        it('returns total and keys', () => {
+            assert.deepEqual(transformReply([3, '1', '2', '3']), {
+                total: 3,
+                documents: ['1', '2', '3']
+            })
+        });
+    });
+
+    describe('client.ft.searchNoContent', () => {
+        testUtils.testWithClient('returns total and keys', async client => {
+            await Promise.all([
+                client.ft.create('index', {
+                    field: SchemaFieldTypes.TEXT
+                }),
+                client.hSet('1', 'field', 'field1'),
+                client.hSet('2', 'field', 'field2'),
+                client.hSet('3', 'field', 'field3')
+            ]);
+
+            assert.deepEqual(
+                await client.ft.searchNoContent('index', '*'),
+                {
+                    total: 3,
+                    documents: ['1','2','3']
+                }
+            );
+        }, GLOBAL.SERVERS.OPEN);
+    });
+});
diff --git a/packages/search/lib/commands/SEARCH_NOCONTENT.ts b/packages/search/lib/commands/SEARCH_NOCONTENT.ts
new file mode 100644
index 00000000000..ab50ae2b9ff
--- /dev/null
+++ b/packages/search/lib/commands/SEARCH_NOCONTENT.ts
@@ -0,0 +1,30 @@
+import { RedisCommandArguments } from "@redis/client/dist/lib/commands";
+import { pushSearchOptions } from ".";
+import { SearchOptions, SearchRawReply } from "./SEARCH";
+
+export const FIRST_KEY_INDEX = 1;
+
+export const IS_READ_ONLY = true;
+
+export function transformArguments(
+    index: string,
+    query: string,
+    options?: SearchOptions
+): RedisCommandArguments {
+    return pushSearchOptions(
+        ['FT.SEARCH', index, query, 'NOCONTENT'],
+        options
+    );
+}
+
+export interface SearchNoContentReply {
+    total: number;
+    documents: Array<string>;
+};
+
+export function transformReply(reply: SearchRawReply): SearchNoContentReply {
+    return {
+        total: reply[0],
+        documents: reply.slice(1)
+    };
+}
diff --git a/packages/search/lib/commands/index.ts b/packages/search/lib/commands/index.ts
index 74a49cb1bba..f907e1999e6 100644
--- a/packages/search/lib/commands/index.ts
+++ b/packages/search/lib/commands/index.ts
@@ -20,6 +20,7 @@ import * as INFO from './INFO';
 import * as PROFILESEARCH from './PROFILE_SEARCH';
 import * as PROFILEAGGREGATE from './PROFILE_AGGREGATE';
 import * as SEARCH from './SEARCH';
+import * as SEARCH_NOCONTENT from './SEARCH_NOCONTENT';
 import * as SPELLCHECK from './SPELLCHECK';
 import * as SUGADD from './SUGADD';
 import * as SUGDEL from './SUGDEL';
@@ -80,6 +81,8 @@ export default {
     profileAggregate: PROFILEAGGREGATE,
     SEARCH,
     search: SEARCH,
+    SEARCH_NOCONTENT,
+    searchNoContent: SEARCH_NOCONTENT,
     SPELLCHECK,
     spellCheck: SPELLCHECK,
     SUGADD,
@@ -182,28 +185,46 @@ export enum SchemaFieldTypes {
     NUMERIC = 'NUMERIC',
     GEO = 'GEO',
     TAG = 'TAG',
-    VECTOR = 'VECTOR'
+    VECTOR = 'VECTOR',
+    GEOSHAPE = 'GEOSHAPE'
 }
-
+  
 type CreateSchemaField<
     T extends SchemaFieldTypes,
     E = Record<PropertyKey, unknown>
 > = T | ({
     type: T;
     AS?: string;
+    INDEXMISSING?: boolean;
 } & E);
 
+type CommonFieldArguments = {
+    SORTABLE?: boolean | 'UNF';
+    NOINDEX?: boolean;
+};
+
 type CreateSchemaCommonField<
     T extends SchemaFieldTypes,
     E = Record<PropertyKey, unknown>
 > = CreateSchemaField<
     T,
-    ({
-        SORTABLE?: true | 'UNF';
-        NOINDEX?: true;
-    } & E)
+    (CommonFieldArguments & E)
 >;
 
+function pushCommonFieldArguments(args: RedisCommandArguments, fieldOptions: CommonFieldArguments) {
+    if (fieldOptions.SORTABLE) {
+        args.push('SORTABLE');
+
+        if (fieldOptions.SORTABLE === 'UNF') {
+            args.push('UNF');
+        }
+    }
+
+    if (fieldOptions.NOINDEX) {
+        args.push('NOINDEX');
+    }
+}
+
 export enum SchemaTextFieldPhonetics {
     DM_EN = 'dm:en',
     DM_FR = 'dm:fr',
@@ -216,6 +237,7 @@ type CreateSchemaTextField = CreateSchemaCommonField<SchemaFieldTypes.TEXT, {
     WEIGHT?: number;
     PHONETIC?: SchemaTextFieldPhonetics;
     WITHSUFFIXTRIE?: boolean;
+    INDEXEMPTY?: boolean;
 }>;
 
 type CreateSchemaNumericField = CreateSchemaCommonField<SchemaFieldTypes.NUMERIC>;
@@ -226,6 +248,7 @@ type CreateSchemaTagField = CreateSchemaCommonField<SchemaFieldTypes.TAG, {
     SEPARATOR?: string;
     CASESENSITIVE?: true;
     WITHSUFFIXTRIE?: boolean;
+    INDEXEMPTY?: boolean;
 }>;
 
 export enum VectorAlgorithms {
@@ -254,6 +277,17 @@ type CreateSchemaHNSWVectorField = CreateSchemaVectorField<VectorAlgorithms.HNSW
     EF_RUNTIME?: number;
 }>;
 
+export const SCHEMA_GEO_SHAPE_COORD_SYSTEM = {
+    SPHERICAL: 'SPHERICAL',
+    FLAT: 'FLAT'
+} as const;
+
+export type SchemaGeoShapeFieldCoordSystem = typeof SCHEMA_GEO_SHAPE_COORD_SYSTEM[keyof typeof SCHEMA_GEO_SHAPE_COORD_SYSTEM];
+
+type CreateSchemaGeoShapeField = CreateSchemaCommonField<SchemaFieldTypes.GEOSHAPE, {
+    COORD_SYSTEM?: SchemaGeoShapeFieldCoordSystem;
+}>;
+
 export interface RediSearchSchema {
     [field: string]:
         CreateSchemaTextField |
@@ -261,7 +295,8 @@ export interface RediSearchSchema {
         CreateSchemaGeoField |
         CreateSchemaTagField |
         CreateSchemaFlatVectorField |
-        CreateSchemaHNSWVectorField;
+        CreateSchemaHNSWVectorField |
+        CreateSchemaGeoShapeField;
 }
 
 export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema) {
@@ -297,11 +332,18 @@ export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema
                     args.push('WITHSUFFIXTRIE');
                 }
 
+                pushCommonFieldArguments(args, fieldOptions);
+
+                if (fieldOptions.INDEXEMPTY) {
+                    args.push('INDEXEMPTY');
+                }
+
                 break;
 
-            // case SchemaFieldTypes.NUMERIC:
-            // case SchemaFieldTypes.GEO:
-            //     break;
+            case SchemaFieldTypes.NUMERIC:
+            case SchemaFieldTypes.GEO:
+                pushCommonFieldArguments(args, fieldOptions);
+                break;
 
             case SchemaFieldTypes.TAG:
                 if (fieldOptions.SEPARATOR) {
@@ -316,6 +358,12 @@ export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema
                     args.push('WITHSUFFIXTRIE');
                 }
 
+                pushCommonFieldArguments(args, fieldOptions);
+
+                if (fieldOptions.INDEXEMPTY) {
+                    args.push('INDEXEMPTY');
+                }
+
                 break;
 
             case SchemaFieldTypes.VECTOR:
@@ -357,19 +405,20 @@ export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema
                     }
                 });
 
-                continue; // vector fields do not contain SORTABLE and NOINDEX options
-        }
+                break;
 
-        if (fieldOptions.SORTABLE) {
-            args.push('SORTABLE');
+            case SchemaFieldTypes.GEOSHAPE:
+                if (fieldOptions.COORD_SYSTEM !== undefined) {
+                    args.push('COORD_SYSTEM', fieldOptions.COORD_SYSTEM);
+                }
 
-            if (fieldOptions.SORTABLE === 'UNF') {
-                args.push('UNF');
-            }
+                pushCommonFieldArguments(args, fieldOptions);
+
+                break;
         }
 
-        if (fieldOptions.NOINDEX) {
-            args.push('NOINDEX');
+        if (fieldOptions.INDEXMISSING) {
+            args.push('INDEXMISSING');
         }
     }
 }
@@ -506,6 +555,14 @@ export function pushSearchOptions(
         args.push('DIALECT', options.DIALECT.toString());
     }
 
+    if (options?.RETURN?.length === 0) {
+        args.preserve = true;
+    }
+
+    if (options?.TIMEOUT !== undefined) {
+        args.push('TIMEOUT', options.TIMEOUT.toString());
+    }
+
     return args;
 }
 
diff --git a/packages/search/lib/index.ts b/packages/search/lib/index.ts
index 296136021ef..0f84c11466f 100644
--- a/packages/search/lib/index.ts
+++ b/packages/search/lib/index.ts
@@ -1,5 +1,5 @@
 export { default } from './commands';
 
-export { RediSearchSchema, SchemaFieldTypes, SchemaTextFieldPhonetics, SearchReply, VectorAlgorithms } from './commands';
-export { AggregateSteps, AggregateGroupByReducers } from './commands/AGGREGATE';
+export { RediSearchSchema, RedisSearchLanguages, SchemaFieldTypes, SchemaTextFieldPhonetics, SearchReply, VectorAlgorithms } from './commands';
+export { AggregateGroupByReducers, AggregateSteps } from './commands/AGGREGATE';
 export { SearchOptions } from './commands/SEARCH';
diff --git a/packages/search/package.json b/packages/search/package.json
index 64591968715..aaf9bc50f11 100644
--- a/packages/search/package.json
+++ b/packages/search/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/search",
-  "version": "1.1.0",
+  "version": "1.2.0",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -18,12 +18,24 @@
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
     "@redis/test-utils": "*",
-    "@types/node": "^18.11.6",
+    "@types/node": "^20.6.2",
     "nyc": "^15.1.0",
-    "release-it": "^15.5.0",
+    "release-it": "^16.1.5",
     "source-map-support": "^0.5.21",
     "ts-node": "^10.9.1",
-    "typedoc": "^0.23.18",
-    "typescript": "^4.8.4"
-  }
+    "typedoc": "^0.25.1",
+    "typescript": "^5.2.2"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/redis/node-redis.git"
+  },
+  "bugs": {
+    "url": "https://github.com/redis/node-redis/issues"
+  },
+  "homepage": "https://github.com/redis/node-redis/tree/master/packages/search",
+  "keywords": [
+    "redis",
+    "RediSearch"
+  ]
 }
diff --git a/packages/test-utils/lib/dockers.ts b/packages/test-utils/lib/dockers.ts
index 8f0be95b094..a7e1c610eee 100644
--- a/packages/test-utils/lib/dockers.ts
+++ b/packages/test-utils/lib/dockers.ts
@@ -1,8 +1,8 @@
 import { createConnection } from 'net';
 import { once } from 'events';
-import { RedisModules, RedisFunctions, RedisScripts } from '@redis/client/dist/lib/commands';
-import RedisClient, { RedisClientType } from '@redis/client/dist/lib/client';
+import RedisClient from '@redis/client/dist/lib/client';
 import { promiseTimeout } from '@redis/client/dist/lib/utils';
+import { ClusterSlotsReply } from '@redis/client/dist/lib/commands/CLUSTER_SLOTS';
 import * as path from 'path';
 import { promisify } from 'util';
 import { exec } from 'child_process';
@@ -64,7 +64,7 @@ async function spawnRedisServerDocker({ image, version }: RedisServerDockerConfi
     }
 
     while (await isPortAvailable(port)) {
-        await promiseTimeout(500);
+        await promiseTimeout(50);
     }
 
     return {
@@ -102,17 +102,65 @@ after(() => {
 });
 
 export interface RedisClusterDockersConfig extends RedisServerDockerConfig {
-    numberOfNodes?: number;
+    numberOfMasters?: number;
+    numberOfReplicas?: number;
 }
 
-async function spawnRedisClusterNodeDocker(
+async function spawnRedisClusterNodeDockers(
     dockersConfig: RedisClusterDockersConfig,
     serverArguments: Array<string>,
     fromSlot: number,
-    toSlot: number,
-    waitForState: boolean,
-    meetPort?: number
-): Promise<RedisServerDocker> {
+    toSlot: number
+) {
+    const range: Array<number> = [];
+    for (let i = fromSlot; i < toSlot; i++) {
+        range.push(i);
+    }
+
+    const master = await spawnRedisClusterNodeDocker(
+        dockersConfig,
+        serverArguments
+    );
+
+    await master.client.clusterAddSlots(range);
+
+    if (!dockersConfig.numberOfReplicas) return [master];
+    
+    const replicasPromises: Array<ReturnType<typeof spawnRedisClusterNodeDocker>> = [];
+    for (let i = 0; i < (dockersConfig.numberOfReplicas ?? 0); i++) {
+        replicasPromises.push(
+            spawnRedisClusterNodeDocker(dockersConfig, [
+                ...serverArguments,
+                '--cluster-enabled',
+                'yes',
+                '--cluster-node-timeout',
+                '5000'
+            ]).then(async replica => {
+                await replica.client.clusterMeet('127.0.0.1', master.docker.port);
+
+                while ((await replica.client.clusterSlots()).length === 0) {
+                    await promiseTimeout(50);
+                }
+
+                await replica.client.clusterReplicate(
+                    await master.client.clusterMyId()
+                );
+
+                return replica;
+            })
+        );
+    }
+
+    return [
+        master,
+        ...await Promise.all(replicasPromises)
+    ];
+}
+
+async function spawnRedisClusterNodeDocker(
+    dockersConfig: RedisClusterDockersConfig,
+    serverArguments: Array<string>
+) {
     const docker = await spawnRedisServerDocker(dockersConfig, [
             ...serverArguments,
             '--cluster-enabled',
@@ -128,78 +176,64 @@ async function spawnRedisClusterNodeDocker(
 
     await client.connect();
 
-    try {
-        const range = [];
-        for (let i = fromSlot; i < toSlot; i++) {
-            range.push(i);
-        }
-
-        const promises: Array<Promise<unknown>> = [client.clusterAddSlots(range)];
-
-        if (meetPort) {
-            promises.push(client.clusterMeet('127.0.0.1', meetPort));
-        }
-
-        if (waitForState) {
-            promises.push(waitForClusterState(client));
-        }
-
-        await Promise.all(promises);
-
-        return docker;
-    } finally {
-        await client.disconnect();
-    }
-}
-
-async function waitForClusterState<
-    M extends RedisModules,
-    F extends RedisFunctions,
-    S extends RedisScripts
->(client: RedisClientType<M, F, S>): Promise<void> {
-    while ((await client.clusterInfo()).state !== 'ok') {
-        await promiseTimeout(500);
-    }
+    return {
+        docker,
+        client
+    };
 }
 
 const SLOTS = 16384;
 
-async function spawnRedisClusterDockers(dockersConfig: RedisClusterDockersConfig, serverArguments: Array<string>): Promise<Array<RedisServerDocker>> {
-    const numberOfNodes = dockersConfig.numberOfNodes ?? 3,
-        slotsPerNode = Math.floor(SLOTS / numberOfNodes),
-        dockers: Array<RedisServerDocker> = [];
-    for (let i = 0; i < numberOfNodes; i++) {
+async function spawnRedisClusterDockers(
+    dockersConfig: RedisClusterDockersConfig,
+    serverArguments: Array<string>
+): Promise<Array<RedisServerDocker>> {
+    const numberOfMasters = dockersConfig.numberOfMasters ?? 2,
+        slotsPerNode = Math.floor(SLOTS / numberOfMasters),
+        spawnPromises: Array<ReturnType<typeof spawnRedisClusterNodeDockers>> = [];
+    for (let i = 0; i < numberOfMasters; i++) {
         const fromSlot = i * slotsPerNode,
-            [ toSlot, waitForState ] = i === numberOfNodes - 1 ? [SLOTS, true] : [fromSlot + slotsPerNode, false];
-        dockers.push(
-            await spawnRedisClusterNodeDocker(
+            toSlot = i === numberOfMasters - 1 ? SLOTS : fromSlot + slotsPerNode;
+        spawnPromises.push(
+            spawnRedisClusterNodeDockers(
                 dockersConfig,
                 serverArguments,
                 fromSlot,
-                toSlot,
-                waitForState,
-                i === 0 ? undefined : dockers[i - 1].port
+                toSlot
             )
         );
     }
 
-    const client = RedisClient.create({
-        socket: {
-            port: dockers[0].port
-        }
-    });
+    const nodes = (await Promise.all(spawnPromises)).flat(),
+        meetPromises: Array<Promise<unknown>> = [];
+    for (let i = 1; i < nodes.length; i++) {
+        meetPromises.push(
+            nodes[i].client.clusterMeet('127.0.0.1', nodes[0].docker.port)
+        );
+    }
 
-    await client.connect();
+    await Promise.all(meetPromises);
 
-    try {
-        while ((await client.clusterInfo()).state !== 'ok') {
-            await promiseTimeout(500);
-        }
-    } finally {
-        await client.disconnect();
+    await Promise.all(
+        nodes.map(async ({ client }) => {
+            while (totalNodes(await client.clusterSlots()) !== nodes.length) {
+                await promiseTimeout(50);
+            }
+        
+            return client.disconnect();
+        })
+    );
+
+    return nodes.map(({ docker }) => docker);
+}
+
+function totalNodes(slots: ClusterSlotsReply) {
+    let total = slots.length;
+    for (const slot of slots) {
+        total += slot.replicas.length;
     }
 
-    return dockers;
+    return total;
 }
 
 const RUNNING_CLUSTERS = new Map<Array<string>, ReturnType<typeof spawnRedisClusterDockers>>();
diff --git a/packages/test-utils/lib/index.ts b/packages/test-utils/lib/index.ts
index 7b9494c8d66..b9195c5717a 100644
--- a/packages/test-utils/lib/index.ts
+++ b/packages/test-utils/lib/index.ts
@@ -9,7 +9,7 @@ import { hideBin } from 'yargs/helpers';
 interface TestUtilsConfig {
     dockerImageName: string;
     dockerImageVersionArgument: string;
-    defaultDockerVersion: string;
+    defaultDockerVersion?: string;
 }
 
 interface CommonTestOptions {
@@ -33,7 +33,8 @@ interface ClusterTestOptions<
 > extends CommonTestOptions {
     serverArguments: Array<string>;
     clusterConfiguration?: Partial<RedisClusterOptions<M, F, S>>;
-    numberOfNodes?: number;
+    numberOfMasters?: number;
+    numberOfReplicas?: number;
 }
 
 interface Version {
@@ -43,7 +44,7 @@ interface Version {
 
 export default class TestUtils {
     static #parseVersionNumber(version: string): Array<number> {
-        if (version === 'edge') return [Infinity];
+        if (version === 'latest' || version === 'edge') return [Infinity];
 
         const dashIndex = version.indexOf('-');
         return (dashIndex === -1 ? version : version.substring(0, dashIndex))
@@ -58,7 +59,7 @@ export default class TestUtils {
             });
     }
 
-    static #getVersion(argumentName: string, defaultVersion: string): Version {
+    static #getVersion(argumentName: string, defaultVersion = 'latest'): Version {
         return yargs(hideBin(process.argv))
             .option(argumentName, {
                 type: 'string',
@@ -163,9 +164,13 @@ export default class TestUtils {
         M extends RedisModules,
         F extends RedisFunctions,
         S extends RedisScripts
-    >(cluster: RedisClusterType<M, F, S>): Promise<void> {
-        await Promise.all(
-            cluster.getMasters().map(({ client }) => client.flushAll())
+    >(cluster: RedisClusterType<M, F, S>): Promise<unknown> {
+        return Promise.all(
+            cluster.masters.map(async ({ client }) => {
+                if (client) {
+                    await (await client).flushAll();
+                }
+            })
         );
     }
 
@@ -186,7 +191,8 @@ export default class TestUtils {
 
                 dockersPromise = spawnRedisCluster({
                     ...dockerImage,
-                    numberOfNodes: options?.numberOfNodes
+                    numberOfMasters: options?.numberOfMasters,
+                    numberOfReplicas: options?.numberOfReplicas 
                 }, options.serverArguments);
                 return dockersPromise;
             });
@@ -197,15 +203,15 @@ export default class TestUtils {
 
             const dockers = await dockersPromise,
                 cluster = RedisCluster.create({
-                    ...options.clusterConfiguration,
                     rootNodes: dockers.map(({ port }) => ({
                         socket: {
                             port
                         }
-                    }))
+                    })),
+                    minimizeConnections: true,
+                    ...options.clusterConfiguration
                 });
 
-
             await cluster.connect();
 
             try {
diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json
index 4549aa71a81..2f4e366536e 100644
--- a/packages/test-utils/package.json
+++ b/packages/test-utils/package.json
@@ -11,14 +11,14 @@
   },
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
-    "@types/mocha": "^10.0.0",
-    "@types/node": "^18.11.6",
-    "@types/yargs": "^17.0.13",
-    "mocha": "^10.1.0",
+    "@types/mocha": "^10.0.1",
+    "@types/node": "^20.6.2",
+    "@types/yargs": "^17.0.24",
+    "mocha": "^10.2.0",
     "nyc": "^15.1.0",
     "source-map-support": "^0.5.21",
     "ts-node": "^10.9.1",
-    "typescript": "^4.8.4",
-    "yargs": "^17.6.0"
+    "typescript": "^5.2.2",
+    "yargs": "^17.7.2"
   }
 }
diff --git a/packages/time-series/lib/commands/ADD.spec.ts b/packages/time-series/lib/commands/ADD.spec.ts
index 94ad30627f8..07e67c1adec 100644
--- a/packages/time-series/lib/commands/ADD.spec.ts
+++ b/packages/time-series/lib/commands/ADD.spec.ts
@@ -57,16 +57,26 @@ describe('ADD', () => {
             );
         });
 
-        it('with RETENTION, ENCODING, CHUNK_SIZE, ON_DUPLICATE, LABELS', () => {
+        it('with IGNORE', () => {
+          assert.deepEqual(
+            transformArguments('key', '*', 1, {
+              IGNORE: { MAX_TIME_DIFF: 1, MAX_VAL_DIFF: 1}
+            }),
+            ['TS.ADD', 'key', '*', '1', 'IGNORE', '1', '1']
+          )
+        });
+
+        it('with RETENTION, ENCODING, CHUNK_SIZE, ON_DUPLICATE, LABELS, IGNORE', () => {
             assert.deepEqual(
                 transformArguments('key', '*', 1, {
                     RETENTION: 1,
                     ENCODING: TimeSeriesEncoding.UNCOMPRESSED,
                     CHUNK_SIZE: 1,
                     ON_DUPLICATE: TimeSeriesDuplicatePolicies.BLOCK,
-                    LABELS: { label: 'value' }
+                    LABELS: { label: 'value' },
+                    IGNORE: { MAX_TIME_DIFF: 1, MAX_VAL_DIFF: 1}
                 }),
-                ['TS.ADD', 'key', '*', '1', 'RETENTION', '1', 'ENCODING', 'UNCOMPRESSED', 'CHUNK_SIZE', '1', 'ON_DUPLICATE', 'BLOCK', 'LABELS', 'label', 'value']
+                ['TS.ADD', 'key', '*', '1', 'RETENTION', '1', 'ENCODING', 'UNCOMPRESSED', 'CHUNK_SIZE', '1', 'ON_DUPLICATE', 'BLOCK', 'LABELS', 'label', 'value', 'IGNORE', '1', '1']
             );
         });
     });
diff --git a/packages/time-series/lib/commands/ADD.ts b/packages/time-series/lib/commands/ADD.ts
index 1988a964513..3ed185b9b75 100644
--- a/packages/time-series/lib/commands/ADD.ts
+++ b/packages/time-series/lib/commands/ADD.ts
@@ -8,14 +8,21 @@ import {
     Labels,
     pushLabelsArgument,
     Timestamp,
+    pushIgnoreArgument,
 } from '.';
 
+export interface TsIgnoreOptions {
+  MAX_TIME_DIFF: number;
+  MAX_VAL_DIFF: number;
+}
+
 interface AddOptions {
     RETENTION?: number;
     ENCODING?: TimeSeriesEncoding;
     CHUNK_SIZE?: number;
     ON_DUPLICATE?: TimeSeriesDuplicatePolicies;
     LABELS?: Labels;
+    IGNORE?: TsIgnoreOptions;
 }
 
 export const FIRST_KEY_INDEX = 1;
@@ -40,6 +47,8 @@ export function transformArguments(key: string, timestamp: Timestamp, value: num
 
     pushLabelsArgument(args, options?.LABELS);
 
+    pushIgnoreArgument(args, options?.IGNORE);
+
     return args;
 }
 
diff --git a/packages/time-series/lib/commands/ALTER.spec.ts b/packages/time-series/lib/commands/ALTER.spec.ts
index cd066533aa4..7add3eeec3a 100644
--- a/packages/time-series/lib/commands/ALTER.spec.ts
+++ b/packages/time-series/lib/commands/ALTER.spec.ts
@@ -48,15 +48,25 @@ describe('ALTER', () => {
             );
         });
 
-        it('with RETENTION, CHUNK_SIZE, DUPLICATE_POLICY, LABELS', () => {
+        it('with IGNORE with MAX_TIME_DIFF', () => {
+            assert.deepEqual(
+                transformArguments('key', {
+                IGNORE: { MAX_TIME_DIFF: 1, MAX_VAL_DIFF: 1}
+                }),
+                ['TS.ALTER', 'key', 'IGNORE', '1', '1']
+            )
+        });
+
+        it('with RETENTION, CHUNK_SIZE, DUPLICATE_POLICY, LABELS, IGNORE', () => {
             assert.deepEqual(
                 transformArguments('key', {
                     RETENTION: 1,
                     CHUNK_SIZE: 1,
                     DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.BLOCK,
-                    LABELS: { label: 'value' }
+                    LABELS: { label: 'value' },
+                    IGNORE: { MAX_TIME_DIFF: 1, MAX_VAL_DIFF: 1}
                 }),
-                ['TS.ALTER', 'key', 'RETENTION', '1', 'CHUNK_SIZE', '1', 'DUPLICATE_POLICY', 'BLOCK', 'LABELS', 'label', 'value']
+                ['TS.ALTER', 'key', 'RETENTION', '1', 'CHUNK_SIZE', '1', 'DUPLICATE_POLICY', 'BLOCK', 'LABELS', 'label', 'value', 'IGNORE', '1', '1']
             );
         });
     });
diff --git a/packages/time-series/lib/commands/ALTER.ts b/packages/time-series/lib/commands/ALTER.ts
index 7b9e1e774c6..576153a0cca 100644
--- a/packages/time-series/lib/commands/ALTER.ts
+++ b/packages/time-series/lib/commands/ALTER.ts
@@ -1,4 +1,5 @@
-import { pushRetentionArgument, Labels, pushLabelsArgument, TimeSeriesDuplicatePolicies, pushChunkSizeArgument, pushDuplicatePolicy } from '.';
+import { pushRetentionArgument, Labels, pushLabelsArgument, TimeSeriesDuplicatePolicies, pushChunkSizeArgument, pushDuplicatePolicy, pushIgnoreArgument } from '.';
+import { TsIgnoreOptions } from './ADD';
 
 export const FIRST_KEY_INDEX = 1;
 
@@ -7,6 +8,7 @@ interface AlterOptions {
     CHUNK_SIZE?: number;
     DUPLICATE_POLICY?: TimeSeriesDuplicatePolicies;
     LABELS?: Labels;
+    IGNORE?: TsIgnoreOptions;
 }
 
 export function transformArguments(key: string, options?: AlterOptions): Array<string> {
@@ -20,6 +22,8 @@ export function transformArguments(key: string, options?: AlterOptions): Array<s
 
     pushLabelsArgument(args, options?.LABELS);
 
+    pushIgnoreArgument(args, options?.IGNORE);
+
     return args;
 }
 
diff --git a/packages/time-series/lib/commands/CREATE.spec.ts b/packages/time-series/lib/commands/CREATE.spec.ts
index fe1da99b096..eb7a1c6a637 100644
--- a/packages/time-series/lib/commands/CREATE.spec.ts
+++ b/packages/time-series/lib/commands/CREATE.spec.ts
@@ -56,17 +56,27 @@ describe('CREATE', () => {
                 ['TS.CREATE', 'key', 'LABELS', 'label', 'value']
             );
         });
+   
+        it('with IGNORE with MAX_TIME_DIFF', () => {
+            assert.deepEqual(
+                transformArguments('key', {
+                    IGNORE: { MAX_TIME_DIFF: 1, MAX_VAL_DIFF: 1}
+                }),
+                ['TS.CREATE', 'key', 'IGNORE', '1', '1']
+            )
+        });
 
-        it('with RETENTION, ENCODING, CHUNK_SIZE, DUPLICATE_POLICY, LABELS', () => {
+        it('with RETENTION, ENCODING, CHUNK_SIZE, DUPLICATE_POLICY, LABELS, IGNORE', () => {
             assert.deepEqual(
                 transformArguments('key', {
                     RETENTION: 1,
                     ENCODING: TimeSeriesEncoding.UNCOMPRESSED,
                     CHUNK_SIZE: 1,
                     DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.BLOCK,
-                    LABELS: { label: 'value' }
+                    LABELS: { label: 'value' },
+                    IGNORE: { MAX_TIME_DIFF: 1, MAX_VAL_DIFF: 1}
                 }),
-                ['TS.CREATE', 'key', 'RETENTION', '1', 'ENCODING', 'UNCOMPRESSED', 'CHUNK_SIZE', '1', 'DUPLICATE_POLICY', 'BLOCK', 'LABELS', 'label', 'value']
+                ['TS.CREATE', 'key', 'RETENTION', '1', 'ENCODING', 'UNCOMPRESSED', 'CHUNK_SIZE', '1', 'DUPLICATE_POLICY', 'BLOCK', 'LABELS', 'label', 'value', 'IGNORE', '1', '1']
             );
         });
     });
diff --git a/packages/time-series/lib/commands/CREATE.ts b/packages/time-series/lib/commands/CREATE.ts
index a360950feff..a84d4b5f9fb 100644
--- a/packages/time-series/lib/commands/CREATE.ts
+++ b/packages/time-series/lib/commands/CREATE.ts
@@ -6,8 +6,10 @@ import {
     TimeSeriesDuplicatePolicies,
     Labels,
     pushLabelsArgument,
-    pushDuplicatePolicy
+    pushDuplicatePolicy,
+    pushIgnoreArgument
 } from '.';
+import { TsIgnoreOptions } from './ADD';
 
 export const FIRST_KEY_INDEX = 1;
 
@@ -17,6 +19,7 @@ interface CreateOptions {
     CHUNK_SIZE?: number;
     DUPLICATE_POLICY?: TimeSeriesDuplicatePolicies;
     LABELS?: Labels;
+    IGNORE?: TsIgnoreOptions;
 }
 
 export function transformArguments(key: string, options?: CreateOptions): Array<string> {
@@ -32,6 +35,8 @@ export function transformArguments(key: string, options?: CreateOptions): Array<
 
     pushLabelsArgument(args, options?.LABELS);
 
+    pushIgnoreArgument(args, options?.IGNORE);
+
     return args;
 }
 
diff --git a/packages/time-series/lib/commands/index.ts b/packages/time-series/lib/commands/index.ts
index 19cd075ba49..ca382498060 100644
--- a/packages/time-series/lib/commands/index.ts
+++ b/packages/time-series/lib/commands/index.ts
@@ -127,8 +127,14 @@ export function transformTimestampArgument(timestamp: Timestamp): string {
     ).toString();
 }
 
+export function pushIgnoreArgument(args: RedisCommandArguments, ignore?: ADD.TsIgnoreOptions) {
+  if (ignore !== undefined) {
+    args.push('IGNORE', ignore.MAX_TIME_DIFF.toString(), ignore.MAX_VAL_DIFF.toString());
+  }
+}
+
 export function pushRetentionArgument(args: RedisCommandArguments, retention?: number): RedisCommandArguments {
-    if (retention) {
+    if (retention !== undefined) {
         args.push(
             'RETENTION',
             retention.toString()
@@ -144,7 +150,7 @@ export enum TimeSeriesEncoding {
 }
 
 export function pushEncodingArgument(args: RedisCommandArguments, encoding?: TimeSeriesEncoding): RedisCommandArguments {
-    if (encoding) {
+    if (encoding !== undefined) {
         args.push(
             'ENCODING',
             encoding
@@ -155,7 +161,7 @@ export function pushEncodingArgument(args: RedisCommandArguments, encoding?: Tim
 }
 
 export function pushChunkSizeArgument(args: RedisCommandArguments, chunkSize?: number): RedisCommandArguments {
-    if (chunkSize) {
+    if (chunkSize !== undefined) {
         args.push(
             'CHUNK_SIZE',
             chunkSize.toString()
@@ -166,7 +172,7 @@ export function pushChunkSizeArgument(args: RedisCommandArguments, chunkSize?: n
 }
 
 export function pushDuplicatePolicy(args: RedisCommandArguments, duplicatePolicy?: TimeSeriesDuplicatePolicies): RedisCommandArguments {
-    if (duplicatePolicy) {
+    if (duplicatePolicy !== undefined) {
         args.push(
             'DUPLICATE_POLICY',
             duplicatePolicy
diff --git a/packages/time-series/lib/test-utils.ts b/packages/time-series/lib/test-utils.ts
index da883906028..6d534ccccef 100644
--- a/packages/time-series/lib/test-utils.ts
+++ b/packages/time-series/lib/test-utils.ts
@@ -3,8 +3,7 @@ import TimeSeries from '.';
 
 export default new TestUtils({
     dockerImageName: 'redislabs/redistimeseries',
-    dockerImageVersionArgument: 'timeseries-version',
-    defaultDockerVersion: '1.8.0'
+    dockerImageVersionArgument: 'timeseries-version'
 });
 
 export const GLOBAL = {
diff --git a/packages/time-series/package.json b/packages/time-series/package.json
index 8f0530fb486..65ee1e99c23 100644
--- a/packages/time-series/package.json
+++ b/packages/time-series/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/time-series",
-  "version": "1.0.4",
+  "version": "1.1.0",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -18,12 +18,24 @@
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
     "@redis/test-utils": "*",
-    "@types/node": "^18.11.6",
+    "@types/node": "^20.6.2",
     "nyc": "^15.1.0",
-    "release-it": "^15.5.0",
+    "release-it": "^16.1.5",
     "source-map-support": "^0.5.21",
     "ts-node": "^10.9.1",
-    "typedoc": "^0.23.18",
-    "typescript": "^4.8.4"
-  }
+    "typedoc": "^0.25.1",
+    "typescript": "^5.2.2"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/redis/node-redis.git"
+  },
+  "bugs": {
+    "url": "https://github.com/redis/node-redis/issues"
+  },
+  "homepage": "https://github.com/redis/node-redis/tree/master/packages/time-series",
+  "keywords": [
+    "redis",
+    "RedisTimeSeries"
+  ]
 }
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 68325e51dcc..1157be947b9 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -4,7 +4,8 @@
     "declaration": true,
     "allowJs": true,
     "useDefineForClassFields": true,
-    "esModuleInterop": false
+    "esModuleInterop": false,
+    "resolveJsonModule": true
   },
   "ts-node": {
     "files": true

From c1edc2e71842280f008869a0558cf00d8774fd88 Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Wed, 23 Oct 2024 07:48:36 -0700
Subject: [PATCH 16/20] DOC-4039: add TCEs to the query pages - reissue (#2846)

---
 doctests/data/query_vector.json | 3989 ++++++++++++++++++++++++++++++-
 doctests/package.json           |    3 +-
 doctests/query-agg.js           |  139 ++
 doctests/query-combined.js      |  192 ++
 doctests/query-ft.js            |   84 +
 doctests/query-geo.js           |   82 +
 doctests/query-range.js         |   98 +
 doctests/query-vector.js        |  111 +
 8 files changed, 4617 insertions(+), 81 deletions(-)
 create mode 100644 doctests/query-agg.js
 create mode 100644 doctests/query-combined.js
 create mode 100644 doctests/query-ft.js
 create mode 100644 doctests/query-geo.js
 create mode 100644 doctests/query-range.js
 create mode 100644 doctests/query-vector.js

diff --git a/doctests/data/query_vector.json b/doctests/data/query_vector.json
index 0d128bbedb1..625479e111b 100644
--- a/doctests/data/query_vector.json
+++ b/doctests/data/query_vector.json
@@ -1,123 +1,3952 @@
 [
   {
-    "model": "Jigger",
     "brand": "Velorim",
+    "condition": "new",
+    "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids\u2019 pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.",
+    "description_embeddings": [
+      -0.026918452233076096,
+      0.07200391590595245,
+      0.019199736416339874,
+      -0.024749649688601494,
+      -0.09264523535966873,
+      0.017702950164675713,
+      0.11252444237470627,
+      0.09377790987491608,
+      0.005099582951515913,
+      0.07054618746042252,
+      0.0025260779075324535,
+      -0.04007257893681526,
+      0.013598357327282429,
+      0.03940897434949875,
+      -0.0069704861380159855,
+      0.057934146374464035,
+      0.15386416018009186,
+      0.04337097704410553,
+      0.07119690626859665,
+      -0.048173222690820694,
+      -0.09069827198982239,
+      -0.016886970028281212,
+      -0.04425429925322533,
+      -0.019464140757918358,
+      -0.027470778673887253,
+      0.005336642265319824,
+      -0.09170512855052948,
+      0.03556380048394203,
+      0.023559197783470154,
+      -0.03628315031528473,
+      -0.04448218643665314,
+      0.011364061385393143,
+      0.009603296406567097,
+      -0.04861818626523018,
+      -0.03343017399311066,
+      -0.01483147218823433,
+      0.06086479872465134,
+      0.02109363302588463,
+      -0.025959225371479988,
+      0.014000430703163147,
+      -0.00846729427576065,
+      0.07305800914764404,
+      0.02457829751074314,
+      -0.12663941085338593,
+      0.010544337332248688,
+      0.013315590098500252,
+      0.07280771434307098,
+      -0.08232685923576355,
+      0.0040486594662070274,
+      -0.026350753381848335,
+      0.06408613175153732,
+      -0.01415738184005022,
+      0.04628903791308403,
+      -0.02050374448299408,
+      0.04177685081958771,
+      -0.09207800775766373,
+      -0.005421833600848913,
+      -0.005136478692293167,
+      -0.024564260616898537,
+      0.026354163885116577,
+      -0.05851329490542412,
+      0.03147275745868683,
+      -0.02183554694056511,
+      0.03346295654773712,
+      -0.02240697667002678,
+      -0.09603817760944366,
+      -0.02274233102798462,
+      -0.039677977561950684,
+      0.007695100735872984,
+      0.039304088801145554,
+      -0.017668871209025383,
+      0.022897064685821533,
+      -0.039273541420698166,
+      0.08864572644233704,
+      -0.04432578384876251,
+      -0.06769558042287827,
+      0.06696884334087372,
+      0.07118263095617294,
+      -0.024863263592123985,
+      0.01151553075760603,
+      -0.11591693758964539,
+      -0.025131937116384506,
+      0.052269868552684784,
+      -0.03035089746117592,
+      0.00906881783157587,
+      0.04585501551628113,
+      0.038361817598342896,
+      0.03026638925075531,
+      0.015340524725615978,
+      -0.006911538541316986,
+      0.022395918145775795,
+      0.13969141244888306,
+      0.047686025500297546,
+      0.05438247323036194,
+      0.02779674343764782,
+      -0.04191797226667404,
+      -0.021741557866334915,
+      0.003305602353066206,
+      -0.11100355535745621,
+      0.016258426010608673,
+      0.06977421790361404,
+      0.08189859241247177,
+      0.0966871827840805,
+      0.03519754856824875,
+      0.05674563720822334,
+      0.034512776881456375,
+      0.07052291929721832,
+      -0.06342307478189468,
+      0.051868196576833725,
+      -0.013776403851807117,
+      -0.007541927974671125,
+      -0.043183840811252594,
+      0.021481933072209358,
+      0.0380198135972023,
+      -0.07870583236217499,
+      -0.10873759537935257,
+      -0.08491706103086472,
+      0.03155837208032608,
+      -0.03790571913123131,
+      0.041968367993831635,
+      -0.00593406381085515,
+      0.036538854241371155,
+      -0.004705581348389387,
+      0.004229994490742683,
+      -0.00729013979434967,
+      -0.019296232610940933,
+      -0.014331319369375706,
+      -4.401502220942261e-34,
+      -0.0067550260573625565,
+      0.07402423769235611,
+      -0.012888211756944656,
+      -0.055266380310058594,
+      0.04810081049799919,
+      0.005175809375941753,
+      -0.004325157031416893,
+      -0.10392399877309799,
+      -0.03650582954287529,
+      0.07477248460054398,
+      0.0022102247457951307,
+      -0.05040738359093666,
+      -0.003033560933545232,
+      0.060498371720314026,
+      0.08619660884141922,
+      -0.04577762633562088,
+      -0.10468175262212753,
+      -0.07177772372961044,
+      -0.05756700038909912,
+      -0.02839704230427742,
+      -0.028650879859924316,
+      -0.010213681496679783,
+      0.008074316196143627,
+      0.03448071703314781,
+      -0.025478240102529526,
+      -0.029753824695944786,
+      0.05397271364927292,
+      -0.0006062929751351476,
+      -0.03292117267847061,
+      0.040799956768751144,
+      -0.0933983102440834,
+      -0.026921836659312248,
+      0.00327915046364069,
+      -0.025635670870542526,
+      -0.057946983724832535,
+      -0.06664302200078964,
+      0.04280361905694008,
+      -0.027111517265439034,
+      -0.08359260112047195,
+      0.03483080118894577,
+      0.023318039253354073,
+      -0.08598511666059494,
+      -0.08378149569034576,
+      0.054067932069301605,
+      -0.014853178523480892,
+      -0.05498708039522171,
+      0.0711284726858139,
+      0.12539872527122498,
+      -0.04355800896883011,
+      -0.027553806081414223,
+      -0.009111037477850914,
+      -0.058482203632593155,
+      0.07053986191749573,
+      -0.009027705527842045,
+      -0.017481567338109016,
+      0.011404255405068398,
+      0.06084389239549637,
+      -0.028110956773161888,
+      -0.08594057708978653,
+      0.05215488001704216,
+      -0.07651112973690033,
+      -0.027076181024312973,
+      -0.01357623003423214,
+      -0.01263132132589817,
+      -0.0193876251578331,
+      0.013576658442616463,
+      0.038156066089868546,
+      -0.04309772700071335,
+      -0.04051121696829796,
+      -0.025885144248604774,
+      -0.003073574509471655,
+      -0.0003303807170595974,
+      0.08043289929628372,
+      -0.039484549313783646,
+      0.10091833025217056,
+      -0.04735022410750389,
+      0.027813943102955818,
+      -0.0038837436586618423,
+      -0.05234759673476219,
+      -0.00716474698856473,
+      0.016360750421881676,
+      -0.025806615129113197,
+      -0.03212691470980644,
+      -0.08456144481897354,
+      -0.019326699897646904,
+      -0.03228791803121567,
+      0.07633069902658463,
+      -0.07643644511699677,
+      -0.03988131135702133,
+      0.02396279387176037,
+      -0.055901359766721725,
+      0.009231535717844963,
+      0.0344320572912693,
+      0.07486359030008316,
+      -0.03505600243806839,
+      -2.324423447670953e-34,
+      -0.04453577473759651,
+      0.06512241810560226,
+      0.03920532390475273,
+      0.062222111970186234,
+      -0.015745285898447037,
+      -0.017774563282728195,
+      0.08228200674057007,
+      -0.05798694118857384,
+      -0.042758435010910034,
+      -0.018822822719812393,
+      -0.07607664912939072,
+      -0.02666221559047699,
+      0.036936040967702866,
+      -0.034714240580797195,
+      0.06992944329977036,
+      0.00530517753213644,
+      -0.0005260169273242354,
+      -0.03961028903722763,
+      0.08799499273300171,
+      -0.04191635549068451,
+      0.07468635588884354,
+      -0.010930310003459454,
+      -0.0611649826169014,
+      -0.04100184887647629,
+      0.07131826132535934,
+      0.03241356834769249,
+      -0.0545443594455719,
+      -0.005295638460665941,
+      -0.04712966829538345,
+      0.032524388283491135,
+      -0.05130890756845474,
+      -0.01299980841577053,
+      0.06523969769477844,
+      -0.011433755978941917,
+      0.018730396404862404,
+      0.047184932976961136,
+      -0.043041545897722244,
+      -0.03231072053313255,
+      -0.015864262357354164,
+      0.03991076350212097,
+      -0.017617924138903618,
+      -0.03504975512623787,
+      0.027346905320882797,
+      0.05564267560839653,
+      0.01610865257680416,
+      0.0470576174557209,
+      -0.010647954419255257,
+      0.13047614693641663,
+      -0.011055804789066315,
+      0.011903814040124416,
+      -0.01350466813892126,
+      -0.0019897734746336937,
+      0.053073540329933167,
+      0.0717632919549942,
+      0.007322370074689388,
+      -0.0206251572817564,
+      0.061210062354803085,
+      0.03184640407562256,
+      -0.035093698650598526,
+      -0.0026315131690353155,
+      -0.03291690722107887,
+      -0.04229205846786499,
+      -0.04241437837481499,
+      0.1091129332780838,
+      0.02229561097919941,
+      0.02223002351820469,
+      0.03949614241719246,
+      0.031568314880132675,
+      -0.07121116667985916,
+      -0.07664268463850021,
+      -0.04235681891441345,
+      -0.011173299513757229,
+      0.1190338209271431,
+      -0.09825095534324646,
+      -0.0375107042491436,
+      0.007167852018028498,
+      0.047537703067064285,
+      0.044423725455999374,
+      0.022106878459453583,
+      -0.02811007760465145,
+      0.033864255994558334,
+      0.0643145889043808,
+      0.03725901246070862,
+      -0.0497952364385128,
+      -0.021733446046710014,
+      0.023898839950561523,
+      -0.11254694312810898,
+      -0.06519465893507004,
+      0.04424642026424408,
+      0.09124527126550674,
+      0.006083414424210787,
+      0.09144245833158493,
+      0.02653978019952774,
+      -0.01318738516420126,
+      0.0480327382683754,
+      -3.0391063887691416e-08,
+      0.051376331597566605,
+      -0.0002709411783143878,
+      -0.03103259764611721,
+      -0.018394535407423973,
+      0.05002995952963829,
+      0.05086217448115349,
+      -0.07317503541707993,
+      -0.0172730665653944,
+      -0.08379635214805603,
+      0.1180257499217987,
+      0.08445936441421509,
+      -0.025030585005879402,
+      -0.01965731382369995,
+      0.046042654663324356,
+      0.03724817931652069,
+      0.028524605557322502,
+      0.061249297112226486,
+      -0.027382537722587585,
+      -0.0011134583037346601,
+      -0.001871297718025744,
+      -0.04395337030291557,
+      0.002261978341266513,
+      0.06950556486845016,
+      -0.024213269352912903,
+      -0.0782783254981041,
+      -0.10320401936769485,
+      -0.022083906456828117,
+      -0.04333319142460823,
+      -0.0334695503115654,
+      0.007842703722417355,
+      -0.03523677587509155,
+      0.08107997477054596,
+      0.00924254022538662,
+      -0.013395791873335838,
+      -0.019067300483584404,
+      -0.008446489460766315,
+      -0.1053837463259697,
+      0.06697141379117966,
+      0.06984667479991913,
+      0.007155571132898331,
+      -0.038544610142707825,
+      0.0132181691005826,
+      -0.004773592576384544,
+      -0.022143904119729996,
+      -0.09064015746116638,
+      -0.07600560784339905,
+      -0.042070601135492325,
+      -0.08189931511878967,
+      0.03302472084760666,
+      0.043238356709480286,
+      -0.01407547201961279,
+      -0.03778013586997986,
+      0.030578600242733955,
+      0.021573437377810478,
+      0.04664295166730881,
+      0.056082408875226974,
+      -0.07687672227621078,
+      -0.0018553169211372733,
+      -0.051700614392757416,
+      0.043752558529376984,
+      -0.02636834792792797,
+      0.05589277669787407,
+      0.05282546952366829,
+      -0.016411008313298225
+    ],
+    "model": "Jigger",
+    "pickup_zone": "POLYGON((-74.0610 40.7578, -73.9510 40.7578, -73.9510 40.6678, -74.0610 40.6678, -74.0610 40.7578))",
     "price": 270,
-    "type": "Kids bikes",
-    "specs": {
-      "material": "aluminium",
-      "weight": "10"
-    },
-    "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go. We say rare because this smokin’ little bike is not ideal for a nervous first-time rider, but it’s a true giddy up for a true speedster. The Jigger is a 12 inch lightweight kids bicycle and it will meet your little one’s need for speed. It’s a single speed bike that makes learning to pump pedals simple and intuitive. It even has  a handle in the bottom of the saddle so you can easily help your child during training!  The Jigger is among the most lightweight children’s bikes on the planet. It is designed so that 2-3 year-olds fit comfortably in a molded ride position that allows for efficient riding, balanced handling and agility. The Jigger’s frame design and gears work together so your buddingbiker can stand up out of the seat, stop rapidly, rip over trails and pump tracks. The Jigger’s is amazing on dirt or pavement. Your tike will speed down the bike path in no time. The Jigger will ship with a coaster brake. A freewheel kit is provided at no cost. "
+    "store_location": "-74.0060,40.7128"
   },
   {
-    "model": "Hillcraft",
     "brand": "Bicyk",
+    "condition": "used",
+    "description": "Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\" wheel bike is just too clumsy coming off a 24\" bike. The Hillcraft 26 is just the solution they need!",
+    "description_embeddings": [
+      -0.004883771762251854,
+      0.08099519461393356,
+      -0.022444017231464386,
+      0.05437565594911575,
+      -0.07422323524951935,
+      0.0066548739559948444,
+      -0.06268022209405899,
+      0.042389899492263794,
+      -0.03745086118578911,
+      0.058961447328329086,
+      0.025613723322749138,
+      -0.04209878668189049,
+      0.06861244142055511,
+      0.01983577199280262,
+      0.026353053748607635,
+      0.045618414878845215,
+      0.040685027837753296,
+      0.09574265778064728,
+      0.005801026243716478,
+      -0.027659950777888298,
+      -0.0223013274371624,
+      0.040641166269779205,
+      0.06608107686042786,
+      0.0691058486700058,
+      -0.03629102557897568,
+      0.035505786538124084,
+      -0.09211395680904388,
+      -0.011358118616044521,
+      -0.025078972801566124,
+      -0.017709167674183846,
+      0.07587391883134842,
+      0.08128049969673157,
+      0.060521550476551056,
+      -0.0845090001821518,
+      -0.03779749944806099,
+      0.030346086248755455,
+      0.017926080152392387,
+      0.003489845432341099,
+      -0.05622200667858124,
+      -0.06886664777994156,
+      -0.051538050174713135,
+      0.029196197167038918,
+      -0.0028146395925432444,
+      0.012419342994689941,
+      -0.06346380710601807,
+      -0.011617675423622131,
+      0.04980290308594704,
+      -0.0799335315823555,
+      0.016635078936815262,
+      0.07064730674028397,
+      0.04530491679906845,
+      -0.04372858256101608,
+      0.07056037336587906,
+      -0.05052798613905907,
+      -0.01064316462725401,
+      -0.04754374921321869,
+      -0.08878123015165329,
+      0.005363269243389368,
+      0.032587066292762756,
+      -0.05610528588294983,
+      -0.0012875061947852373,
+      -0.03215320408344269,
+      -0.0045777312479913235,
+      -0.026692084968090057,
+      -0.09758491814136505,
+      -0.046251099556684494,
+      0.03897765651345253,
+      -0.06587375700473785,
+      -0.013586618937551975,
+      -0.020807752385735512,
+      0.023367363959550858,
+      0.011167124845087528,
+      0.003386110533028841,
+      -0.024887114763259888,
+      -0.029615335166454315,
+      -0.02571641281247139,
+      -0.03150812163949013,
+      -0.0395360104739666,
+      -0.049686528742313385,
+      -0.023117102682590485,
+      -0.07580453157424927,
+      0.020851964130997658,
+      0.0917917937040329,
+      -0.038357049226760864,
+      0.05106140300631523,
+      -0.03367459401488304,
+      0.05801103636622429,
+      0.0628814697265625,
+      0.024997225031256676,
+      0.015594316646456718,
+      -0.01490987278521061,
+      0.07070998847484589,
+      -0.039144083857536316,
+      0.0657331570982933,
+      -0.053744420409202576,
+      -0.01675831526517868,
+      -0.008745769970119,
+      -0.07664742320775986,
+      -0.06751038879156113,
+      0.0023392336443066597,
+      0.018902592360973358,
+      0.06754770874977112,
+      0.07430258393287659,
+      0.0806465670466423,
+      -0.031056180596351624,
+      0.06557579338550568,
+      0.06529161334037781,
+      -0.03742394223809242,
+      0.0007822285988368094,
+      0.10523669421672821,
+      0.0038901956286281347,
+      -0.014934191480278969,
+      0.0647430568933487,
+      0.03438747301697731,
+      -0.046527378261089325,
+      0.014247977174818516,
+      -0.020184241235256195,
+      0.016480082646012306,
+      -0.05491460859775543,
+      0.07232335209846497,
+      -0.016330908983945847,
+      0.011368552222847939,
+      -0.001964043825864792,
+      0.0009170984267257154,
+      0.019140562042593956,
+      -0.002758787479251623,
+      -0.05629577115178108,
+      1.7957766384702998e-33,
+      -0.10579885542392731,
+      0.08271613717079163,
+      0.03821941837668419,
+      0.06078806892037392,
+      0.017647448927164078,
+      -0.07404755055904388,
+      0.06083450838923454,
+      -0.07097837328910828,
+      -0.01949647255241871,
+      -0.005204185377806425,
+      0.0160058680921793,
+      -0.03624944016337395,
+      0.065463587641716,
+      -0.04834574833512306,
+      0.09314870834350586,
+      -0.022509299218654633,
+      -0.047614336013793945,
+      -0.042122796177864075,
+      0.0014064351562410593,
+      0.08215921372175217,
+      0.0144058121368289,
+      -0.08526691794395447,
+      -0.01885370910167694,
+      0.020506983622908592,
+      -0.0041589876636862755,
+      -0.0928102508187294,
+      0.0965222716331482,
+      0.05469893291592598,
+      0.002785224001854658,
+      0.006347258575260639,
+      -0.09394793212413788,
+      -0.08587668836116791,
+      0.00999284815043211,
+      -0.015109539031982422,
+      0.035454027354717255,
+      -0.08842843770980835,
+      -0.015698572620749474,
+      0.05549640208482742,
+      -0.011119373142719269,
+      0.012295924127101898,
+      0.007523554377257824,
+      -0.03497130423784256,
+      -0.05309790000319481,
+      -0.021819932386279106,
+      0.011010204441845417,
+      0.0778549313545227,
+      0.122015580534935,
+      0.0451776348054409,
+      -0.0894458070397377,
+      0.0031173918396234512,
+      -0.003828236600384116,
+      0.0010151821188628674,
+      0.0007775757694616914,
+      -0.0007406148943118751,
+      0.0005911831394769251,
+      0.029611686244606972,
+      -0.010095393285155296,
+      -0.015750357881188393,
+      -0.08871200680732727,
+      0.06563369184732437,
+      0.052563928067684174,
+      -0.02150006778538227,
+      0.032858334481716156,
+      -0.039781685918569565,
+      -0.02986454777419567,
+      -0.017254218459129333,
+      0.013349524699151516,
+      0.04903600737452507,
+      -0.102760910987854,
+      0.027411801740527153,
+      -0.007306735496968031,
+      0.03547230362892151,
+      0.03793823719024658,
+      -0.014224819839000702,
+      0.004229242447763681,
+      -0.04914051666855812,
+      -0.05566011741757393,
+      -0.08426816016435623,
+      0.0378078892827034,
+      -0.02177048847079277,
+      0.037800222635269165,
+      0.01145790982991457,
+      -0.03493969514966011,
+      -0.06417357921600342,
+      -0.04812582954764366,
+      -0.030254419893026352,
+      -0.12552082538604736,
+      0.0017056012293323874,
+      -0.053679559379816055,
+      0.019939688965678215,
+      -0.04766315221786499,
+      -0.143480584025383,
+      -0.024615854024887085,
+      0.06507551670074463,
+      0.01710103265941143,
+      -2.55080180279124e-33,
+      -0.01073896698653698,
+      0.08023330569267273,
+      0.028500312939286232,
+      -0.033364687114953995,
+      0.018465891480445862,
+      -0.018969086930155754,
+      0.116150863468647,
+      -0.04905116185545921,
+      0.0067994301207363605,
+      -0.051097989082336426,
+      -0.047208935022354126,
+      0.003005147911608219,
+      -0.006951641291379929,
+      0.0299075860530138,
+      0.023957515135407448,
+      0.005555577110499144,
+      -0.020836569368839264,
+      0.013542957603931427,
+      0.09286782890558243,
+      -0.04009733721613884,
+      0.05567550286650658,
+      0.01991306059062481,
+      -0.16575683653354645,
+      -0.003300475887954235,
+      0.11635366082191467,
+      0.008300523273646832,
+      -0.1112738847732544,
+      0.05307481065392494,
+      0.009467027150094509,
+      0.11263766884803772,
+      -0.04102758690714836,
+      -0.0505208782851696,
+      0.1890914887189865,
+      -0.01593983918428421,
+      0.011381726711988449,
+      0.01095605455338955,
+      -0.08038999140262604,
+      -0.012621873058378696,
+      -0.005316049326211214,
+      0.017261112108826637,
+      0.03283751755952835,
+      -0.04533768445253372,
+      0.03397509828209877,
+      0.04211656376719475,
+      0.024692395702004433,
+      -0.02541458234190941,
+      0.02313675545156002,
+      0.02338019199669361,
+      -0.011879520490765572,
+      -0.05438990890979767,
+      0.03806900233030319,
+      0.01261812262237072,
+      0.02512892708182335,
+      -0.0028746703173965216,
+      -0.016077643260359764,
+      -0.032072994858026505,
+      -0.006427581422030926,
+      0.01777057908475399,
+      0.02934812381863594,
+      -0.05759994685649872,
+      -2.871774631785229e-05,
+      -0.03137838840484619,
+      -0.06273766607046127,
+      0.04409930482506752,
+      -0.05993351340293884,
+      0.007546861190348864,
+      0.0053585791029036045,
+      0.042325496673583984,
+      -0.007369876839220524,
+      0.04489513114094734,
+      -0.12103329598903656,
+      0.017391694709658623,
+      0.0304956566542387,
+      -0.034047987312078476,
+      0.02484256401658058,
+      -0.06834809482097626,
+      0.06508748978376389,
+      0.08324999362230301,
+      -0.020252887159585953,
+      -0.014722783118486404,
+      0.02126440405845642,
+      -0.05160334333777428,
+      0.045947108417749405,
+      0.022960059344768524,
+      0.023375188931822777,
+      -0.060902271419763565,
+      -0.05150751397013664,
+      -0.1094929575920105,
+      -0.04899677261710167,
+      0.09132419526576996,
+      0.051848214119672775,
+      -0.0077659315429627895,
+      0.0012422297149896622,
+      0.058530740439891815,
+      0.040777210146188736,
+      -3.354356081786136e-08,
+      0.025891084223985672,
+      -0.04088461399078369,
+      -0.06885679066181183,
+      0.01951301097869873,
+      0.047974348068237305,
+      0.04472370818257332,
+      0.004657004959881306,
+      0.001041706302203238,
+      -0.02763887122273445,
+      0.03814717009663582,
+      0.03166148066520691,
+      0.0063626947812736034,
+      0.09577886760234833,
+      0.06234167888760567,
+      0.0010398400481790304,
+      0.010609040968120098,
+      0.020408503711223602,
+      0.05596008151769638,
+      0.00923844799399376,
+      0.011290326714515686,
+      0.02393697388470173,
+      -0.03378620743751526,
+      0.010788901709020138,
+      0.0072112190537154675,
+      -0.03552679717540741,
+      -0.10475718975067139,
+      0.003995304461568594,
+      -0.002284976886585355,
+      -0.014504319056868553,
+      -0.06887608021497726,
+      0.03398992121219635,
+      -0.005206231493502855,
+      0.049566611647605896,
+      0.00902023445814848,
+      0.06874160468578339,
+      0.014804325066506863,
+      -0.07230424880981445,
+      0.0428827665746212,
+      0.013657039031386375,
+      0.027973631396889687,
+      -0.035619381815195084,
+      0.06485525518655777,
+      -0.06238642707467079,
+      -0.012459578923881054,
+      0.020500177517533302,
+      -0.0715484470129013,
+      -0.16523504257202148,
+      0.013638298027217388,
+      0.07008316367864609,
+      0.026970835402607918,
+      0.004871702753007412,
+      -0.0012540861498564482,
+      -0.028708957135677338,
+      0.05812879279255867,
+      0.12611250579357147,
+      0.09877888858318329,
+      -0.04118988662958145,
+      -0.02214396744966507,
+      -0.10328112542629242,
+      0.029945021495223045,
+      0.004513312131166458,
+      0.011272193863987923,
+      0.03294430673122406,
+      -0.042709026485681534
+    ],
+    "model": "Hillcraft",
+    "pickup_zone": "POLYGON((-118.2887 34.0972, -118.1987 34.0972, -118.1987 33.9872, -118.2887 33.9872, -118.2887 34.0972))",
     "price": 1200,
-    "type": "Kids Mountain Bikes",
-    "specs": {
-      "material": "carbon",
-      "weight": "11"
-    },
-    "description": "Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\" wheel bike is just too clumsy coming off a 24\" bike. The Hillcraft 26 is just the solution they need! Imagine 120mm travel. Boost front/rear.  You have NOTHING to tweak because it is easy to assemble right out of the box. The Hillcraft 26 is an efficient trail trekking machine. Up or down does not matter - dominate the trails going both down and up with this amazing bike. The name Monarch comes from Monarch trail in Colorado where we love to ride.  It’s a highly technical, steep and rocky trail but the rip on the waydown is so fulfilling.  Don’t ride the trail on a hardtail! It is so much more fun on the full suspension Hillcraft!  Hit your local trail with the Hillcraft Monarch 26 to get to where you want to go.  "
+    "store_location": "-118.2437,34.0522"
   },
   {
-    "model": "Chook air 5",
     "brand": "Nord",
+    "condition": "used",
+    "description": "The Chook Air 5  gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower  top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails.",
+    "description_embeddings": [
+      -0.0018494834657758474,
+      0.057690851390361786,
+      0.038153987377882004,
+      0.06570218503475189,
+      0.028856752440333366,
+      -0.062333013862371445,
+      -0.014953209087252617,
+      0.046022992581129074,
+      -0.08184631168842316,
+      0.03648914024233818,
+      0.03869181126356125,
+      0.010564669035375118,
+      -0.020310621708631516,
+      -0.04062078520655632,
+      -0.0125962495803833,
+      0.14169928431510925,
+      0.03418859466910362,
+      -0.06641822308301926,
+      0.005633663386106491,
+      -0.09943458437919617,
+      0.023237863555550575,
+      -0.04369724169373512,
+      0.016574522480368614,
+      0.07258585095405579,
+      0.018674470484256744,
+      -0.05764088034629822,
+      -0.0795072391629219,
+      0.04034125804901123,
+      -0.036483921110630035,
+      -0.033106740564107895,
+      0.02980787307024002,
+      -0.0028512384742498398,
+      0.00786224752664566,
+      -0.03016488254070282,
+      -0.12349128723144531,
+      0.031072411686182022,
+      0.08362030982971191,
+      0.025227056816220284,
+      -0.030982907861471176,
+      -0.006486377213150263,
+      -0.023590318858623505,
+      -0.03374557942152023,
+      -0.04145599156618118,
+      -0.09421771764755249,
+      -0.0013142612297087908,
+      -0.003397064981982112,
+      -0.0031338112894445658,
+      -0.11464792490005493,
+      0.040542472153902054,
+      0.02896481193602085,
+      0.007327641360461712,
+      -0.06064218282699585,
+      0.049546848982572556,
+      -0.05917377769947052,
+      -0.01963184028863907,
+      -0.002139812568202615,
+      -0.14361988008022308,
+      -0.05401389300823212,
+      0.12506668269634247,
+      -0.07141950726509094,
+      -0.0032961040269583464,
+      0.015251584351062775,
+      -0.05507654324173927,
+      -0.009836667217314243,
+      -0.02802908606827259,
+      -0.01053905300796032,
+      -0.03239851072430611,
+      -0.10646941512823105,
+      0.03140658512711525,
+      0.028125958517193794,
+      -0.004000179003924131,
+      -0.0018343725241720676,
+      0.01727917790412903,
+      -0.013935663737356663,
+      -0.02435036562383175,
+      0.04411163926124573,
+      -0.009158330969512463,
+      -0.023309389129281044,
+      0.01229795441031456,
+      -0.04689493402838707,
+      -0.02138197235763073,
+      0.013063939288258553,
+      0.02832808345556259,
+      0.031972818076610565,
+      0.020882662385702133,
+      -0.015083174221217632,
+      0.002903456799685955,
+      -0.047304242849349976,
+      -0.10658963769674301,
+      -0.06274145841598511,
+      -0.030370736494660378,
+      0.0539257749915123,
+      0.00848578754812479,
+      0.02172423154115677,
+      -0.007691903971135616,
+      -0.10581931471824646,
+      0.06078812852501869,
+      0.007988635450601578,
+      -0.116583913564682,
+      0.05237157270312309,
+      0.024445366114377975,
+      -0.02832716703414917,
+      0.04004029557108879,
+      0.02844531089067459,
+      -0.0455174520611763,
+      -0.07379734516143799,
+      0.09453199058771133,
+      -0.011599121615290642,
+      -0.0027194281574338675,
+      0.014355232007801533,
+      -0.059690698981285095,
+      -0.012937567196786404,
+      0.034315045922994614,
+      -0.047598548233509064,
+      -0.03261064738035202,
+      0.05839747563004494,
+      -0.12691465020179749,
+      0.03778312727808952,
+      0.006131120957434177,
+      0.04806787148118019,
+      -0.03441976010799408,
+      0.08042734116315842,
+      0.008934197947382927,
+      0.027216315269470215,
+      0.0016972541343420744,
+      -0.10113930702209473,
+      -0.0003218930505681783,
+      9.75532108829862e-34,
+      -0.0537416972219944,
+      0.06875170767307281,
+      -0.01566525548696518,
+      0.01952524110674858,
+      -0.0005404680850915611,
+      -0.08984242379665375,
+      0.04537447541952133,
+      -0.1295408457517624,
+      7.603532867506146e-05,
+      0.040753066539764404,
+      0.016371281817555428,
+      0.029906686395406723,
+      -0.005372706335037947,
+      -0.06687828153371811,
+      0.11607439070940018,
+      0.016209086403250694,
+      -0.11238335072994232,
+      -0.057236358523368835,
+      -0.09619198739528656,
+      0.027146028354763985,
+      -0.09542766213417053,
+      -0.0360424630343914,
+      -0.09913153201341629,
+      0.04242968559265137,
+      0.05494842678308487,
+      -0.025294257327914238,
+      0.06307625770568848,
+      0.007745219860225916,
+      -0.019641151651740074,
+      0.07056662440299988,
+      -0.05425839126110077,
+      0.012385660782456398,
+      -0.006104010157287121,
+      -0.07186716794967651,
+      -0.10919132828712463,
+      -0.0017968777101486921,
+      0.010471112094819546,
+      -0.011221444234251976,
+      -0.035078633576631546,
+      0.009300827980041504,
+      0.0802159234881401,
+      -0.10042990744113922,
+      -0.01718892529606819,
+      0.05525779724121094,
+      -0.019847391173243523,
+      0.08405174314975739,
+      0.06403975188732147,
+      0.0627448782324791,
+      -0.07871688157320023,
+      0.0002676364383660257,
+      -0.05110163986682892,
+      0.006078454665839672,
+      -0.019803548231720924,
+      -0.014253707602620125,
+      0.039836447685956955,
+      0.021812820807099342,
+      0.00014793995069339871,
+      -0.006739508826285601,
+      -0.023166682571172714,
+      0.05429920181632042,
+      0.1337796151638031,
+      -0.01773720420897007,
+      0.024304436519742012,
+      -0.016411837190389633,
+      -0.07777299731969833,
+      0.042669400572776794,
+      0.06226645037531853,
+      -0.023803485557436943,
+      0.00396164134144783,
+      -0.049458179622888565,
+      -0.004774407483637333,
+      0.036529600620269775,
+      0.02002328634262085,
+      -0.02465248480439186,
+      -0.024076614528894424,
+      -0.03887653350830078,
+      0.057176534086465836,
+      -0.03888818621635437,
+      -0.027698175981640816,
+      0.001469603506848216,
+      0.04755152389407158,
+      -0.0938708707690239,
+      0.013991769403219223,
+      -0.026987746357917786,
+      -0.03277081623673439,
+      -0.04837489873170853,
+      0.02711542509496212,
+      -0.09185922145843506,
+      -0.03453921154141426,
+      0.03532274439930916,
+      -0.024472877383232117,
+      -0.09732313454151154,
+      0.008513586595654488,
+      0.03207352012395859,
+      0.030766190961003304,
+      -2.5405224720352836e-33,
+      0.08067575097084045,
+      -0.008160247467458248,
+      0.03101508319377899,
+      0.005022854544222355,
+      0.0010000152979046106,
+      0.06958161294460297,
+      0.10594375431537628,
+      -0.06177408620715141,
+      -0.01650322414934635,
+      0.03043895959854126,
+      -0.018333615735173225,
+      0.06436911225318909,
+      0.02439672127366066,
+      -0.01213911734521389,
+      0.09937868267297745,
+      0.02093592658638954,
+      -0.003140130080282688,
+      -0.016580305993556976,
+      0.10430759936571121,
+      -0.019038936123251915,
+      0.05574416741728783,
+      0.07455366849899292,
+      -0.029936065897345543,
+      0.0017704741330817342,
+      0.07022519409656525,
+      0.02108696848154068,
+      -0.050372399389743805,
+      0.027957700192928314,
+      0.005698348395526409,
+      0.03494682535529137,
+      -0.02610155940055847,
+      -0.0068950653076171875,
+      0.1346345692873001,
+      0.03947756066918373,
+      -0.05966781824827194,
+      -0.010489783249795437,
+      -0.04099087417125702,
+      -0.027186688035726547,
+      -0.04620056599378586,
+      -0.02478279173374176,
+      -0.007060651201754808,
+      -0.023514581844210625,
+      0.06082035228610039,
+      -0.05849218741059303,
+      -0.0036981222219765186,
+      0.04169313609600067,
+      0.09352244436740875,
+      0.020741308107972145,
+      -0.0019505824893712997,
+      -0.10489305853843689,
+      0.08789870887994766,
+      0.039999835193157196,
+      -0.014334832318127155,
+      0.008347390219569206,
+      0.03113699145615101,
+      0.10894497483968735,
+      0.027165820822119713,
+      0.0064145540818572044,
+      -0.00803150050342083,
+      -0.055484138429164886,
+      -0.03251631557941437,
+      0.02290980890393257,
+      0.04825572296977043,
+      0.01608354039490223,
+      -0.04969468340277672,
+      -0.004120110999792814,
+      -0.03278858959674835,
+      0.009696378372609615,
+      -0.04376300796866417,
+      -0.0009336083312518895,
+      -0.0313178189098835,
+      -0.05882050469517708,
+      0.057815250009298325,
+      -0.02050788328051567,
+      -0.024381538853049278,
+      0.06283771246671677,
+      0.06954411417245865,
+      0.09720556437969208,
+      -0.056403111666440964,
+      -0.04526498168706894,
+      -0.07259991019964218,
+      0.001844316371716559,
+      0.04090375825762749,
+      0.06941819936037064,
+      -0.041316937655210495,
+      0.002292247023433447,
+      -0.03425106778740883,
+      -0.0628972053527832,
+      0.0063382769003510475,
+      0.09668626636266708,
+      0.062228571623563766,
+      0.03658486530184746,
+      -0.08789398521184921,
+      0.0009696391643956304,
+      -0.004108588211238384,
+      -3.183854957455878e-08,
+      0.09346635639667511,
+      0.042943451553583145,
+      -0.0005091542261652648,
+      0.026524608954787254,
+      0.009858721867203712,
+      0.03737989068031311,
+      -0.014056878164410591,
+      0.038327474147081375,
+      -0.010239921510219574,
+      0.05757640674710274,
+      0.014411918818950653,
+      0.038742948323488235,
+      0.06475342065095901,
+      -0.0011537548853084445,
+      -0.017729472368955612,
+      0.05167960748076439,
+      0.024419916793704033,
+      0.08681508898735046,
+      0.015235288999974728,
+      0.036676522344350815,
+      -0.03421042487025261,
+      -0.019762659445405006,
+      0.09467294812202454,
+      -0.053133491426706314,
+      -0.04356615990400314,
+      -0.03919585049152374,
+      0.015591761097311974,
+      0.021372869610786438,
+      -0.0058142030611634254,
+      -0.022864477708935738,
+      -0.02901598811149597,
+      0.0458187572658062,
+      -0.030826766043901443,
+      -0.008975986391305923,
+      0.03365883231163025,
+      -0.010484383441507816,
+      -0.1445801854133606,
+      0.05828193947672844,
+      -0.028194306418299675,
+      0.05975533276796341,
+      0.014028828591108322,
+      0.0036430624313652515,
+      0.024983061477541924,
+      0.01454286277294159,
+      -0.006972659844905138,
+      0.037446193397045135,
+      -0.06949692964553833,
+      -0.09630566090345383,
+      0.03263894096016884,
+      0.048720087856054306,
+      -0.06886433064937592,
+      0.018142051994800568,
+      0.03894415125250816,
+      0.05843216925859451,
+      0.06860719621181488,
+      0.04971907287836075,
+      -0.025701280683279037,
+      -0.06293400377035141,
+      -0.05422094464302063,
+      0.01912975125014782,
+      0.009564549662172794,
+      0.055643752217292786,
+      -0.0027948219794780016,
+      0.0329461470246315
+    ],
+    "model": "Chook air 5",
+    "pickup_zone": "POLYGON((-87.6848 41.9331, -87.5748 41.9331, -87.5748 41.8231, -87.6848 41.8231, -87.6848 41.9331))",
     "price": 815,
-    "type": "Kids Mountain Bikes",
-    "specs": {
-      "material": "alloy",
-      "weight": "9.1"
-    },
-    "description": "The Chook Air 5  gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower  top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails. The Chook Air 5 is the perfect intro to mountain biking."
+    "store_location": "-87.6298,41.8781"
   },
   {
-    "model": "Eva 291",
     "brand": "Eva",
+    "condition": "used",
+    "description": "The sister company to Nord, Eva launched in 2005 as the first and only women-dedicated bicycle brand. Designed by women for women, allEva bikes are optimized for the feminine physique using analytics from a body metrics database. If you like 29ers, try the Eva 291. It\u2019s a brand new bike for 2022.. This full-suspension, cross-country ride has been designed for velocity. The 291 has 100mm of front and rear travel, a superlight aluminum frame and fast-rolling 29-inch wheels. Yippee!",
+    "description_embeddings": [
+      0.035103436559438705,
+      0.02666405402123928,
+      -0.06364161521196365,
+      0.02551678754389286,
+      -0.005281867925077677,
+      -0.04041111096739769,
+      -0.020820949226617813,
+      -0.03485208749771118,
+      -0.07683732360601425,
+      0.021527189761400223,
+      0.007516156416386366,
+      -0.0034474905114620924,
+      0.030465560033917427,
+      -0.06572654843330383,
+      -0.020914506167173386,
+      0.032637566328048706,
+      0.0815017819404602,
+      -0.022764643654227257,
+      0.07385077327489853,
+      0.058004263788461685,
+      -0.03062591142952442,
+      -0.03927106410264969,
+      0.01410673838108778,
+      0.05480317771434784,
+      -0.05647570267319679,
+      -0.008725483901798725,
+      -0.05373937636613846,
+      0.03546926751732826,
+      -0.026455262675881386,
+      -0.09718386828899384,
+      -0.040623344480991364,
+      0.03622450679540634,
+      0.08971034735441208,
+      -0.038574062287807465,
+      -0.05105822533369064,
+      0.021020587533712387,
+      0.003312851767987013,
+      -0.008969941176474094,
+      -0.0568903312087059,
+      0.033502694219350815,
+      -0.0578635074198246,
+      -0.03721226751804352,
+      -0.036668986082077026,
+      0.0022641047835350037,
+      0.038053013384342194,
+      0.03350543603301048,
+      0.05258995667099953,
+      -0.007619654294103384,
+      -0.05145309492945671,
+      0.026286069303750992,
+      0.09238694608211517,
+      -0.06733417510986328,
+      0.05791507661342621,
+      -0.07623173296451569,
+      -0.0052175214514136314,
+      -0.04393303394317627,
+      -0.15249019861221313,
+      -0.019764462485909462,
+      -0.03331150859594345,
+      -0.11831824481487274,
+      0.05683637782931328,
+      0.01903577335178852,
+      -0.023615414276719093,
+      0.04120348393917084,
+      -0.05669170990586281,
+      0.002014430705457926,
+      0.009953595697879791,
+      0.008390115574002266,
+      -0.025982441380620003,
+      -0.05977262556552887,
+      0.0611012764275074,
+      0.010146236047148705,
+      -0.047625984996557236,
+      0.09061623364686966,
+      0.02551751770079136,
+      0.06041749566793442,
+      0.1113404780626297,
+      0.017673874273896217,
+      -0.05184035003185272,
+      0.023109234869480133,
+      -0.04408435523509979,
+      -0.09029985964298248,
+      0.06733208149671555,
+      0.049696795642375946,
+      0.05554559826850891,
+      0.01563390903174877,
+      -0.019527558237314224,
+      -0.014796985313296318,
+      0.003595865098759532,
+      0.012917418964207172,
+      -0.06858907639980316,
+      -0.008697138167917728,
+      0.04721860587596893,
+      0.03153855353593826,
+      -0.05275731533765793,
+      0.019923491403460503,
+      -0.009707989171147346,
+      -0.018920045346021652,
+      0.03773808106780052,
+      0.042773403227329254,
+      -0.03819388151168823,
+      0.04029008001089096,
+      0.060834936797618866,
+      0.07531940191984177,
+      -0.04695741459727287,
+      0.00488079572096467,
+      0.13518987596035004,
+      -0.014429144561290741,
+      0.0314130075275898,
+      0.04135369136929512,
+      -0.021350333467125893,
+      -0.01289785373955965,
+      0.032701168209314346,
+      -0.037027571350336075,
+      -0.018168980255723,
+      -0.07188623398542404,
+      -0.036501020193099976,
+      0.03303954005241394,
+      0.10676111280918121,
+      -0.03277475759387016,
+      -0.06245853006839752,
+      -0.011879103258252144,
+      0.0533418171107769,
+      -0.01446340698748827,
+      0.03530410677194595,
+      0.05820532143115997,
+      -0.0015766610158607364,
+      -8.477015062817539e-34,
+      -0.10837127268314362,
+      0.015582970343530178,
+      0.0182977095246315,
+      0.055213626474142075,
+      -0.03584470599889755,
+      0.02778925560414791,
+      0.08698058873414993,
+      -0.04999695345759392,
+      -0.0842076763510704,
+      -0.040448326617479324,
+      -0.06311061233282089,
+      0.02668358013033867,
+      0.04676111042499542,
+      -0.006417605560272932,
+      0.12788759171962738,
+      0.02197197638452053,
+      0.07035308331251144,
+      -0.04392284154891968,
+      -0.008788101375102997,
+      -0.001108768628910184,
+      0.07960236072540283,
+      -0.0019975434988737106,
+      -0.010499294847249985,
+      0.03599945828318596,
+      0.02329486794769764,
+      -0.01962442137300968,
+      0.15486162900924683,
+      0.027215363457798958,
+      -0.022036811336874962,
+      0.04227740690112114,
+      -0.07894206047058105,
+      -0.03180933743715286,
+      0.020022651180624962,
+      -0.05859709531068802,
+      -0.0009564562351442873,
+      0.009732870385050774,
+      -0.09007531404495239,
+      0.041766807436943054,
+      0.003291067900136113,
+      0.0950121283531189,
+      0.02693203091621399,
+      -0.01629827171564102,
+      -0.01884087361395359,
+      -0.029889501631259918,
+      -0.003714299062266946,
+      0.09247232973575592,
+      0.06151247024536133,
+      0.09120925515890121,
+      -0.011266379617154598,
+      0.03680066391825676,
+      -0.1628604233264923,
+      -0.008045083843171597,
+      -0.023876454681158066,
+      0.046465914696455,
+      0.01841152086853981,
+      0.01759498566389084,
+      -0.012628139927983284,
+      0.02123965509235859,
+      -0.07098977267742157,
+      0.025028834119439125,
+      -0.032171521335840225,
+      0.0538402758538723,
+      -0.00211805896833539,
+      -0.019548164680600166,
+      -0.046793293207883835,
+      0.04394293949007988,
+      0.022090770304203033,
+      -0.058215122669935226,
+      -0.05101722851395607,
+      0.014057288877665997,
+      -0.05860457569360733,
+      0.006166193168610334,
+      0.04641130194067955,
+      0.03165149688720703,
+      0.045289356261491776,
+      0.038580797612667084,
+      -0.0335664264857769,
+      0.013378577306866646,
+      0.058321163058280945,
+      -0.03730795532464981,
+      -0.01996016688644886,
+      0.025774186477065086,
+      0.001352976425550878,
+      0.023636724799871445,
+      0.026727410033345222,
+      -0.0730309784412384,
+      -0.01613243669271469,
+      -0.009525856003165245,
+      -0.03985843434929848,
+      -0.003976964857429266,
+      -0.006743384525179863,
+      -0.06324627995491028,
+      0.03959967568516731,
+      0.021898096427321434,
+      -0.004184887744486332,
+      -3.110083923319741e-34,
+      0.03726857528090477,
+      -0.016945818439126015,
+      0.05512943118810654,
+      0.0471712127327919,
+      0.097488172352314,
+      0.02456829510629177,
+      0.08276744186878204,
+      -0.02230781689286232,
+      -0.03785759210586548,
+      0.010082835331559181,
+      0.07151538133621216,
+      -0.04426267370581627,
+      0.03402319550514221,
+      0.05808456242084503,
+      0.07566764950752258,
+      0.07006501406431198,
+      0.002404613886028528,
+      -0.10078012198209763,
+      0.0029093879275023937,
+      -0.12370351701974869,
+      -0.03431423008441925,
+      0.08334372937679291,
+      0.001441179309040308,
+      -0.08001153916120529,
+      0.020076438784599304,
+      0.011177998036146164,
+      0.034560561180114746,
+      0.041609298437833786,
+      -0.04921843111515045,
+      0.03598331660032272,
+      -0.10671709477901459,
+      0.02969883382320404,
+      0.048317357897758484,
+      0.12375228852033615,
+      0.040479566901922226,
+      0.0330270379781723,
+      -0.06994733214378357,
+      0.008698385208845139,
+      0.03447363153100014,
+      -0.012882913462817669,
+      -0.02672695368528366,
+      -0.06423910707235336,
+      -0.0506032295525074,
+      0.0053747911006212234,
+      0.0682206079363823,
+      -0.005316274706274271,
+      0.027013784274458885,
+      -0.006269444711506367,
+      0.08528510481119156,
+      -0.0731915608048439,
+      0.0046186731196939945,
+      -0.024244142696261406,
+      0.0360478051006794,
+      0.020591434091329575,
+      0.04302601516246796,
+      -0.14392279088497162,
+      0.05873512104153633,
+      -0.010028650052845478,
+      -0.04548479616641998,
+      -0.013535127975046635,
+      0.01113649271428585,
+      0.028603754937648773,
+      -0.04036158323287964,
+      0.0704532265663147,
+      -0.09373150765895844,
+      -0.07198052108287811,
+      -0.002203285926952958,
+      -0.0855080857872963,
+      -0.08842256665229797,
+      -9.343179408460855e-05,
+      -0.029457710683345795,
+      -0.02197202481329441,
+      -0.048936717212200165,
+      0.06165122613310814,
+      -0.0626755878329277,
+      0.009602922946214676,
+      0.07251632958650589,
+      0.03113914094865322,
+      -0.0010769155342131853,
+      -0.040936876088380814,
+      -0.04328843951225281,
+      -0.020654935389757156,
+      0.08143945783376694,
+      0.03210373967885971,
+      0.03849901258945465,
+      0.08388370275497437,
+      -0.04882088676095009,
+      -0.04764509201049805,
+      -0.01594746671617031,
+      0.08005915582180023,
+      -0.0007682700525037944,
+      0.04356953501701355,
+      -0.08784972876310349,
+      -0.009003485552966595,
+      -0.012332507409155369,
+      -3.9398202034135466e-08,
+      0.006421600468456745,
+      0.04334808140993118,
+      0.0013437344459816813,
+      -0.009495558217167854,
+      -0.022657591849565506,
+      -0.012704327702522278,
+      0.018703341484069824,
+      -0.07545771449804306,
+      -0.07807240635156631,
+      0.0031038280576467514,
+      -0.023932253941893578,
+      0.040701914578676224,
+      0.10603249073028564,
+      0.03773405775427818,
+      0.05925403907895088,
+      -0.02083730883896351,
+      0.052759915590286255,
+      0.08195225894451141,
+      -0.057340435683727264,
+      -0.03538660705089569,
+      0.04492119327187538,
+      -0.07101765275001526,
+      0.02868317998945713,
+      -0.11165601015090942,
+      -0.03126508370041847,
+      -0.07953942567110062,
+      -0.022893071174621582,
+      -0.08839578926563263,
+      0.00727836275473237,
+      -0.08685773611068726,
+      0.026177138090133667,
+      0.028831886127591133,
+      0.03626682609319687,
+      -0.045381225645542145,
+      -0.013574030250310898,
+      0.028583087027072906,
+      -0.004301569424569607,
+      0.04326719045639038,
+      -0.023370176553726196,
+      0.057897310703992844,
+      -0.029195263981819153,
+      -0.001789534231647849,
+      0.032133687287569046,
+      0.003419605316594243,
+      0.028055502101778984,
+      -0.0038284522015601397,
+      -0.022835813462734222,
+      -0.07568305730819702,
+      0.017481982707977295,
+      0.013085611164569855,
+      0.009357997216284275,
+      -0.030347391963005066,
+      -0.0020967889577150345,
+      0.03544173017144203,
+      0.004640925209969282,
+      0.025202661752700806,
+      -0.0916307270526886,
+      -0.06341513246297836,
+      -0.017053432762622833,
+      0.06747056543827057,
+      0.0467485710978508,
+      -0.14364545047283173,
+      0.024641912430524826,
+      -0.04414863884449005
+    ],
+    "model": "Eva 291",
+    "pickup_zone": "POLYGON((-80.2433 25.8067, -80.1333 25.8067, -80.1333 25.6967, -80.2433 25.6967, -80.2433 25.8067))",
     "price": 3400,
-    "type": "Mountain Bikes",
-    "specs": {
-      "material": "carbon",
-      "weight": "9.1"
-    },
-    "description": "The sister company to Nord, Eva launched in 2005 as the first and only women-dedicated bicycle brand. Designed by women for women, allEva bikes are optimized for the feminine physique using analytics from a body metrics database. If you like 29ers, try the Eva 291. It’s a brand new bike for 2022.. This full-suspension, cross-country ride has been designed for velocity. The 291 has 100mm of front and rear travel, a superlight aluminum frame and fast-rolling 29-inch wheels. Yippee!"
+    "store_location": "-80.1918,25.7617"
   },
   {
-    "model": "Kahuna",
     "brand": "Noka Bikes",
+    "condition": "used",
+    "description": "Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women\u2019s saddle, different bars and unique colourway.",
+    "description_embeddings": [
+      0.07420087605714798,
+      -0.01575474441051483,
+      0.010670951567590237,
+      0.07449527084827423,
+      0.0060751838609576225,
+      0.03211340680718422,
+      -0.008086569607257843,
+      0.025549469515681267,
+      -0.07154879719018936,
+      0.014914358966052532,
+      -0.030715830624103546,
+      -0.0064881909638643265,
+      -0.0071744490414857864,
+      -0.0495535172522068,
+      0.03856685757637024,
+      0.056132566183805466,
+      0.10794447362422943,
+      -0.010181701742112637,
+      0.0811777114868164,
+      0.10135157406330109,
+      -0.0769873708486557,
+      -0.019640743732452393,
+      -0.028702793642878532,
+      0.07654724270105362,
+      -0.07045057415962219,
+      -0.10104052722454071,
+      -0.004679638426750898,
+      -0.0027665267698466778,
+      0.030919065698981285,
+      -0.05461210012435913,
+      -0.020669877529144287,
+      0.031864751130342484,
+      0.0835040882229805,
+      -0.05930671840906143,
+      -0.006361816544085741,
+      -0.044132985174655914,
+      0.035945694893598557,
+      -0.0027891425415873528,
+      -0.07598478347063065,
+      -0.03105698712170124,
+      -0.059601303189992905,
+      -0.018435664474964142,
+      -0.03314891457557678,
+      0.06877987831830978,
+      -0.016064301133155823,
+      0.01545438077300787,
+      0.056307148188352585,
+      -0.08382677286863327,
+      -0.05274924635887146,
+      0.01139853335916996,
+      0.10750263929367065,
+      -0.004042057786136866,
+      0.003356053726747632,
+      -0.01083006989210844,
+      -0.06153054162859917,
+      -0.054990023374557495,
+      -0.1360272616147995,
+      0.025806479156017303,
+      0.043233320116996765,
+      -0.009591769427061081,
+      0.04422037675976753,
+      0.02436559833586216,
+      -0.0012137923622503877,
+      -0.015348327346146107,
+      0.02425999939441681,
+      -0.03409525752067566,
+      -0.08487176895141602,
+      0.017345253378152847,
+      0.035498712211847305,
+      -0.05615586042404175,
+      0.02745831571519375,
+      0.04017677903175354,
+      -0.0936250239610672,
+      0.048734042793512344,
+      0.024287866428494453,
+      -0.030274393036961555,
+      0.08800201117992401,
+      0.0879313051700592,
+      -0.0550895519554615,
+      -0.0026407642289996147,
+      -0.09552258998155594,
+      -0.05870680510997772,
+      0.09009534120559692,
+      0.05674433708190918,
+      0.05360940843820572,
+      -0.0023017164785414934,
+      0.005036584101617336,
+      -0.017987212166190147,
+      -0.05129106715321541,
+      -0.0012550759129226208,
+      -0.05818512290716171,
+      0.06725005060434341,
+      0.02540011890232563,
+      0.054589059203863144,
+      0.01723511517047882,
+      -0.04752320423722267,
+      0.10586173087358475,
+      0.05530202388763428,
+      -0.03287632390856743,
+      0.05258375406265259,
+      0.01655220240354538,
+      0.011849797330796719,
+      0.032285332679748535,
+      0.03760116547346115,
+      -0.017522728070616722,
+      -0.05457543954253197,
+      0.006817341782152653,
+      -0.028400525450706482,
+      -0.0027318967040628195,
+      -0.04200681298971176,
+      -0.026171568781137466,
+      -0.03272707015275955,
+      0.016305547207593918,
+      0.01545319240540266,
+      0.0056663742288947105,
+      -0.0977277085185051,
+      -0.0009383464348502457,
+      -0.005693590268492699,
+      0.039240892976522446,
+      0.01645808108150959,
+      -0.01950509287416935,
+      0.007762903813272715,
+      -0.004406424704939127,
+      0.016364052891731262,
+      -0.006125410553067923,
+      -0.029666034504771233,
+      0.044946398586034775,
+      1.8357034061219326e-33,
+      -0.053835414350032806,
+      0.03495992720127106,
+      -0.05977822467684746,
+      -0.009059705771505833,
+      0.004659880883991718,
+      0.022712793201208115,
+      0.04409413039684296,
+      -0.10094501823186874,
+      -0.08702167868614197,
+      0.0066354661248624325,
+      0.011878615245223045,
+      0.0033176038414239883,
+      -0.012380938045680523,
+      0.0010130798909813166,
+      0.0644172728061676,
+      -0.07130810618400574,
+      -0.0045928386971354485,
+      -0.03375661373138428,
+      -0.022520871832966805,
+      0.07504180818796158,
+      0.009861051104962826,
+      0.07191396504640579,
+      -0.014361198991537094,
+      0.01449025422334671,
+      -0.010663183405995369,
+      -0.028888769447803497,
+      0.09297508746385574,
+      0.04386264830827713,
+      -0.09579017758369446,
+      0.007718369830399752,
+      -0.11800525337457657,
+      -0.020133504644036293,
+      -0.0034684871789067984,
+      -0.03735410049557686,
+      0.006975250784307718,
+      -0.012902614660561085,
+      0.04201272875070572,
+      0.04273228347301483,
+      -0.07133302837610245,
+      0.09145014733076096,
+      0.0048939259722828865,
+      -0.058044496923685074,
+      -0.017591776326298714,
+      -0.03502552956342697,
+      -0.05678534135222435,
+      0.05471408739686012,
+      0.09568087011575699,
+      0.09486310184001923,
+      -0.045761823654174805,
+      0.018188882619142532,
+      -0.12331638485193253,
+      -0.023129422217607498,
+      -0.05455191433429718,
+      0.06732556223869324,
+      0.048286039382219315,
+      -0.0014048831071704626,
+      0.03308422118425369,
+      -0.009839850477874279,
+      -0.05661558359861374,
+      0.03290552645921707,
+      0.03661618381738663,
+      0.0047610136680305,
+      -0.05254451557993889,
+      0.006052205804735422,
+      -0.13153813779354095,
+      -0.006893055979162455,
+      0.037368785589933395,
+      -0.03058353252708912,
+      -0.0017269864911213517,
+      -0.008851475082337856,
+      -0.0740399956703186,
+      0.057353563606739044,
+      0.12296456098556519,
+      0.0413251556456089,
+      0.09911972284317017,
+      0.016817500814795494,
+      -0.048074446618556976,
+      0.05658562108874321,
+      -0.012700358405709267,
+      -0.08663205802440643,
+      0.0014393541496247053,
+      0.00613820506259799,
+      -0.04446813836693764,
+      0.04673916846513748,
+      -0.02757285162806511,
+      -0.05133393779397011,
+      -0.028082016855478287,
+      -0.04668722674250603,
+      -0.03849129378795624,
+      -0.047927819192409515,
+      -0.06503037363290787,
+      -0.08361010253429413,
+      0.0393000952899456,
+      0.04658354073762894,
+      0.009724845178425312,
+      -2.0251938301584547e-33,
+      0.07265108078718185,
+      -0.04307040572166443,
+      0.04996086284518242,
+      0.03520473092794418,
+      0.1084771379828453,
+      0.005833788774907589,
+      0.046216338872909546,
+      -0.04042917117476463,
+      -0.04179416596889496,
+      0.03598152473568916,
+      0.04082870855927467,
+      -0.10612837225198746,
+      -0.010728210210800171,
+      0.03610331192612648,
+      0.027484672144055367,
+      -0.008130725473165512,
+      0.026157474145293236,
+      -0.07420457899570465,
+      0.025218356400728226,
+      -0.0898737907409668,
+      -0.02742879092693329,
+      0.03535477817058563,
+      -0.062408916652202606,
+      -0.1569257229566574,
+      -0.018789052963256836,
+      0.04845775291323662,
+      -0.015149657614529133,
+      -0.0018356313230469823,
+      -0.04590461030602455,
+      0.023325689136981964,
+      -0.13069787621498108,
+      -0.01994006149470806,
+      -0.021577563136816025,
+      -0.0231519415974617,
+      -0.002478161361068487,
+      0.022444186732172966,
+      -0.04681165888905525,
+      0.02769998274743557,
+      0.003438781714066863,
+      0.03829822316765785,
+      0.0243418887257576,
+      -0.020368436351418495,
+      -0.005010040942579508,
+      0.04648580029606819,
+      0.061260052025318146,
+      0.03784928843379021,
+      0.008547516539692879,
+      0.027585946023464203,
+      0.043608926236629486,
+      0.047329846769571304,
+      0.10433284938335419,
+      0.0069401939399540424,
+      0.043503858149051666,
+      0.06499945372343063,
+      -0.01040438748896122,
+      -0.11596397310495377,
+      0.06451629102230072,
+      0.032956890761852264,
+      0.0007023254293017089,
+      0.0898808017373085,
+      -0.055529963225126266,
+      -0.006572310347110033,
+      -0.06089714914560318,
+      0.022685443982481956,
+      -0.0013110691215842962,
+      -0.09440209716558456,
+      -0.03121936321258545,
+      -0.003408250631764531,
+      -0.08051110059022903,
+      0.01802976056933403,
+      0.032015636563301086,
+      -9.986010991269723e-05,
+      -0.011806532740592957,
+      0.06818002462387085,
+      0.028290249407291412,
+      -0.005312844179570675,
+      0.06016719341278076,
+      0.014397598803043365,
+      0.07122596353292465,
+      0.007864296436309814,
+      0.03002011403441429,
+      -0.05413847416639328,
+      0.09744291007518768,
+      -0.01965983398258686,
+      0.04150940105319023,
+      0.14307892322540283,
+      -0.11320102959871292,
+      0.03503091260790825,
+      0.003515399992465973,
+      -0.023677969351410866,
+      0.03955819085240364,
+      0.0534457303583622,
+      0.01904974691569805,
+      0.031267836689949036,
+      -0.018026702105998993,
+      -3.930426117904062e-08,
+      0.0003057526773773134,
+      0.013398992829024792,
+      -0.10113491117954254,
+      -0.016498351469635963,
+      -0.00534934364259243,
+      0.017148228362202644,
+      -0.03217773512005806,
+      -0.030934104695916176,
+      -0.06334194540977478,
+      0.07242853194475174,
+      -0.0047585368156433105,
+      -0.01996637135744095,
+      -0.0016463182400912046,
+      0.01777566224336624,
+      -0.04115547239780426,
+      0.02906038798391819,
+      0.10273877531290054,
+      0.022776247933506966,
+      0.030065912753343582,
+      -0.014570299535989761,
+      0.047994960099458694,
+      -0.044575825333595276,
+      0.025753378868103027,
+      -0.002644166350364685,
+      -0.09429919719696045,
+      -0.11280428618192673,
+      0.021306486800312996,
+      0.010426397435367107,
+      0.021093064919114113,
+      -0.00363176385872066,
+      -0.024409662932157516,
+      0.11473581194877625,
+      0.0020395806059241295,
+      -0.08371622860431671,
+      -0.03764123469591141,
+      0.039440982043743134,
+      -0.022172994911670685,
+      0.0410802997648716,
+      -0.05086303874850273,
+      0.053952641785144806,
+      -0.06084167957305908,
+      -0.036132071167230606,
+      0.02080748789012432,
+      -0.043120622634887695,
+      0.04048219695687294,
+      0.05917482078075409,
+      0.04085611552000046,
+      -0.05118294060230255,
+      0.015727631747722626,
+      0.01915580965578556,
+      0.03531794995069504,
+      -0.058007121086120605,
+      0.08498086780309677,
+      0.0036822939291596413,
+      0.018125539645552635,
+      0.10145474225282669,
+      -0.05804500728845596,
+      -0.008451723493635654,
+      -0.029611116275191307,
+      0.008798911236226559,
+      -0.03220565244555473,
+      -0.05617227777838707,
+      0.03482669219374657,
+      -0.03508705273270607
+    ],
+    "model": "Kahuna",
+    "pickup_zone": "POLYGON((-122.4644 37.8199, -122.3544 37.8199, -122.3544 37.7099, -122.4644 37.7099, -122.4644 37.8199))",
     "price": 3200,
-    "type": "Mountain Bikes",
-    "specs": {
-      "material": "alloy",
-      "weight": "9.8"
-    },
-    "description": "Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway."
+    "store_location": "-122.4194,37.7749"
   },
   {
-    "model": "XBN 2.1 Alloy",
     "brand": "Breakout",
+    "condition": "new",
+    "description": "The XBN 2.1 Alloy is our entry-level road bike \u2013 but that\u2019s not to say that it\u2019s a basic machine. With an internal weld aluminium frame, a full carbon fork, and the slick-shifting Claris gears from Shimano\u2019s, this is a bike which doesn\u2019t break the bank and delivers craved performance.",
+    "description_embeddings": [
+      -0.03482655808329582,
+      -0.024290302768349648,
+      0.029588153585791588,
+      -0.04068901762366295,
+      0.006173150148242712,
+      -0.06071849912405014,
+      0.021348219364881516,
+      0.032668184489011765,
+      -0.12000397592782974,
+      -0.026135660707950592,
+      -0.0262606181204319,
+      -0.014927615411579609,
+      0.06986956298351288,
+      -0.006424048915505409,
+      -0.002834598533809185,
+      -0.005902229342609644,
+      0.07471967488527298,
+      -0.10197333246469498,
+      0.08836513012647629,
+      0.0504477359354496,
+      0.005102860741317272,
+      0.0359189435839653,
+      -0.0477643720805645,
+      0.02106260135769844,
+      0.030146656557917595,
+      0.04048784077167511,
+      -0.023416390642523766,
+      -0.0016326266340911388,
+      0.039820387959480286,
+      -0.04475116729736328,
+      -0.03422572463750839,
+      0.09266746789216995,
+      -0.04106999188661575,
+      -0.02442021667957306,
+      -0.006325263995677233,
+      -0.057226430624723434,
+      0.12074039876461029,
+      0.012658749707043171,
+      -0.09748225659132004,
+      -0.048439353704452515,
+      -0.004550903104245663,
+      -0.014449959620833397,
+      0.03684601932764053,
+      0.018772389739751816,
+      0.09577438980340958,
+      0.04358510673046112,
+      0.06987427175045013,
+      -0.0561334528028965,
+      -0.03684744983911514,
+      0.02584502473473549,
+      0.039536770433187485,
+      -0.061133887618780136,
+      0.05351594462990761,
+      -0.025124184787273407,
+      0.09431525319814682,
+      0.05062168091535568,
+      -0.11715397238731384,
+      0.044368330389261246,
+      -0.024262988939881325,
+      -0.024561986327171326,
+      0.036067184060811996,
+      0.025171849876642227,
+      0.033648427575826645,
+      0.046933531761169434,
+      0.09548858553171158,
+      -0.06253167241811752,
+      -0.045195333659648895,
+      -0.04183578118681908,
+      -0.040385909378528595,
+      -0.027590686455368996,
+      0.08240272104740143,
+      -0.04743463918566704,
+      0.004482025280594826,
+      0.03219064325094223,
+      0.0007497097249142826,
+      -0.04202196002006531,
+      0.10904812812805176,
+      -0.06721051037311554,
+      -0.023717032745480537,
+      -0.01718866638839245,
+      -0.11568725854158401,
+      0.038704562932252884,
+      0.04929516091942787,
+      -0.03311185538768768,
+      -0.0017465045675635338,
+      -0.06153444945812225,
+      0.019559966400265694,
+      -0.010708335787057877,
+      -0.06623212993144989,
+      0.03114122338593006,
+      0.03581896796822548,
+      0.05368824675679207,
+      0.016093581914901733,
+      -0.0077278027310967445,
+      0.025581376627087593,
+      0.02375067211687565,
+      -0.024797597900032997,
+      0.08371419459581375,
+      -0.023117447271943092,
+      0.04535554349422455,
+      -0.007224411237984896,
+      0.06131899356842041,
+      0.02283627539873123,
+      -0.052097078412771225,
+      -0.07922855019569397,
+      0.0016958570340648293,
+      0.051785532385110855,
+      0.06701217591762543,
+      -0.02913537621498108,
+      0.020526740700006485,
+      0.03941992297768593,
+      -0.02217993699014187,
+      -0.08051256835460663,
+      -0.10155311226844788,
+      -0.05453299731016159,
+      -0.06470758467912674,
+      0.002029003808274865,
+      -0.013401892967522144,
+      -0.011006158776581287,
+      0.045922696590423584,
+      -0.040529411286115646,
+      0.00991761963814497,
+      -0.06682797521352768,
+      0.05892198532819748,
+      -0.028617633506655693,
+      -0.06339140236377716,
+      0.0044001322239637375,
+      -4.362402064591546e-33,
+      -0.10147389024496078,
+      0.039431530982255936,
+      -0.04599899426102638,
+      -0.049156975001096725,
+      -0.02249804697930813,
+      -0.026725362986326218,
+      0.04369090870022774,
+      -0.0005211823736317456,
+      -0.030739039182662964,
+      -0.0065231663174927235,
+      0.025333819910883904,
+      0.10470504313707352,
+      0.021332278847694397,
+      0.05556178465485573,
+      0.035125020891427994,
+      -0.1538446545600891,
+      0.007054235320538282,
+      -0.036041803658008575,
+      0.05932909622788429,
+      0.0337519533932209,
+      0.014841740019619465,
+      0.030220910906791687,
+      0.04296395927667618,
+      0.02538421005010605,
+      -0.006869863253086805,
+      -0.0031259972602128983,
+      0.11390665918588638,
+      -0.046557214111089706,
+      0.00429841224104166,
+      0.0428440123796463,
+      -0.1384042203426361,
+      0.04695465788245201,
+      -0.0574827715754509,
+      -0.030760489404201508,
+      -0.07478123158216476,
+      -0.029447706416249275,
+      -0.06204935908317566,
+      -0.03058161959052086,
+      -0.02502700313925743,
+      -0.019530421122908592,
+      -0.02094511315226555,
+      -0.03218250721693039,
+      -0.05274674668908119,
+      -0.02680223248898983,
+      -0.01955571211874485,
+      0.018619371578097343,
+      0.007585515268146992,
+      0.07155954837799072,
+      -0.018960801884531975,
+      -0.05782055854797363,
+      0.017819860950112343,
+      0.04109930992126465,
+      -0.03562675416469574,
+      0.016705146059393883,
+      0.0415029413998127,
+      0.05103381723165512,
+      0.035572972148656845,
+      -0.015020242892205715,
+      -0.03179502114653587,
+      0.0891512930393219,
+      0.007475084625184536,
+      0.042234599590301514,
+      -0.0542532242834568,
+      0.05480321869254112,
+      -0.10602187365293503,
+      0.054763536900281906,
+      0.04739809036254883,
+      -0.03327919542789459,
+      0.0082072913646698,
+      -0.0650608167052269,
+      -0.08271145075559616,
+      -0.10922762006521225,
+      0.03824940696358681,
+      0.05978637561202049,
+      0.10005365312099457,
+      0.029007570818066597,
+      -0.034110404551029205,
+      0.02545103058218956,
+      0.05190473049879074,
+      -0.003596875350922346,
+      -0.08473207801580429,
+      0.012021052651107311,
+      0.018175840377807617,
+      0.017920689657330513,
+      -0.03348258137702942,
+      0.04048585146665573,
+      0.030843179672956467,
+      0.019531769677996635,
+      -0.00910205114632845,
+      0.05721440538764,
+      0.007200753781944513,
+      -0.11394353210926056,
+      0.03483451530337334,
+      0.029621547088027,
+      -0.03755185008049011,
+      9.393710556981876e-34,
+      -0.009642334654927254,
+      -0.001342272269539535,
+      0.01180787943303585,
+      0.026348579674959183,
+      -0.011158440262079239,
+      -0.0019478596514090896,
+      0.028490403667092323,
+      -0.052807874977588654,
+      -0.029139718040823936,
+      0.08380713313817978,
+      0.09657946228981018,
+      0.00991911068558693,
+      0.03502354025840759,
+      -0.016754556447267532,
+      0.017460109665989876,
+      -0.01642783358693123,
+      0.022211389616131783,
+      -0.008778599090874195,
+      3.654864485724829e-05,
+      -0.09229966253042221,
+      0.04083291441202164,
+      0.08299239724874496,
+      -0.04151370748877525,
+      -0.05360836163163185,
+      -0.07950830459594727,
+      0.03959093242883682,
+      -0.13340364396572113,
+      0.054901909083127975,
+      0.05736061558127403,
+      0.04770279303193092,
+      -0.11388063430786133,
+      0.0237369854003191,
+      0.02305987849831581,
+      -0.013226242735981941,
+      -0.020716888830065727,
+      0.03368164971470833,
+      -0.002396275522187352,
+      -0.012604329735040665,
+      -0.02715742215514183,
+      0.0019254887010902166,
+      -0.00887741707265377,
+      -0.028728270903229713,
+      -0.05864499509334564,
+      0.10937061905860901,
+      -0.004027256276458502,
+      0.019197454676032066,
+      -0.03928225114941597,
+      -0.018220100551843643,
+      0.02466396614909172,
+      0.00980517640709877,
+      0.05513712763786316,
+      0.10625418275594711,
+      0.08366440236568451,
+      -0.02691512741148472,
+      -0.026599230244755745,
+      -0.049529410898685455,
+      -0.05376818776130676,
+      -0.003328752936795354,
+      -0.04345694184303284,
+      0.11166279017925262,
+      0.0407760851085186,
+      -0.00792837142944336,
+      0.03168283402919769,
+      -0.0018123856279999018,
+      0.0357111431658268,
+      -0.1368872970342636,
+      0.00755245191976428,
+      -0.010281031019985676,
+      -0.07121222466230392,
+      0.03101137839257717,
+      0.0662078782916069,
+      0.007085337769240141,
+      -0.007063422352075577,
+      -0.05238816514611244,
+      -0.004185437690466642,
+      0.00880429521203041,
+      0.05528423562645912,
+      -0.08964741230010986,
+      0.0042182342149317265,
+      -0.029020531103014946,
+      0.014597366563975811,
+      0.0002752764557953924,
+      0.032267484813928604,
+      0.11250412464141846,
+      0.002768452512100339,
+      -0.026546282693743706,
+      0.017761094495654106,
+      0.023686127737164497,
+      -0.012699384242296219,
+      0.018606871366500854,
+      -0.009665136225521564,
+      -0.06902427226305008,
+      -0.04932688549160957,
+      0.051991984248161316,
+      -0.05918996408581734,
+      -4.18107468647122e-08,
+      -0.06375139951705933,
+      -0.0029491656459867954,
+      0.032401617616415024,
+      -0.024946069344878197,
+      -0.026347795501351357,
+      0.020192604511976242,
+      -0.025759287178516388,
+      0.037004951387643814,
+      0.043629322201013565,
+      0.06278910487890244,
+      0.02097572200000286,
+      -0.07064115256071091,
+      -0.005097216460853815,
+      0.016486743465065956,
+      -0.0032796994782984257,
+      0.07957274466753006,
+      0.03776371479034424,
+      0.04259084165096283,
+      -0.005312138702720404,
+      -0.11992045491933823,
+      0.0859612300992012,
+      -0.0500827394425869,
+      0.02553708106279373,
+      -0.052115052938461304,
+      -0.07368568331003189,
+      -0.11394031345844269,
+      -0.04513951390981674,
+      0.022121727466583252,
+      -0.010451988317072392,
+      0.003997989930212498,
+      -0.13713733851909637,
+      0.030619636178016663,
+      0.05786789208650589,
+      0.05840904265642166,
+      0.04732450470328331,
+      -0.012547117657959461,
+      -0.027409126982092857,
+      0.049672048538923264,
+      -0.00018399256805423647,
+      -0.004273589234799147,
+      -0.011101006530225277,
+      0.017240682616829872,
+      -0.002812016289681196,
+      0.034935809671878815,
+      0.006601597648113966,
+      0.014211715199053288,
+      -0.06332860141992569,
+      -0.05397455021739006,
+      -0.038572490215301514,
+      -0.06450864672660828,
+      0.07963147014379501,
+      0.029951799660921097,
+      0.03153093531727791,
+      -0.03852103650569916,
+      -0.025755248963832855,
+      0.13077980279922485,
+      -0.08185151219367981,
+      -0.09442253410816193,
+      0.01002975832670927,
+      0.02509395219385624,
+      -0.029981056228280067,
+      -0.025097224861383438,
+      0.04001101851463318,
+      0.006130080670118332
+    ],
+    "model": "XBN 2.1 Alloy",
+    "pickup_zone": "POLYGON((-0.1778 51.5524, 0.0822 51.5524, 0.0822 51.4024, -0.1778 51.4024, -0.1778 51.5524))",
     "price": 810,
-    "type": "Road Bikes",
-    "specs": {
-      "material": "alloy",
-      "weight": "7.2"
-    },
-    "description": "The XBN 2.1 Alloy is our entry-level road bike – but that’s not to say that it’s a basic machine. With an internal weld aluminium frame, a full carbon fork, and the slick-shifting Claris gears from Shimano’s, this is a bike which doesn’t break the bank and delivers craved performance. The 6061 alloy frame is triple-butted which ensures a lighter weight and smoother ride. And it’s comfortable with dropped seat stays and the carbon fork. The carefully crafted 50-34 tooth chainset and 11-32 tooth cassette give an easy-on-the-legs bottom gear for climbing, and the high-quality Vittoria Zaffiro tires balance grip, rolling friction and puncture protection when coasting down the other side.  "
+    "store_location": "-0.1278,51.5074"
   },
   {
-    "model": "WattBike",
     "brand": "ScramBikes",
+    "condition": "new",
+    "description": "The WattBike is the best e-bike for people who still feel young at heart. It has a Bafang 1000W mid-drive system and a 48V 17.5AH Samsung Lithium-Ion battery, allowing you to ride for more than 60 miles on one charge. It\u2019s great for tackling hilly terrain or if you just fancy a more leisurely ride. With three working modes, you can choose between E-bike, assisted bicycle, and normal bike modes.",
+    "description_embeddings": [
+      -0.006927311420440674,
+      0.15900678932666779,
+      -0.005495064426213503,
+      0.06652409583330154,
+      0.027506737038493156,
+      0.03928178921341896,
+      0.0212758406996727,
+      0.08142763376235962,
+      -0.004556896630674601,
+      0.04261007905006409,
+      0.0852041020989418,
+      -0.048658017069101334,
+      0.04896014556288719,
+      0.008289206773042679,
+      0.09533551335334778,
+      0.042673129588365555,
+      0.11990982294082642,
+      -0.09381455183029175,
+      -0.001154645229689777,
+      -0.009989846497774124,
+      0.042972203344106674,
+      0.055328626185655594,
+      0.044754382222890854,
+      0.01764347031712532,
+      0.04503790661692619,
+      -0.003830699948593974,
+      -0.03431522846221924,
+      0.03080279380083084,
+      -0.07722456008195877,
+      -0.09261710941791534,
+      0.04810558632016182,
+      0.04917953535914421,
+      0.027227703481912613,
+      -0.04199009761214256,
+      -0.11837311834096909,
+      0.028090154752135277,
+      0.08678824454545975,
+      -0.052036624401807785,
+      -0.06585966050624847,
+      -0.04037070646882057,
+      -0.08040877431631088,
+      0.0018185328226536512,
+      0.043989114463329315,
+      -0.011817573569715023,
+      0.006730342749506235,
+      -0.011594205163419247,
+      0.008361537009477615,
+      -0.054372794926166534,
+      0.033345889300107956,
+      -0.03933562710881233,
+      0.10115987062454224,
+      -0.08934503048658371,
+      0.04519934952259064,
+      0.03582148626446724,
+      -0.021424520760774612,
+      -0.07357319444417953,
+      -0.07426925748586655,
+      0.018053170293569565,
+      0.04639451205730438,
+      -0.07499486207962036,
+      0.057791586965322495,
+      -0.05478687211871147,
+      0.030340412631630898,
+      -0.0056327772326767445,
+      -0.0452428013086319,
+      -0.044913534075021744,
+      0.0526629202067852,
+      -0.08259481936693192,
+      -0.05616062134504318,
+      0.0005400424124673009,
+      -0.04933836683630943,
+      1.7464293705415912e-05,
+      -0.007984945550560951,
+      0.009467384777963161,
+      -0.04055757448077202,
+      -0.0056908270344138145,
+      0.036597516387701035,
+      0.023873118683695793,
+      0.00418807053938508,
+      0.04676923528313637,
+      -0.053795333951711655,
+      -0.015527212992310524,
+      -0.080276258289814,
+      0.026996882632374763,
+      0.1144171804189682,
+      -0.011178486980497837,
+      0.06854862719774246,
+      0.022201502695679665,
+      -0.01913747377693653,
+      0.009713435545563698,
+      0.01423699501901865,
+      0.04772024229168892,
+      0.034634001553058624,
+      0.0756441131234169,
+      -0.01204933412373066,
+      -0.031088251620531082,
+      -0.02462930977344513,
+      -0.04386857897043228,
+      -0.07706759870052338,
+      -0.002071107504889369,
+      -0.019828464835882187,
+      0.10314348340034485,
+      0.07235224545001984,
+      0.03167572245001793,
+      -0.02631053328514099,
+      -0.036559153348207474,
+      0.012040914967656136,
+      0.08063311874866486,
+      0.008269569836556911,
+      -0.012434666976332664,
+      0.00650354428216815,
+      -0.05601133033633232,
+      -0.028117282316088676,
+      -0.025071244686841965,
+      -0.01907099038362503,
+      0.003760937135666609,
+      -0.052525606006383896,
+      0.07173370569944382,
+      0.09372185170650482,
+      0.1006019189953804,
+      0.023999499157071114,
+      0.041847433894872665,
+      0.02114962227642536,
+      0.05726422369480133,
+      0.008218048140406609,
+      -0.06967302411794662,
+      0.01968124881386757,
+      1.844028477519647e-33,
+      -0.031731415539979935,
+      0.03648626059293747,
+      -0.026035945862531662,
+      -0.026796391233801842,
+      0.009511047042906284,
+      0.050696976482868195,
+      -0.03008556365966797,
+      -0.027142174541950226,
+      -0.07182826101779938,
+      -0.02520623430609703,
+      -0.005983793176710606,
+      0.07632830739021301,
+      0.09301365166902542,
+      0.0744069442152977,
+      0.10173527896404266,
+      -0.08317957073450089,
+      -0.06219454109668732,
+      -0.0776224136352539,
+      0.013563201762735844,
+      0.005839265417307615,
+      0.011761599220335484,
+      -0.0701083242893219,
+      0.005647188518196344,
+      -0.007439272943884134,
+      -4.4855809392174706e-05,
+      -0.05095696449279785,
+      0.13620494306087494,
+      0.017342044040560722,
+      -0.01352923084050417,
+      0.03086051531136036,
+      -0.0740780308842659,
+      -0.06721310317516327,
+      -0.06769067794084549,
+      0.01185466069728136,
+      -0.07234086841344833,
+      0.0020215404219925404,
+      -0.0108563881367445,
+      0.007788154762238264,
+      0.07912690192461014,
+      -0.02952556498348713,
+      -0.010350959375500679,
+      0.025074176490306854,
+      -0.050776757299900055,
+      0.00947178341448307,
+      0.03259417414665222,
+      0.0319671556353569,
+      0.0379379540681839,
+      0.05242982879281044,
+      -0.07516643404960632,
+      0.020074544474482536,
+      -0.08712191134691238,
+      -0.01204316969960928,
+      -0.006554455496370792,
+      -0.005875407252460718,
+      -0.06922540068626404,
+      0.041081465780735016,
+      -0.003257623640820384,
+      0.0391659140586853,
+      -0.03731334209442139,
+      -0.03579063341021538,
+      -0.04008869081735611,
+      0.05648549646139145,
+      -0.01142149232327938,
+      -0.05515728518366814,
+      -0.06406072527170181,
+      -0.013155528344213963,
+      0.0029902313835918903,
+      -0.020829875022172928,
+      -0.13008210062980652,
+      -0.039412979036569595,
+      0.05974568799138069,
+      -0.06617670506238937,
+      0.09968123584985733,
+      -0.04378099367022514,
+      0.008272947743535042,
+      -0.007245620246976614,
+      -0.05228377878665924,
+      -0.05929296463727951,
+      -0.07816570997238159,
+      0.04665905237197876,
+      -0.01630396395921707,
+      -0.020880484953522682,
+      -0.06532212346792221,
+      -0.003213261254131794,
+      0.0416768379509449,
+      -0.05093088001012802,
+      -0.0871049091219902,
+      -0.014571009203791618,
+      0.0010796786518767476,
+      0.007087667006999254,
+      0.05550219491124153,
+      -0.07753361761569977,
+      0.022848013788461685,
+      0.02596968039870262,
+      0.04259824752807617,
+      -2.380165022444961e-33,
+      0.05820159241557121,
+      0.046025633811950684,
+      0.10894608497619629,
+      0.05244075506925583,
+      0.15792003273963928,
+      0.024086199700832367,
+      0.029237573966383934,
+      -0.023072607815265656,
+      -0.07495220005512238,
+      -0.013094011694192886,
+      -0.004260784015059471,
+      -0.053080882877111435,
+      -0.00895928218960762,
+      -0.03149857744574547,
+      0.13309381902217865,
+      0.038643430918455124,
+      -0.02136029675602913,
+      -0.030247559770941734,
+      0.08822915703058243,
+      -0.026076463982462883,
+      0.050446517765522,
+      0.011856893077492714,
+      -0.06957101821899414,
+      -0.02773614600300789,
+      0.04625667631626129,
+      0.008786994963884354,
+      -0.07701855897903442,
+      0.001076446962542832,
+      -0.004858669359236956,
+      0.0067254831083118916,
+      -0.02791707031428814,
+      -0.019495468586683273,
+      0.0703381896018982,
+      0.030558260157704353,
+      -0.05546342208981514,
+      0.0420801043510437,
+      -0.03730127215385437,
+      -0.01322201732546091,
+      0.038336288183927536,
+      0.06427455693483353,
+      0.028238974511623383,
+      -0.06713984161615372,
+      0.03150900453329086,
+      0.024600861594080925,
+      0.016221575438976288,
+      0.025838203728199005,
+      -0.02313261851668358,
+      0.0557485967874527,
+      0.015211678110063076,
+      0.029895616695284843,
+      0.06008606031537056,
+      0.04473312199115753,
+      -0.050083715468645096,
+      -0.017571061849594116,
+      -0.014091495424509048,
+      -0.06641074270009995,
+      -0.008071008138358593,
+      0.03312089666724205,
+      -0.09482058882713318,
+      -0.08763624727725983,
+      0.030528157949447632,
+      0.013274747878313065,
+      0.06158939003944397,
+      0.0748405009508133,
+      -0.12128522247076035,
+      -0.12076683342456818,
+      0.0464591421186924,
+      0.0045278542675077915,
+      -0.002574144396930933,
+      -0.028266169130802155,
+      -0.04953430965542793,
+      -0.007604515179991722,
+      -0.01084962673485279,
+      -0.06370151042938232,
+      0.00812828354537487,
+      -0.027805447578430176,
+      0.044624149799346924,
+      0.016610005870461464,
+      -0.027103105559945107,
+      -0.046117331832647324,
+      -0.002852817066013813,
+      0.05479831248521805,
+      0.05342277139425278,
+      -0.03752776235342026,
+      -0.0053502353839576244,
+      -0.018950853496789932,
+      -0.07712738960981369,
+      -0.13029317557811737,
+      -0.013171681202948093,
+      0.02069253847002983,
+      0.029317859560251236,
+      0.018668048083782196,
+      -0.061371881514787674,
+      0.05376929044723511,
+      0.01483837515115738,
+      -3.964297690117746e-08,
+      0.03559036925435066,
+      -0.005289694294333458,
+      -0.013635152950882912,
+      -0.020672710612416267,
+      0.039649732410907745,
+      -0.06206038221716881,
+      0.04933065176010132,
+      0.010378899984061718,
+      0.020493512973189354,
+      0.027486076578497887,
+      0.07419533282518387,
+      -0.03473059833049774,
+      0.05251400172710419,
+      0.013588557951152325,
+      0.01814397983253002,
+      -0.024619124829769135,
+      0.11751414835453033,
+      0.05483951419591904,
+      0.022471528500318527,
+      0.0301313828676939,
+      0.018649602308869362,
+      -0.06219587102532387,
+      0.04238469526171684,
+      -0.053293377161026,
+      0.002427657600492239,
+      -0.0019911346025764942,
+      0.004944113548845053,
+      -0.061433035880327225,
+      -0.013191037811338902,
+      -0.030179856345057487,
+      -0.051340680569410324,
+      0.022094713523983955,
+      -0.035341646522283554,
+      -0.007219062652438879,
+      -0.06182244420051575,
+      -0.06059279292821884,
+      -0.041057273745536804,
+      0.002089729532599449,
+      -0.043397895991802216,
+      0.07170896232128143,
+      0.036471735686063766,
+      -0.015439609996974468,
+      -0.01848314143717289,
+      0.0056609525345265865,
+      -0.0012752920156344771,
+      -0.056571539491415024,
+      -0.01979043148458004,
+      -0.12011151015758514,
+      -0.02223217859864235,
+      0.029830070212483406,
+      0.027551136910915375,
+      -0.0010704555315896869,
+      0.000702365068718791,
+      -0.005173679441213608,
+      -0.019360698759555817,
+      0.17009279131889343,
+      -0.04601005092263222,
+      -0.04016156122088432,
+      -0.01600208878517151,
+      0.04198170080780983,
+      0.02032368630170822,
+      -0.06263051927089691,
+      -0.048464443534612656,
+      0.009351130574941635
+    ],
+    "model": "WattBike",
+    "pickup_zone": "POLYGON((2.1767 48.9016, 2.5267 48.9016, 2.5267 48.5516, 2.1767 48.5516, 2.1767 48.9016))",
     "price": 2300,
-    "type": "eBikes",
-    "specs": {
-      "material": "alloy",
-      "weight": "15"
-    },
-    "description": "The WattBike is the best e-bike for people who still feel young at heart. It has a  Bafang 500 watt geared hub motor that can reach 20 miles per hour on both steep inclines and city streets. The lithium-ion battery, which gets nearly 40 miles per charge, has a lightweight form factor, making it easier for seniors to use. It comes fully assembled (no convoluted instructions!) and includes a sturdy helmet at no cost. The Plush saddle softens over time with use. The included Seatpost, however, is easily adjustable and adds to this bike’s fantastic rating for seniors, as do the hydraulic disc brakes from Tektro.  "
+    "store_location": "2.3522,48.8566"
   },
   {
-    "model": "Soothe Electric bike",
     "brand": "Peaknetic",
-    "price": 1950,
-    "type": "eBikes",
-    "specs": {
-      "material": "alloy",
-      "weight": "14.7"
-    },
-    "description": "The Soothe is an everyday electric bike, from the makers of Exercycle  bikes, that conveys style while you get around the city. The Soothe lives up to its name by keeping your posture upright and relaxed for the ride ahead, keeping those aches and pains from riding at bay. It includes a low-step frame , our memory foam seat, bump-resistant shocks and conveniently placed thumb throttle. "
-  },
-  {
+    "condition": "new",
+    "description": "If you struggle with stiff fingers or a kinked neck or back after a few minutes on the road, this lightweight, aluminum bike alleviates those issues and allows you to enjoy the ride. From the ergonomic grips to the lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. The rear-inclined seat tube facilitates stability by allowing you to put a foot on the ground to balance at a stop, and the low step-over frame makes it accessible for all ability and mobility levels. The saddle is very soft, with a wide back to support your hip joints and a cutout in the center to redistribute that pressure. Rim brakes deliver satisfactory braking control, and the wide tires provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts facilitate setting up the Roll Low-Entry as your preferred commuter, and the BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder.",
+    "description_embeddings": [
+      0.0022135202307254076,
+      0.0681997612118721,
+      0.0064607178792357445,
+      0.007070810534060001,
+      -0.054231829941272736,
+      0.008059866726398468,
+      0.040072083473205566,
+      0.0956423208117485,
+      0.049143481999635696,
+      0.0379914790391922,
+      -0.020757146179676056,
+      0.06460786610841751,
+      0.07982552796602249,
+      -0.0321788415312767,
+      -0.006194670218974352,
+      0.0375053696334362,
+      0.1270381063222885,
+      -0.02341461181640625,
+      -0.007247396744787693,
+      0.0682845488190651,
+      -0.026470346376299858,
+      0.005658577661961317,
+      0.04653697833418846,
+      0.03987714648246765,
+      -0.12344618886709213,
+      0.03188862279057503,
+      -0.02708076685667038,
+      0.06964577734470367,
+      0.02201199159026146,
+      -0.02890665829181671,
+      -0.040280576795339584,
+      0.06318672746419907,
+      0.07309666275978088,
+      -0.08932560682296753,
+      -0.11648543179035187,
+      -0.029937371611595154,
+      0.10487373173236847,
+      0.041655637323856354,
+      -0.022871389985084534,
+      -0.04677774757146835,
+      0.02746077999472618,
+      0.01847464218735695,
+      0.08173345029354095,
+      0.06561841815710068,
+      0.05970228090882301,
+      -0.024480478838086128,
+      0.06907600909471512,
+      -0.03947169706225395,
+      0.024855393916368484,
+      -0.013199429027736187,
+      0.09996063262224197,
+      0.0028578736819326878,
+      0.08506831526756287,
+      0.014810853637754917,
+      -0.03929787874221802,
+      0.0018542942125350237,
+      -0.14215077459812164,
+      0.06970464438199997,
+      0.0265016071498394,
+      -0.06698428839445114,
+      0.07732488960027695,
+      -0.04583248123526573,
+      0.028696633875370026,
+      0.013155206106603146,
+      0.02578958310186863,
+      -0.029291296377778053,
+      -0.00031816380214877427,
+      -0.125708669424057,
+      -0.042060736566782,
+      -0.05381627008318901,
+      -0.0538906455039978,
+      0.0014778936747461557,
+      -0.09889215975999832,
+      -0.0429794080555439,
+      -0.013458915054798126,
+      -0.04558553919196129,
+      0.09005370736122131,
+      -0.04213777929544449,
+      -0.1349189579486847,
+      0.055852413177490234,
+      0.006197084207087755,
+      0.016338912770152092,
+      0.032463233917951584,
+      0.02548987604677677,
+      0.030681701377034187,
+      -0.0703219398856163,
+      0.05395807698369026,
+      -0.009628057479858398,
+      -0.031475286930799484,
+      -0.027579376474022865,
+      0.04098684713244438,
+      0.03901920095086098,
+      -0.01192146260291338,
+      -0.04101356491446495,
+      -0.08753280341625214,
+      0.0705665871500969,
+      0.03578994423151016,
+      0.032069701701402664,
+      -0.03211764618754387,
+      0.09590566158294678,
+      0.0611797571182251,
+      0.004700345452874899,
+      0.10438291728496552,
+      0.07409676164388657,
+      -0.0090691689401865,
+      0.011407091282308102,
+      0.05370165407657623,
+      -0.020438825711607933,
+      -0.04398776963353157,
+      0.032895661890506744,
+      -0.0012730252929031849,
+      0.018297234550118446,
+      -0.04333885386586189,
+      0.06208101287484169,
+      -0.08955910801887512,
+      -0.04672509804368019,
+      -0.06376977264881134,
+      0.022537674754858017,
+      0.02881341427564621,
+      -0.0030273371376097202,
+      -0.06542699784040451,
+      0.007231372408568859,
+      0.01855703443288803,
+      0.012365416623651981,
+      0.018434280529618263,
+      -0.04855069890618324,
+      -0.08907819539308548,
+      -2.615521077916409e-34,
+      -0.046131156384944916,
+      -0.028526470065116882,
+      0.01342072058469057,
+      -0.010418130084872246,
+      -0.019669201225042343,
+      -0.07430055737495422,
+      -0.006000629626214504,
+      -0.03320513665676117,
+      -0.05303066596388817,
+      0.07680810242891312,
+      -0.0061429338529706,
+      0.06154831871390343,
+      0.09432042390108109,
+      0.0038354273419827223,
+      0.14506474137306213,
+      -0.07032876461744308,
+      -0.07443196326494217,
+      -0.04439792409539223,
+      -0.005104243289679289,
+      -3.3934433304239064e-05,
+      -0.08257872611284256,
+      -0.056131236255168915,
+      0.04174238070845604,
+      0.0017745267832651734,
+      -0.002772972686216235,
+      0.006998051423579454,
+      0.09371285885572433,
+      -0.013138788752257824,
+      -0.042773280292749405,
+      0.00896062795072794,
+      -0.09441300481557846,
+      -0.007952050305902958,
+      -0.015586148016154766,
+      -0.017506571486592293,
+      0.01347337942570448,
+      0.027937229722738266,
+      -0.11657726019620895,
+      -0.03324989974498749,
+      -0.018427638337016106,
+      -0.04819897934794426,
+      -0.04077771306037903,
+      -0.0001697312545729801,
+      -0.05697356536984444,
+      0.07191669940948486,
+      0.017228955402970314,
+      0.03711475431919098,
+      0.042057864367961884,
+      0.004786928184330463,
+      -0.06956200301647186,
+      0.06036132574081421,
+      -0.0016305814497172832,
+      0.02468821406364441,
+      -0.013794313184916973,
+      -0.025994934141635895,
+      -0.07489914447069168,
+      0.01067660003900528,
+      -0.010298662818968296,
+      -0.022154971957206726,
+      -0.09746527671813965,
+      0.06335768103599548,
+      -0.022728655487298965,
+      -0.0005628599901683629,
+      -0.04313022270798683,
+      -0.04123309254646301,
+      -0.08378659188747406,
+      0.020546691492199898,
+      0.01680913008749485,
+      -0.010155763477087021,
+      0.008547178469598293,
+      -0.0211178008466959,
+      0.023050235584378242,
+      0.06479462236166,
+      0.061528537422418594,
+      0.022156352177262306,
+      0.019619867205619812,
+      0.07456795871257782,
+      0.049971628934144974,
+      -0.07878398895263672,
+      0.04972408711910248,
+      -0.015442566946148872,
+      0.044758349657058716,
+      -0.037393294274806976,
+      -0.03831558674573898,
+      -0.016534404829144478,
+      -0.05692937225103378,
+      0.02438316121697426,
+      -0.008604591712355614,
+      -0.06003899499773979,
+      0.04884570837020874,
+      -0.05407913774251938,
+      -0.004864877089858055,
+      -0.039421387016773224,
+      -0.0335439033806324,
+      0.05149518698453903,
+      -0.00761334178969264,
+      -4.919814414418271e-34,
+      0.0605306513607502,
+      0.013155259191989899,
+      0.0022042335476726294,
+      -0.016238724812865257,
+      0.017820321023464203,
+      -0.029504502192139626,
+      0.1179562360048294,
+      -0.08494631201028824,
+      -0.05847567319869995,
+      -0.03412671759724617,
+      0.01584434323012829,
+      0.0205944012850523,
+      0.011703073978424072,
+      0.024820921942591667,
+      0.07683313637971878,
+      0.016703670844435692,
+      -0.0465223602950573,
+      -0.08929521590471268,
+      0.013778958469629288,
+      -0.06448621302843094,
+      0.047237128019332886,
+      0.11140323430299759,
+      -0.036479681730270386,
+      -0.055252984166145325,
+      -0.08155377954244614,
+      -0.0011454259511083364,
+      -0.07414430379867554,
+      0.04839516803622246,
+      -0.036127883940935135,
+      0.04249665141105652,
+      -0.05564387887716293,
+      0.008439254947006702,
+      0.056384216994047165,
+      0.0037136792670935392,
+      -0.06267311424016953,
+      0.06599505990743637,
+      -0.0944608598947525,
+      -0.01900491677224636,
+      0.0017078104428946972,
+      0.018181079998612404,
+      0.0072936019860208035,
+      0.03901578113436699,
+      0.022009696811437607,
+      -0.02042953297495842,
+      0.04422936588525772,
+      0.099826380610466,
+      0.0022175773046910763,
+      0.05569764971733093,
+      0.005229232832789421,
+      -0.06281892955303192,
+      0.06203164905309677,
+      0.05493532121181488,
+      0.06598878651857376,
+      0.06272768974304199,
+      0.05623844638466835,
+      -0.053184594959020615,
+      0.012609804049134254,
+      -0.009191329590976238,
+      -0.07956400513648987,
+      -0.005095178727060556,
+      -0.06295286118984222,
+      0.05799472704529762,
+      0.004298996180295944,
+      -0.0245245061814785,
+      -0.010027579963207245,
+      -0.02338206022977829,
+      -0.03576310724020004,
+      -0.0735088586807251,
+      -0.10477573424577713,
+      0.010318689979612827,
+      -0.031293049454689026,
+      -0.06913845986127853,
+      0.07762496173381805,
+      -0.029345618560910225,
+      0.03347797319293022,
+      0.014305013231933117,
+      0.06321006268262863,
+      -0.09872464835643768,
+      -0.040937263518571854,
+      0.028350593522191048,
+      -0.08784928917884827,
+      0.005375882610678673,
+      0.059733789414167404,
+      0.027322115376591682,
+      -0.04657347500324249,
+      0.02783248759806156,
+      -0.12815773487091064,
+      0.004414730705320835,
+      -0.009058866649866104,
+      0.06062375009059906,
+      0.04072198644280434,
+      0.05082780495285988,
+      -0.036888547241687775,
+      0.07301440089941025,
+      0.022250277921557426,
+      -4.836826761334123e-08,
+      -0.02333931438624859,
+      -0.0006597689352929592,
+      -0.011001646518707275,
+      0.01690472476184368,
+      -0.0037487675435841084,
+      0.039681874215602875,
+      -0.012263616546988487,
+      0.010128140449523926,
+      0.03165998309850693,
+      0.0028211181052029133,
+      0.009292887523770332,
+      -0.05068610981106758,
+      -0.05350435897707939,
+      0.0027450143825262785,
+      -0.02869512513279915,
+      0.18523184955120087,
+      0.010015024803578854,
+      0.04042758792638779,
+      0.010014397092163563,
+      -0.07638011872768402,
+      -0.04126984626054764,
+      -0.06051325798034668,
+      0.04609273001551628,
+      -0.00863336119800806,
+      -0.010159372352063656,
+      -0.0686831921339035,
+      -0.022274712100625038,
+      0.054596077650785446,
+      -0.004217579495161772,
+      0.005010589957237244,
+      -0.0023027928546071053,
+      0.054350487887859344,
+      0.051168326288461685,
+      -0.0005977987311780453,
+      0.0008231411338783801,
+      -0.005349422339349985,
+      -0.04023698344826698,
+      0.01875622756779194,
+      0.051792532205581665,
+      0.0725129023194313,
+      0.003990984987467527,
+      -0.0412585511803627,
+      -0.030975697562098503,
+      0.02229507826268673,
+      -0.023536084219813347,
+      0.004254089202731848,
+      -0.047596003860235214,
+      0.054139409214258194,
+      0.024750487878918648,
+      0.00830126740038395,
+      0.04204926639795303,
+      -0.05580601468682289,
+      0.014396552927792072,
+      0.0785103291273117,
+      -0.01755904220044613,
+      0.09679318964481354,
+      -0.01722336746752262,
+      -0.03680667281150818,
+      -0.021823544055223465,
+      0.044612541794776917,
+      -0.0008680447936058044,
+      0.027066197246313095,
+      -0.008826435543596745,
+      -0.034606464207172394
+    ],
     "model": "Secto",
-    "brand": "Peaknetic",
+    "pickup_zone": "POLYGON((13.3260 52.5700, 13.6550 52.5700, 13.6550 52.2700, 13.3260 52.2700, 13.3260 52.5700))",
     "price": 430,
-    "type": "Commuter bikes",
-    "specs": {
-      "material": "aluminium",
-      "weight": "10.0"
-    },
-    "description": "If you struggle with stiff fingers or a kinked neck or back after a few minutes on the road, this lightweight, aluminum bike alleviates those issues and allows you to enjoy the ride. From the ergonomic grips to the lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. The rear-inclined seat tube facilitates stability by allowing you to put a foot on the ground to balance at a stop, and the low step-over frame makes it accessible for all ability and mobility levels. The saddle is very soft, with a wide back to support your hip joints and a cutout in the center to redistribute that pressure. Rim brakes deliver satisfactory braking control, and the wide tires provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts facilitate setting up the Roll Low-Entry as your preferred commuter, and the BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder."
+    "store_location": "13.4050,52.5200"
   },
   {
-    "model": "Summit",
     "brand": "nHill",
+    "condition": "new",
+    "description": "This budget mountain bike from nHill performs well both on bike paths and on the trail. The fork with 100mm of travel absorbs rough terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. The Shimano Tourney drivetrain offered enough gears for finding a comfortable pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. Whether you want an affordable bike that you can take to work, but also take trail in mountains on the weekends or you\u2019re just after a stable, comfortable ride for the bike path, the Summit gives a good value for money.",
+    "description_embeddings": [
+      -0.024333441630005836,
+      0.029308300465345383,
+      -0.012847754172980785,
+      -0.013123984448611736,
+      -0.039905961602926254,
+      -0.04596070945262909,
+      -0.01287133153527975,
+      0.03984961286187172,
+      -0.043438445776700974,
+      0.012349214404821396,
+      -0.021342391148209572,
+      -0.027458613738417625,
+      -0.004793129395693541,
+      0.016479987651109695,
+      0.02052542380988598,
+      -0.009542089886963367,
+      0.10066469013690948,
+      0.017397526651620865,
+      0.07893014699220657,
+      -0.0765308141708374,
+      -0.007650941610336304,
+      9.538845188217238e-05,
+      0.03314477205276489,
+      0.026631362736225128,
+      -0.01621824875473976,
+      0.03593063727021217,
+      -0.014871303923428059,
+      0.05259871482849121,
+      0.027785824611783028,
+      -0.044416770339012146,
+      -0.026691904291510582,
+      -0.01390022411942482,
+      -0.0573929138481617,
+      -0.08761026710271835,
+      0.012642575427889824,
+      0.04252056032419205,
+      0.04015251249074936,
+      -0.0052475095726549625,
+      -0.08608037978410721,
+      0.0028531427960842848,
+      -0.003371630096808076,
+      -0.02032443881034851,
+      -0.029511747881770134,
+      -0.043690912425518036,
+      0.042122989892959595,
+      -0.057133886963129044,
+      0.019293654710054398,
+      -0.019127611070871353,
+      0.036713697016239166,
+      -0.00833116751164198,
+      0.009040397591888905,
+      -0.1087319627404213,
+      0.09127230197191238,
+      -0.048213958740234375,
+      -0.023604029789566994,
+      0.0008899428648874164,
+      -0.093184694647789,
+      -0.03436879441142082,
+      0.00807907897979021,
+      -0.0520450733602047,
+      0.02262270636856556,
+      -0.03259866312146187,
+      -0.0391012541949749,
+      0.001295328140258789,
+      0.06636986881494522,
+      -0.04248524457216263,
+      -0.07093628495931625,
+      -0.06715728342533112,
+      0.007415436673909426,
+      -0.06185786426067352,
+      0.036563266068696976,
+      0.030749274417757988,
+      0.007705106865614653,
+      0.0023627770133316517,
+      -0.026215652003884315,
+      -0.020864665508270264,
+      0.05270038917660713,
+      0.021477004513144493,
+      0.0068344962783157825,
+      0.024355463683605194,
+      -0.03746088594198227,
+      0.031043346971273422,
+      0.09879995882511139,
+      -0.050035204738378525,
+      0.08045479655265808,
+      -0.04274336248636246,
+      0.02994127944111824,
+      -0.03783947601914406,
+      0.039749279618263245,
+      0.046901557594537735,
+      0.08667739480733871,
+      0.02831847593188286,
+      -0.008148318156599998,
+      0.007401767186820507,
+      -0.10989774018526077,
+      -0.014092149212956429,
+      9.036048140842468e-06,
+      0.054770372807979584,
+      -0.012413500808179379,
+      0.01861056312918663,
+      0.060349978506565094,
+      0.06291640549898148,
+      0.007055714726448059,
+      -0.021361181512475014,
+      0.03852728381752968,
+      -0.018908292055130005,
+      0.047424111515283585,
+      0.054501011967659,
+      0.017648596316576004,
+      0.11429999768733978,
+      -0.041358742862939835,
+      -0.03363256901502609,
+      0.0030338421929627657,
+      0.030056871473789215,
+      0.008060693740844727,
+      -0.0688784271478653,
+      -0.09984277933835983,
+      0.030267179012298584,
+      -0.028509166091680527,
+      0.02268315851688385,
+      -0.07580948621034622,
+      -0.0405895970761776,
+      0.03384138271212578,
+      0.07081738114356995,
+      0.019772004336118698,
+      -0.06172173097729683,
+      0.008248022757470608,
+      1.9840379362262432e-33,
+      0.037930894643068314,
+      0.04577890411019325,
+      -0.03732670471072197,
+      -0.032416991889476776,
+      0.014588817022740841,
+      -0.06602118909358978,
+      -0.013814577832818031,
+      -0.10539791733026505,
+      -0.12850415706634521,
+      -0.005076196976006031,
+      -0.07302963733673096,
+      0.07235066592693329,
+      -0.04646436870098114,
+      0.059371400624513626,
+      0.09111672639846802,
+      -0.10133209824562073,
+      -0.05483068525791168,
+      -0.053797587752342224,
+      -0.03709062561392784,
+      0.08241501450538635,
+      0.03958267718553543,
+      0.01433452870696783,
+      0.05912068858742714,
+      -0.0029660870786756277,
+      0.01806815154850483,
+      -0.0680701732635498,
+      0.013625666499137878,
+      0.015582672320306301,
+      -0.02142208069562912,
+      0.06357447057962418,
+      -0.12094264477491379,
+      -0.09666852653026581,
+      -0.03333089128136635,
+      -0.06621623784303665,
+      -0.03821765258908272,
+      -0.010776739567518234,
+      -0.08198492974042892,
+      -0.03277386352419853,
+      0.014794036746025085,
+      0.013517632149159908,
+      -0.0034003634937107563,
+      0.005664682947099209,
+      -0.022207774221897125,
+      0.015086682513356209,
+      -0.06799489259719849,
+      0.08191754668951035,
+      0.15600024163722992,
+      0.07579171657562256,
+      -0.05843832343816757,
+      -0.008412746712565422,
+      -0.07857701182365417,
+      -0.0038521387614309788,
+      -0.02901686355471611,
+      0.0006679021753370762,
+      -0.0697081908583641,
+      -0.05330892279744148,
+      0.053166620433330536,
+      0.004783661104738712,
+      0.013741954229772091,
+      0.07203977555036545,
+      -0.015861764550209045,
+      0.033332549035549164,
+      -0.022547632455825806,
+      -0.011850795708596706,
+      -0.09526507556438446,
+      -0.016078950837254524,
+      -0.004922114312648773,
+      0.004731250926852226,
+      -0.006536174099892378,
+      0.004852978512644768,
+      0.01268527377396822,
+      0.05300697684288025,
+      0.11899229139089584,
+      0.025274425745010376,
+      0.11763036996126175,
+      -0.08781222999095917,
+      -0.016429787501692772,
+      -0.02661072462797165,
+      -0.01769474893808365,
+      0.05961911380290985,
+      0.005877051502466202,
+      -0.03780582174658775,
+      -0.028037618845701218,
+      0.023397648707032204,
+      -0.006716609466820955,
+      0.015020519495010376,
+      0.040884219110012054,
+      -0.06197969987988472,
+      -0.029691174626350403,
+      -0.004976964555680752,
+      -0.03422437235713005,
+      0.018984060734510422,
+      -0.00813105795532465,
+      -0.020747167989611626,
+      0.0281930360943079,
+      -3.2326105667872445e-33,
+      0.12847235798835754,
+      0.026267321780323982,
+      0.10983140766620636,
+      0.011159190908074379,
+      -0.044980239123106,
+      0.017553674057126045,
+      -0.004794386215507984,
+      -0.015802551060914993,
+      -0.01226617582142353,
+      -0.019019361585378647,
+      0.011876302771270275,
+      -0.023136194795370102,
+      0.03209578990936279,
+      0.07442695647478104,
+      0.05641649663448334,
+      -0.05300089344382286,
+      -0.03638714924454689,
+      -0.014843880198895931,
+      0.036886364221572876,
+      -0.1257546991109848,
+      -0.008151554502546787,
+      0.07542898505926132,
+      -0.11252967268228531,
+      -0.09049033373594284,
+      -0.0030374047346413136,
+      0.04011000320315361,
+      -0.1538117229938507,
+      0.07717141509056091,
+      -0.04436258599162102,
+      0.07290291786193848,
+      -0.0072043901309370995,
+      0.03950807452201843,
+      0.002569766016677022,
+      -0.006248284596949816,
+      0.001176450401544571,
+      0.12515375018119812,
+      0.02005600742995739,
+      -0.00013864059292245656,
+      0.024221621453762054,
+      0.05465780198574066,
+      0.09940708428621292,
+      -0.053944025188684464,
+      0.09602796286344528,
+      0.00014552564243786037,
+      0.026602625846862793,
+      0.016811460256576538,
+      0.0015170868718996644,
+      0.08731727302074432,
+      0.005771235562860966,
+      -0.009904555976390839,
+      0.06958170980215073,
+      0.09265917539596558,
+      0.005830116104334593,
+      0.10210693627595901,
+      0.0011325017549097538,
+      -0.006749417632818222,
+      0.01503710262477398,
+      -0.03714510798454285,
+      -0.0939728170633316,
+      -0.03357759863138199,
+      -0.050196800380945206,
+      -0.006316252052783966,
+      -0.06414957344532013,
+      0.007235861383378506,
+      -0.01670873910188675,
+      -0.07423098385334015,
+      0.018221961334347725,
+      -0.05320512503385544,
+      -0.010248126462101936,
+      0.013013344258069992,
+      -0.12916545569896698,
+      -0.04244375228881836,
+      0.08774643391370773,
+      -0.03917357325553894,
+      -0.027767449617385864,
+      0.02099072001874447,
+      0.0595061257481575,
+      0.01945589855313301,
+      0.03815269470214844,
+      -0.028747402131557465,
+      -0.025533201172947884,
+      -0.038349006325006485,
+      -0.014486055821180344,
+      -0.013576257973909378,
+      0.051731329411268234,
+      0.06515145301818848,
+      -0.011720783077180386,
+      -0.1163521260023117,
+      -0.03931708261370659,
+      0.03394515439867973,
+      0.09380073100328445,
+      0.00931628793478012,
+      -0.01171857863664627,
+      0.04104544222354889,
+      -0.008916886523365974,
+      -4.140364140425845e-08,
+      0.061763226985931396,
+      0.02101300284266472,
+      -0.019075985997915268,
+      -0.002017116406932473,
+      0.015830116346478462,
+      -0.009857675060629845,
+      -0.018932191655039787,
+      -0.0007055550813674927,
+      0.013249439187347889,
+      0.0642324835062027,
+      0.12860508263111115,
+      0.03213700279593468,
+      -0.0670522004365921,
+      0.041800037026405334,
+      -0.0426088348031044,
+      0.0437115803360939,
+      0.021514814347028732,
+      0.12901803851127625,
+      0.015236952342092991,
+      -0.02232329733669758,
+      -0.05031055584549904,
+      -0.052778035402297974,
+      0.000233030179515481,
+      -0.022497626021504402,
+      -0.014370465651154518,
+      0.017518600448966026,
+      0.014312495477497578,
+      0.010902844369411469,
+      0.0027771666646003723,
+      -0.04195915535092354,
+      -0.06504479050636292,
+      0.038553908467292786,
+      -0.01374481339007616,
+      0.03843652829527855,
+      0.09058628976345062,
+      -0.0230315700173378,
+      -0.11761228740215302,
+      0.06487669050693512,
+      -0.005885662976652384,
+      0.06288695335388184,
+      0.05191958323121071,
+      0.011840583756566048,
+      -0.027309859171509743,
+      0.040654800832271576,
+      -0.005980184301733971,
+      0.03252403438091278,
+      -0.043744225054979324,
+      0.006068602204322815,
+      -0.00032751375692896545,
+      -0.022902367636561394,
+      -0.050694938749074936,
+      0.026743048802018166,
+      0.06005466729402542,
+      0.02092430181801319,
+      0.02072584442794323,
+      0.08342021703720093,
+      -0.05768749862909317,
+      -0.08585236966609955,
+      -0.03160274401307106,
+      0.05222279205918312,
+      0.029474787414073944,
+      -0.08763033896684647,
+      -0.01591801643371582,
+      -0.07798203080892563
+    ],
+    "model": "Summit",
+    "pickup_zone": "POLYGON((1.9450 41.4301, 2.4018 41.4301, 2.4018 41.1987, 1.9450 41.1987, 1.9450 41.4301))",
     "price": 1200,
-    "type": "Mountain Bike",
-    "specs": {
-      "material": "alloy",
-      "weight": "11.3"
-    },
-    "description": "This budget mountain bike from nHill performs well both on bike paths and on the trail. The fork with 100mm of travel absorbs rough terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. The Shimano Tourney drivetrain offered enough gears for finding a comfortable pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. Whether you want an affordable bike that you can take to work, but also take trail riding on the weekends or you’re just after a stable, comfortable ride for the bike path, the Summit gives a good value for money."
+    "store_location": "2.1734, 41.3851"
   },
   {
-    "model": "ThrillCycle",
     "brand": "BikeShind",
+    "condition": "refurbished",
+    "description": "An artsy,  retro-inspired bicycle that\u2019s as functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn\u2019t suggest taking it to the mountains. Fenders protect you from mud, and a rear basket lets you transport groceries, flowers and books. The ThrillCycle comes with a limited lifetime warranty, so this little guy will last you long past graduation.",
+    "description_embeddings": [
+      -0.005154624115675688,
+      0.10099548101425171,
+      0.04890008643269539,
+      0.0625317171216011,
+      -0.0363173745572567,
+      0.025850096717476845,
+      0.032137978821992874,
+      -0.03442877531051636,
+      -0.10096120089292526,
+      -0.007441149093210697,
+      0.002616145182400942,
+      0.002316742204129696,
+      0.042584337294101715,
+      0.026208963245153427,
+      0.018415318801999092,
+      0.050033390522003174,
+      0.14831797778606415,
+      -0.006160213612020016,
+      0.05086936056613922,
+      0.0131875304505229,
+      -0.05973455682396889,
+      0.045886117964982986,
+      -0.025052331387996674,
+      0.04576171189546585,
+      -0.006168896332383156,
+      0.03315199911594391,
+      -0.07763667404651642,
+      0.05837876722216606,
+      -0.03229084238409996,
+      -0.021293187513947487,
+      -0.008595496416091919,
+      0.06880632787942886,
+      -0.04528025537729263,
+      -0.020664094015955925,
+      -0.029125794768333435,
+      0.0445701889693737,
+      0.023799002170562744,
+      -0.013527574017643929,
+      -0.01646343804895878,
+      0.027023920789361,
+      0.0014843698590993881,
+      0.014952401630580425,
+      -0.010172702372074127,
+      0.07603776454925537,
+      0.017975280061364174,
+      -0.08911248296499252,
+      0.055482957512140274,
+      -0.027819648385047913,
+      0.019395964220166206,
+      0.05424710363149643,
+      0.06634850054979324,
+      -0.05045575276017189,
+      -0.0006240577204152942,
+      -0.06339468061923981,
+      -0.023632608354091644,
+      -0.060364823788404465,
+      -0.11193189769983292,
+      0.046562716364860535,
+      -0.010353066958487034,
+      -0.043506212532520294,
+      0.051063187420368195,
+      0.003231980837881565,
+      0.027102531865239143,
+      0.002380193443968892,
+      -0.0056939758360385895,
+      -0.026826998218894005,
+      -0.014482468366622925,
+      -0.0185822993516922,
+      0.013927196152508259,
+      -0.10704471915960312,
+      0.0673733651638031,
+      -0.0010599792003631592,
+      -0.07455477863550186,
+      -0.014452059753239155,
+      -0.02294282428920269,
+      -0.010201872326433659,
+      0.023037923499941826,
+      -0.05595972761511803,
+      -0.09120096266269684,
+      -0.029177049174904823,
+      -0.02343042939901352,
+      -0.029726101085543633,
+      0.07366959005594254,
+      -0.046458736062049866,
+      0.006261167582124472,
+      -0.013148028403520584,
+      -0.0014217026764526963,
+      0.017440352588891983,
+      -0.04511420056223869,
+      0.008813070133328438,
+      -0.022654451429843903,
+      -0.014097515493631363,
+      -0.020799456164240837,
+      -0.05456947907805443,
+      -0.07338607311248779,
+      0.017073828727006912,
+      -0.04925030097365379,
+      -0.024428002536296844,
+      -0.00979585014283657,
+      0.025696750730276108,
+      0.07033320516347885,
+      0.0389082096517086,
+      0.12711860239505768,
+      0.07472020387649536,
+      -0.019501805305480957,
+      0.01663217693567276,
+      0.027799105271697044,
+      0.039703886955976486,
+      -0.029871169477701187,
+      0.005997804459184408,
+      -0.0015701024094596505,
+      0.0411832258105278,
+      8.85713889147155e-05,
+      -0.029442811384797096,
+      0.009789851494133472,
+      -0.04723270237445831,
+      -0.09891993552446365,
+      0.05102938041090965,
+      -0.007144609931856394,
+      0.01668076030910015,
+      0.004902719985693693,
+      0.02218448370695114,
+      0.03827798366546631,
+      0.001542922342196107,
+      0.004610520787537098,
+      -0.12595036625862122,
+      0.07361572980880737,
+      -1.521196586481568e-33,
+      -0.01484542153775692,
+      0.024973904713988304,
+      0.006633534096181393,
+      0.01254032738506794,
+      0.06355929374694824,
+      -0.04809075966477394,
+      0.02005922608077526,
+      -0.06251886487007141,
+      -0.06941430270671844,
+      0.02304103970527649,
+      -0.020975833758711815,
+      0.08137834072113037,
+      0.049319952726364136,
+      0.11945393681526184,
+      0.17472721636295319,
+      -0.03430051729083061,
+      -0.07276412844657898,
+      -0.11828659474849701,
+      0.04918891564011574,
+      -0.07279565185308456,
+      -0.06228293105959892,
+      -0.03494764119386673,
+      0.004517378751188517,
+      -0.0431801863014698,
+      -0.07457974553108215,
+      -0.0003888327337335795,
+      0.05853814631700516,
+      0.05362739413976669,
+      0.01866878569126129,
+      0.004751134198158979,
+      -0.07936650514602661,
+      0.033309247344732285,
+      -0.01660560630261898,
+      -0.08851712942123413,
+      0.042956508696079254,
+      0.03460550308227539,
+      -0.054352447390556335,
+      -0.016094308346509933,
+      0.019760286435484886,
+      -0.03591147065162659,
+      -0.04307156056165695,
+      -0.04029138758778572,
+      -0.09315019100904465,
+      0.055713504552841187,
+      0.003642909461632371,
+      0.0391569547355175,
+      0.1300928145647049,
+      0.026774607598781586,
+      -0.054334208369255066,
+      -0.060861144214868546,
+      -0.020662454888224602,
+      -0.034525640308856964,
+      0.004193050786852837,
+      0.02453654631972313,
+      -0.09028972685337067,
+      0.004444751888513565,
+      0.06320545822381973,
+      0.01895289309322834,
+      -0.04660886526107788,
+      0.08611723780632019,
+      0.05705415457487106,
+      0.030612647533416748,
+      0.019753821194171906,
+      -0.061483170837163925,
+      -0.025262145325541496,
+      0.054222241044044495,
+      0.017605014145374298,
+      -0.013110420666635036,
+      0.04744894057512283,
+      -0.004785404074937105,
+      0.04680679365992546,
+      0.001831064117141068,
+      0.07773134112358093,
+      0.008347200229763985,
+      0.08674833923578262,
+      0.024294976145029068,
+      -0.03695613518357277,
+      -0.0440739244222641,
+      0.00895663257688284,
+      -0.0060102143324911594,
+      -0.0361272394657135,
+      -0.08447428047657013,
+      -0.08971717208623886,
+      0.03131894767284393,
+      0.0721370130777359,
+      0.031180810183286667,
+      0.039390258491039276,
+      -0.09044987708330154,
+      -0.007888346910476685,
+      0.008131768554449081,
+      -0.03624662756919861,
+      -0.033649034798145294,
+      0.031620997935533524,
+      0.05870470404624939,
+      0.018141048029065132,
+      -5.7662626416839565e-34,
+      0.09117024391889572,
+      -0.023953478783369064,
+      0.080879345536232,
+      0.0035459804348647594,
+      -0.013222851790487766,
+      -0.025237491354346275,
+      0.019038159400224686,
+      -0.06588941067457199,
+      -0.11689981818199158,
+      0.0007165187271311879,
+      -0.0933104082942009,
+      0.014618181623518467,
+      0.12644915282726288,
+      0.0027253602165728807,
+      0.15038658678531647,
+      0.0053163510747253895,
+      -0.005645217839628458,
+      0.009321562945842743,
+      0.002719732467085123,
+      -0.01651378907263279,
+      0.0063886744901537895,
+      0.05738385394215584,
+      -0.14213474094867706,
+      -0.0669025406241417,
+      -0.05766160413622856,
+      0.0031909833196550608,
+      -0.13478563725948334,
+      -0.03741385415196419,
+      0.041654907166957855,
+      0.04030514881014824,
+      -0.05102578178048134,
+      0.0028968513943254948,
+      0.0738285705447197,
+      -0.03643025830388069,
+      -0.015445208176970482,
+      0.06674294173717499,
+      0.029759766533970833,
+      -0.024196317419409752,
+      -0.009355752728879452,
+      0.023269686847925186,
+      0.01623220555484295,
+      -0.08251868188381195,
+      0.020170293748378754,
+      0.0749305933713913,
+      0.08206077665090561,
+      0.012237507849931717,
+      -0.026570556685328484,
+      0.016253553330898285,
+      -0.003425935748964548,
+      0.005059909541159868,
+      0.12109038233757019,
+      0.08107315003871918,
+      -0.04097432270646095,
+      0.0009462210582569242,
+      0.058092083781957626,
+      -0.03609737753868103,
+      -0.01580999232828617,
+      -0.0342475026845932,
+      0.012185491621494293,
+      -0.058348096907138824,
+      -0.05934947729110718,
+      0.026715252548456192,
+      -0.031246516853570938,
+      0.012632215395569801,
+      -0.01100403256714344,
+      -0.05962579324841499,
+      -0.000801989808678627,
+      -0.06919746845960617,
+      -0.1299775391817093,
+      -0.03721063956618309,
+      -0.03989635780453682,
+      0.04918158799409866,
+      -0.0022671804763376713,
+      -0.04244564101099968,
+      -0.02631748840212822,
+      -0.04100838303565979,
+      0.08634430915117264,
+      0.05031242221593857,
+      0.06688959896564484,
+      0.024407675489783287,
+      0.0018788984743878245,
+      -0.026026425883173943,
+      0.04438408091664314,
+      0.02198263816535473,
+      -0.014974343590438366,
+      -0.026490231975913048,
+      -0.09914876520633698,
+      -0.09834708273410797,
+      0.017346272245049477,
+      0.00089951854897663,
+      0.05497178062796593,
+      0.06180766969919205,
+      -0.050425756722688675,
+      0.013637324795126915,
+      -0.03599657490849495,
+      -4.404103037813911e-08,
+      -0.0024933917447924614,
+      0.049585312604904175,
+      -0.020710783079266548,
+      -0.014283453114330769,
+      -0.0064896950498223305,
+      0.04579087719321251,
+      0.02242390066385269,
+      0.02515084482729435,
+      -0.031156959012150764,
+      0.006718308199197054,
+      0.061417631804943085,
+      -0.009935885667800903,
+      -0.021248064935207367,
+      0.011152776889503002,
+      -0.059073783457279205,
+      0.05840323865413666,
+      0.06523993611335754,
+      0.03690555691719055,
+      0.03174441307783127,
+      0.02336188219487667,
+      0.003073832020163536,
+      -0.017117813229560852,
+      0.02877660095691681,
+      0.0017827276606112719,
+      -0.07995487004518509,
+      -0.032443612813949585,
+      -0.01474942360073328,
+      -0.016080526635050774,
+      0.0771399736404419,
+      0.017354682087898254,
+      -0.02578366920351982,
+      0.004991421941667795,
+      0.006590475793927908,
+      -0.032372940331697464,
+      0.038421064615249634,
+      -0.1204696074128151,
+      -0.05457846075296402,
+      0.036750562489032745,
+      0.013932188041508198,
+      0.0031626380514353514,
+      0.009978784248232841,
+      -0.0138266421854496,
+      0.006769631989300251,
+      0.059896957129240036,
+      0.00822784099727869,
+      -0.05025117099285126,
+      -0.10305225104093552,
+      -0.07187453657388687,
+      0.00836241990327835,
+      0.049537766724824905,
+      0.007570290472358465,
+      -0.08729138970375061,
+      -0.020592620596289635,
+      0.04918212443590164,
+      0.054685790091753006,
+      0.04091939702630043,
+      -0.05420788377523422,
+      -0.04473182559013367,
+      -0.11178043484687805,
+      0.09808126091957092,
+      -0.015394269488751888,
+      -0.0039725536480546,
+      0.03283742815256119,
+      -0.05677533522248268
+    ],
+    "model": "ThrillCycle",
+    "pickup_zone": "POLYGON((12.4464 42.1028, 12.5464 42.1028, 12.5464 41.7028, 12.4464 41.7028, 12.4464 42.1028))",
     "price": 815,
-    "type": "Commuter Bikes",
-    "specs": {
-      "material": "alloy",
-      "weight": "12.7"
-    },
-    "description": "An artsy,  retro-inspired bicycle that’s as functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn’t suggest taking it to the mountains. Fenders protect you from mud, and a rear basket lets you transport groceries, flowers and books. The ThrillCycle comes with a limited lifetime warranty, so this little guy will last you long past graduation."
+    "store_location": "12.4964,41.9028"
   }
 ]
\ No newline at end of file
diff --git a/doctests/package.json b/doctests/package.json
index 76db8b3d8c7..7acf7fdb1ab 100644
--- a/doctests/package.json
+++ b/doctests/package.json
@@ -6,7 +6,8 @@
   "private": true,
   "type": "module",
   "dependencies": {
-    "redis": "../"
+    "redis": "../",
+    "@xenova/transformers": "^2.17.2"
   }
 }
 
diff --git a/doctests/query-agg.js b/doctests/query-agg.js
new file mode 100644
index 00000000000..0fb7bc1e198
--- /dev/null
+++ b/doctests/query-agg.js
@@ -0,0 +1,139 @@
+// EXAMPLE: query_agg
+// HIDE_START
+import assert from 'node:assert';
+import fs from 'node:fs';
+import { createClient } from 'redis';
+import { SchemaFieldTypes, AggregateSteps, AggregateGroupByReducers } from '@redis/search';
+
+const client = createClient();
+
+await client.connect().catch(console.error);
+
+// create index
+await client.ft.create('idx:bicycle', {
+  '$.condition': {
+    type: SchemaFieldTypes.TAG,
+    AS: 'condition'
+  },
+  '$.price': {
+    type: SchemaFieldTypes.NUMERIC,
+    AS: 'price'
+  }
+}, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+})
+
+// load data
+const bicycles = JSON.parse(fs.readFileSync('data/query_em.json', 'utf8'));
+
+await Promise.all(
+  bicycles.map((bicycle, bid) => {
+      return client.json.set(`bicycle:${bid}`, '$', bicycle);
+  })
+);
+// HIDE_END
+
+// STEP_START agg1
+const res1 = await client.ft.aggregate('idx:bicycle', '@condition:{new}', {
+  LOAD: ['__key', 'price'],
+  APPLY: {
+    expression: '@price - (@price * 0.1)',
+    AS: 'discounted'
+  }
+});
+
+console.log(res1.results.length); // >>> 5
+console.log(res1.results); // >>>
+//[
+//  [Object: null prototype] { __key: 'bicycle:0', price: '270' },
+//  [Object: null prototype] { __key: 'bicycle:5', price: '810' },
+//  [Object: null prototype] { __key: 'bicycle:6', price: '2300' },
+//  [Object: null prototype] { __key: 'bicycle:7', price: '430' },
+//  [Object: null prototype] { __key: 'bicycle:8', price: '1200' }
+//]
+// REMOVE_START
+assert.strictEqual(res1.results.length, 5);
+// REMOVE_END
+// STEP_END
+
+// STEP_START agg2
+const res2 = await client.ft.aggregate('idx:bicycle', '*', {
+  LOAD: ['@price'],
+  STEPS: [{
+      type: AggregateSteps.APPLY,
+      expression: '@price<1000',
+      AS: 'price_category'
+    },{
+      type: AggregateSteps.GROUPBY,
+      properties: '@condition',
+      REDUCE:[{
+        type: AggregateGroupByReducers.SUM,
+        property: '@price_category',
+        AS: 'num_affordable'
+      }]
+    }]
+});
+console.log(res2.results.length); // >>> 3
+console.log(res2.results); // >>>
+//[[Object: null prototype] { condition: 'refurbished', num_affordable: '1' },
+//  [Object: null prototype] { condition: 'used', num_affordable: '1' },
+//  [Object: null prototype] { condition: 'new', num_affordable: '3' }
+//]
+// REMOVE_START
+assert.strictEqual(res2.results.length, 3);
+// REMOVE_END
+// STEP_END
+
+// STEP_START agg3
+const res3 = await client.ft.aggregate('idx:bicycle', '*', {
+  STEPS: [{
+      type: AggregateSteps.APPLY,
+      expression: "'bicycle'",
+      AS: 'type'
+    }, {
+      type: AggregateSteps.GROUPBY,
+      properties: '@type',
+      REDUCE: [{
+        type: AggregateGroupByReducers.COUNT,
+        property: null,
+        AS: 'num_total'
+      }]
+    }]
+});
+console.log(res3.results.length); // >>> 1
+console.log(res3.results); // >>>
+//[ [Object: null prototype] { type: 'bicycle', num_total: '10' } ]
+// REMOVE_START
+assert.strictEqual(res3.results.length, 1);
+// REMOVE_END
+// STEP_END
+
+// STEP_START agg4
+const res4 = await client.ft.aggregate('idx:bicycle', '*', {
+  LOAD: ['__key'],
+  STEPS: [{
+      type: AggregateSteps.GROUPBY,
+      properties: '@condition',
+      REDUCE: [{
+        type: AggregateGroupByReducers.TOLIST,
+        property: '__key',
+        AS: 'bicycles'
+      }]
+    }]
+});
+console.log(res4.results.length); // >>> 3
+console.log(res4.results); // >>>
+//[[Object: null prototype] {condition: 'refurbished', bicycles: [ 'bicycle:9' ]},
+//  [Object: null prototype] {condition: 'used', bicycles: [ 'bicycle:1', 'bicycle:2', 'bicycle:3', 'bicycle:4' ]},
+//  [Object: null prototype] {condition: 'new', bicycles: [ 'bicycle:5', 'bicycle:6', 'bicycle:7', 'bicycle:0', 'bicycle:8' ]}]
+// REMOVE_START
+assert.strictEqual(res4.results.length, 3);
+// REMOVE_END
+// STEP_END
+
+// REMOVE_START
+// destroy index and data
+await client.ft.dropIndex('idx:bicycle', { DD: true });
+await client.disconnect();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/query-combined.js b/doctests/query-combined.js
new file mode 100644
index 00000000000..0ca6bc6717a
--- /dev/null
+++ b/doctests/query-combined.js
@@ -0,0 +1,192 @@
+// EXAMPLE: query_combined
+// HIDE_START
+import assert from 'node:assert';
+import fs from 'node:fs';
+import { createClient } from 'redis';
+import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
+import { pipeline } from '@xenova/transformers';
+
+function float32Buffer(arr) {
+  const floatArray = new Float32Array(arr);
+  const float32Buffer = Buffer.from(floatArray.buffer);
+  return float32Buffer;
+}
+
+async function embedText(sentence) {
+  let modelName = 'Xenova/all-MiniLM-L6-v2';
+  let pipe = await pipeline('feature-extraction', modelName);
+
+  let vectorOutput = await pipe(sentence, {
+      pooling: 'mean',
+      normalize: true,
+  });
+
+  if (vectorOutput == null) {
+    throw new Error('vectorOutput is undefined');
+  }
+
+  const embedding = Object.values(vectorOutput.data);
+
+  return embedding;
+}
+
+let query = 'Bike for small kids';
+let vector_query = float32Buffer(await embedText('That is a very happy person'));
+
+const client = createClient();
+await client.connect().catch(console.error);
+
+// create index
+await client.ft.create('idx:bicycle', {
+    '$.description': {
+      type: SchemaFieldTypes.TEXT,
+      AS: 'description'
+    },
+    '$.condition': {
+      type: SchemaFieldTypes.TAG,
+      AS: 'condition'
+    },
+    '$.price': {
+      type: SchemaFieldTypes.NUMERIC,
+      AS: 'price'
+    },
+    '$.description_embeddings': {
+        type: SchemaFieldTypes.VECTOR,
+        TYPE: 'FLOAT32',
+        ALGORITHM: VectorAlgorithms.FLAT,
+        DIM: 384,
+        DISTANCE_METRIC: 'COSINE',
+        AS: 'vector',
+    }
+}, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+});
+
+// load data
+const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
+
+await Promise.all(
+  bicycles.map((bicycle, bid) => {
+      return client.json.set(`bicycle:${bid}`, '$', bicycle);
+  })
+);
+// HIDE_END
+
+// STEP_START combined1
+const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
+console.log(res1.total); // >>> 1
+console.log(res1); // >>>
+//{
+//  total: 1,
+//  documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
+//}
+// REMOVE_START
+assert.strictEqual(res1.total, 1);
+// REMOVE_END
+// STEP_END
+
+// STEP_START combined2
+const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
+console.log(res2.total); // >>> 1
+console.log(res2); // >>>
+// {
+//   total: 1,
+//   documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
+// }
+// REMOVE_START
+assert.strictEqual(res2.total, 1);
+// REMOVE_END
+// STEP_END
+
+// STEP_START combined3
+const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
+console.log(res3.total); // >>> 2
+console.log(res3); // >>>
+//{
+//  total: 2,
+//  documents: [
+//    { id: 'bicycle:2', value: [Object: null prototype] },
+//    { id: 'bicycle:1', value: [Object: null prototype] }
+//  ]
+//}
+// REMOVE_START
+assert.strictEqual(res3.total, 2);
+// REMOVE_END
+// STEP_END
+
+// STEP_START combined4
+const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
+console.log(res4.total); // >>> 2
+console.log(res4); // >>>
+//{
+//  total: 2,
+//  documents: [
+//    { id: 'bicycle:2', value: [Object: null prototype] },
+//    { id: 'bicycle:1', value: [Object: null prototype] }
+//  ]
+//}
+// REMOVE_START
+assert.strictEqual(res4.total, 2);
+// REMOVE_END
+// STEP_END
+
+// STEP_START combined5
+const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
+console.log(res5.total); // >>> 3
+console.log(res5); // >>>
+//{
+//  total: 3,
+//  documents: [
+//    { id: 'bicycle:1', value: [Object: null prototype] },
+//    { id: 'bicycle:0', value: [Object: null prototype] },
+//    { id: 'bicycle:2', value: [Object: null prototype] }
+//  ]
+//}
+// REMOVE_START
+assert.strictEqual(res5.total, 3);
+// REMOVE_END
+// STEP_END
+
+// STEP_START combined6
+const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
+console.log(res6.total); // >>> 2
+console.log(res6); // >>>
+//{
+//  total: 2,
+//  documents: [
+//    { id: 'bicycle:2', value: [Object: null prototype] },
+//    { id: 'bicycle:9', value: [Object: null prototype] }
+//  ]
+//}
+// REMOVE_START
+assert.strictEqual(res6.total, 2);
+// REMOVE_END
+// STEP_END
+
+// STEP_START combined7
+const res7 = await client.ft.search('idx:bicycle', 
+  '(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
+    PARAMS: { query_vector: vector_query },
+    DIALECT: 2
+  }
+);
+console.log(res7.total); // >>> 2
+console.log(res7); // >>>
+//{
+//  total: 2,
+//  documents: [
+//    { id: 'bicycle:2', value: [Object: null prototype] },
+//    { id: 'bicycle:9', value: [Object: null prototype] }
+//  ]
+//}
+// REMOVE_START
+assert.strictEqual(res7.total, 2);
+// REMOVE_END
+// STEP_END
+
+// REMOVE_START
+// destroy index and data
+await client.ft.dropIndex('idx:bicycle', { DD: true });
+await client.disconnect();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/query-ft.js b/doctests/query-ft.js
new file mode 100644
index 00000000000..fa68bdc673e
--- /dev/null
+++ b/doctests/query-ft.js
@@ -0,0 +1,84 @@
+// EXAMPLE: query_ft
+// HIDE_START
+import assert from 'node:assert';
+import fs from 'node:fs';
+import { createClient, SchemaFieldTypes, AggregateGroupByReducers, AggregateSteps} from 'redis';
+
+const client = createClient();
+
+await client.connect().catch(console.error);
+
+// create index
+await client.ft.create('idx:bicycle', {
+  '$.model': {
+    type: SchemaFieldTypes.TEXT,
+    AS: 'model'
+  },
+  '$.brand': {
+    type: SchemaFieldTypes.TEXT,
+    AS: 'brand'
+  },
+  '$.description': {
+    type: SchemaFieldTypes.TEXT,
+    AS: 'description'
+  }
+}, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+})
+
+// load data
+const bicycles = JSON.parse(fs.readFileSync('data/query_em.json', 'utf8'));
+
+await Promise.all(
+  bicycles.map((bicycle, bid) => {
+      return client.json.set(`bicycle:${bid}`, '$', bicycle);
+  })
+);
+// HIDE_END
+
+// STEP_START ft1
+const res1 = await client.ft.search('idx:bicycle', '@description: kids');
+console.log(res1.total); // >>> 2
+// REMOVE_START
+assert.strictEqual(res1.total, 2);
+// REMOVE_END
+// STEP_END
+
+// STEP_START ft2
+const res2 = await client.ft.search('idx:bicycle', '@model: ka*');
+console.log(res2.total); // >>> 1
+// REMOVE_START
+assert.strictEqual(res2.total, 1);
+// REMOVE_END
+// STEP_END
+
+// STEP_START ft3
+const res3 = await client.ft.search('idx:bicycle', '@brand: *bikes');
+console.log(res3.total); // >>> 2
+// REMOVE_START
+assert.strictEqual(res3.total, 2);
+// REMOVE_END
+// STEP_END
+
+// STEP_START ft4
+const res4 = await client.ft.search('idx:bicycle', '%optamized%');
+console.log(res4); // >>> { total: 1, documents: [ { id: 'bicycle:3', value: [Object: null prototype] } ]}
+// REMOVE_START
+assert.strictEqual(res4.total, 1);
+// REMOVE_END
+// STEP_END
+
+// STEP_START ft5
+const res5 = await client.ft.search('idx:bicycle', '%%optamised%%');
+console.log(res5); // >>> { total: 1, documents: [ { id: 'bicycle:3', value: [Object: null prototype] } ]}
+// REMOVE_START
+assert.strictEqual(res5.total, 1);
+// REMOVE_END
+// STEP_END
+
+// REMOVE_START
+// destroy index and data
+await client.ft.dropIndex('idx:bicycle', { DD: true });
+await client.disconnect();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/query-geo.js b/doctests/query-geo.js
new file mode 100644
index 00000000000..675e3e7c02f
--- /dev/null
+++ b/doctests/query-geo.js
@@ -0,0 +1,82 @@
+// EXAMPLE: query_geo
+// HIDE_START
+import assert from 'node:assert';
+import fs from 'node:fs';
+import { createClient } from 'redis';
+import { SchemaFieldTypes } from '@redis/search';
+
+const client = createClient();
+
+await client.connect().catch(console.error);
+
+// create index
+await client.ft.create('idx:bicycle', {
+  '$.store_location': {
+    type: SchemaFieldTypes.GEO,
+    AS: 'store_location'
+  },
+   '$.pickup_zone': {
+    type: SchemaFieldTypes.GEOSHAPE,
+    AS: 'pickup_zone'
+  }
+}, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+})
+
+// load data
+const bicycles = JSON.parse(fs.readFileSync('data/query_em.json', 'utf8'));
+
+await Promise.all(
+  bicycles.map((bicycle, bid) => {
+      return client.json.set(`bicycle:${bid}`, '$', bicycle);
+  })
+);
+// HIDE_END
+
+// STEP_START geo1
+const res1= await client.ft.search('idx:bicycle', '@store_location:[-0.1778 51.5524 20 mi]');
+console.log(res1.total); // >>> 1
+console.log(res1); // >>> {total: 1, documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]}
+// REMOVE_START
+assert.strictEqual(res1.total, 1);
+// REMOVE_END
+// STEP_END
+
+// STEP_START geo2
+const params_dict_geo2 = { bike: 'POINT(-0.1278 51.5074)' };
+const q_geo2 = '@pickup_zone:[CONTAINS $bike]';
+const res2 = await client.ft.search('idx:bicycle', q_geo2, { PARAMS: params_dict_geo2, DIALECT: 3 });
+console.log(res2.total); // >>> 1
+console.log(res2); // >>> {total: 1, documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]}
+// REMOVE_START
+assert.strictEqual(res2.total, 1);
+// REMOVE_END
+// STEP_END
+
+// STEP_START geo3
+const params_dict_geo3 = { europe: 'POLYGON((-25 35, 40 35, 40 70, -25 70, -25 35))' };
+const q_geo3 = '@pickup_zone:[WITHIN $europe]';
+const res3 = await client.ft.search('idx:bicycle', q_geo3, { PARAMS: params_dict_geo3, DIALECT: 3 });
+console.log(res3.total); // >>> 5
+console.log(res3); // >>>
+// {
+//   total: 5,
+//   documents: [
+//     { id: 'bicycle:5', value: [Object: null prototype] },
+//     { id: 'bicycle:6', value: [Object: null prototype] },
+//     { id: 'bicycle:7', value: [Object: null prototype] },
+//     { id: 'bicycle:8', value: [Object: null prototype] },
+//     { id: 'bicycle:9', value: [Object: null prototype] }
+//   ]
+// }
+// REMOVE_START
+assert.strictEqual(res3.total, 5);
+// REMOVE_END
+// STEP_END
+
+// REMOVE_START
+// destroy index and data
+await client.ft.dropIndex('idx:bicycle', { DD: true });
+await client.disconnect();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/query-range.js b/doctests/query-range.js
new file mode 100644
index 00000000000..4f6c81e5d3a
--- /dev/null
+++ b/doctests/query-range.js
@@ -0,0 +1,98 @@
+// EXAMPLE: query_range
+// HIDE_START
+import assert from 'node:assert';
+import fs from 'node:fs';
+import { createClient, SchemaFieldTypes, AggregateGroupByReducers, AggregateSteps} from 'redis';
+
+const client = createClient();
+
+await client.connect().catch(console.error);
+
+// create index
+await client.ft.create('idx:bicycle', {
+  '$.description': {
+    type: SchemaFieldTypes.TEXT,
+    AS: 'description'
+  },
+  '$.price': {
+    type: SchemaFieldTypes.NUMERIC,
+    AS: 'price'
+  },
+  '$.condition': {
+    type: SchemaFieldTypes.TAG,
+    AS: 'condition'
+  }
+}, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+})
+
+// load data
+const bicycles = JSON.parse(fs.readFileSync('data/query_em.json', 'utf8'));
+
+await Promise.all(
+  bicycles.map((bicycle, bid) => {
+      return client.json.set(`bicycle:${bid}`, '$', bicycle);
+  })
+);
+// HIDE_END
+
+// STEP_START range1
+const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000]');
+console.log(res1.total); // >>> 3
+// REMOVE_START
+assert.strictEqual(res1.total, 3);
+// REMOVE_END
+// STEP_END
+
+// STEP_START range2
+// FILTER is not supported
+// const res2 = await client.ft.search('idx:bicycle', '*', {
+//   FILTER: {
+//     field: 'price',
+//     min: 500,
+//     max: 1000,
+//   }
+// });
+// console.log(res2.total); // >>> 3
+// REMOVE_START
+// assert.strictEqual(res2.total, 3);
+// REMOVE_END
+// STEP_END
+
+// STEP_START range3
+// FILTER is not supported
+// const res3 = await client.ft.search('idx:bicycle', '*', {
+//   FILTER: {
+//     field: 'price',
+//     min: '(1000',
+//     max: '+inf,
+//   }
+// });
+// console.log(res3.total); // >>> 5
+// REMOVE_START
+// assert.strictEqual(res3.total, 5);
+// REMOVE_END
+// STEP_END
+
+// STEP_START range4
+const res4 = await client.ft.search(
+  'idx:bicycle',
+  '@price:[-inf 2000]',
+  {
+    SORTBY: 'price',
+    LIMIT: { from: 0, size: 5 }
+  }
+);
+console.log(res4.total); // >>> 7
+console.log(res4); // >>> { total: 7, documents: [ { id: 'bicycle:0', value: [Object: null prototype] }, { id: 'bicycle:7', value: [Object: null prototype] }, { id: 'bicycle:5', value: [Object: null prototype] }, { id: 'bicycle:2', value: [Object: null prototype] }, { id: 'bicycle:9', value: [Object: null prototype] } ] }
+// REMOVE_START
+assert.strictEqual(res4.total, 7);
+// REMOVE_END
+// STEP_END
+
+// REMOVE_START
+// destroy index and data
+await client.ft.dropIndex('idx:bicycle', { DD: true });
+await client.disconnect();
+// REMOVE_END
\ No newline at end of file
diff --git a/doctests/query-vector.js b/doctests/query-vector.js
new file mode 100644
index 00000000000..d6db3161f8d
--- /dev/null
+++ b/doctests/query-vector.js
@@ -0,0 +1,111 @@
+// EXAMPLE: query_vector
+// HIDE_START
+import assert from 'node:assert';
+import fs from 'node:fs';
+import { createClient } from 'redis';
+import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
+import { pipeline } from '@xenova/transformers';
+
+function float32Buffer(arr) {
+  const floatArray = new Float32Array(arr);
+  const float32Buffer = Buffer.from(floatArray.buffer);
+  return float32Buffer;
+}
+
+async function embedText(sentence) {
+  let modelName = 'Xenova/all-MiniLM-L6-v2';
+  let pipe = await pipeline('feature-extraction', modelName);
+
+  let vectorOutput = await pipe(sentence, {
+      pooling: 'mean',
+      normalize: true,
+  });
+
+  const embedding = Object.values(vectorOutput?.data);
+
+  return embedding;
+}
+
+let query = 'Bike for small kids';
+let vector_query = float32Buffer(await embedText('That is a very happy person'));
+
+const client = createClient();
+await client.connect().catch(console.error);
+
+// create index
+await client.ft.create('idx:bicycle', {
+    '$.description': {
+      type: SchemaFieldTypes.TEXT,
+      AS: 'description'
+    },
+    '$.description_embeddings': {
+        type: SchemaFieldTypes.VECTOR,
+        TYPE: 'FLOAT32',
+        ALGORITHM: VectorAlgorithms.FLAT,
+        DIM: 384,
+        DISTANCE_METRIC: 'COSINE',
+        AS: 'vector'
+    }
+}, {
+    ON: 'JSON',
+    PREFIX: 'bicycle:'
+});
+
+// load data
+const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
+
+await Promise.all(
+  bicycles.map((bicycle, bid) => {
+      return client.json.set(`bicycle:${bid}`, '$', bicycle);
+  })
+);
+// HIDE_END
+
+// STEP_START vector1
+const res1 = await client.ft.search('idx:bicycle', 
+  '*=>[KNN 3 @vector $query_vector AS score]', {
+    PARAMS: { query_vector: vector_query },
+    RETURN: ['description'],
+    DIALECT: 2
+  }
+);
+console.log(res1.total); // >>> 3
+console.log(res1); // >>>
+//{
+//  total: 3,
+//  documents: [
+//    { id: 'bicycle:0', value: [Object: null prototype] {} },
+//    { id: 'bicycle:2', value: [Object: null prototype] {} },
+//    { id: 'bicycle:9', value: [Object: null prototype] {} }
+//  ]
+//}
+// REMOVE_START
+assert.strictEqual(res1.total, 3);
+// REMOVE_END
+// STEP_END
+
+// STEP_START vector2
+const res2 = await client.ft.search('idx:bicycle', 
+  '@vector:[VECTOR_RANGE 0.9 $query_vector]=>{$YIELD_DISTANCE_AS: vector_dist}', {
+    PARAMS: { query_vector: vector_query },
+    SORTBY: 'vector_dist',
+    RETURN: ['vector_dist', 'description'],
+    DIALECT: 2
+  }
+);
+console.log(res2.total); // >>> 1
+console.log(res2); // >>>
+//{
+//  total: 1,
+//  documents: [ { id: 'bicycle:0', value: [Object: null prototype] } ]
+//}
+// REMOVE_START
+assert.strictEqual(res2.total, 1);
+// REMOVE_END
+// STEP_END
+
+// REMOVE_START
+// destroy index and data
+await client.ft.dropIndex('idx:bicycle', { DD: true });
+await client.disconnect();
+// REMOVE_END
\ No newline at end of file

From 001087f5201cc4bfeab634f297b1753c8a09cd71 Mon Sep 17 00:00:00 2001
From: isaac <87535414+katongole-isaac@users.noreply.github.com>
Date: Wed, 13 Nov 2024 22:57:37 +0300
Subject: [PATCH 17/20] Update cmds-hash.js (#2863)

Update comment-line (58) from `foo` to `null`
---
 doctests/cmds-hash.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doctests/cmds-hash.js b/doctests/cmds-hash.js
index d47fa1944ae..ca72802831b 100644
--- a/doctests/cmds-hash.js
+++ b/doctests/cmds-hash.js
@@ -55,7 +55,7 @@ const res8 = await client.hGet('myhash', 'field1')
 console.log(res8) // foo
 
 const res9 = await client.hGet('myhash', 'field2')
-console.log(res9) // foo
+console.log(res9) // null
 
 // REMOVE_START
 assert.equal(res7, 1);

From cb26059e5d0871e05c81ff30f569d72cf6bb3b85 Mon Sep 17 00:00:00 2001
From: David Dougherty <david.dougherty@redis.com>
Date: Tue, 22 Apr 2025 07:50:35 -0700
Subject: [PATCH 18/20] DOC-4423: add TCEs for various command pages (#2885)

* DOC-4423: add TCEs for various command pages

* fix problematic doctest

from redis docs for ACL DELUSER:
Delete all the specified ACL users and terminate all the connections
 that are authenticated with such users

Nodejs complains: Warning: Detected unsettled top-level await
which in turn gives the error code 13 in the workflow

await client.auth({ username: 'test-user' ...});
// deleting the user that is currently logged in -> bad
await client.sendCommand(['ACL', 'DELUSER', 'test-user']);
await client.quit()

fix: authenticate with the default user before deleting the test-user

---------

Co-authored-by: Nikolay Karadzhov <nkaradzhov89@gmail.com>
---
 doctests/cmds-cnxmgmt.js    |  49 ++++++++++++++
 doctests/cmds-hash.js       |  40 ++++++++++-
 doctests/cmds-list.js       | 129 ++++++++++++++++++++++++++++++++++++
 doctests/cmds-servermgmt.js |  45 +++++++++++++
 doctests/cmds-set.js        |  44 ++++++++++++
 5 files changed, 306 insertions(+), 1 deletion(-)
 create mode 100644 doctests/cmds-cnxmgmt.js
 create mode 100644 doctests/cmds-list.js
 create mode 100644 doctests/cmds-servermgmt.js
 create mode 100644 doctests/cmds-set.js

diff --git a/doctests/cmds-cnxmgmt.js b/doctests/cmds-cnxmgmt.js
new file mode 100644
index 00000000000..2f4fc8dc95a
--- /dev/null
+++ b/doctests/cmds-cnxmgmt.js
@@ -0,0 +1,49 @@
+// EXAMPLE: cmds_cnxmgmt
+// REMOVE_START
+import assert from "node:assert";
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START auth1
+// REMOVE_START
+await client.sendCommand(['CONFIG', 'SET', 'requirepass', 'temp_pass']);
+// REMOVE_END
+const res1 = await client.auth({ password: 'temp_pass' });
+console.log(res1); // OK
+
+const res2 = await client.auth({ username: 'default', password: 'temp_pass' });
+console.log(res2); // OK
+
+// REMOVE_START
+assert.equal(res1, "OK");
+assert.equal(res2, "OK");
+await client.sendCommand(['CONFIG', 'SET', 'requirepass', '']);
+// REMOVE_END
+// STEP_END
+
+// STEP_START auth2
+// REMOVE_START
+await client.sendCommand([
+  'ACL', 'SETUSER', 'test-user',
+  'on', '>strong_password', '+acl'
+]);
+// REMOVE_END
+const res3 = await client.auth({ username: 'test-user', password: 'strong_password' });
+console.log(res3); // OK
+
+// REMOVE_START
+assert.equal(res3, "OK");
+await client.auth({ username: 'default', password: '' })
+await client.sendCommand(['ACL', 'DELUSER', 'test-user']);
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-hash.js b/doctests/cmds-hash.js
index ca72802831b..48b75153b3e 100644
--- a/doctests/cmds-hash.js
+++ b/doctests/cmds-hash.js
@@ -65,7 +65,45 @@ await client.del('myhash')
 // REMOVE_END
 // STEP_END
 
+// STEP_START hgetall
+const res10 = await client.hSet(
+  'myhash',
+  {
+    'field1': 'Hello',
+    'field2': 'World'
+  }
+)
+
+const res11 = await client.hGetAll('myhash')
+console.log(res11) // [Object: null prototype] { field1: 'Hello', field2: 'World' }
+
+// REMOVE_START
+assert.deepEqual(res11, {
+  field1: 'Hello',
+  field2: 'World'
+});
+await client.del('myhash')
+// REMOVE_END
+// STEP_END
+
+// STEP_START hvals
+const res12 = await client.hSet(
+  'myhash',
+  {
+    'field1': 'Hello',
+    'field2': 'World'
+  }
+)
+
+const res13 = await client.hVals('myhash')
+console.log(res13) // [ 'Hello', 'World' ]
+
+// REMOVE_START
+assert.deepEqual(res13, [ 'Hello', 'World' ]);
+await client.del('myhash')
+// REMOVE_END
+// STEP_END
+
 // HIDE_START
 await client.quit();
 // HIDE_END
-
diff --git a/doctests/cmds-list.js b/doctests/cmds-list.js
new file mode 100644
index 00000000000..65e78d0c8d8
--- /dev/null
+++ b/doctests/cmds-list.js
@@ -0,0 +1,129 @@
+// EXAMPLE: cmds_list
+// HIDE_START
+import assert from 'node:assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START lpush
+const res1 = await client.lPush('mylist', 'world');
+console.log(res1); // 1
+
+const res2 = await client.lPush('mylist', 'hello');
+console.log(res2); // 2
+
+const res3 = await client.lRange('mylist', 0, -1);
+console.log(res3); // [ 'hello', 'world' ]
+
+// REMOVE_START
+assert.deepEqual(res3, [ 'hello', 'world' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START lrange
+const res4 = await client.rPush('mylist', 'one');
+console.log(res4); // 1
+
+const res5 = await client.rPush('mylist', 'two');
+console.log(res5); // 2
+
+const res6 = await client.rPush('mylist', 'three');
+console.log(res6); // 3
+
+const res7 = await client.lRange('mylist', 0, 0);
+console.log(res7); // [ 'one' ]
+
+const res8 = await client.lRange('mylist', -3, 2);
+console.log(res8); // [ 'one', 'two', 'three' ]
+
+const res9 = await client.lRange('mylist', -100, 100);
+console.log(res9); // [ 'one', 'two', 'three' ]
+
+const res10 = await client.lRange('mylist', 5, 10);
+console.log(res10); // []
+
+// REMOVE_START
+assert.deepEqual(res7, [ 'one' ]);
+assert.deepEqual(res8, [ 'one', 'two', 'three' ]);
+assert.deepEqual(res9, [ 'one', 'two', 'three' ]);
+assert.deepEqual(res10, []);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START llen
+const res11 = await client.lPush('mylist', 'World');
+console.log(res11); // 1
+
+const res12 = await client.lPush('mylist', 'Hello');
+console.log(res12); // 2
+
+const res13 = await client.lLen('mylist');
+console.log(res13); // 2
+
+// REMOVE_START
+assert.equal(res13, 2);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START rpush
+const res14 = await client.rPush('mylist', 'hello');
+console.log(res14); // 1
+
+const res15 = await client.rPush('mylist', 'world');
+console.log(res15); // 2
+
+const res16 = await client.lRange('mylist', 0, -1);
+console.log(res16); // [ 'hello', 'world' ]
+
+// REMOVE_START
+assert.deepEqual(res16, [ 'hello', 'world' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START lpop
+const res17 = await client.rPush('mylist', ["one", "two", "three", "four", "five"]);
+console.log(res17); // 5
+
+const res18 = await client.lPop('mylist');
+console.log(res18); // 'one'
+
+const res19 = await client.lPopCount('mylist', 2);
+console.log(res19); // [ 'two', 'three' ]
+
+const res20 = await client.lRange('mylist', 0, -1);
+console.log(res20); // [ 'four', 'five' ]
+
+// REMOVE_START
+assert.deepEqual(res20, [ 'four', 'five' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START rpop
+const res21 = await client.rPush('mylist', ["one", "two", "three", "four", "five"]);
+console.log(res21); // 5
+
+const res22 = await client.rPop('mylist');
+console.log(res22); // 'five'
+
+const res23 = await client.rPopCount('mylist', 2);
+console.log(res23); // [ 'four', 'three' ]
+
+const res24 = await client.lRange('mylist', 0, -1);
+console.log(res24); // [ 'one', 'two' ]
+
+// REMOVE_START
+assert.deepEqual(res24, [ 'one', 'two' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-servermgmt.js b/doctests/cmds-servermgmt.js
new file mode 100644
index 00000000000..5ac6e5909c4
--- /dev/null
+++ b/doctests/cmds-servermgmt.js
@@ -0,0 +1,45 @@
+// EXAMPLE: cmds_servermgmt
+// REMOVE_START
+import assert from 'node:assert';
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START flushall
+// REMOVE_START
+await client.set('foo', '1');
+await client.set('bar', '2');
+await client.set('baz', '3');
+// REMOVE_END
+const res1 = await client.flushAll('SYNC'); // or ASYNC
+console.log(res1); // OK
+
+const res2 = await client.keys('*');
+console.log(res2); // []
+
+// REMOVE_START
+assert.equal(res1, 'OK');
+assert.deepEqual(res2, []);
+// REMOVE_END
+// STEP_END
+
+// STEP_START info
+const res3 = await client.info();
+console.log(res3)
+// # Server
+// redis_version:7.4.0
+// redis_git_sha1:c9d29f6a
+// redis_git_dirty:0
+// redis_build_id:4c367a16e3f9616
+// redis_mode:standalone
+// ...
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-set.js b/doctests/cmds-set.js
new file mode 100644
index 00000000000..80374436a58
--- /dev/null
+++ b/doctests/cmds-set.js
@@ -0,0 +1,44 @@
+// EXAMPLE: cmds_set
+// REMOVE_START
+import assert from 'node:assert';
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START sadd
+const res1 = await client.sAdd('myset', ['Hello', 'World']);
+console.log(res1);  // 2
+
+const res2 = await client.sAdd('myset', ['World']);
+console.log(res2);  // 0
+
+const res3 = await client.sMembers('myset')
+console.log(res3);  // ['Hello', 'World']
+
+// REMOVE_START
+assert.deepEqual(res3, ['Hello', 'World']);
+await client.del('myset');
+// REMOVE_END
+// STEP_END
+
+// STEP_START smembers
+const res4 = await client.sAdd('myset', ['Hello', 'World']);
+console.log(res4);  // 2
+
+const res5 = await client.sMembers('myset')
+console.log(res5);  // ['Hello', 'World']
+
+// REMOVE_START
+assert.deepEqual(res5, ['Hello', 'World']);
+await client.del('myset');
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END

From 7c4f0eac76c5983325a1ba9225be062436ad56c1 Mon Sep 17 00:00:00 2001
From: Jacques Cornat <cornat.jacques@gmail.com>
Date: Tue, 27 May 2025 17:12:58 +0200
Subject: [PATCH 19/20] Fix Node.js console.log output (#2974)

---
 doctests/dt-json.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doctests/dt-json.js b/doctests/dt-json.js
index 83eee04b586..c06253482d1 100644
--- a/doctests/dt-json.js
+++ b/doctests/dt-json.js
@@ -68,7 +68,7 @@ const res12 = await client.json.get("newbike", "$");
 console.log(res12); //  [ 'Deimos', { crashes: 0 }, null ]
 
 const res13 = await client.json.get("newbike", "$[1].crashes");
-console.log(res13); //  [ 'Deimos', { crashes: 0 }, null ]
+console.log(res13); //  [0]
 
 const res14 = await client.json.del("newbike", "$.[-1]");
 console.log(res14); //  [1]

From dea0c64d90d6922896ee0177a91e6763c2b7b50a Mon Sep 17 00:00:00 2001
From: Nikolay Karadzhov <nkaradzhov89@gmail.com>
Date: Wed, 28 May 2025 11:49:55 +0300
Subject: [PATCH 20/20] fix(doctest): properly provide the path param (#2978)

path param was not properly provided to some commands. javascript doesnt catch this error, but ts does
---
 doctests/dt-json.js | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/doctests/dt-json.js b/doctests/dt-json.js
index c06253482d1..4453326f6c2 100644
--- a/doctests/dt-json.js
+++ b/doctests/dt-json.js
@@ -16,15 +16,15 @@ await client.flushDb();
 const res1 = await client.json.set("bike", "$", '"Hyperion"');
 console.log(res1); // OK
 
-const res2 = await client.json.get("bike", "$");
-console.log(res2); // "Hyperion"
+const res2 = await client.json.get("bike", { path: "$" });
+console.log(res2); // ['"Hyperion"']
 
 const res3 = await client.json.type("bike", "$");
 console.log(res3); //  [ 'string' ]
 // STEP_END
 
 // REMOVE_START
-assert.equal(res2, '"Hyperion"');
+assert.deepEqual(res2, ['"Hyperion"']);
 // REMOVE_END
 
 // STEP_START str
@@ -34,12 +34,12 @@ console.log(res4) //  [10]
 const res5 = await client.json.strAppend("bike", '" (Enduro bikes)"');
 console.log(res5) //  27
 
-const res6 = await client.json.get("bike", "$");
+const res6 = await client.json.get("bike", { path: "$" });
 console.log(res6) //  ['"Hyperion"" (Enduro bikes)"']
 // STEP_END
 
 // REMOVE_START
-assert.equal(res6, ['"Hyperion"" (Enduro bikes)"']);
+assert.deepEqual(res6, ['"Hyperion"" (Enduro bikes)"']);
 // REMOVE_END
 
 // STEP_START num
@@ -64,23 +64,23 @@ assert.deepEqual(res10, [1.75])
 const res11 = await client.json.set("newbike", "$", ["Deimos", {"crashes": 0 }, null]);
 console.log(res11); //  OK
 
-const res12 = await client.json.get("newbike", "$");
-console.log(res12); //  [ 'Deimos', { crashes: 0 }, null ]
+const res12 = await client.json.get("newbike", { path: "$" });
+console.log(res12); //  [[ 'Deimos', { crashes: 0 }, null ]]
 
-const res13 = await client.json.get("newbike", "$[1].crashes");
+const res13 = await client.json.get("newbike", { path: "$[1].crashes" });
 console.log(res13); //  [0]
 
 const res14 = await client.json.del("newbike", "$.[-1]");
 console.log(res14); //  [1]
 
-const res15 = await client.json.get("newbike", "$");
-console.log(res15); //  [ 'Deimos', { crashes: 0 } ]
+const res15 = await client.json.get("newbike", { path: "$" });
+console.log(res15); //  [[ 'Deimos', { crashes: 0 } ]]
 // STEP_END
 
 // REMOVE_START
-assert.deepEqual(res15, ["Deimos", {
+assert.deepEqual(res15, [["Deimos", {
   "crashes": 0
-}]);
+}]]);
 // REMOVE_END
 
 // STEP_START arr2
@@ -90,20 +90,20 @@ console.log(res16); //  OK
 const res17 = await client.json.arrAppend("riders", "$", "Norem");
 console.log(res17); //  [1]
 
-const res18 = await client.json.get("riders", "$");
-console.log(res18); //  [ 'Norem' ]
+const res18 = await client.json.get("riders", { path: "$" });
+console.log(res18); //  [[ 'Norem' ]]
 
 const res19 = await client.json.arrInsert("riders", "$", 1, "Prickett", "Royse", "Castilla");
 console.log(res19); //  [4]
 
-const res20 = await client.json.get("riders", "$");
-console.log(res20); //  [ 'Norem', 'Prickett', 'Royse', 'Castilla' ]
+const res20 = await client.json.get("riders", { path: "$" });
+console.log(res20); //  [[ 'Norem', 'Prickett', 'Royse', 'Castilla' ]]
 
 const res21 = await client.json.arrTrim("riders", "$", 1, 1);
 console.log(res21); //  [1]
 
-const res22 = await client.json.get("riders", "$");
-console.log(res22); //  [ 'Prickett' ]
+const res22 = await client.json.get("riders", { path: "$" });
+console.log(res22); //  [[ 'Prickett' ]]
 
 const res23 = await client.json.arrPop("riders", "$");
 console.log(res23); //  [ 'Prickett' ]
@@ -366,7 +366,7 @@ const res37c = await client.json.set(
 
 const res37d = await client.json.get(
   'bikes:inventory',
-  '$.inventory.mountain_bikes[?(@.specs.material =~ @.regex_pat)].model'
+  { path: '$.inventory.mountain_bikes[?(@.specs.material =~ @.regex_pat)].model' }
 );
 console.log(res37d); // ['Quaoar', 'Weywot']
 // STEP_END
@@ -398,7 +398,7 @@ const res40a = await client.json.set(
 // Get all prices from the inventory
 const res40b = await client.json.get(
   'bikes:inventory',
-  '$..price'
+  { path: "$..price" }
 );
 console.log(res40b); // [1500, 2072, 3264, 1500, 3941]
 // STEP_END
