Skip to content

Commit 7ea1edd

Browse files
authored
fix(client): correct HELLO modules reply type (redis#3411)
* fix(client): correct HELLO modules reply type * fix(client): type HELLO modules entries like MODULE LIST
1 parent 839ab6d commit 7ea1edd

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

packages/client/lib/commands/HELLO.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ export type HelloReply = TuplesToMapReply<[
1717
[BlobStringReply<'id'>, NumberReply],
1818
[BlobStringReply<'mode'>, BlobStringReply],
1919
[BlobStringReply<'role'>, BlobStringReply],
20-
[BlobStringReply<'modules'>, ArrayReply<BlobStringReply>]
20+
[BlobStringReply<'modules'>, ArrayReply<TuplesToMapReply<[
21+
[BlobStringReply<'name'>, BlobStringReply],
22+
[BlobStringReply<'ver'>, NumberReply]
23+
/** path and args exist only on Redis 7.0+ */
24+
]>>]
2125
]>;
2226

2327
export default {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Compile-time regression: each entry of the HELLO reply's modules field is a
3+
* structured entry (name, ver), not a plain string. The declared reply type
4+
* used to label it Array<BlobStringReply>, so consumers had no type-safe
5+
* access to the module fields. path and args exist only on Redis 7.0+ and are
6+
* intentionally left out of the declared shape, mirroring MODULE LIST.
7+
*
8+
* Lives outside `lib/` so it is not picked up by the production build /
9+
* typedoc. Checked with `npm run test:types -w @redis/client`.
10+
*/
11+
import { createClient } from '../index';
12+
13+
type Client = ReturnType<typeof createClient>;
14+
type HelloReply = Awaited<ReturnType<Client['hello']>>;
15+
type ModuleEntry = HelloReply['modules'][number];
16+
17+
export function helloModulesAreStructured(entry: ModuleEntry): void {
18+
// Mapped (RESP3-style) entries must expose the server's fields.
19+
if (!Array.isArray(entry)) {
20+
const name: string = entry.name;
21+
const ver: number = entry.ver;
22+
23+
// A module version is a number, not a string.
24+
// @ts-expect-error module versions are numbers
25+
const notAString: string = entry.ver;
26+
27+
if (process.env.NODE_ENV !== 'production') {
28+
console.log(name, ver, notAString);
29+
}
30+
31+
return;
32+
}
33+
34+
// Flat (RESP2-style) entries stay arrays.
35+
if (entry.length < 0) {
36+
console.log(entry);
37+
}
38+
}

0 commit comments

Comments
 (0)