init claude-code
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import type { SecureStorage, SecureStorageData } from './types.js'
|
||||
|
||||
/**
|
||||
* Creates a fallback storage that tries to use the primary storage first,
|
||||
* and if that fails, falls back to the secondary storage
|
||||
*/
|
||||
export function createFallbackStorage(
|
||||
primary: SecureStorage,
|
||||
secondary: SecureStorage,
|
||||
): SecureStorage {
|
||||
return {
|
||||
name: `${primary.name}-with-${secondary.name}-fallback`,
|
||||
read(): SecureStorageData {
|
||||
const result = primary.read()
|
||||
if (result !== null && result !== undefined) {
|
||||
return result
|
||||
}
|
||||
return secondary.read() || {}
|
||||
},
|
||||
async readAsync(): Promise<SecureStorageData | null> {
|
||||
const result = await primary.readAsync()
|
||||
if (result !== null && result !== undefined) {
|
||||
return result
|
||||
}
|
||||
return (await secondary.readAsync()) || {}
|
||||
},
|
||||
update(data: SecureStorageData): { success: boolean; warning?: string } {
|
||||
// Capture state before update
|
||||
const primaryDataBefore = primary.read()
|
||||
|
||||
const result = primary.update(data)
|
||||
|
||||
if (result.success) {
|
||||
// Delete secondary when migrating to primary for the first time
|
||||
// This preserves credentials when sharing .claude between host and containers
|
||||
// See: https://github.com/anthropics/claude-code/issues/1414
|
||||
if (primaryDataBefore === null) {
|
||||
secondary.delete()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const fallbackResult = secondary.update(data)
|
||||
|
||||
if (fallbackResult.success) {
|
||||
// Primary write failed but primary may still hold an *older* valid
|
||||
// entry. read() prefers primary whenever it returns non-null, so that
|
||||
// stale entry would shadow the fresh data we just wrote to secondary —
|
||||
// e.g. a refresh token the server has already rotated away, causing a
|
||||
// /login loop (#30337). Best-effort delete; if this also fails the
|
||||
// user's keychain is in a bad state we can't fix from here.
|
||||
if (primaryDataBefore !== null) {
|
||||
primary.delete()
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
warning: fallbackResult.warning,
|
||||
}
|
||||
}
|
||||
|
||||
return { success: false }
|
||||
},
|
||||
delete(): boolean {
|
||||
const primarySuccess = primary.delete()
|
||||
const secondarySuccess = secondary.delete()
|
||||
|
||||
return primarySuccess || secondarySuccess
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user