Skip to content

Commit 2a1bde7

Browse files
feat(cli): startup banner shows resolved storage driver and DB URL
The 'Server is ready' banner now includes a 'Driver:' line that prints the auto-resolved storage driver (e.g. MongoDBDriver, SqlDriver(pg)) along with the connection credentials are redacted to user:****@hostURL to make it safe for log capture. Useful when verifying that OS_DATABASE_URL was picked up correctly and the URL-scheme inference selected the intended driver. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 404fb51 commit 2a1bde7

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

packages/cli/src/commands/serve.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,19 @@ export default class Serve extends Command {
138138
};
139139
const trackPlugin = (name: string) => { loadedPlugins.push(shortPluginName(name)); };
140140

141+
// Track resolved storage driver + redacted URL for the startup banner.
142+
let resolvedDriverLabel: string | undefined;
143+
let resolvedDatabaseUrl: string | undefined;
144+
const redactDbUrl = (url: string | undefined): string | undefined => {
145+
if (!url) return undefined;
146+
try {
147+
// Redact passwords inside connection URLs: protocol://user:****@host/db
148+
return url.replace(/(\/\/[^/@:]+):[^/@]+@/, '$1:****@');
149+
} catch {
150+
return url;
151+
}
152+
};
153+
141154
// Save original console/stdout methods — we'll suppress noise during boot
142155
const originalConsoleLog = console.log;
143156
const originalConsoleDebug = console.debug;
@@ -299,6 +312,8 @@ export default class Serve extends Command {
299312
url: databaseUrl ?? 'mongodb://localhost:27017/objectstack',
300313
}) as any));
301314
trackPlugin('MongoDBDriver');
315+
resolvedDriverLabel = 'MongoDBDriver';
316+
resolvedDatabaseUrl = databaseUrl ?? 'mongodb://localhost:27017/objectstack';
302317
} else if (driverType === 'sqlite' || driverType === 'sql') {
303318
const { SqlDriver } = await import('@objectstack/driver-sql');
304319
const filePath = (databaseUrl ?? ':memory:').replace(/^file:/, '').replace(/^sqlite:/, '').replace(/^sql:\/\//, '');
@@ -308,6 +323,8 @@ export default class Serve extends Command {
308323
useNullAsDefault: true,
309324
}) as any));
310325
trackPlugin('SqlDriver');
326+
resolvedDriverLabel = 'SqlDriver(sqlite)';
327+
resolvedDatabaseUrl = databaseUrl ?? ':memory:';
311328
} else if (driverType === 'postgres' || driverType === 'postgresql' || driverType === 'pg') {
312329
const { SqlDriver } = await import('@objectstack/driver-sql');
313330
await kernel.use(new DriverPlugin(new SqlDriver({
@@ -316,6 +333,8 @@ export default class Serve extends Command {
316333
pool: { min: 0, max: 5 },
317334
}) as any));
318335
trackPlugin('PostgresDriver');
336+
resolvedDriverLabel = 'SqlDriver(pg)';
337+
resolvedDatabaseUrl = databaseUrl;
319338
} else if (driverType === 'mysql' || driverType === 'mysql2') {
320339
const { SqlDriver } = await import('@objectstack/driver-sql');
321340
await kernel.use(new DriverPlugin(new SqlDriver({
@@ -324,18 +343,24 @@ export default class Serve extends Command {
324343
pool: { min: 0, max: 5 },
325344
}) as any));
326345
trackPlugin('MySQLDriver');
346+
resolvedDriverLabel = 'SqlDriver(mysql2)';
347+
resolvedDatabaseUrl = databaseUrl;
327348
} else if (driverType === 'turso' || driverType === 'libsql') {
328349
const { TursoDriver } = await import('@objectstack/driver-turso');
329350
await kernel.use(new DriverPlugin(new TursoDriver({
330351
url: databaseUrl ?? 'file:./local.db',
331352
authToken: process.env.OS_DATABASE_AUTH_TOKEN,
332353
} as any) as any));
333354
trackPlugin('TursoDriver');
355+
resolvedDriverLabel = 'TursoDriver';
356+
resolvedDatabaseUrl = databaseUrl ?? 'file:./local.db';
334357
} else if (isDev) {
335358
// Default in dev: in-memory driver
336359
const { InMemoryDriver } = await import('@objectstack/driver-memory');
337360
await kernel.use(new DriverPlugin(new InMemoryDriver()));
338361
trackPlugin('MemoryDriver');
362+
resolvedDriverLabel = 'InMemoryDriver';
363+
resolvedDatabaseUrl = '(in-memory)';
339364
}
340365
} catch (e: any) {
341366
// silent
@@ -708,6 +733,8 @@ export default class Serve extends Command {
708733
studioPath: STUDIO_PATH,
709734
accountPath: ACCOUNT_PATH,
710735
dashboardPath: loadedPlugins.includes('DashboardUI') ? DASHBOARD_PATH : undefined,
736+
driverLabel: resolvedDriverLabel,
737+
databaseUrl: redactDbUrl(resolvedDatabaseUrl),
711738
});
712739

713740
// Kernel already registers SIGINT/SIGTERM handlers during bootstrap.

packages/cli/src/utils/format.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ export interface ServerReadyOptions {
187187
studioPath?: string;
188188
accountPath?: string;
189189
dashboardPath?: string;
190+
/** Resolved storage driver display name (e.g. "MongoDBDriver", "SqlDriver(pg)"). */
191+
driverLabel?: string;
192+
/** Resolved DB URL with credentials redacted. */
193+
databaseUrl?: string;
190194
}
191195

192196
export function printServerReady(opts: ServerReadyOptions) {
@@ -207,6 +211,10 @@ export function printServerReady(opts: ServerReadyOptions) {
207211
console.log('');
208212
console.log(chalk.dim(` Config: ${opts.configFile}`));
209213
console.log(chalk.dim(` Mode: ${opts.isDev ? 'development' : 'production'}`));
214+
if (opts.driverLabel) {
215+
const dbInfo = opts.databaseUrl ? `${opts.driverLabel} ${chalk.dim('→')} ${opts.databaseUrl}` : opts.driverLabel;
216+
console.log(chalk.dim(` Driver: ${dbInfo}`));
217+
}
210218
console.log(chalk.dim(` Plugins: ${opts.pluginCount} loaded`));
211219
if (opts.pluginNames && opts.pluginNames.length > 0) {
212220
console.log(chalk.dim(` ${opts.pluginNames.join(', ')}`));

0 commit comments

Comments
 (0)