@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_URLis set in the env, the store wraps a Redis client. - Otherwise it uses an in-memory
Mapwith 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.