-
Notifications
You must be signed in to change notification settings - Fork 197
feat(state-libsql): libSQL state supported in vercel integrations/tursocloud #406
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@chat-adapter/state-libsql": minor | ||
| --- | ||
|
|
||
| Add `@chat-adapter/state-libsql`: libSQL / Turso state adapter backed by `@libsql/client`. Supports both local SQLite files (`file:`) and remote libSQL / Turso servers (`libsql:`/`http(s):`/`ws(s):`) with the same API. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # @chat-adapter/state-libsql |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| # @chat-adapter/state-libsql | ||
|
|
||
| [](https://www.npmjs.com/package/@chat-adapter/state-libsql) | ||
| [](https://www.npmjs.com/package/@chat-adapter/state-libsql) | ||
|
|
||
| libSQL / Turso state adapter for [Chat SDK](https://chat-sdk.dev). Ships two variants — import the one that matches your runtime. | ||
|
|
||
| | Import path | Driver | Best for | | ||
| |---|---|---| | ||
| | `@chat-adapter/state-libsql` | [`libsql`](https://www.npmjs.com/package/libsql) (native binding) | Node. Fast local file access, also supports remote libSQL / Turso. | | ||
| | `@chat-adapter/state-libsql/client` | [`@libsql/client`](https://www.npmjs.com/package/@libsql/client) (pure JS) | Edge / serverless (Vercel) where native modules aren't available. | | ||
|
|
||
| Both entry points expose the same chat-sdk `StateAdapter` surface with `createLibSqlState` and `LibSqlStateAdapter`. | ||
|
|
||
| ## Installation | ||
|
|
||
| Install the package plus **one** of the two drivers: | ||
|
|
||
| ```bash | ||
| # Node / local-file primary | ||
| pnpm add @chat-adapter/state-libsql libsql | ||
|
|
||
| # edge / Turso-primary | ||
| pnpm add @chat-adapter/state-libsql @libsql/client | ||
| ``` | ||
|
|
||
| Both drivers are declared `optional` peer dependencies — pnpm / npm won't complain if you only install one. | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Node + local file | ||
|
|
||
| ```typescript | ||
| import { Chat } from "chat"; | ||
| import { createLibSqlState } from "@chat-adapter/state-libsql"; | ||
|
|
||
| const bot = new Chat({ | ||
| userName: "mybot", | ||
| adapters: { /* ... */ }, | ||
| state: createLibSqlState({ url: "file:./chat-state.db" }), | ||
| }); | ||
| ``` | ||
|
|
||
| ### Edge / serverless + Turso | ||
|
|
||
| ```typescript | ||
| import { createLibSqlState } from "@chat-adapter/state-libsql/client"; | ||
|
|
||
| const state = createLibSqlState({ | ||
| url: "libsql://your-db.turso.io", | ||
| authToken: process.env.TURSO_AUTH_TOKEN, | ||
| }); | ||
| ``` | ||
|
|
||
| ### Auto-detect via env vars | ||
|
|
||
| Both variants read `TURSO_DATABASE_URL` and `TURSO_AUTH_TOKEN` if no options are provided: | ||
|
|
||
| ```typescript | ||
| const state = createLibSqlState(); // uses TURSO_DATABASE_URL / TURSO_AUTH_TOKEN | ||
| ``` | ||
|
|
||
| ### Injecting your own client | ||
|
|
||
| Native: | ||
|
|
||
| ```typescript | ||
| import Database from "libsql/promise"; | ||
| import { createLibSqlState } from "@chat-adapter/state-libsql"; | ||
|
|
||
| const db = new Database("file:./chat-state.db", {}); | ||
| const state = createLibSqlState({ client: db }); | ||
| ``` | ||
|
|
||
| `@libsql/client`: | ||
|
|
||
| ```typescript | ||
| import { createClient } from "@libsql/client"; | ||
| import { createLibSqlState } from "@chat-adapter/state-libsql/client"; | ||
|
|
||
| const client = createClient({ | ||
| url: process.env.TURSO_DATABASE_URL!, | ||
| authToken: process.env.TURSO_AUTH_TOKEN, | ||
| }); | ||
| const state = createLibSqlState({ client }); | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| Both entry points accept the same core options: | ||
|
|
||
| | Option | Required | Description | | ||
| |--------|----------|-------------| | ||
| | `url` | No* | libSQL connection URL / path | | ||
| | `authToken` | No | Auth token for remote libSQL / Turso | | ||
| | `client` | No | Existing driver client instance | | ||
| | `keyPrefix` | No | Prefix for all state rows (default: `"chat-sdk"`) | | ||
| | `logger` | No | Logger instance (defaults to `ConsoleLogger("info").child("libsql")`) | | ||
|
|
||
| *Either `url`, the `TURSO_DATABASE_URL` env var, or `client` is required. | ||
|
|
||
| The default entry additionally accepts `syncUrl`, `syncPeriod`, `encryptionKey`, `offline`, `timeout`. | ||
| The `/client` entry additionally accepts a `config` pass-through for `@libsql/client` (`encryptionKey`, `syncUrl`, `intMode`, `tls`, …). | ||
|
|
||
| ### URL schemes | ||
|
|
||
| | Scheme | Default (`libsql`) | `/client` (`@libsql/client`) | | ||
| |--------|:------------------:|:----------------------------:| | ||
| | `file:...` | ✅ | ✅ | | ||
| | `:memory:` | ✅ | — | | ||
| | `libsql:...` | ✅ | ✅ | | ||
| | `http(s)://...` | ✅ | ✅ | | ||
| | `ws(s)://...` | — | ✅ | | ||
|
|
||
| Always prefix local paths with `file:` — both drivers accept it, and it keeps your config portable if you later switch entry points. | ||
|
|
||
| ## Environment variables | ||
|
|
||
| ```bash | ||
| # Local file (works with both entries) | ||
| TURSO_DATABASE_URL=file:./chat-state.db | ||
|
|
||
| # or remote libSQL / Turso | ||
| TURSO_DATABASE_URL=libsql://your-db.turso.io | ||
| TURSO_AUTH_TOKEN=your-token | ||
| ``` | ||
|
|
||
| ## Data model | ||
|
|
||
| The adapter creates these tables automatically on `connect()`: | ||
|
|
||
| ``` | ||
| chat_state_subscriptions | ||
| chat_state_locks | ||
| chat_state_cache | ||
| chat_state_lists | ||
| chat_state_queues | ||
| ``` | ||
|
|
||
| All rows are namespaced by `key_prefix`. Timestamps are stored as millisecond integers. | ||
|
|
||
| ## Features | ||
|
|
||
| | Feature | Supported | | ||
| |---------|-----------| | ||
| | Persistence | Yes | | ||
| | Multi-instance | Yes (remote mode) | | ||
| | Subscriptions | Yes | | ||
| | Distributed locking | Yes | | ||
| | Key-value caching | Yes (with TTL) | | ||
| | Message queue | Yes | | ||
| | Ordered lists | Yes | | ||
| | Automatic table creation | Yes | | ||
| | Key prefix namespacing | Yes | | ||
|
|
||
| ## Locking considerations | ||
|
|
||
| Lock acquisition runs inside a write transaction that clears any expired lock and then performs `INSERT ... ON CONFLICT DO NOTHING RETURNING`. This gives atomic compare-and-set semantics against both local SQLite files and remote libSQL / Turso servers. | ||
|
|
||
| For multi-instance deployments, use a remote libSQL / Turso URL — a local file database only coordinates processes on the same host. | ||
|
|
||
| ## Expired row cleanup | ||
|
|
||
| SQLite does not expire rows automatically. The adapter performs opportunistic cleanup on every relevant operation (`get`, `getList`, `dequeue`, lock acquisition). For long-running deployments you may want to run a periodic cleanup: | ||
|
|
||
| ```sql | ||
| DELETE FROM chat_state_locks WHERE expires_at <= strftime('%s','now') * 1000; | ||
| DELETE FROM chat_state_cache WHERE expires_at IS NOT NULL AND expires_at <= strftime('%s','now') * 1000; | ||
| DELETE FROM chat_state_queues WHERE expires_at <= strftime('%s','now') * 1000; | ||
| DELETE FROM chat_state_lists WHERE expires_at IS NOT NULL AND expires_at <= strftime('%s','now') * 1000; | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| MIT |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| { | ||
| "name": "@chat-adapter/state-libsql", | ||
| "version": "0.0.0", | ||
| "description": "libSQL / Turso state adapter for chat (local file or remote)", | ||
| "type": "module", | ||
| "main": "./dist/index.js", | ||
| "module": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "sideEffects": false, | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.js" | ||
| }, | ||
| "./client": { | ||
| "types": "./dist/client.d.ts", | ||
| "import": "./dist/client.js" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "test": "vitest run --coverage", | ||
| "test:watch": "vitest", | ||
| "typecheck": "tsc --noEmit", | ||
| "clean": "rm -rf dist" | ||
| }, | ||
| "dependencies": { | ||
| "chat": "workspace:*" | ||
| }, | ||
| "peerDependencies": { | ||
| "@libsql/client": ">=0.15.0", | ||
| "libsql": ">=0.5.0" | ||
| }, | ||
| "peerDependenciesMeta": { | ||
| "@libsql/client": { | ||
| "optional": true | ||
| }, | ||
| "libsql": { | ||
| "optional": true | ||
| } | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/vercel/chat.git", | ||
| "directory": "packages/state-libsql" | ||
| }, | ||
| "homepage": "https://github.com/vercel/chat#readme", | ||
| "bugs": { | ||
| "url": "https://github.com/vercel/chat/issues" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "devDependencies": { | ||
| "@libsql/client": "^0.15.15", | ||
| "@types/node": "^25.3.2", | ||
| "@vitest/coverage-v8": "^4.0.18", | ||
| "libsql": "^0.5.29", | ||
| "tsup": "^8.3.5", | ||
| "typescript": "^5.7.2", | ||
| "vitest": "^4.0.18" | ||
| }, | ||
| "keywords": [ | ||
| "chat", | ||
| "state", | ||
| "libsql", | ||
| "turso", | ||
| "sqlite" | ||
| ], | ||
| "license": "MIT" | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing
"libsql/promise"and"@chat-adapter/state-libsql/client"inVALID_PACKAGE_README_IMPORTScauses test failure for state-libsql README validation.