From 3d284aead3f4be0042211f8277c57f81e9a9c3a3 Mon Sep 17 00:00:00 2001 From: gergokee <55487440+gergokee@users.noreply.github.com> Date: Wed, 1 Apr 2026 22:19:48 +0200 Subject: [PATCH] feat: support async serialize/deserialize in CacheValueSerializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Widen CacheValueSerializer.serialize and .deserialize return types from sync-only to string | Promise and CacheHandlerValue | null | Promise respectively, and add await at both call sites in redis-strings.ts. This allows users to replace blocking sync codecs (e.g. brotliCompressSync) with non-blocking async variants (e.g. brotliCompress) without blocking the Node.js event loop under load. Existing sync implementations continue to work unchanged — await on a non-Promise is a no-op in JavaScript. --- .../src/handlers/redis-strings.ts | 4 ++-- .../src/handlers/redis-strings.types.ts | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/nextjs-cache-handler/src/handlers/redis-strings.ts b/packages/nextjs-cache-handler/src/handlers/redis-strings.ts index 0662064..4a90322 100644 --- a/packages/nextjs-cache-handler/src/handlers/redis-strings.ts +++ b/packages/nextjs-cache-handler/src/handlers/redis-strings.ts @@ -193,7 +193,7 @@ export default function createHandler({ return null; } - const cacheValue = valueSerializer.deserialize(result); + const cacheValue = await valueSerializer.deserialize(result); if (!cacheValue) { return null; @@ -254,7 +254,7 @@ export default function createHandler({ parseBuffersToStrings({ ...cacheHandlerValue, value: valueForStorage }); } - const serializedValue = valueSerializer.serialize({ + const serializedValue = await valueSerializer.serialize({ ...cacheHandlerValue, value: valueForStorage, }); diff --git a/packages/nextjs-cache-handler/src/handlers/redis-strings.types.ts b/packages/nextjs-cache-handler/src/handlers/redis-strings.types.ts index 65e1106..9af95c1 100644 --- a/packages/nextjs-cache-handler/src/handlers/redis-strings.types.ts +++ b/packages/nextjs-cache-handler/src/handlers/redis-strings.types.ts @@ -5,10 +5,14 @@ import type { CacheHandlerValue } from "./cache-handler.types"; /** * Pluggable wire-format codec for Redis string values (JSON, compression, encryption, etc.). * Default behavior is JSON.stringify / JSON.parse (see `jsonCacheValueSerializer` export). + * + * Both methods may return a `Promise`, enabling non-blocking async codecs such as + * stream-based compression (`zlib.brotliCompress`) or encryption (`crypto.subtle`). + * Synchronous implementations continue to work unchanged — `await` on a plain value is a no-op. */ export type CacheValueSerializer = { - serialize(value: CacheHandlerValue): string; - deserialize(stored: string): CacheHandlerValue | null; + serialize(value: CacheHandlerValue): string | Promise; + deserialize(stored: string): CacheHandlerValue | null | Promise; }; export type RedisCompliantCachedRouteValue = { @@ -86,6 +90,10 @@ export type CreateRedisStringsHandlerOptions< * Optional codec for values stored in Redis (`SET`/`GET`). * Implement compression, encryption, or custom formats in your app; this package stays dependency-free. * + * Both `serialize` and `deserialize` may return a `Promise`, enabling non-blocking async codecs + * (e.g. `zlib.brotliCompress` / `zlib.brotliDecompress`) that avoid blocking the Node.js event loop. + * Synchronous implementations continue to work unchanged. + * * @default JSON.stringify / JSON.parse (same as previous releases) */ valueSerializer?: CacheValueSerializer;