diff --git a/src/_utils.ts b/src/_utils.ts index ffeec859..b870cd42 100644 --- a/src/_utils.ts +++ b/src/_utils.ts @@ -45,41 +45,3 @@ export function stringify(value: any): string { throw new Error("[unstorage] Cannot stringify value!"); } - -export const BASE64_PREFIX = "base64:"; - -export function serializeRaw(value: any) { - if (typeof value === "string") { - return value; - } - return BASE64_PREFIX + base64Encode(value); -} - -export function deserializeRaw(value: any) { - if (typeof value !== "string") { - // Return non-strings as-is - return value; - } - if (!value.startsWith(BASE64_PREFIX)) { - // Return unknown strings as-is - return value; - } - return base64Decode(value.slice(BASE64_PREFIX.length)); -} - -function base64Decode(input: string) { - if (globalThis.Buffer) { - return Buffer.from(input, "base64"); - } - return Uint8Array.from( - globalThis.atob(input), - (c) => c.codePointAt(0) as number - ); -} - -function base64Encode(input: Uint8Array) { - if (globalThis.Buffer) { - return Buffer.from(input).toString("base64"); - } - return globalThis.btoa(String.fromCodePoint(...input)); -} diff --git a/src/drivers/redis.ts b/src/drivers/redis.ts index 47e7c03c..d4fb8eb3 100644 --- a/src/drivers/redis.ts +++ b/src/drivers/redis.ts @@ -1,4 +1,10 @@ -import { defineDriver, joinKeys } from "./utils"; +import { + defineDriver, + joinKeys, + createError, + serializeRaw, + deserializeRaw, +} from "./utils"; // TODO: use named import in v2 import Redis, { Cluster, @@ -32,6 +38,12 @@ export interface RedisOptions extends _RedisOptions { * Default TTL for all items in seconds. */ ttl?: number; + + /** + * Whether to save Buffer/Uint8Arry as binary data or a base64-encoded string + * This option applies to the experimental getItemRaw/setItemRaw methods + */ + saveRawAsBinary?: boolean; } const DRIVER_NAME = "redis"; @@ -75,6 +87,42 @@ export default defineDriver((opts: RedisOptions) => { await getRedisClient().set(p(key), value); } }, + async getItemRaw(key) { + if (opts.saveRawAsBinary) { + const value = await getRedisClient().getBuffer(p(key)); + return value ?? null; + } else { + const value = await getRedisClient().get(p(key)); + return deserializeRaw(value); + } + }, + async setItemRaw(key, value, tOptions) { + let valueToSave: any; + if (opts.saveRawAsBinary) { + if (value instanceof Uint8Array) { + if (value instanceof Buffer) { + valueToSave = value; + } else { + valueToSave = Buffer.copyBytesFrom( + value, + value.byteOffset, + value.byteLength + ); + } + } else { + throw createError(DRIVER_NAME, "Expected Buffer or Uint8Array"); + } + } else { + valueToSave = serializeRaw(value); + } + + const ttl = tOptions?.ttl ?? opts.ttl; + if (ttl) { + await getRedisClient().set(p(key), valueToSave, "EX", ttl); + } else { + await getRedisClient().set(p(key), valueToSave); + } + }, async removeItem(key) { await getRedisClient().del(p(key)); }, diff --git a/src/drivers/utils/index.ts b/src/drivers/utils/index.ts index 16e584a3..c25fb348 100644 --- a/src/drivers/utils/index.ts +++ b/src/drivers/utils/index.ts @@ -51,3 +51,41 @@ export function createRequiredError(driver: string, name: string | string[]) { } return createError(driver, `Missing required option \`${name}\`.`); } + +export const BASE64_PREFIX = "base64:"; + +export function serializeRaw(value: any) { + if (typeof value === "string") { + return value; + } + return BASE64_PREFIX + base64Encode(value); +} + +export function deserializeRaw(value: any) { + if (typeof value !== "string") { + // Return non-strings as-is + return value; + } + if (!value.startsWith(BASE64_PREFIX)) { + // Return unknown strings as-is + return value; + } + return base64Decode(value.slice(BASE64_PREFIX.length)); +} + +function base64Decode(input: string) { + if (globalThis.Buffer) { + return Buffer.from(input, "base64"); + } + return Uint8Array.from( + globalThis.atob(input), + (c) => c.codePointAt(0) as number + ); +} + +function base64Encode(input: Uint8Array) { + if (globalThis.Buffer) { + return Buffer.from(input).toString("base64"); + } + return globalThis.btoa(String.fromCodePoint(...input)); +} diff --git a/src/storage.ts b/src/storage.ts index 7cacb064..1bbe8960 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -9,7 +9,8 @@ import type { TransactionOptions, } from "./types"; import memory from "./drivers/memory"; -import { asyncCall, deserializeRaw, serializeRaw, stringify } from "./_utils"; +import { serializeRaw, deserializeRaw } from "./drivers/utils"; +import { asyncCall, stringify } from "./_utils"; import { normalizeKey, normalizeBaseKey,