README.md

@cutticat/storages

Key-value storage library with TTL support.

Contents

Overview

The library provides a JsonStorage<T> type (set, get, delete, clear). SchemaJsonStorage is the shared base: it loads a raw entry, optionally runs a Zod schema, and returns T. NullJsonStorage implements the type directly and stores nothing. The other backends extend the base:

  • InMemoryJsonStorage — stores values in memory (any type, no serialization)
  • WebJsonStorage — adapts a browser Storage (localStorage, sessionStorage)
  • FileJsonStorage — stores JSON files on disk (Node.js)
  • RedisJsonStorage — stores JSON in Redis
  • PgJsonStorage — stores JSON in PostgreSQL

All storages support optional time-to-live (TTL) for entries.

Installation

pnpm i @cutticat/storages

Node.js storages require peer dependencies:

pnpm i redis   # for RedisJsonStorage
pnpm i pg      # for PgJsonStorage

FileJsonStorage uses @cutticat/fs-extras (included as a dependency).

Quick start

import { InMemoryJsonStorage } from "@cutticat/storages"

const storage = new InMemoryJsonStorage<string>()
await storage.set("key", "value", 60000)
const value = await storage.get("key")

With Redis and a Zod schema:

import { z } from "zod"
import { createClient } from "redis"
import { RedisJsonStorage } from "@cutticat/storages/node"

const client = createClient({ url: "redis://localhost:6379" })
await client.connect()

const schema = z.object({ id: z.number(), name: z.string() })
const storage = new RedisJsonStorage({
  client,
  prefix: "app:",
  schema,
})

await storage.set("user:1", { id: 1, name: "John" }, 60000)
const user = await storage.get("user:1")

Entry points

  • @cutticat/storages — neutral: JsonStorage, SchemaJsonStorage, InMemoryJsonStorage, NullJsonStorage, isUsableTtl, JsonStorageEntrySchema.
  • @cutticat/storages/node — node: same plus FileJsonStorage, RedisJsonStorage, PgJsonStorage (require redis / pg).
  • @cutticat/storages/browser — browser: same as the neutral entry plus WebJsonStorage.

API

JsonStorage<T>

  • set(key, value, ttl?) — stores a value with optional TTL (ms)
  • get(key) — returns the value or undefined
  • delete(key) — removes an entry
  • clear() — clears the storage

SchemaJsonStorage<T>

Abstract base. A subclass implements set, delete, clear, and _getRaw. get treats undefined from _getRaw as a missing key, then runs an optional Zod schema.

Options:

  • schema — optional Zod schema for validation on read
  • throwOnParseError — when true, throws on invalid data (default false, returns undefined)
  • prepareRaw — turns the raw entry into the value the schema sees (default parses JSON strings)

isUsableTtl

Returns whether a TTL is a finite number greater than zero. A missing TTL and Infinity mean the value stays.

JsonStorageEntrySchema

Envelope { value, expiresAt } written by FileJsonStorage and WebJsonStorage. JsonStorageEntry is the type inferred from the schema.

NullJsonStorage<T>

Empty storage: stores nothing, always returns undefined. Implements JsonStorage directly. For tests and mocks.

InMemoryJsonStorage<T>

In-memory storage. Stores values as-is (no JSON). Suitable for any type. Optional schema and throwOnParseError, same as the base. TTL is a timer: get does not recheck the deadline. The runtime clamps a delay above 2^31−1 ms (about 24.8 days), so a longer TTL can expire immediately.

FileJsonStorage<T>

File system storage (Node.js). Stores each value in a separate JSON file. Uses @cutticat/fs-extras.

Options:

  • rootDir — root directory for files
  • schema — optional Zod schema for validation on read
  • throwOnParseError — when true, throws on invalid data (default false)
  • throwOnReadError — when true, throws on file read errors (default false)
  • now — function to get the current time (default Date.now, useful for tests)
  • keyToPath — function to map a key to a file path (default base64url, useful for tests)

clear deletes rootDir and everything inside it. A file that is not the { value, expiresAt } envelope is removed on read. A value that fails schema stays on disk; get returns undefined.

RedisJsonStorage<T>

Redis storage. Serializes to JSON on write, deserializes on read.

Options:

  • client — Redis client
  • prefix — prefix for all keys (default "", so clear matches every key)
  • schema — optional Zod schema for validation on read
  • throwOnParseError — when true, throws on invalid data (default false, returns undefined)

TTL is milliseconds, sent as SET with expiration type PX. clear runs KEYS for the prefix and deletes the matches. KEYS walks the keyspace.

WebJsonStorage<T>

Adapter over a browser Storage (localStorage, sessionStorage, or the same shape). Each value is a JSON envelope { value, expiresAt }. clear deletes keys that start with the prefix.

Options:

  • storage — browser storage
  • prefix — prefix for all keys (default "", so clear matches every key)
  • schema — optional Zod schema for validation on read
  • throwOnParseError — when true, throws on invalid data (default false, returns undefined)
  • now — function to get the current time (default Date.now, useful for tests)

A value that is not the { value, expiresAt } envelope is removed on read. A value that fails schema stays in storage; get returns undefined.

PgJsonStorage<T>

PostgreSQL storage. Serializes to JSON on write, deserializes on read. Creates the table on first access.

Options:

  • pool — pg connection pool
  • tableName — table name (default cutticat_pg_storage)
  • schema — optional Zod schema for validation on read
  • throwOnParseError — when true, throws on invalid data (default false, returns undefined)
  • now — function to get the current time (default Date.now, useful for tests)

Expiry reads expires_at as a Date, a finite timestamp in milliseconds, or a date string.

Documentation

See also:

Full API documentation is available in JSDoc comments.

Requirements

  • Node.js >= 22.18.0
  • pnpm >= 10.17.0
  • TypeScript >= 5.9.0
  • redis >= 4.7.0 (for RedisJsonStorage)
  • pg >= 8.0.0 (for PgJsonStorage)
Описание
A library with various TTL-enabled key-value stores
Конвейеры
8 успешных
2 с ошибкой
Разработчики