├── src ├── views │ ├── index.hbs │ ├── layouts │ │ └── default.hbs │ └── home │ │ └── index.hbs ├── public │ └── styles.css ├── service │ └── redisClient.js └── index.js ├── .dockerignore ├── redis-cluster-demo.jpg ├── .env.example ├── redis ├── Dockerfile ├── redis.conf └── entrypoint.sh ├── renovate.json ├── Dockerfile ├── .gitignore ├── README.md ├── package.json ├── docker-compose.yml └── pnpm-lock.yaml /src/views/index.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /redis-cluster-demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunojppb/redis-cluster-demo/HEAD/redis-cluster-demo.jpg -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Duplicate this file and name it `.env` 2 | # Now configure your environment variables :) 3 | PORT=4000 -------------------------------------------------------------------------------- /redis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:latest 2 | 3 | COPY ./entrypoint.sh /entrypoint.sh 4 | RUN chmod 755 /entrypoint.sh 5 | 6 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:24-slim as build 2 | 3 | RUN mkdir -p /app 4 | WORKDIR /app 5 | COPY . /app 6 | 7 | # Install all dependencies 8 | RUN npm install 9 | -------------------------------------------------------------------------------- /redis/redis.conf: -------------------------------------------------------------------------------- 1 | # Custom config file to enable cluster mode 2 | # on all Redis instances started via Docker 3 | port 6379 4 | cluster-enabled yes 5 | # The cluster file is created and managed by Redis 6 | # We just need to declare it here 7 | cluster-config-file nodes.conf 8 | cluster-node-timeout 5000 9 | appendonly yes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store* 3 | Icon? 4 | ._* 5 | 6 | # Windows 7 | Thumbs.db 8 | ehthumbs.db 9 | Desktop.ini 10 | 11 | # Linux 12 | .directory 13 | *~ 14 | 15 | # IDE 16 | .vscode 17 | .idea 18 | 19 | # npm 20 | node_modules 21 | package-lock.json 22 | *.log 23 | *.gz 24 | coverage 25 | .env 26 | 27 | # Benchmarking 28 | benchmarks/graphs -------------------------------------------------------------------------------- /src/views/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Redis Cluster 9 | 10 | 11 |
12 | {{{ body }}} 13 |
14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redis Cluster Demo 2 | 3 | How to use a redis cluster with multiple shards using Docker and docker-compose. [You can read the full blogpost about this setup here.](https://bpaulino.com/entries/how-to-use-redis-cluster-for-caching) 4 | 5 | [![Redis Cluster blogpost](redis-cluster-demo.jpg)](https://bpaulino.com/entries/how-to-use-redis-cluster-for-caching) 6 | 7 | > **Please note:** This is not meant to be used in production, but for local development only. 8 | > There is no point in using a Redis cluster in the same node using this docker-compose setup. If your node is down, your entire Redis cluster will be down. 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redis-cluster", 3 | "version": "1.0.0", 4 | "description": "Redis Cluster with multiple shards with Node.js", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "dev": "nodemon -e js,hbs,css src/index.js", 8 | "start": "node src/index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "Bruno Paulino", 12 | "license": "MIT", 13 | "dependencies": { 14 | "dotenv": "17.2.3", 15 | "express": "5.1.0", 16 | "express-handlebars": "8.0.4", 17 | "ioredis": "5.8.2" 18 | }, 19 | "devDependencies": { 20 | "nodemon": "3.1.10" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/public/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --primary-color: #0F2438; 3 | --secondary-color: #20364C; 4 | --text-color: #CFD2D6; 5 | } 6 | 7 | 8 | html, body { 9 | font-family: system-ui; 10 | background-color: var(--primary-color); 11 | color: var(--text-color); 12 | position: relative; 13 | height: 100%; 14 | transition: color 0.5s; 15 | } 16 | 17 | form { 18 | padding: 8px; 19 | } 20 | 21 | fieldset { 22 | margin-top: 8px; 23 | border: none; 24 | padding: 0; 25 | } 26 | 27 | input { 28 | padding: 8px; 29 | } 30 | 31 | input[type="text"] { 32 | margin-top: 4px; 33 | } 34 | 35 | input[type="submit"] { 36 | margin-top: 16px; 37 | font-weight: bold; 38 | } -------------------------------------------------------------------------------- /redis/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Using the redis-cli tool available as default in the Redis base image 4 | # we need to create the cluster so they can coordinate with each other 5 | # which key slots they need to hold per shard 6 | 7 | # wait a little so we give some time for the Redis containers 8 | # to spin up and be available on the network 9 | sleep 5 10 | # redis-cli doesn't support hostnames, we must match the 11 | # container IP addresses from our docker-compose configuration. 12 | # `--cluster-replicas 1` Will make sure that every master node will have its replica node 13 | echo "yes" | redis-cli --cluster create \ 14 | 173.18.0.2:6379 \ 15 | 173.18.0.3:6379 \ 16 | 173.18.0.4:6379 \ 17 | 173.18.0.5:6379 \ 18 | 173.18.0.6:6379 \ 19 | 173.18.0.7:6379 \ 20 | --cluster-replicas 1 21 | echo "🚀 Redis cluster ready." -------------------------------------------------------------------------------- /src/views/home/index.hbs: -------------------------------------------------------------------------------- 1 |
2 |

Redis Cluster Demo

3 | {{#if dataSaved}} 4 | Data saved successfuly 5 | {{/if}} 6 | 7 |
8 |
9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 |

Search for data

21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 | {{#if value}} 29 |
30 |

Value stored in Redis:

31 | {{ value }} 32 |
-------------------------------------------------------------------------------- /src/service/redisClient.js: -------------------------------------------------------------------------------- 1 | const Redis = require('ioredis') 2 | 3 | /** 4 | * Get an existing Redis client instance. Build one if necessary 5 | * @return {Cluster|null} redis client 6 | * */ 7 | function buildRedisClient() { 8 | 9 | try { 10 | // cluster URLs should be passed in with the following format: 11 | // REDIS_CLUSTER_URLS=10.0.0.1:6379,10.0.0.2:6379,10.0.0.3:6379 12 | const nodes = process.env.REDIS_CLUSTER_URLS.split(',').map(url => { 13 | const [host, port] = url.split(':') 14 | return { host, port } 15 | }) 16 | 17 | const client = new Redis.Cluster(nodes, { 18 | redisOptions: { 19 | enableAutoPipelining: true, 20 | }, 21 | }) 22 | 23 | client.on('error', error => { 24 | console.error('Redis Error', error) 25 | }) 26 | 27 | client.on('connect', () => { 28 | console.log('Redis Connection stablished') 29 | }) 30 | 31 | client.on('ready', () => { 32 | console.log('Redis client ready') 33 | }) 34 | 35 | client.on('end', () => { 36 | console.log('Redis client connection ended') 37 | }) 38 | 39 | // Emits when an error occurs when connecting 40 | // to a node when using Redis in Cluster mode 41 | client.on('node error', (error, node) => { 42 | console.error(`Redis error in node ${node}`, error) 43 | }) 44 | 45 | return client 46 | } catch (error) { 47 | console.error('Could not create a Redis cluster client', error) 48 | 49 | return null 50 | } 51 | } 52 | 53 | module.exports = buildRedisClient 54 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const path = require('path') 3 | const express = require('express') 4 | const { engine } = require('express-handlebars') 5 | const buildRedisClient = require('./service/redisClient') 6 | 7 | 8 | const app = express() 9 | const port = process.env.PORT || 3000 10 | 11 | const redis = buildRedisClient() 12 | 13 | app.use(express.urlencoded({ extended: true })) 14 | 15 | /** A rough debugging middleware */ 16 | app.use((req, resp, next) => { 17 | console.log(`${req.method} | URL=${req.url}`) 18 | return next() 19 | }) 20 | 21 | /** handlebars template engine */ 22 | const VIEWS_PATH = `${__dirname}/views` 23 | app.engine('.hbs', engine({ 24 | extname: '.hbs' 25 | })); 26 | app.set('view engine', '.hbs'); 27 | app.set('views', VIEWS_PATH) 28 | 29 | app.use( 30 | '/static', express.static(path.join(__dirname, '/public')) 31 | ) 32 | 33 | app.get('/', async (request, response) => { 34 | return response.render('home/index', { 35 | layout: 'default', 36 | }) 37 | }) 38 | 39 | app.post('/save-data', async (request, response) => { 40 | const { key, value } = request.body 41 | await redis.set(key, value) 42 | return response.status(201).render('home/index', { 43 | layout: 'default', 44 | dataSaved: true, 45 | }) 46 | }) 47 | 48 | app.post('/search', async (request, response) => { 49 | const { key } = request.body 50 | const value = await redis.get(key) 51 | return response.status(200).render('home/index', { 52 | layout: 'default', 53 | value, 54 | }) 55 | }) 56 | 57 | app.listen(port, () => { 58 | console.log(`App listening on port ${port}`) 59 | }) -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | volumes: 2 | redis_1_data: {} 3 | redis_2_data: {} 4 | redis_3_data: {} 5 | redis_4_data: {} 6 | redis_5_data: {} 7 | redis_6_data: {} 8 | # This volume is specific for the demo Express application 9 | # built in this repo. You probably won't need that on your own setup. 10 | node_modules: {} 11 | 12 | services: 13 | app: 14 | container_name: express_app 15 | build: 16 | context: . 17 | environment: 18 | PORT: 4000 19 | NODE_ENV: production 20 | REDIS_CLUSTER_URLS: "redis_1:6379,redis_2:6379,redis_3:6379,redis_4:6379,redis_5:6379,redis_6:6379" 21 | volumes: 22 | - .:/app 23 | - node_modules:/app/node_modules 24 | command: ["npm", "run", "dev"] 25 | depends_on: 26 | - redis_1 27 | - redis_2 28 | - redis_3 29 | - redis_4 30 | - redis_5 31 | - redis_6 32 | - cluster_initiator 33 | ports: 34 | - "4000:4000" 35 | stdin_open: true 36 | networks: 37 | redis_cluster_net: 38 | ipv4_address: 173.18.0.10 39 | 40 | # Here we have six Redis containers with Cluster mode enabled, 41 | # three of them will work as master nodes and each one of 42 | # will have a replica, so in case of failures, the replica becomes the master. 43 | # They are configured by the `cluster_initiator` container. 44 | redis_1: 45 | image: "redis:latest" 46 | container_name: redis_1 47 | ports: 48 | - "6379" 49 | volumes: 50 | - redis_1_data:/data 51 | - ./redis/redis.conf:/usr/local/etc/redis/redis.conf 52 | command: ["redis-server", "/usr/local/etc/redis/redis.conf"] 53 | networks: 54 | redis_cluster_net: 55 | ipv4_address: 173.18.0.2 56 | 57 | redis_2: 58 | image: "redis:latest" 59 | container_name: redis_2 60 | ports: 61 | - "6379" 62 | volumes: 63 | - redis_2_data:/data 64 | - ./redis/redis.conf:/usr/local/etc/redis/redis.conf 65 | command: ["redis-server", "/usr/local/etc/redis/redis.conf"] 66 | networks: 67 | redis_cluster_net: 68 | ipv4_address: 173.18.0.3 69 | 70 | redis_3: 71 | image: "redis:latest" 72 | container_name: redis_3 73 | ports: 74 | - "6379" 75 | volumes: 76 | - redis_3_data:/data 77 | - ./redis/redis.conf:/usr/local/etc/redis/redis.conf 78 | command: ["redis-server", "/usr/local/etc/redis/redis.conf"] 79 | networks: 80 | redis_cluster_net: 81 | ipv4_address: 173.18.0.4 82 | 83 | redis_4: 84 | image: "redis:latest" 85 | container_name: redis_4 86 | ports: 87 | - "6379" 88 | volumes: 89 | - redis_4_data:/data 90 | - ./redis/redis.conf:/usr/local/etc/redis/redis.conf 91 | command: ["redis-server", "/usr/local/etc/redis/redis.conf"] 92 | networks: 93 | redis_cluster_net: 94 | ipv4_address: 173.18.0.5 95 | 96 | redis_5: 97 | image: "redis:latest" 98 | container_name: redis_5 99 | ports: 100 | - "6379" 101 | volumes: 102 | - redis_5_data:/data 103 | - ./redis/redis.conf:/usr/local/etc/redis/redis.conf 104 | command: ["redis-server", "/usr/local/etc/redis/redis.conf"] 105 | networks: 106 | redis_cluster_net: 107 | ipv4_address: 173.18.0.6 108 | 109 | redis_6: 110 | image: "redis:latest" 111 | container_name: redis_6 112 | ports: 113 | - "6379" 114 | volumes: 115 | - redis_6_data:/data 116 | - ./redis/redis.conf:/usr/local/etc/redis/redis.conf 117 | command: ["redis-server", "/usr/local/etc/redis/redis.conf"] 118 | networks: 119 | redis_cluster_net: 120 | ipv4_address: 173.18.0.7 121 | 122 | # Ephemeral container to create the Redis cluster connections. 123 | # Once the setup is done, this container shuts down 124 | # and the cluster can be used by the service app container 125 | cluster_initiator: 126 | container_name: cluster_initiator 127 | build: 128 | context: redis 129 | dockerfile: Dockerfile 130 | tty: true 131 | depends_on: 132 | - redis_1 133 | - redis_2 134 | - redis_3 135 | - redis_4 136 | - redis_5 137 | - redis_6 138 | networks: 139 | redis_cluster_net: 140 | ipv4_address: 173.18.0.8 141 | 142 | # Web UI to browse through our Redis data across all nodes 143 | redis_commander: 144 | image: rediscommander/redis-commander:latest 145 | container_name: redis_web 146 | environment: 147 | REDIS_HOSTS: "local:redis_1:6379,local:redis_2:6379,local:redis_3:6379" 148 | ports: 149 | - "5050:8081" 150 | depends_on: 151 | - redis_1 152 | - redis_2 153 | - redis_3 154 | - redis_4 155 | - redis_5 156 | - redis_6 157 | - cluster_initiator 158 | networks: 159 | redis_cluster_net: 160 | ipv4_address: 173.18.0.9 161 | 162 | # Rename the default network so we can easily identify it 163 | # Across all containers 164 | networks: 165 | redis_cluster_net: 166 | driver: bridge 167 | ipam: 168 | driver: default 169 | config: 170 | - subnet: 173.18.0.0/16 171 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | dotenv: 9 | specifier: 17.2.3 10 | version: 17.2.3 11 | express: 12 | specifier: 5.1.0 13 | version: 5.1.0 14 | express-handlebars: 15 | specifier: 8.0.4 16 | version: 8.0.4 17 | ioredis: 18 | specifier: 5.8.2 19 | version: 5.8.2 20 | 21 | devDependencies: 22 | nodemon: 23 | specifier: 3.1.10 24 | version: 3.1.10 25 | 26 | packages: 27 | 28 | /@ioredis/commands@1.4.0: 29 | resolution: {integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==} 30 | dev: false 31 | 32 | /@isaacs/balanced-match@4.0.1: 33 | resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} 34 | engines: {node: 20 || >=22} 35 | dev: false 36 | 37 | /@isaacs/brace-expansion@5.0.0: 38 | resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} 39 | engines: {node: 20 || >=22} 40 | dependencies: 41 | '@isaacs/balanced-match': 4.0.1 42 | dev: false 43 | 44 | /@isaacs/cliui@8.0.2: 45 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 46 | engines: {node: '>=12'} 47 | dependencies: 48 | string-width: 5.1.2 49 | string-width-cjs: /string-width@4.2.3 50 | strip-ansi: 7.1.0 51 | strip-ansi-cjs: /strip-ansi@6.0.1 52 | wrap-ansi: 8.1.0 53 | wrap-ansi-cjs: /wrap-ansi@7.0.0 54 | dev: false 55 | 56 | /accepts@2.0.0: 57 | resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} 58 | engines: {node: '>= 0.6'} 59 | dependencies: 60 | mime-types: 3.0.1 61 | negotiator: 1.0.0 62 | dev: false 63 | 64 | /ansi-regex@5.0.1: 65 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 66 | engines: {node: '>=8'} 67 | dev: false 68 | 69 | /ansi-regex@6.0.1: 70 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} 71 | engines: {node: '>=12'} 72 | dev: false 73 | 74 | /ansi-styles@4.3.0: 75 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 76 | engines: {node: '>=8'} 77 | dependencies: 78 | color-convert: 2.0.1 79 | dev: false 80 | 81 | /ansi-styles@6.2.1: 82 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 83 | engines: {node: '>=12'} 84 | dev: false 85 | 86 | /anymatch@3.1.3: 87 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 88 | engines: {node: '>= 8'} 89 | dependencies: 90 | normalize-path: 3.0.0 91 | picomatch: 2.3.1 92 | dev: true 93 | 94 | /balanced-match@1.0.2: 95 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 96 | dev: true 97 | 98 | /binary-extensions@2.3.0: 99 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 100 | engines: {node: '>=8'} 101 | dev: true 102 | 103 | /body-parser@2.2.0: 104 | resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} 105 | engines: {node: '>=18'} 106 | dependencies: 107 | bytes: 3.1.2 108 | content-type: 1.0.5 109 | debug: 4.4.0(supports-color@5.5.0) 110 | http-errors: 2.0.0 111 | iconv-lite: 0.6.3 112 | on-finished: 2.4.1 113 | qs: 6.14.0 114 | raw-body: 3.0.0 115 | type-is: 2.0.1 116 | transitivePeerDependencies: 117 | - supports-color 118 | dev: false 119 | 120 | /brace-expansion@1.1.11: 121 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 122 | dependencies: 123 | balanced-match: 1.0.2 124 | concat-map: 0.0.1 125 | dev: true 126 | 127 | /braces@3.0.3: 128 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 129 | engines: {node: '>=8'} 130 | dependencies: 131 | fill-range: 7.1.1 132 | dev: true 133 | 134 | /bytes@3.1.2: 135 | resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} 136 | engines: {node: '>= 0.8'} 137 | dev: false 138 | 139 | /call-bind-apply-helpers@1.0.2: 140 | resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 141 | engines: {node: '>= 0.4'} 142 | dependencies: 143 | es-errors: 1.3.0 144 | function-bind: 1.1.2 145 | dev: false 146 | 147 | /call-bound@1.0.4: 148 | resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} 149 | engines: {node: '>= 0.4'} 150 | dependencies: 151 | call-bind-apply-helpers: 1.0.2 152 | get-intrinsic: 1.3.0 153 | dev: false 154 | 155 | /chokidar@3.6.0: 156 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 157 | engines: {node: '>= 8.10.0'} 158 | dependencies: 159 | anymatch: 3.1.3 160 | braces: 3.0.3 161 | glob-parent: 5.1.2 162 | is-binary-path: 2.1.0 163 | is-glob: 4.0.3 164 | normalize-path: 3.0.0 165 | readdirp: 3.6.0 166 | optionalDependencies: 167 | fsevents: 2.3.3 168 | dev: true 169 | 170 | /cluster-key-slot@1.1.2: 171 | resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} 172 | engines: {node: '>=0.10.0'} 173 | dev: false 174 | 175 | /color-convert@2.0.1: 176 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 177 | engines: {node: '>=7.0.0'} 178 | dependencies: 179 | color-name: 1.1.4 180 | dev: false 181 | 182 | /color-name@1.1.4: 183 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 184 | dev: false 185 | 186 | /concat-map@0.0.1: 187 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 188 | dev: true 189 | 190 | /content-disposition@1.0.0: 191 | resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} 192 | engines: {node: '>= 0.6'} 193 | dependencies: 194 | safe-buffer: 5.2.1 195 | dev: false 196 | 197 | /content-type@1.0.5: 198 | resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} 199 | engines: {node: '>= 0.6'} 200 | dev: false 201 | 202 | /cookie-signature@1.2.2: 203 | resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} 204 | engines: {node: '>=6.6.0'} 205 | dev: false 206 | 207 | /cookie@0.7.1: 208 | resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} 209 | engines: {node: '>= 0.6'} 210 | dev: false 211 | 212 | /cross-spawn@7.0.6: 213 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 214 | engines: {node: '>= 8'} 215 | dependencies: 216 | path-key: 3.1.1 217 | shebang-command: 2.0.0 218 | which: 2.0.2 219 | dev: false 220 | 221 | /debug@4.4.0(supports-color@5.5.0): 222 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 223 | engines: {node: '>=6.0'} 224 | peerDependencies: 225 | supports-color: '*' 226 | peerDependenciesMeta: 227 | supports-color: 228 | optional: true 229 | dependencies: 230 | ms: 2.1.3 231 | supports-color: 5.5.0 232 | 233 | /denque@2.1.0: 234 | resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} 235 | engines: {node: '>=0.10'} 236 | dev: false 237 | 238 | /depd@2.0.0: 239 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} 240 | engines: {node: '>= 0.8'} 241 | dev: false 242 | 243 | /dotenv@17.2.3: 244 | resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} 245 | engines: {node: '>=12'} 246 | dev: false 247 | 248 | /dunder-proto@1.0.1: 249 | resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} 250 | engines: {node: '>= 0.4'} 251 | dependencies: 252 | call-bind-apply-helpers: 1.0.2 253 | es-errors: 1.3.0 254 | gopd: 1.2.0 255 | dev: false 256 | 257 | /eastasianwidth@0.2.0: 258 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 259 | dev: false 260 | 261 | /ee-first@1.1.1: 262 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} 263 | dev: false 264 | 265 | /emoji-regex@8.0.0: 266 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 267 | dev: false 268 | 269 | /emoji-regex@9.2.2: 270 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 271 | dev: false 272 | 273 | /encodeurl@2.0.0: 274 | resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} 275 | engines: {node: '>= 0.8'} 276 | dev: false 277 | 278 | /es-define-property@1.0.1: 279 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 280 | engines: {node: '>= 0.4'} 281 | dev: false 282 | 283 | /es-errors@1.3.0: 284 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 285 | engines: {node: '>= 0.4'} 286 | dev: false 287 | 288 | /es-object-atoms@1.1.1: 289 | resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} 290 | engines: {node: '>= 0.4'} 291 | dependencies: 292 | es-errors: 1.3.0 293 | dev: false 294 | 295 | /escape-html@1.0.3: 296 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} 297 | dev: false 298 | 299 | /etag@1.8.1: 300 | resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} 301 | engines: {node: '>= 0.6'} 302 | dev: false 303 | 304 | /express-handlebars@8.0.4: 305 | resolution: {integrity: sha512-1mXd9jxLfZgFjpPGamAizVhwukvwLlXRV0dPcsEvW2hqUlYICMtJAQrqFSmgwHFvbVeIA/afPOtmHtNF516pmQ==} 306 | engines: {node: '>=22.21.0'} 307 | dependencies: 308 | glob: 12.0.0 309 | graceful-fs: 4.2.11 310 | handlebars: 4.7.8 311 | dev: false 312 | 313 | /express@5.1.0: 314 | resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} 315 | engines: {node: '>= 18'} 316 | dependencies: 317 | accepts: 2.0.0 318 | body-parser: 2.2.0 319 | content-disposition: 1.0.0 320 | content-type: 1.0.5 321 | cookie: 0.7.1 322 | cookie-signature: 1.2.2 323 | debug: 4.4.0(supports-color@5.5.0) 324 | encodeurl: 2.0.0 325 | escape-html: 1.0.3 326 | etag: 1.8.1 327 | finalhandler: 2.1.0 328 | fresh: 2.0.0 329 | http-errors: 2.0.0 330 | merge-descriptors: 2.0.0 331 | mime-types: 3.0.1 332 | on-finished: 2.4.1 333 | once: 1.4.0 334 | parseurl: 1.3.3 335 | proxy-addr: 2.0.7 336 | qs: 6.14.0 337 | range-parser: 1.2.1 338 | router: 2.2.0 339 | send: 1.2.0 340 | serve-static: 2.2.0 341 | statuses: 2.0.1 342 | type-is: 2.0.1 343 | vary: 1.1.2 344 | transitivePeerDependencies: 345 | - supports-color 346 | dev: false 347 | 348 | /fill-range@7.1.1: 349 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 350 | engines: {node: '>=8'} 351 | dependencies: 352 | to-regex-range: 5.0.1 353 | dev: true 354 | 355 | /finalhandler@2.1.0: 356 | resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} 357 | engines: {node: '>= 0.8'} 358 | dependencies: 359 | debug: 4.4.0(supports-color@5.5.0) 360 | encodeurl: 2.0.0 361 | escape-html: 1.0.3 362 | on-finished: 2.4.1 363 | parseurl: 1.3.3 364 | statuses: 2.0.1 365 | transitivePeerDependencies: 366 | - supports-color 367 | dev: false 368 | 369 | /foreground-child@3.3.1: 370 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 371 | engines: {node: '>=14'} 372 | dependencies: 373 | cross-spawn: 7.0.6 374 | signal-exit: 4.1.0 375 | dev: false 376 | 377 | /forwarded@0.2.0: 378 | resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} 379 | engines: {node: '>= 0.6'} 380 | dev: false 381 | 382 | /fresh@2.0.0: 383 | resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} 384 | engines: {node: '>= 0.8'} 385 | dev: false 386 | 387 | /fsevents@2.3.3: 388 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 389 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 390 | os: [darwin] 391 | requiresBuild: true 392 | dev: true 393 | optional: true 394 | 395 | /function-bind@1.1.2: 396 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 397 | dev: false 398 | 399 | /get-intrinsic@1.3.0: 400 | resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} 401 | engines: {node: '>= 0.4'} 402 | dependencies: 403 | call-bind-apply-helpers: 1.0.2 404 | es-define-property: 1.0.1 405 | es-errors: 1.3.0 406 | es-object-atoms: 1.1.1 407 | function-bind: 1.1.2 408 | get-proto: 1.0.1 409 | gopd: 1.2.0 410 | has-symbols: 1.1.0 411 | hasown: 2.0.2 412 | math-intrinsics: 1.1.0 413 | dev: false 414 | 415 | /get-proto@1.0.1: 416 | resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} 417 | engines: {node: '>= 0.4'} 418 | dependencies: 419 | dunder-proto: 1.0.1 420 | es-object-atoms: 1.1.1 421 | dev: false 422 | 423 | /glob-parent@5.1.2: 424 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 425 | engines: {node: '>= 6'} 426 | dependencies: 427 | is-glob: 4.0.3 428 | dev: true 429 | 430 | /glob@12.0.0: 431 | resolution: {integrity: sha512-5Qcll1z7IKgHr5g485ePDdHcNQY0k2dtv/bjYy0iuyGxQw2qSOiiXUXJ+AYQpg3HNoUMHqAruX478Jeev7UULw==} 432 | engines: {node: 20 || >=22} 433 | hasBin: true 434 | dependencies: 435 | foreground-child: 3.3.1 436 | jackspeak: 4.1.1 437 | minimatch: 10.1.1 438 | minipass: 7.1.2 439 | package-json-from-dist: 1.0.1 440 | path-scurry: 2.0.0 441 | dev: false 442 | 443 | /gopd@1.2.0: 444 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} 445 | engines: {node: '>= 0.4'} 446 | dev: false 447 | 448 | /graceful-fs@4.2.11: 449 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 450 | dev: false 451 | 452 | /handlebars@4.7.8: 453 | resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} 454 | engines: {node: '>=0.4.7'} 455 | hasBin: true 456 | dependencies: 457 | minimist: 1.2.8 458 | neo-async: 2.6.2 459 | source-map: 0.6.1 460 | wordwrap: 1.0.0 461 | optionalDependencies: 462 | uglify-js: 3.18.0 463 | dev: false 464 | 465 | /has-flag@3.0.0: 466 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 467 | engines: {node: '>=4'} 468 | 469 | /has-symbols@1.1.0: 470 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 471 | engines: {node: '>= 0.4'} 472 | dev: false 473 | 474 | /hasown@2.0.2: 475 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 476 | engines: {node: '>= 0.4'} 477 | dependencies: 478 | function-bind: 1.1.2 479 | dev: false 480 | 481 | /http-errors@2.0.0: 482 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 483 | engines: {node: '>= 0.8'} 484 | dependencies: 485 | depd: 2.0.0 486 | inherits: 2.0.4 487 | setprototypeof: 1.2.0 488 | statuses: 2.0.1 489 | toidentifier: 1.0.1 490 | dev: false 491 | 492 | /iconv-lite@0.6.3: 493 | resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} 494 | engines: {node: '>=0.10.0'} 495 | dependencies: 496 | safer-buffer: 2.1.2 497 | dev: false 498 | 499 | /ignore-by-default@1.0.1: 500 | resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} 501 | dev: true 502 | 503 | /inherits@2.0.4: 504 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 505 | dev: false 506 | 507 | /ioredis@5.8.2: 508 | resolution: {integrity: sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==} 509 | engines: {node: '>=12.22.0'} 510 | dependencies: 511 | '@ioredis/commands': 1.4.0 512 | cluster-key-slot: 1.1.2 513 | debug: 4.4.0(supports-color@5.5.0) 514 | denque: 2.1.0 515 | lodash.defaults: 4.2.0 516 | lodash.isarguments: 3.1.0 517 | redis-errors: 1.2.0 518 | redis-parser: 3.0.0 519 | standard-as-callback: 2.1.0 520 | transitivePeerDependencies: 521 | - supports-color 522 | dev: false 523 | 524 | /ipaddr.js@1.9.1: 525 | resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} 526 | engines: {node: '>= 0.10'} 527 | dev: false 528 | 529 | /is-binary-path@2.1.0: 530 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 531 | engines: {node: '>=8'} 532 | dependencies: 533 | binary-extensions: 2.3.0 534 | dev: true 535 | 536 | /is-extglob@2.1.1: 537 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 538 | engines: {node: '>=0.10.0'} 539 | dev: true 540 | 541 | /is-fullwidth-code-point@3.0.0: 542 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 543 | engines: {node: '>=8'} 544 | dev: false 545 | 546 | /is-glob@4.0.3: 547 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 548 | engines: {node: '>=0.10.0'} 549 | dependencies: 550 | is-extglob: 2.1.1 551 | dev: true 552 | 553 | /is-number@7.0.0: 554 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 555 | engines: {node: '>=0.12.0'} 556 | dev: true 557 | 558 | /is-promise@4.0.0: 559 | resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} 560 | dev: false 561 | 562 | /isexe@2.0.0: 563 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 564 | dev: false 565 | 566 | /jackspeak@4.1.1: 567 | resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} 568 | engines: {node: 20 || >=22} 569 | dependencies: 570 | '@isaacs/cliui': 8.0.2 571 | dev: false 572 | 573 | /lodash.defaults@4.2.0: 574 | resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} 575 | dev: false 576 | 577 | /lodash.isarguments@3.1.0: 578 | resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} 579 | dev: false 580 | 581 | /lru-cache@11.0.2: 582 | resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} 583 | engines: {node: 20 || >=22} 584 | dev: false 585 | 586 | /math-intrinsics@1.1.0: 587 | resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 588 | engines: {node: '>= 0.4'} 589 | dev: false 590 | 591 | /media-typer@1.1.0: 592 | resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} 593 | engines: {node: '>= 0.8'} 594 | dev: false 595 | 596 | /merge-descriptors@2.0.0: 597 | resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} 598 | engines: {node: '>=18'} 599 | dev: false 600 | 601 | /mime-db@1.54.0: 602 | resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} 603 | engines: {node: '>= 0.6'} 604 | dev: false 605 | 606 | /mime-types@3.0.1: 607 | resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} 608 | engines: {node: '>= 0.6'} 609 | dependencies: 610 | mime-db: 1.54.0 611 | dev: false 612 | 613 | /minimatch@10.1.1: 614 | resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} 615 | engines: {node: 20 || >=22} 616 | dependencies: 617 | '@isaacs/brace-expansion': 5.0.0 618 | dev: false 619 | 620 | /minimatch@3.1.2: 621 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 622 | dependencies: 623 | brace-expansion: 1.1.11 624 | dev: true 625 | 626 | /minimist@1.2.8: 627 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 628 | dev: false 629 | 630 | /minipass@7.1.2: 631 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 632 | engines: {node: '>=16 || 14 >=14.17'} 633 | dev: false 634 | 635 | /ms@2.1.3: 636 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 637 | 638 | /negotiator@1.0.0: 639 | resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} 640 | engines: {node: '>= 0.6'} 641 | dev: false 642 | 643 | /neo-async@2.6.2: 644 | resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} 645 | dev: false 646 | 647 | /nodemon@3.1.10: 648 | resolution: {integrity: sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==} 649 | engines: {node: '>=10'} 650 | hasBin: true 651 | dependencies: 652 | chokidar: 3.6.0 653 | debug: 4.4.0(supports-color@5.5.0) 654 | ignore-by-default: 1.0.1 655 | minimatch: 3.1.2 656 | pstree.remy: 1.1.8 657 | semver: 7.6.2 658 | simple-update-notifier: 2.0.0 659 | supports-color: 5.5.0 660 | touch: 3.1.1 661 | undefsafe: 2.0.5 662 | dev: true 663 | 664 | /normalize-path@3.0.0: 665 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 666 | engines: {node: '>=0.10.0'} 667 | dev: true 668 | 669 | /object-inspect@1.13.4: 670 | resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} 671 | engines: {node: '>= 0.4'} 672 | dev: false 673 | 674 | /on-finished@2.4.1: 675 | resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} 676 | engines: {node: '>= 0.8'} 677 | dependencies: 678 | ee-first: 1.1.1 679 | dev: false 680 | 681 | /once@1.4.0: 682 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 683 | dependencies: 684 | wrappy: 1.0.2 685 | dev: false 686 | 687 | /package-json-from-dist@1.0.1: 688 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 689 | dev: false 690 | 691 | /parseurl@1.3.3: 692 | resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} 693 | engines: {node: '>= 0.8'} 694 | dev: false 695 | 696 | /path-key@3.1.1: 697 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 698 | engines: {node: '>=8'} 699 | dev: false 700 | 701 | /path-scurry@2.0.0: 702 | resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} 703 | engines: {node: 20 || >=22} 704 | dependencies: 705 | lru-cache: 11.0.2 706 | minipass: 7.1.2 707 | dev: false 708 | 709 | /path-to-regexp@8.2.0: 710 | resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} 711 | engines: {node: '>=16'} 712 | dev: false 713 | 714 | /picomatch@2.3.1: 715 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 716 | engines: {node: '>=8.6'} 717 | dev: true 718 | 719 | /proxy-addr@2.0.7: 720 | resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} 721 | engines: {node: '>= 0.10'} 722 | dependencies: 723 | forwarded: 0.2.0 724 | ipaddr.js: 1.9.1 725 | dev: false 726 | 727 | /pstree.remy@1.1.8: 728 | resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} 729 | dev: true 730 | 731 | /qs@6.14.0: 732 | resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} 733 | engines: {node: '>=0.6'} 734 | dependencies: 735 | side-channel: 1.1.0 736 | dev: false 737 | 738 | /range-parser@1.2.1: 739 | resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} 740 | engines: {node: '>= 0.6'} 741 | dev: false 742 | 743 | /raw-body@3.0.0: 744 | resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} 745 | engines: {node: '>= 0.8'} 746 | dependencies: 747 | bytes: 3.1.2 748 | http-errors: 2.0.0 749 | iconv-lite: 0.6.3 750 | unpipe: 1.0.0 751 | dev: false 752 | 753 | /readdirp@3.6.0: 754 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 755 | engines: {node: '>=8.10.0'} 756 | dependencies: 757 | picomatch: 2.3.1 758 | dev: true 759 | 760 | /redis-errors@1.2.0: 761 | resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} 762 | engines: {node: '>=4'} 763 | dev: false 764 | 765 | /redis-parser@3.0.0: 766 | resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} 767 | engines: {node: '>=4'} 768 | dependencies: 769 | redis-errors: 1.2.0 770 | dev: false 771 | 772 | /router@2.2.0: 773 | resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} 774 | engines: {node: '>= 18'} 775 | dependencies: 776 | debug: 4.4.0(supports-color@5.5.0) 777 | depd: 2.0.0 778 | is-promise: 4.0.0 779 | parseurl: 1.3.3 780 | path-to-regexp: 8.2.0 781 | transitivePeerDependencies: 782 | - supports-color 783 | dev: false 784 | 785 | /safe-buffer@5.2.1: 786 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 787 | dev: false 788 | 789 | /safer-buffer@2.1.2: 790 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 791 | dev: false 792 | 793 | /semver@7.6.2: 794 | resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} 795 | engines: {node: '>=10'} 796 | hasBin: true 797 | dev: true 798 | 799 | /send@1.2.0: 800 | resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} 801 | engines: {node: '>= 18'} 802 | dependencies: 803 | debug: 4.4.0(supports-color@5.5.0) 804 | encodeurl: 2.0.0 805 | escape-html: 1.0.3 806 | etag: 1.8.1 807 | fresh: 2.0.0 808 | http-errors: 2.0.0 809 | mime-types: 3.0.1 810 | ms: 2.1.3 811 | on-finished: 2.4.1 812 | range-parser: 1.2.1 813 | statuses: 2.0.1 814 | transitivePeerDependencies: 815 | - supports-color 816 | dev: false 817 | 818 | /serve-static@2.2.0: 819 | resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} 820 | engines: {node: '>= 18'} 821 | dependencies: 822 | encodeurl: 2.0.0 823 | escape-html: 1.0.3 824 | parseurl: 1.3.3 825 | send: 1.2.0 826 | transitivePeerDependencies: 827 | - supports-color 828 | dev: false 829 | 830 | /setprototypeof@1.2.0: 831 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} 832 | dev: false 833 | 834 | /shebang-command@2.0.0: 835 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 836 | engines: {node: '>=8'} 837 | dependencies: 838 | shebang-regex: 3.0.0 839 | dev: false 840 | 841 | /shebang-regex@3.0.0: 842 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 843 | engines: {node: '>=8'} 844 | dev: false 845 | 846 | /side-channel-list@1.0.0: 847 | resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} 848 | engines: {node: '>= 0.4'} 849 | dependencies: 850 | es-errors: 1.3.0 851 | object-inspect: 1.13.4 852 | dev: false 853 | 854 | /side-channel-map@1.0.1: 855 | resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} 856 | engines: {node: '>= 0.4'} 857 | dependencies: 858 | call-bound: 1.0.4 859 | es-errors: 1.3.0 860 | get-intrinsic: 1.3.0 861 | object-inspect: 1.13.4 862 | dev: false 863 | 864 | /side-channel-weakmap@1.0.2: 865 | resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} 866 | engines: {node: '>= 0.4'} 867 | dependencies: 868 | call-bound: 1.0.4 869 | es-errors: 1.3.0 870 | get-intrinsic: 1.3.0 871 | object-inspect: 1.13.4 872 | side-channel-map: 1.0.1 873 | dev: false 874 | 875 | /side-channel@1.1.0: 876 | resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} 877 | engines: {node: '>= 0.4'} 878 | dependencies: 879 | es-errors: 1.3.0 880 | object-inspect: 1.13.4 881 | side-channel-list: 1.0.0 882 | side-channel-map: 1.0.1 883 | side-channel-weakmap: 1.0.2 884 | dev: false 885 | 886 | /signal-exit@4.1.0: 887 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 888 | engines: {node: '>=14'} 889 | dev: false 890 | 891 | /simple-update-notifier@2.0.0: 892 | resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} 893 | engines: {node: '>=10'} 894 | dependencies: 895 | semver: 7.6.2 896 | dev: true 897 | 898 | /source-map@0.6.1: 899 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 900 | engines: {node: '>=0.10.0'} 901 | dev: false 902 | 903 | /standard-as-callback@2.1.0: 904 | resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} 905 | dev: false 906 | 907 | /statuses@2.0.1: 908 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} 909 | engines: {node: '>= 0.8'} 910 | dev: false 911 | 912 | /string-width@4.2.3: 913 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 914 | engines: {node: '>=8'} 915 | dependencies: 916 | emoji-regex: 8.0.0 917 | is-fullwidth-code-point: 3.0.0 918 | strip-ansi: 6.0.1 919 | dev: false 920 | 921 | /string-width@5.1.2: 922 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 923 | engines: {node: '>=12'} 924 | dependencies: 925 | eastasianwidth: 0.2.0 926 | emoji-regex: 9.2.2 927 | strip-ansi: 7.1.0 928 | dev: false 929 | 930 | /strip-ansi@6.0.1: 931 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 932 | engines: {node: '>=8'} 933 | dependencies: 934 | ansi-regex: 5.0.1 935 | dev: false 936 | 937 | /strip-ansi@7.1.0: 938 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 939 | engines: {node: '>=12'} 940 | dependencies: 941 | ansi-regex: 6.0.1 942 | dev: false 943 | 944 | /supports-color@5.5.0: 945 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 946 | engines: {node: '>=4'} 947 | dependencies: 948 | has-flag: 3.0.0 949 | 950 | /to-regex-range@5.0.1: 951 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 952 | engines: {node: '>=8.0'} 953 | dependencies: 954 | is-number: 7.0.0 955 | dev: true 956 | 957 | /toidentifier@1.0.1: 958 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} 959 | engines: {node: '>=0.6'} 960 | dev: false 961 | 962 | /touch@3.1.1: 963 | resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} 964 | hasBin: true 965 | dev: true 966 | 967 | /type-is@2.0.1: 968 | resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} 969 | engines: {node: '>= 0.6'} 970 | dependencies: 971 | content-type: 1.0.5 972 | media-typer: 1.1.0 973 | mime-types: 3.0.1 974 | dev: false 975 | 976 | /uglify-js@3.18.0: 977 | resolution: {integrity: sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==} 978 | engines: {node: '>=0.8.0'} 979 | hasBin: true 980 | requiresBuild: true 981 | dev: false 982 | optional: true 983 | 984 | /undefsafe@2.0.5: 985 | resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} 986 | dev: true 987 | 988 | /unpipe@1.0.0: 989 | resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} 990 | engines: {node: '>= 0.8'} 991 | dev: false 992 | 993 | /vary@1.1.2: 994 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 995 | engines: {node: '>= 0.8'} 996 | dev: false 997 | 998 | /which@2.0.2: 999 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1000 | engines: {node: '>= 8'} 1001 | hasBin: true 1002 | dependencies: 1003 | isexe: 2.0.0 1004 | dev: false 1005 | 1006 | /wordwrap@1.0.0: 1007 | resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} 1008 | dev: false 1009 | 1010 | /wrap-ansi@7.0.0: 1011 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1012 | engines: {node: '>=10'} 1013 | dependencies: 1014 | ansi-styles: 4.3.0 1015 | string-width: 4.2.3 1016 | strip-ansi: 6.0.1 1017 | dev: false 1018 | 1019 | /wrap-ansi@8.1.0: 1020 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1021 | engines: {node: '>=12'} 1022 | dependencies: 1023 | ansi-styles: 6.2.1 1024 | string-width: 5.1.2 1025 | strip-ansi: 7.1.0 1026 | dev: false 1027 | 1028 | /wrappy@1.0.2: 1029 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1030 | dev: false 1031 | --------------------------------------------------------------------------------