Skip to content

Drivers

StorageAdapter delegates all persistence to a driver — any object implementing the StorageDriver interface. Pick a built-in driver or write your own.

LocalStorageDriver

Wraps window.localStorage. Browser only.

typescript
import { LocalStorageDriver } from '@logosdx/storage'

const storage = new StorageAdapter<AppStorage>({
    driver: new LocalStorageDriver(),
    prefix: 'myapp'
})

SessionStorageDriver

Wraps window.sessionStorage. Browser only. Data is cleared when the tab or window is closed.

typescript
import { SessionStorageDriver } from '@logosdx/storage'

const storage = new StorageAdapter<AppStorage>({
    driver: new SessionStorageDriver(),
    prefix: 'session'
})

WebStorageDriver

Base class for LocalStorageDriver and SessionStorageDriver. Use it to wrap any Storage-compatible backend:

typescript
import { WebStorageDriver } from '@logosdx/storage'

const driver = new WebStorageDriver(customStorageBackend)

String coercion

Web Storage backends can only store strings. The driver calls String(value) on every write. When using the default structured: false, this is transparent because the adapter JSON-serializes first. However, setting structured: true with a WebStorage driver will silently coerce objects to "[object Object]" — always leave structured: false (the default) for WebStorage backends.

FileSystemDriver

Persists key-value data as a JSON file on disk. Node.js only. Lazy-loads node:fs/promises on the first operation (not on construction).

typescript
import { FileSystemDriver } from '@logosdx/storage'

const storage = new StorageAdapter<AppSettings>({
    driver: new FileSystemDriver('./data/settings.json'),
    prefix: 'app'
})

await storage.set('theme', 'dark')
const theme = await storage.get('theme') // 'dark'

Notes:

  • The file is read on first access and written on every set(), remove(), and clear().
  • If the file does not exist, it starts with an empty store.

IndexedDBDriver

Stores structured cloneable data in IndexedDB. Browser only. Ideal for large datasets and complex objects since IndexedDB natively supports structured cloning.

typescript
import { IndexedDBDriver } from '@logosdx/storage'

const storage = new StorageAdapter<AppData>({
    driver: new IndexedDBDriver('my-app', 'settings'),
    structured: true  // skip JSON serialization -- IndexedDB handles it
})

await storage.set('preferences', { theme: 'dark', fontSize: 14 })

Constructor:

typescript
new IndexedDBDriver(dbName: string, storeName?: string)
  • dbName: IndexedDB database name.
  • storeName: Object store name. Defaults to 'store'.

Notes:

  • The database connection opens lazily on the first operation.
  • The object store is created automatically via onupgradeneeded if it does not already exist.

Custom Drivers

Implement the StorageDriver interface to use any backend. Here is an example using Redis:

typescript
import type { StorageDriver } from '@logosdx/storage'
import Redis from 'ioredis'

export class RedisDriver implements StorageDriver {

    #client: Redis

    constructor(redisUrl: string) {

        this.#client = new Redis(redisUrl)
    }

    async get(key: string) {

        const raw = await this.#client.get(key)
        return raw ?? null
    }

    async set(key: string, value: unknown) {

        await this.#client.set(key, String(value))
    }

    async remove(key: string) {

        await this.#client.del(key)
    }

    async keys() {

        return this.#client.keys('*')
    }

    async clear() {

        const allKeys = await this.keys()

        if (allKeys.length > 0) {

            await this.#client.del(...allKeys)
        }
    }
}

// Usage
const storage = new StorageAdapter<SessionData>({
    driver: new RedisDriver('redis://localhost:6379'),
    prefix: 'sessions'
})