From d7e22c23c4b7fa75a039f94dc79466a5742336cd Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 30 Apr 2026 11:50:58 +0200 Subject: [PATCH] Fix config read crash when database connection is a string The readDatabaseConfig function would crash when trying to read sub-keys of backend.database.connection when the value is a plain string (e.g. ':memory:' for better-sqlite3). Guard by checking the raw value type before attempting to read structured connection keys. Signed-off-by: Patrik Oldsberg Made-with: Cursor --- .../src/lib/runner/runBackend.test.ts | 13 ++++++++++++- .../cli-module-build/src/lib/runner/runBackend.ts | 7 +++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/cli-module-build/src/lib/runner/runBackend.test.ts b/packages/cli-module-build/src/lib/runner/runBackend.test.ts index 1bf2ef1568..0cf2b6bd4c 100644 --- a/packages/cli-module-build/src/lib/runner/runBackend.test.ts +++ b/packages/cli-module-build/src/lib/runner/runBackend.test.ts @@ -87,6 +87,7 @@ describe('runBackend', () => { mockToConfig.mockResolvedValue({ close: jest.fn(), + getOptional: () => undefined, getOptionalString: () => undefined, getOptionalNumber: () => undefined, }); @@ -184,6 +185,7 @@ describe('runBackend', () => { it('should start embedded DB and inject all defaults when no user connection config is provided', async () => { mockToConfig.mockResolvedValue({ close: jest.fn(), + getOptional: () => undefined, getOptionalString: (key: string) => key === 'backend.database.client' ? 'embedded-postgres' : undefined, getOptionalNumber: () => undefined, @@ -232,6 +234,7 @@ describe('runBackend', () => { }; mockToConfig.mockResolvedValue({ close: jest.fn(), + getOptional: () => ({ host: '0.0.0.0', port: 15432 }), getOptionalString: (key: string) => { const val = configValues[key]; return typeof val === 'string' ? val : undefined; @@ -288,6 +291,12 @@ describe('runBackend', () => { }; mockToConfig.mockResolvedValue({ close: jest.fn(), + getOptional: () => ({ + host: '0.0.0.0', + port: 15432, + user: 'myuser', + password: 'mypass', + }), getOptionalString: (key: string) => { const val = configValues[key]; return typeof val === 'string' ? val : undefined; @@ -328,6 +337,7 @@ describe('runBackend', () => { it('should resolve config paths relative to targetDir', async () => { mockToConfig.mockResolvedValue({ close: jest.fn(), + getOptional: () => undefined, getOptionalString: () => undefined, getOptionalNumber: () => undefined, }); @@ -346,9 +356,10 @@ describe('runBackend', () => { ); }); - it('should not start embedded DB for other database clients', async () => { + it('should not start embedded DB for other database clients with a string connection', async () => { mockToConfig.mockResolvedValue({ close: jest.fn(), + getOptional: () => ':memory:', getOptionalString: (key: string) => key === 'backend.database.client' ? 'better-sqlite3' : undefined, getOptionalNumber: () => undefined, diff --git a/packages/cli-module-build/src/lib/runner/runBackend.ts b/packages/cli-module-build/src/lib/runner/runBackend.ts index 1046235d35..9e872fed38 100644 --- a/packages/cli-module-build/src/lib/runner/runBackend.ts +++ b/packages/cli-module-build/src/lib/runner/runBackend.ts @@ -252,6 +252,13 @@ async function readDatabaseConfig( return undefined; } + // Only read structured connection config if the value is an object; + // it can also be a plain string (e.g. ':memory:' for better-sqlite3). + const rawConnection = config.getOptional('backend.database.connection'); + if (typeof rawConnection === 'string' || rawConnection === undefined) { + return { client }; + } + const host = config.getOptionalString('backend.database.connection.host'); const port = config.getOptionalNumber('backend.database.connection.port'); const user = config.getOptionalString('backend.database.connection.user');