Skip to content

Commit b9f9229

Browse files
authored
Merge pull request #316 from objectstack-ai/copilot/update-data-driver-to-turso
2 parents 6f32df6 + cd1144f commit b9f9229

6 files changed

Lines changed: 741 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Changed
11+
- **Vercel deployment — switched from InMemoryDriver to TursoDriver** — The Vercel serverless
12+
handler (`api/[[...route]].ts`) now uses `@objectstack/driver-turso` (TursoDriver) instead of
13+
`@objectstack/driver-memory` (InMemoryDriver). In production, set `TURSO_DATABASE_URL` and
14+
`TURSO_AUTH_TOKEN` environment variables to connect to a Turso cloud database for persistent
15+
data across cold starts. Without those variables, falls back to `:memory:` (ephemeral SQLite,
16+
same behavior as before). Added `@objectstack/driver-turso@^3.3.0` to devDependencies and
17+
updated `vercel.json` `includeFiles` to bundle the Turso driver and its dependencies.
1118
- **Upgrade all dependencies recursively** — Ran `pnpm upgrade -r` across the monorepo.
1219
- `@objectstack/*` packages upgraded from `^3.2.8` to `^3.3.0` (spec, cli, runtime, objectql, driver-memory, plugin-auth, plugin-hono-server, service-i18n, studio)
1320
- `@object-ui/console` upgraded from `^3.1.3` to `^3.1.4`

