-
Notifications
You must be signed in to change notification settings - Fork 2
feat(apps/demo): use @objectql/driver-turso instead of memory driver #432
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
Changes from 2 commits
13a5cbf
6f78818
d2c37c5
37016be
f8360c3
138eccd
477a1b2
cd08385
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,8 +2,9 @@ | |
| * Vercel Serverless Function — ObjectQL Demo Handler | ||
| * | ||
| * Bootstraps the ObjectStack kernel with ObjectQL plugins and the | ||
| * project-tracker demo metadata, using @objectstack/driver-memory | ||
| * for zero-config in-memory data. | ||
| * project-tracker demo metadata, using @objectql/driver-turso when | ||
| * TURSO_DATABASE_URL is set, or @objectstack/driver-memory as a | ||
| * zero-config fallback. | ||
| * | ||
| * Uses `getRequestListener()` from `@hono/node-server` together with | ||
| * an `extractBody()` helper to handle Vercel's pre-buffered request | ||
|
|
@@ -14,8 +15,10 @@ | |
| * a fresh `Request` object prevents POST/PUT/PATCH requests (e.g. | ||
| * login) from hanging indefinitely. | ||
| * | ||
| * Data lives in the function instance's memory and persists across | ||
| * warm invocations (Vercel Fluid Compute) but resets on cold start. | ||
| * When using Turso, data is persisted in the Turso cloud database. | ||
| * When using InMemoryDriver, data lives in the function instance's | ||
| * memory and persists across warm invocations (Vercel Fluid Compute) | ||
| * but resets on cold start. | ||
| * | ||
| * Both Console (/) and Studio (/_studio/) UIs are served as static SPAs. | ||
| * | ||
|
|
@@ -30,6 +33,7 @@ import { ObjectKernel, DriverPlugin, AppPlugin, createDispatcherPlugin, createRe | |
| import { HonoHttpServer } from '@objectstack/plugin-hono-server'; | ||
| import { AuthPlugin } from '@objectstack/plugin-auth'; | ||
| import { InMemoryDriver } from '@objectstack/driver-memory'; | ||
| import { createTursoDriver, type TursoDriver } from '@objectql/driver-turso'; | ||
| import { ObjectQLPlugin } from '@objectstack/objectql'; | ||
| import { getRequestListener } from '@hono/node-server'; | ||
| import type { Hono } from 'hono'; | ||
|
|
@@ -278,10 +282,32 @@ async function bootstrap(): Promise<Hono> { | |
| await withTimeout(kernel.use(new ObjectQLPlugin()), PLUGIN_TIMEOUT_MS, 'ObjectQLPlugin'); | ||
| log('ObjectQLPlugin registered.'); | ||
|
|
||
| // 2. In-memory data driver (no external DB required) | ||
| log('Registering DriverPlugin (InMemoryDriver)…'); | ||
| await withTimeout(kernel.use(new DriverPlugin(new InMemoryDriver(), 'memory')), PLUGIN_TIMEOUT_MS, 'DriverPlugin'); | ||
| log('DriverPlugin registered.'); | ||
| // 2. Data driver — Turso when TURSO_DATABASE_URL is set, InMemoryDriver otherwise | ||
| const tursoUrl = process.env.TURSO_DATABASE_URL; | ||
| let tursoDriver: TursoDriver | null = null; | ||
| if (tursoUrl) { | ||
| log(`Registering TursoDriver (${tursoUrl})…`); | ||
| const syncUrl = process.env.TURSO_SYNC_URL; | ||
| tursoDriver = createTursoDriver({ | ||
| url: tursoUrl, | ||
| authToken: process.env.TURSO_AUTH_TOKEN, | ||
| syncUrl, | ||
| sync: syncUrl | ||
| ? { | ||
| intervalSeconds: Number(process.env.TURSO_SYNC_INTERVAL) || 60, | ||
| onConnect: true, | ||
| } | ||
| : undefined, | ||
|
Comment on lines
+301
to
+306
|
||
| }); | ||
| // DriverPlugin from @objectstack/runtime expects the upstream Driver interface; | ||
| // TursoDriver implements @objectql/types Driver which is structurally compatible. | ||
| await withTimeout(kernel.use(new DriverPlugin(tursoDriver as any, 'turso')), PLUGIN_TIMEOUT_MS, 'DriverPlugin-turso'); | ||
| log('TursoDriver registered.'); | ||
|
||
| } else { | ||
| log('Registering DriverPlugin (InMemoryDriver)…'); | ||
| await withTimeout(kernel.use(new DriverPlugin(new InMemoryDriver(), 'memory')), PLUGIN_TIMEOUT_MS, 'DriverPlugin-memory'); | ||
| log('InMemoryDriver registered.'); | ||
| } | ||
|
|
||
| // 3. HTTP server adapter — register the Hono app without TCP listener | ||
| const httpServer = new HonoHttpServer(); | ||
|
|
@@ -445,7 +471,14 @@ async function bootstrap(): Promise<Hono> { | |
| log('Studio SPA registered.'); | ||
| } | ||
|
|
||
| // 12. Bootstrap kernel (init + start all plugins, fire kernel:ready) | ||
| // 12. Connect Turso driver (if applicable) before kernel bootstrap | ||
| if (tursoDriver) { | ||
| log('Connecting TursoDriver…'); | ||
| await withTimeout(tursoDriver.connect(), PLUGIN_TIMEOUT_MS, 'TursoDriver.connect()'); | ||
| log('TursoDriver connected.'); | ||
| } | ||
|
|
||
| // 13. Bootstrap kernel (init + start all plugins, fire kernel:ready) | ||
| log('Running kernel.bootstrap()…'); | ||
| await withTimeout(kernel.bootstrap(), KERNEL_BOOTSTRAP_TIMEOUT_MS, 'kernel.bootstrap()'); | ||
| log(`Bootstrap complete in ${elapsed()}.`); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,8 +1,9 @@ | ||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||
| * ObjectQL Demo — Application Configuration | ||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||
| * Minimal ObjectStack configuration for the demo application. | ||||||||||||||||||||||||||||||||||||||||||
| * Uses in-memory driver with the project-tracker showcase example. | ||||||||||||||||||||||||||||||||||||||||||
| * ObjectStack configuration for the demo application. | ||||||||||||||||||||||||||||||||||||||||||
| * Uses @objectql/driver-turso when TURSO_DATABASE_URL is set, | ||||||||||||||||||||||||||||||||||||||||||
| * falls back to MemoryDriver for zero-config local development. | ||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||
| * For local development: `pnpm dev` (uses @objectstack/cli) | ||||||||||||||||||||||||||||||||||||||||||
| * For Vercel deployment: configured via api/[[...route]].ts | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -29,10 +30,33 @@ import { FormulaPlugin } from '@objectql/plugin-formula'; | |||||||||||||||||||||||||||||||||||||||||
| import { ObjectQLSecurityPlugin } from '@objectql/plugin-security'; | ||||||||||||||||||||||||||||||||||||||||||
| import { createApiRegistryPlugin } from '@objectstack/core'; | ||||||||||||||||||||||||||||||||||||||||||
| import { MemoryDriver } from '@objectql/driver-memory'; | ||||||||||||||||||||||||||||||||||||||||||
| import { createTursoDriver } from '@objectql/driver-turso'; | ||||||||||||||||||||||||||||||||||||||||||
| import { createAppPlugin } from '@objectql/platform-node'; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // In-memory driver — zero-config, no external DB required. | ||||||||||||||||||||||||||||||||||||||||||
| const defaultDriver = new MemoryDriver(); | ||||||||||||||||||||||||||||||||||||||||||
| // Choose driver based on environment — Turso when TURSO_DATABASE_URL is set, | ||||||||||||||||||||||||||||||||||||||||||
| // MemoryDriver otherwise (zero-config fallback for quick starts). | ||||||||||||||||||||||||||||||||||||||||||
| function createDefaultDriver() { | ||||||||||||||||||||||||||||||||||||||||||
| const tursoUrl = process.env.TURSO_DATABASE_URL; | ||||||||||||||||||||||||||||||||||||||||||
| if (tursoUrl) { | ||||||||||||||||||||||||||||||||||||||||||
| console.log(`🗄️ Driver: Turso (${tursoUrl})`); | ||||||||||||||||||||||||||||||||||||||||||
| const syncUrl = process.env.TURSO_SYNC_URL; | ||||||||||||||||||||||||||||||||||||||||||
| return createTursoDriver({ | ||||||||||||||||||||||||||||||||||||||||||
| url: tursoUrl, | ||||||||||||||||||||||||||||||||||||||||||
| authToken: process.env.TURSO_AUTH_TOKEN, | ||||||||||||||||||||||||||||||||||||||||||
| syncUrl, | ||||||||||||||||||||||||||||||||||||||||||
| sync: syncUrl | ||||||||||||||||||||||||||||||||||||||||||
| ? { | ||||||||||||||||||||||||||||||||||||||||||
| intervalSeconds: Number(process.env.TURSO_SYNC_INTERVAL) || 60, | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| return createTursoDriver({ | |
| url: tursoUrl, | |
| authToken: process.env.TURSO_AUTH_TOKEN, | |
| syncUrl, | |
| sync: syncUrl | |
| ? { | |
| intervalSeconds: Number(process.env.TURSO_SYNC_INTERVAL) || 60, | |
| const rawSyncInterval = process.env.TURSO_SYNC_INTERVAL; | |
| const parsedSyncInterval = | |
| rawSyncInterval !== undefined ? Number(rawSyncInterval) : NaN; | |
| const syncIntervalSeconds = Number.isFinite(parsedSyncInterval) | |
| ? parsedSyncInterval | |
| : 60; | |
| return createTursoDriver({ | |
| url: tursoUrl, | |
| authToken: process.env.TURSO_AUTH_TOKEN, | |
| syncUrl, | |
| sync: syncUrl | |
| ? { | |
| intervalSeconds: syncIntervalSeconds, |
Copilot
AI
Mar 21, 2026
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.
The start hook uses (defaultDriver as any) and a runtime typeof ...connect check, but both MemoryDriver and TursoDriver expose async connect(). Prefer typing defaultDriver against a shared interface/type and calling await defaultDriver.connect() directly to avoid any and keep this type-safe.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
The architecture diagram now shows
TursoDriverunconditionally, but this demo still falls back to the in-memory driver whenTURSO_DATABASE_URLis not set. Update the diagram to reflect the conditional driver choice (e.g., “TursoDriver / InMemoryDriver”) to keep the docs consistent with the behavior described above.