Built-in Storage

MemoryStorage

Best for development, single-process, or stateless deployments.

import { MemoryStorage } from '@carloscortezcloud/sayay-guard';

const storage = new MemoryStorage();
// Data is lost on restart

KVStorage (Cloudflare KV)

Works across Workers in production. Eventually consistent.

import { KVStorage } from '@carloscortezcloud/sayay-guard';

const storage = new KVStorage(env.BUDGET_KV);
// Keys: budget:{userId}:{date}

Custom Storage

Implement the SayayStorage interface for any backend:

interface SayayStorage {
  getSpend(userId: string): Promise<{ daily: number; monthly: number; session: number }>;
  addSpend(userId: string, costUsd: number): Promise<void>;
}

Redis Example

import { createClient } from 'redis';

class RedisStorage implements SayayStorage {
  private client;

  constructor() {
    this.client = createClient({ url: process.env.REDIS_URL });
  }

  async getSpend(userId: string) {
    const today = new Date().toISOString().slice(0, 10);
    const daily = await this.client.get(`budget:${userId}:daily:${today}`) || '0';
    const monthly = await this.client.get(`budget:${userId}:monthly`) || '0';
    return {
      daily: Number(daily),
      monthly: Number(monthly),
      session: 0,
    };
  }

  async addSpend(userId: string, costUsd: number) {
    const today = new Date().toISOString().slice(0, 10);
    await this.client.incrByFloat(`budget:${userId}:daily:${today}`, costUsd);
    await this.client.incrByFloat(`budget:${userId}:monthly`, costUsd);
  }
}

D1 (Cloudflare)

class D1Storage implements SayayStorage {
  constructor(private db: D1Database) {}

  async getSpend(userId: string) {
    const today = new Date().toISOString().slice(0, 10);
    const row = await this.db.prepare(
      `SELECT daily, monthly FROM budgets WHERE user_id = ? AND date = ?`
    ).bind(userId, today).first();
    return {
      daily: row?.daily || 0,
      monthly: row?.monthly || 0,
      session: 0,
    };
  }

  async addSpend(userId: string, costUsd: number) { /* similar */ }
}

Python Storage

The Python SDK ships three built-in storages. All use the same key scheme (sayay:{user}:daily:{date}).

from sayay import SayayGuard, MemoryStorage, FileStorage

# In-memory — best for dev / single-process
guard = SayayGuard(storage=MemoryStorage(), budget={"dailyUsd": 5.0})

# File — JSON on disk, survives restarts
guard = SayayGuard(storage=FileStorage("budgets.json"), budget={"dailyUsd": 5.0})

RedisStorage

Requires the optional extra — pip install "sayay[redis]":

from sayay import SayayGuard, RedisStorage

guard = SayayGuard(
    storage=RedisStorage(host="localhost", port=6379),
    budget={"dailyUsd": 5.0},
)

The redis client is lazily imported, so you get a helpful error message if the extra isn’t installed.