Skip to content

Commit 5de419e

Browse files
fix issues (#136)
* fix: prevent delete button click when card is not swiped open * refactor: improve CreateRepoInput type safety * security: require AUTH_SECRET and use secure random generation * fix: SSH key path validation, async passphrase stripping, and port handling * fix: use correct console methods for logger levels * Add error handling to DB update functions and improve migration logging * Add error handling for session lookup in auth middleware * Add structured git error handling with user-friendly messages - Parse git errors with specific error codes (AUTH_FAILED, REPO_NOT_FOUND, PUSH_REJECTED, MERGE_CONFLICT, etc.) and appropriate HTTP status codes - Return structured error responses with summary and detail from backend - Add GitErrorBanner component for better error display in UI - Add optional onError callback to useGit hook for external error handling * Make IPC server initialization/disposal async and fix SSH host key handler * add try-catch error handling in frontend lib utilities * remove unresolved promise handlers in speech synthesizer callbacks * Extract error types to shared package * Import GitErrorCode from shared package * Refactor API layer to use shared FetchError and fetchWrapper * Update prompt parser and source control components * Extract MCP server list to separate component with improved badge menu UX * merge useSettingsDialogUrl into useSettingsDialog and extract getRepoDisplayName utility * add separate loading state for passkey sign in * refactor hooks: use fetchWrapper, improve error handling, add proper types * replace browser confirm() with DeleteDialog component in settings * fix: add missing variables parameter in React Query onError callbacks * Refactor message parts to use separate Zustand store * Update QuestionPrompt styling for light/dark mode
1 parent 7f7d106 commit 5de419e

75 files changed

Lines changed: 1965 additions & 1342 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/src/auth/middleware.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ export function createAuthMiddleware(auth: AuthInstance) {
1818
logger.debug(`Cookie names: ${cookieNames}`)
1919
}
2020

21-
const session = await auth.api.getSession({
22-
headers: c.req.raw.headers,
23-
})
21+
let session
22+
try {
23+
session = await auth.api.getSession({
24+
headers: c.req.raw.headers,
25+
})
26+
} catch (error) {
27+
logger.error('Session lookup failed', { error })
28+
return c.json({ error: 'Internal Server Error' }, 500)
29+
}
2430

2531
logger.debug(`Session result: ${session ? 'found' : 'not found'}`)
2632

@@ -69,9 +75,15 @@ export function createAdminMiddleware(auth: AuthInstance) {
6975
user: Session['user']
7076
}
7177
}>(async (c, next) => {
72-
const session = await auth.api.getSession({
73-
headers: c.req.raw.headers,
74-
})
78+
let session
79+
try {
80+
session = await auth.api.getSession({
81+
headers: c.req.raw.headers,
82+
})
83+
} catch (error) {
84+
logger.error('Session lookup failed', { error })
85+
return c.json({ error: 'Internal Server Error' }, 500)
86+
}
7587

7688
if (!session) {
7789
return c.json({ error: 'Unauthorized' }, 401)

backend/src/db/migrations.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export function runMigrations(db: Database): void {
6666
WHERE branch IS NOT NULL
6767
`)
6868
} catch (error) {
69-
logger.debug('Index already exists or could not be created', error)
69+
logger.warn('Index already exists or could not be created', error)
7070
}
7171

7272
try {
@@ -75,7 +75,7 @@ export function runMigrations(db: Database): void {
7575
ON repos(local_path)
7676
`)
7777
} catch (error) {
78-
logger.debug('Local path index already exists or could not be created', error)
78+
logger.warn('Local path index already exists or could not be created', error)
7979
}
8080

8181
const requiredColumns = [
@@ -111,7 +111,7 @@ export function runMigrations(db: Database): void {
111111
try {
112112
db.run(indexSql)
113113
} catch (error) {
114-
logger.debug('Index already exists:', error)
114+
logger.warn('Index already exists:', error)
115115
}
116116
}
117117

backend/src/db/queries.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function createRepo(db: Database, repo: CreateRepoInput): Repo {
4040

4141
const existing = repo.isLocal
4242
? getRepoByLocalPath(db, normalizedPath)
43-
: getRepoByUrlAndBranch(db, repo.repoUrl!, repo.branch)
43+
: getRepoByUrlAndBranch(db, repo.repoUrl, repo.branch)
4444

4545
if (existing) {
4646
return existing
@@ -73,7 +73,7 @@ export function createRepo(db: Database, repo: CreateRepoInput): Repo {
7373
if (errorMessage.includes('UNIQUE constraint failed') || (error && typeof error === 'object' && 'code' in error && error.code === 'SQLITE_CONSTRAINT_UNIQUE')) {
7474
const conflictRepo = repo.isLocal
7575
? getRepoByLocalPath(db, normalizedPath)
76-
: getRepoByUrlAndBranch(db, repo.repoUrl!, repo.branch)
76+
: getRepoByUrlAndBranch(db, repo.repoUrl, repo.branch)
7777

7878
if (conflictRepo) {
7979
return conflictRepo
@@ -158,22 +158,34 @@ function getRepoName(repo: Repo): string {
158158

159159
export function updateRepoStatus(db: Database, id: number, cloneStatus: Repo['cloneStatus']): void {
160160
const stmt = db.prepare('UPDATE repos SET clone_status = ? WHERE id = ?')
161-
stmt.run(cloneStatus, id)
161+
const result = stmt.run(cloneStatus, id)
162+
if (result.changes === 0) {
163+
throw new Error(`Repository with id ${id} not found`)
164+
}
162165
}
163166

164167
export function updateRepoConfigName(db: Database, id: number, configName: string): void {
165168
const stmt = db.prepare('UPDATE repos SET opencode_config_name = ? WHERE id = ?')
166-
stmt.run(configName, id)
169+
const result = stmt.run(configName, id)
170+
if (result.changes === 0) {
171+
throw new Error(`Repository with id ${id} not found`)
172+
}
167173
}
168174

169175
export function updateLastPulled(db: Database, id: number): void {
170176
const stmt = db.prepare('UPDATE repos SET last_pulled = ? WHERE id = ?')
171-
stmt.run(Date.now(), id)
177+
const result = stmt.run(Date.now(), id)
178+
if (result.changes === 0) {
179+
throw new Error(`Repository with id ${id} not found`)
180+
}
172181
}
173182

174183
export function updateRepoBranch(db: Database, id: number, branch: string): void {
175184
const stmt = db.prepare('UPDATE repos SET branch = ? WHERE id = ?')
176-
stmt.run(branch, id)
185+
const result = stmt.run(branch, id)
186+
if (result.changes === 0) {
187+
throw new Error(`Repository with id ${id} not found`)
188+
}
177189
}
178190

179191
export function deleteRepo(db: Database, id: number): void {

backend/src/db/transactions.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

backend/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ try {
189189
settingsService.initializeLastKnownGoodConfig()
190190

191191
ipcServer = await createIPCServer(process.env.STORAGE_PATH || undefined)
192-
gitAuthService.initialize(ipcServer, db)
192+
await gitAuthService.initialize(ipcServer, db)
193193
logger.info(`Git IPC server running at ${ipcServer.ipcHandlePath}`)
194194

195195
opencodeServerManager.setDatabase(db)
@@ -340,7 +340,7 @@ const shutdown = async (signal: string) => {
340340
sseAggregator.shutdown()
341341
logger.info('SSE Aggregator stopped')
342342
if (ipcServer) {
343-
ipcServer.dispose()
343+
await ipcServer.dispose()
344344
logger.info('Git IPC server stopped')
345345
}
346346
await opencodeServerManager.stop()

backend/src/ipc/ipcServer.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ export class IPCServer {
7777
})
7878
}
7979

80-
dispose(): void {
81-
this.server.close()
80+
dispose(): Promise<void> {
81+
return new Promise((resolve) => {
82+
this.server.close(() => resolve())
83+
})
8284
}
8385
}
8486

backend/src/ipc/passphraseHandler.ts

Lines changed: 0 additions & 54 deletions
This file was deleted.

backend/src/ipc/sshHostKeyHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ export class SSHHostKeyHandler implements IPCHandler {
119119
const result = await executeCommand(
120120
['ssh-keyscan', '-t', 'ed25519,rsa,ecdsa', ...portArgs, host],
121121
{ silent: true, ignoreExitCode: true }
122-
)
123-
const output = (result as unknown as { stdout: string }).stdout
122+
) as string | { exitCode: number; stdout: string; stderr: string }
123+
const output = typeof result === 'string' ? result : result.stdout
124124
const bracketedHost = port && port !== '22' ? `[${host}]:${port}` : host
125125
const lines = output.trim().split('\n')
126126
for (const line of lines) {

0 commit comments

Comments
 (0)