@@ -12,6 +12,7 @@ import type {
1212 ProvisionOrganizationResponse ,
1313} from '@objectstack/spec/cloud' ;
1414import { ProvisionEnvironmentRequestSchema , ProvisionOrganizationRequestSchema } from '@objectstack/spec/cloud' ;
15+ import { TursoPlatformClient } from './turso-platform-client.js' ;
1516
1617/**
1718 * Backend-agnostic physical DB provisioning adapter.
@@ -63,6 +64,66 @@ export class NoopSecretEncryptor implements SecretEncryptor {
6364 }
6465}
6566
67+ /**
68+ * Turso Platform adapter — calls the Turso Platform API to provision a new
69+ * cloud database for each environment, then mints a per-database auth token.
70+ *
71+ * Required env vars: `TURSO_ORG_NAME`, `TURSO_API_TOKEN`.
72+ */
73+ export class TursoEnvironmentDatabaseAdapter implements EnvironmentDatabaseAdapter {
74+ readonly driver : DatabaseDriver = 'turso' ;
75+
76+ private readonly client : TursoPlatformClient ;
77+
78+ constructor ( config : { apiToken : string ; organization : string ; apiBaseUrl ?: string } ) {
79+ this . client = new TursoPlatformClient ( config ) ;
80+ }
81+
82+ async createDatabase ( params : {
83+ environmentId : string ;
84+ databaseName : string ;
85+ region : string ;
86+ storageLimitMb : number ;
87+ } ) : Promise < { databaseUrl : string ; plaintextSecret : string } > {
88+ await this . client . createDatabase ( { name : params . databaseName } ) ;
89+ const { jwt } = await this . client . createDatabaseToken ( params . databaseName , {
90+ authorization : 'full-access' ,
91+ } ) ;
92+ const db = await this . client . getDatabase ( params . databaseName ) ;
93+ return {
94+ databaseUrl : `libsql://${ db . Hostname } ` ,
95+ plaintextSecret : jwt ,
96+ } ;
97+ }
98+ }
99+
100+ /**
101+ * Local SQLite adapter for development environments. Creates one `.db` file
102+ * per environment under `baseDir`, named after the stable `databaseName`
103+ * (e.g. `env-{uuid}.db`) so the file survives slug renames.
104+ */
105+ export class LocalSQLiteEnvironmentDatabaseAdapter implements EnvironmentDatabaseAdapter {
106+ readonly driver : DatabaseDriver = 'sqlite' ;
107+
108+ constructor ( private readonly baseDir : string = '.objectstack/data/environments' ) { }
109+
110+ async createDatabase ( params : {
111+ environmentId : string ;
112+ databaseName : string ;
113+ region : string ;
114+ storageLimitMb : number ;
115+ } ) : Promise < { databaseUrl : string ; plaintextSecret : string } > {
116+ const { mkdirSync } = await import ( 'node:fs' ) ;
117+ const { resolve } = await import ( 'node:path' ) ;
118+ const dbPath = resolve ( this . baseDir , `${ params . databaseName } .db` ) ;
119+ mkdirSync ( this . baseDir , { recursive : true } ) ;
120+ return {
121+ databaseUrl : `file:${ dbPath } ` ,
122+ plaintextSecret : '' ,
123+ } ;
124+ }
125+ }
126+
66127/**
67128 * Mock adapter used by dev/test environments when no real provider is
68129 * configured. Returns stable synthetic URLs / tokens.
@@ -421,3 +482,24 @@ export class EnvironmentProvisioningService {
421482 }
422483 }
423484}
485+
486+ /**
487+ * Build the default adapter list from environment variables.
488+ *
489+ * - `TURSO_ORG_NAME` + `TURSO_API_TOKEN` present → `TursoEnvironmentDatabaseAdapter`
490+ * (provisions real cloud databases via the Turso Platform API).
491+ * - Otherwise → `LocalSQLiteEnvironmentDatabaseAdapter`
492+ * (creates one `.db` file per environment under `.objectstack/data/environments/`).
493+ */
494+ export function createDefaultEnvironmentAdapters (
495+ env : Record < string , string | undefined > = process . env ,
496+ ) : EnvironmentDatabaseAdapter [ ] {
497+ const orgName = env . TURSO_ORG_NAME ;
498+ const apiToken = env . TURSO_API_TOKEN ;
499+
500+ if ( orgName && apiToken ) {
501+ return [ new TursoEnvironmentDatabaseAdapter ( { organization : orgName , apiToken } ) ] ;
502+ }
503+
504+ return [ new LocalSQLiteEnvironmentDatabaseAdapter ( ) ] ;
505+ }
0 commit comments