Skip to content

Commit 726b54c

Browse files
authored
feat(redis-strings): optional valueSerializer for custom wire format (#211)
Made-with: Cursor
1 parent 10832e5 commit 726b54c

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

packages/nextjs-cache-handler/src/handlers/redis-strings.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { REVALIDATED_TAGS_KEY } from "../constants";
22
import { isImplicitTag } from "../helpers/isImplicitTag";
33
import { CacheHandlerValue, Handler } from "./cache-handler.types";
4-
import { CreateRedisStringsHandlerOptions } from "./redis-strings.types";
4+
import {
5+
type CacheValueSerializer,
6+
type CreateRedisStringsHandlerOptions,
7+
} from "./redis-strings.types";
58
import {
69
convertStringsToBuffers,
710
parseBuffersToStrings,
@@ -10,6 +13,19 @@ import type { RedisClientType } from "@redis/client";
1013
import { RedisClusterCacheAdapter } from "../helpers/redisClusterAdapter";
1114
import { withAbortSignalProxy } from "../helpers/withAbortSignalProxy";
1215

16+
export type { CacheValueSerializer } from "./redis-strings.types";
17+
18+
export const jsonCacheValueSerializer: CacheValueSerializer = {
19+
serialize(value) {
20+
return JSON.stringify(value);
21+
},
22+
deserialize(stored) {
23+
return JSON.parse(
24+
typeof stored === "string" ? stored : String(stored),
25+
) as CacheHandlerValue | null;
26+
},
27+
};
28+
1329
/**
1430
* Creates a Handler for handling cache operations using Redis strings.
1531
*
@@ -33,6 +49,7 @@ export default function createHandler({
3349
timeoutMs = 5_000,
3450
keyExpirationStrategy = "EXPIREAT",
3551
revalidateTagQuerySize = 10_000,
52+
valueSerializer = jsonCacheValueSerializer,
3653
}: CreateRedisStringsHandlerOptions<
3754
RedisClientType | RedisClusterCacheAdapter
3855
>): Handler {
@@ -176,7 +193,7 @@ export default function createHandler({
176193
return null;
177194
}
178195

179-
const cacheValue = JSON.parse(result) as CacheHandlerValue | null;
196+
const cacheValue = valueSerializer.deserialize(result);
180197

181198
if (!cacheValue) {
182199
return null;
@@ -237,7 +254,7 @@ export default function createHandler({
237254
parseBuffersToStrings({ ...cacheHandlerValue, value: valueForStorage });
238255
}
239256

240-
const serializedValue = JSON.stringify({
257+
const serializedValue = valueSerializer.serialize({
241258
...cacheHandlerValue,
242259
value: valueForStorage,
243260
});

packages/nextjs-cache-handler/src/handlers/redis-strings.types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
import type { RedisClientType } from "@redis/client";
22
import { RedisClusterCacheAdapter } from "../helpers/redisClusterAdapter";
3+
import type { CacheHandlerValue } from "./cache-handler.types";
4+
5+
/**
6+
* Pluggable wire-format codec for Redis string values (JSON, compression, encryption, etc.).
7+
* Default behavior is JSON.stringify / JSON.parse (see `jsonCacheValueSerializer` export).
8+
*/
9+
export type CacheValueSerializer = {
10+
serialize(value: CacheHandlerValue): string;
11+
deserialize(stored: string): CacheHandlerValue | null;
12+
};
313

414
export type RedisCompliantCachedRouteValue = {
515
// See: https://github.com/vercel/next.js/blob/f5444a16ec2ef7b82d30048890b613aa3865c1f1/packages/next/src/server/response-cache/types.ts#L97
@@ -72,4 +82,11 @@ export type CreateRedisStringsHandlerOptions<
7282
* @default 'EXPIREAT'
7383
*/
7484
keyExpirationStrategy?: "EXAT" | "EXPIREAT";
85+
/**
86+
* Optional codec for values stored in Redis (`SET`/`GET`).
87+
* Implement compression, encryption, or custom formats in your app; this package stays dependency-free.
88+
*
89+
* @default JSON.stringify / JSON.parse (same as previous releases)
90+
*/
91+
valueSerializer?: CacheValueSerializer;
7592
};

0 commit comments

Comments
 (0)