Skip to content

@doable/shared

Cross-cutting types, constants, and the KV-store abstraction. Lives at packages/shared/.

What's inside

Module Purpose
constants.ts Plan limits, model lists, default colors, etc.
kv-store.ts Auto-switching KV store: in-memory ↔ Redis
ai/ Shared AI types reused across api/web
types/ Cross-package types (project, workspace, role, …)

KV store

import { getKV } from "@doable/shared/kv-store";

const kv = getKV();
await kv.set("rate:user-42", "1", { ttlSeconds: 60 });
const v = await kv.get("rate:user-42");
await kv.incr("counter:logins");
  • If REDIS_URL is set in the env, the store wraps a Redis client.
  • Otherwise it uses an in-memory Map with TTL eviction.
  • The interface is identical — your code doesn't change.

This is what makes the documented "no Redis required" claim true: middleware (rate-limiting, presence cache, OAuth state) all use this abstraction.

When to add to shared

Add a type here when two or more workspaces in the monorepo need it. If only the API uses it, keep it in services/api. If only the frontend uses it, keep it in apps/web/src/lib.

See also