import { type Cluster, Redis, type RedisOptions } from "ioredis"; /** * A Redis-like client that supports the commands SecureStore needs. * Can be either a standard Redis client or a Redis Cluster client. */ export type RedisClient = Redis | Cluster; /** * Base error class for SecureStore */ export declare class SecureStoreError extends Error { readonly code?: string | undefined; constructor(message: string, code?: string | undefined); } /** * Connection-related errors */ export declare class ConnectionError extends SecureStoreError { constructor(message: string, cause?: Error); } /** * Encryption/decryption errors */ export declare class EncryptionError extends SecureStoreError { constructor(message: string, cause?: Error); } /** * Configuration validation errors */ export declare class ValidationError extends SecureStoreError { constructor(message: string); } /** * Secret validation utilities */ export declare class SecretValidator { /** * Calculate Shannon entropy of a string */ private static calculateEntropy; /** * Check if secret contains common weak patterns */ private static hasWeakPatterns; /** * Validate secret strength */ static validate(secret: string): { valid: boolean; reason?: string; }; /** * Generate cryptographically secure secret. * Uses a mix of uppercase, lowercase, numbers, and special characters. * @param length - Number of characters to generate (defaults to 32) */ static generate(length?: number): string; } /** * Possible Config parameters for SecureStore constructor */ export interface SecureStoreConfig { /** * A unique ID which is used to prefix data stored in Redis. */ uid: string; /** * A 32 character encryption secret. * Use SecretValidator.generate() to create a cryptographically secure secret. */ secret: string; /** * Redis connection configuration. Accepts one of: * - `RedisOptions`: ioredis connection options (host, port, etc.) * - `{ url: string }`: Redis connection URL * - `{ client: RedisClient }`: An existing Redis or Cluster client instance * * When providing an external client: * - SecureStore will NOT close the client on `disconnect()` - you manage its lifecycle * - The client should be connected or in a connectable state * - Both `Redis` and `Cluster` clients are supported */ redis: RedisOptions | { url: string; } | { client: RedisClient; }; /** * Allow weak secrets (bypass entropy validation). Not recommended for production. * @default false */ allowWeakSecrets?: boolean; /** * Optional time-to-live in milliseconds for the backing Redis hash. * When set, every save() applies PEXPIRE and every get() refreshes it * (sliding expiry). Applies per Redis key, so namespaced (postfix) keys * each carry their own TTL, refreshed by whichever operation touches them. * * The TTL is refreshed only by operations, so an idle store expires even * if the consumer process is alive. Size it as a generous backstop, not * a session timeout. * * When unset (default), keys never expire. */ ttl?: number; } /** * Typed namespace interface for type-safe operations */ export interface TypedNamespace = Record> { get(key: K): Promise; save(key: K, data: TSchema[K]): Promise; delete(key: K): Promise; deleteAll(): Promise; } /** * SecureStore class * * Automatically encrypt any data saved to redis * * @export * @class SecureStore */ export default class SecureStore { /** * Redis client */ client: RedisClient | undefined; private readonly config; private connected; private externalClientProvided; /** * Creates an instance of SecureStore. * * @constructor */ constructor(cfg: SecureStoreConfig); /** * Disconnects the Redis client. * If using an external client (passed via `{ client: RedisClient }`), * this method will NOT close the connection - you manage its lifecycle. */ disconnect(client?: RedisClient | undefined): Promise; /** * Check if connected to Redis */ get isConnected(): boolean; /** * Connects the Redis client to the Redis server. * If using an external client, ensures the client is ready. */ connect(): Promise; /** * Save and encrypt arbitrary data to Redis */ save(key: string, data: T, postfix?: string): Promise; /** * Get and decrypt arbitrary data from Redis */ get(key: string, postfix?: string): Promise; /** * Delete arbitrary data from Redis */ delete(key: string, postfix?: string): Promise; /** * Delete the entire backing Redis hash for this store (all keys saved * without a postfix), or for one namespace when a postfix is given. * Safe to call when nothing was stored. Returns the number of Redis * keys removed (0 or 1). */ deleteAll(postfix?: string): Promise; /** * Encrypts arbitrary data, returning an encrypted string */ private encrypt; /** * Decrypts given encrypted string, returning its arbitrary data */ private decrypt; /** * Create a typed namespace for type-safe operations. * Data is stored with the namespace as a postfix to the uid. */ namespace = Record>(name: string): TypedNamespace; /** * Throw if a multi().exec() call was aborted or any queued command failed */ private static assertExecSucceeded; /** * Generate sha256 sum from given text */ private static shasum; }