From 69ee000e14faf349130448d3a6e71e18b879683a Mon Sep 17 00:00:00 2001 From: Nikolay Karadzhov Date: Sat, 31 Oct 2026 17:15:40 +0200 Subject: [PATCH 1/2] chore: add npm run repl with a connected client Opens a Node REPL with a connected `client` in scope. Takes optional --host/--port flags, or REDIS_URL. Exits if the first connect fails. --- package.json | 1 + scripts/repl.mjs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 scripts/repl.mjs diff --git a/package.json b/package.json index 931ea85fd6f..951c5cf9ac8 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "lint:changed": "node scripts/lint-changed.mjs", "test": "npm run cleanup && npm run test --workspaces --if-present", "build": "tsc --build", + "repl": "node scripts/repl.mjs", "check:command-jsdoc": "tsx scripts/check-command-jsdoc.ts", "documentation": "typedoc --entryPointStrategy packages --entryPoints ./packages/client ./packages/bloom ./packages/json ./packages/search ./packages/time-series ./packages/entraid ./packages/redis --out ./documentation", "gh-pages": "gh-pages -d ./documentation -e ./documentation -u 'documentation-bot '", diff --git a/scripts/repl.mjs b/scripts/repl.mjs new file mode 100644 index 00000000000..efe299eb532 --- /dev/null +++ b/scripts/repl.mjs @@ -0,0 +1,39 @@ +// Opens a Node REPL with a connected `client` in scope. +// Uses the built packages, so run `npm run build` after source changes. +// Target another server with `npm run repl -- --host --port ` +// (either flag alone is fine) or with REDIS_URL. Flags win over REDIS_URL. +import repl from 'node:repl'; +import { parseArgs } from 'node:util'; +import { createClient } from 'redis'; + +const { values: { host, port } } = parseArgs({ + options: { + host: { type: 'string', short: 'h' }, + port: { type: 'string', short: 'p' } + } +}); + +const url = host || port + ? `redis://${host ?? 'localhost'}:${port ?? 6379}` + : process.env.REDIS_URL ?? 'redis://localhost:6379'; +const client = createClient({ url }); +// Connection errors such as ECONNREFUSED carry the reason in `code`, not `message`. +const reason = err => err.code ?? err.message; + +// Exit if the first connect fails; after that, keep the default reconnects. +const onConnectError = err => { + console.error(`Could not connect to ${url}: ${reason(err)}`); + process.exit(1); +}; +client.once('error', onConnectError); +await client.connect(); +client.off('error', onConnectError); +client.on('error', err => console.error('Redis client error:', reason(err))); +console.log(`Connected to ${url}. Use \`client\`, e.g. await client.ping()`); + +const server = repl.start('redis> '); +server.context.client = client; +server.on('exit', async () => { + await client.close(); + process.exit(); +}); From c3e36dd1798aa07a90a17197a6d7180d2f895e1b Mon Sep 17 00:00:00 2001 From: Nikolay Karadzhov Date: Sat, 31 Oct 2026 20:26:55 +0200 Subject: [PATCH 2/2] force destroy on exit --- scripts/repl.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/repl.mjs b/scripts/repl.mjs index efe299eb532..b608348eb21 100644 --- a/scripts/repl.mjs +++ b/scripts/repl.mjs @@ -34,6 +34,6 @@ console.log(`Connected to ${url}. Use \`client\`, e.g. await client.ping()`); const server = repl.start('redis> '); server.context.client = client; server.on('exit', async () => { - await client.close(); + client.destroy(); process.exit(); });