@farfarawaylabs/chat-sdk-adapter-d1
v0.2.0
Published
Cloudflare D1 state adapter for Chat SDK
Downloads
62
Maintainers
Readme
@farfarawaylabs/chat-sdk-adapter-d1
Cloudflare D1 state adapter for Chat SDK. Use this when your app runs on Cloudflare Workers and you want state persistence backed by D1 (SQLite at the edge).
Installation
pnpm add @farfarawaylabs/chat-sdk-adapter-d1Usage
Pass your D1 database binding from the Worker environment:
import { Chat } from "chat";
import { createD1State } from "@farfarawaylabs/chat-sdk-adapter-d1";
export default {
async fetch(request: Request, env: Env) {
const bot = new Chat({
userName: "mybot",
adapters: {
/* ... */
},
state: createD1State({ db: env.DB }),
});
// ...
},
};With custom prefix
const state = createD1State({
db: env.DB,
keyPrefix: "my-app",
});Configuration
| Option | Required | Description |
| ----------- | -------- | ----------------------------------------------------------------- |
| db | Yes | Cloudflare D1Database binding |
| keyPrefix | No | Prefix for all state rows (default: "chat-sdk") |
| logger | No | Logger instance (defaults to ConsoleLogger("info").child("d1")) |
Wrangler setup
Add a D1 binding to your wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "chat-state"
database_id = "<your-database-id>"Create the database:
wrangler d1 create chat-stateData model
The adapter creates these tables automatically on connect():
| Table | Purpose |
| -------------------------- | ---------------------------- |
| chat_state_subscriptions | Thread subscription tracking |
| chat_state_locks | Distributed locks with TTL |
| chat_state_cache | Key-value cache with TTL |
| chat_state_lists | Ordered lists with TTL |
All rows are namespaced by key_prefix. Timestamps are stored as integer milliseconds (Unix epoch).
Features
| Feature | Supported | | ------------------------ | -------------- | | Persistence | Yes | | Multi-instance | Yes | | Subscriptions | Yes | | Distributed locking | Yes | | Key-value caching | Yes (with TTL) | | Automatic table creation | Yes | | Key prefix namespacing | Yes |
Locking considerations
D1 is a SQLite-based database. The lock implementation uses a read-then-write approach. Under extreme contention (many workers competing for the same lock simultaneously), this may behave differently than the Redis adapter's atomic SET NX PX. For high-contention distributed locking, prefer the Redis adapter.
Expired row cleanup
D1 does not automatically delete expired rows. The adapter performs opportunistic cleanup — expired cache entries are deleted on the next get() call for that key. For high-throughput deployments, consider running periodic cleanup:
DELETE FROM chat_state_locks WHERE expires_at <= (unixepoch('now') * 1000);
DELETE FROM chat_state_cache WHERE expires_at <= (unixepoch('now') * 1000);
DELETE FROM chat_state_lists WHERE expires_at <= (unixepoch('now') * 1000);License
MIT