api/[[...route]].ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Vercel Serverless Function — ObjectStack Hono Handler
33
*
44
* Bootstraps the full ObjectStack kernel with all HotCRM plugins,
5-
* using @objectstack/driver-memory for zero-config in-memory data.
5+
* using @objectstack/driver-turso for persistent data (Turso cloud) or :memory: fallback.
66
*
77
* Uses `getRequestListener()` from `@hono/node-server` together with an
88
* `extractBody()` helper to handle Vercel's pre-buffered request body.
@@ -12,8 +12,8 @@
1212
* `rawBody` / `body` directly and constructing a fresh `Request` object
1313
* prevents POST/PUT/PATCH requests (e.g. login) from hanging indefinitely.
1414
*
15-
* Data lives in the function instance's memory and persists across
16-
* warm invocations (Vercel Fluid Compute) but resets on cold start.
15+
* When TURSO_DATABASE_URL is set, data persists in a Turso cloud database
16+
* across cold starts. Without it, falls back to :memory: (ephemeral, same as old InMemoryDriver).
1717
*
1818
* Both Console (/) and Studio (/_studio/) UIs are served as static SPAs.
1919
*
@@ -28,7 +28,7 @@ import { ObjectKernel, DriverPlugin, AppPlugin, createDispatcherPlugin, createRe
2828
import { HonoHttpServer } from '@objectstack/plugin-hono-server';
2929
import { AuthPlugin } from '@objectstack/plugin-auth';
3030
import { I18nServicePlugin } from '@objectstack/service-i18n';
31-
import { InMemoryDriver } from '@objectstack/driver-memory';
31+
import { TursoDriver } from '@objectstack/driver-turso';
3232
import { ObjectQLPlugin } from '@objectstack/objectql';
3333
import { getRequestListener } from '@hono/node-server';
3434
import type { Hono } from 'hono';
@@ -342,9 +342,17 @@ async function bootstrap(): Promise<Hono> {
342342
await withTimeout(kernel.use(new ObjectQLPlugin()), PLUGIN_TIMEOUT_MS, 'ObjectQLPlugin');
343343
log('ObjectQLPlugin registered.');
344344

345-
// 2. In-memory data driver (no external DB required)
346-
log('Registering DriverPlugin (InMemoryDriver)…');
347-
await withTimeout(kernel.use(new DriverPlugin(new InMemoryDriver(), 'memory')), PLUGIN_TIMEOUT_MS, 'DriverPlugin');
345+
// 2. Turso/libSQL data driver (persistent across cold starts)
346+
//
347+
// In production (Vercel), reads TURSO_DATABASE_URL and TURSO_AUTH_TOKEN
348+
// environment variables for remote mode (libsql:// cloud database).
349+
// For local development without those variables, falls back to :memory:
350+
// (ephemeral SQLite — same behaviour as the old InMemoryDriver).
351+
log('Registering DriverPlugin (TursoDriver)…');
352+
await withTimeout(kernel.use(new DriverPlugin(new TursoDriver({
353+
url: process.env.TURSO_DATABASE_URL ?? ':memory:',
354+
...(process.env.TURSO_AUTH_TOKEN && { authToken: process.env.TURSO_AUTH_TOKEN }),
355+
}), 'turso')), PLUGIN_TIMEOUT_MS, 'DriverPlugin');
348356
log('DriverPlugin registered.');
349357

350358
// 3. HTTP server adapter — register the Hono app without TCP listener

docs/DEPLOYMENT.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,15 @@ kubectl logs -n hotcrm <pod-name> --previous
171171

172172
## Vercel Deployment (Serverless Mode)
173173

174-
HotCRM can be deployed to **Vercel** as a serverless application using **Hono + Memory Driver** mode.
175-
In this mode the full ObjectStack kernel runs server-side inside a Vercel Serverless Function — no external
176-
database or Redis required. All data is stored in the function instance's memory.
174+
HotCRM can be deployed to **Vercel** as a serverless application using **Hono + Turso Driver** mode.
175+
In this mode the full ObjectStack kernel runs server-side inside a Vercel Serverless Function. When
176+
`TURSO_DATABASE_URL` is set, data persists in a Turso cloud database across cold starts. Without it,
177+
the driver falls back to `:memory:` (ephemeral SQLite, same behaviour as the old InMemoryDriver).
177178

178179
### How It Works
179180

180181
1. A catch-all Vercel Serverless Function (`api/[[...route]].ts`) bootstraps the ObjectStack kernel on first request.
181-
2. `@objectstack/driver-memory` provides an in-memory data store — zero external infrastructure needed.
182+
2. `@objectstack/driver-turso` provides a persistent Turso/libSQL data store. When `TURSO_DATABASE_URL` is set, data persists across cold starts; otherwise falls back to `:memory:`.
182183
3. `HonoHttpServer` from `@objectstack/plugin-hono-server` handles HTTP routing (without TCP listener).
183184
4. `createRestApiPlugin()` auto-generates CRUD endpoints for all 65+ business objects.
184185
5. The kernel instance is reused across warm invocations (Vercel Fluid Compute).
@@ -197,7 +198,7 @@ Vercel Serverless Function
197198
│ ├── 6 Business Plugins │
198199
│ ├── Console UI (/console/) │
199200
│ ├── Studio UI (/_studio/) │
200-
│ └── InMemoryDriver (data store)
201+
│ └── TursoDriver (Turso cloud / :memory:)
201202
│ ↓ │
202203
│ Response │
203204
└──────────────────────────────────────────┘
@@ -213,6 +214,8 @@ Vercel Serverless Function
213214
| Variable | Required | Default | Description |
214215
|----------|----------|---------|-------------|
215216
| `AUTH_SECRET` | **Yes** (production) | Dev fallback | Secret key used by the Auth Plugin (`@objectstack/plugin-auth`) for signing sessions and tokens. In production, set a strong random value (e.g. `openssl rand -base64 32`). A development fallback is used when not set. |
217+
| `TURSO_DATABASE_URL` | No (recommended for prod) | `:memory:` | Turso database URL (e.g. `libsql://my-db-orgname.turso.io`). When set, data persists across cold starts. |
218+
| `TURSO_AUTH_TOKEN` | When using remote URL || JWT auth token for the Turso database. Required when `TURSO_DATABASE_URL` points to a remote Turso cloud database. |
216219

217220
### Quick Start
218221

@@ -289,7 +292,7 @@ Build pipeline:
289292
| `buildCommand` | `bash scripts/build-vercel.sh` | Runs the Vercel build script that builds core, patches console plugin, then compiles all business plugins |
290293
| `functions.memory` | `1024` MB | Memory allocated to the serverless function |
291294
| `functions.maxDuration` | `60` s | Maximum execution time per request (Pro plan) |
292-
| `functions.includeFiles` | `{packages/*/dist,node_modules/@object-ui/console/dist,node_modules/@objectstack/plugin-auth/dist,node_modules/@objectstack/studio/dist}/**` | Bundles business plugin dist/, Auth plugin, and Console/Studio SPA assets with the function |
295+
| `functions.includeFiles` | `{packages/*/dist,node_modules/@object-ui/console/dist,node_modules/@objectstack/*/dist,node_modules/@libsql,node_modules/better-sqlite3,node_modules/@opentelemetry/api}/**` | Bundles business plugin dist/, all @objectstack packages (including Auth, Studio, TursoDriver), libSQL/better-sqlite3 native deps, and OpenTelemetry with the function |
293296
| `rewrites` | `/(.*) → /api/[[...route]]` | Routes all requests to the catch-all handler |
294297

295298
### Architecture Details
@@ -309,14 +312,13 @@ a `HonoHttpServer`, registers it as the `http.server` service, and uses the `han
309312

310313
### Data Behavior
311314

312-
- Data lives in the function instance's process memory
313-
- Warm invocations **share data** — records created in one request are visible in the next
314-
- After ~5–15 minutes of inactivity, Vercel recycles the instance (cold start) and data resets
315-
- For persistent data, see [Docker Deployment](#docker-deployment) or configure an external database
315+
- **With `TURSO_DATABASE_URL`** (production recommended): data persists in a Turso cloud database across cold starts and instance recycling.
316+
- **Without `TURSO_DATABASE_URL`** (local dev / demo): falls back to `:memory:` (ephemeral SQLite) — records persist only while the function instance is warm; data resets on cold start.
317+
- Warm invocations **share data** — records created in one request are visible in the next.
316318

317319
### Limitations
318320

319-
- **Data is ephemeral** — records persist only while the function instance is warm; data resets on cold start.
321+
- **Data is ephemeral without Turso**without `TURSO_DATABASE_URL`, records persist only while the function instance is warm; data resets on cold start. Set `TURSO_DATABASE_URL` + `TURSO_AUTH_TOKEN` for persistent production data.
320322
- **No authentication** — this mode does not enforce permissions or user sessions out of the box.
321323
- **No WebSocket** — Vercel Serverless Functions do not support persistent connections.
322324
- **Cold start latency** — the first request after idle may take 2–5 seconds for kernel bootstrap.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"@object-ui/console": "^3.1.4",
6363
"@objectstack/cli": "^3.3.0",
6464
"@objectstack/driver-memory": "^3.3.0",
65+
"@objectstack/driver-turso": "^3.3.0",
6566
"@objectstack/objectql": "^3.3.0",
6667
"@objectstack/plugin-auth": "^3.3.0",
6768
"@objectstack/plugin-hono-server": "^3.3.0",

0 commit comments

Comments
 (0)