3232/** Engines the shared sqlite step-down (`resolveSqliteDriver`) can produce. */
3333export type SqliteFamilyEngine = 'better-sqlite3' | 'sqlite-wasm' | 'memory' ;
3434
35+ /**
36+ * Thrown by {@link createStorageDriver} when a driver kind is *recognized* but the
37+ * open-core CLI cannot construct it — currently `turso`/libSQL, which ships in the
38+ * ObjectStack cloud / enterprise distribution (`@objectstack/driver-turso`, an
39+ * extension of SqlDriver over `@libsql/client`), composed by the cloud runtime's
40+ * own kernel factory, not by open-core's auto driver-registration.
41+ *
42+ * The whole point of surfacing this as a *typed* error is so `serve.ts` can fail
43+ * LOUDLY (fatal) instead of letting the selection fall through to the SQLite
44+ * default. That silent fall-through is the same "declared ≠ enforced" bug as
45+ * #3276 (the CLI advertised `memory`/`turso` but had no dispatch branch, so both
46+ * silently became SQLite-in-memory).
47+ */
48+ export class UnsupportedDriverError extends Error {
49+ readonly driverType : string ;
50+ constructor ( driverType : string , message : string ) {
51+ super ( message ) ;
52+ this . name = 'UnsupportedDriverError' ;
53+ this . driverType = driverType ;
54+ }
55+ }
56+
3557/**
3658 * Infer a canonical driver kind from an `OS_DATABASE_URL` scheme.
3759 * Returns `''` when the URL is absent or its scheme is unrecognized (the caller
@@ -43,6 +65,11 @@ export function inferDriverTypeFromUrl(url: string | undefined): string {
4365 if ( / ^ m o n g o d b ( \+ s r v ) ? : \/ \/ / i. test ( u ) ) return 'mongodb' ;
4466 if ( / ^ p o s t g r e s ( q l ) ? : \/ \/ / i. test ( u ) ) return 'postgres' ;
4567 if ( / ^ m y s q l 2 ? : \/ \/ / i. test ( u ) ) return 'mysql' ;
68+ // libSQL / Turso URLs are DELIBERATELY still classified as `turso` (not left
69+ // unrecognized). Open-core can't construct that driver, but classifying it
70+ // lets createStorageDriver fail LOUDLY with a clear cloud/EE message — if we
71+ // returned '' here instead, a `libsql://` URL would fall through to the SQLite
72+ // default and silently ignore the remote connection (the very bug we're fixing).
4673 if ( / ^ l i b s q l : \/ \/ / i. test ( u ) ) return 'turso' ;
4774 if ( / ^ h t t p s ? : \/ \/ / i. test ( u ) && / \. t u r s o \. / i. test ( u ) ) return 'turso' ;
4875 if ( / ^ w a s m - s q l i t e : \/ \/ / i. test ( u ) || / \. w a s m \. d b $ / i. test ( u ) ) return 'sqlite-wasm' ;
@@ -101,6 +128,10 @@ export interface StorageDriverResolution {
101128 * nothing matches and we are NOT in dev (production with an unknown/absent
102129 * driver registers no driver, matching the prior inline behavior).
103130 *
131+ * Throws {@link UnsupportedDriverError} for `turso`/libSQL — a cloud/EE driver the
132+ * open-core CLI cannot construct. serve.ts surfaces that as a fatal, actionable
133+ * boot error so the selection never silently degrades to SQLite.
134+ *
104135 * @see {@link resolveDriverType }
105136 */
106137export async function createStorageDriver (
@@ -207,6 +238,27 @@ export async function createStorageDriver(
207238 } ;
208239 }
209240
241+ // turso / libSQL: recognized but NOT constructible by the open-core CLI. The
242+ // driver (`@objectstack/driver-turso`) ships in the cloud / enterprise
243+ // distribution and is composed by the cloud runtime's own kernel factory —
244+ // runtime/standalone-stack.ts explicitly stopped consuming its auth token, and
245+ // its config schema lives in the cloud package so it never pollutes open-core
246+ // `@objectstack/spec`. Fail LOUDLY here rather than let the selection fall
247+ // through to the SQLite default (the reported "declared ≠ enforced" bug):
248+ // serve.ts turns this typed error into a fatal, actionable boot message.
249+ if ( driverType === 'turso' || driverType === 'libsql' ) {
250+ throw new UnsupportedDriverError (
251+ 'turso' ,
252+ 'The `turso`/libSQL driver ships with the ObjectStack cloud / enterprise '
253+ + 'distribution (@objectstack/driver-turso), not the open-core CLI. To use '
254+ + "it, register it explicitly in your stack config (a datasource with driver: "
255+ + "'turso' and config { url, authToken }, with @objectstack/driver-turso "
256+ + 'installed), or run under the cloud distribution. Otherwise select an '
257+ + 'open-core driver via OS_DATABASE_DRIVER / OS_DATABASE_URL: '
258+ + 'sqlite | postgres | mysql | mongodb | memory.' ,
259+ ) ;
260+ }
261+
210262 // #3276: explicit in-memory (mingo) driver. Honored in dev AND production — an
211263 // operator asking for `memory` gets the mingo InMemoryDriver (ephemeral, not
212264 // real SQL), never the SQLite `:memory:` default. This is the branch whose
0 commit comments