mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-26 02:04:37 +08:00
fix(ai): clean up old auth profile when rename + key change shifts profile name
When a model service is renamed and its API key changed simultaneously, onApiKeyCreated derives a new profile name from the new service name and writes a new auth profile, but the old profile (keyed by the old name) was never deleted, leaving an orphaned credential on disk. Capture the old authProfile before applying updates. If onApiKeyCreated returns a different profile name, call onApiKeyDeleted on the old config to trigger cleanup before persisting the new profile. No cleanup is needed for key-only updates (profile name unchanged) or name-only updates (onApiKeyCreated is not called). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
04680fc840
commit
46066d7a5f
2 files changed
+47
-1
No files matched your search
@@ -200,6 +200,46 @@ describe('LLMConfigStore', () => {
|
||||
assert.equal(storeWithHook.getAllConfigs().length, 0, 'config should be removed')
|
||||
})
|
||||
|
||||
it('calls onApiKeyDeleted for old profile when rename + key change causes profile name to change', () => {
|
||||
const deleted: string[] = []
|
||||
const storeWithHook = new LLMConfigStore(storage, {
|
||||
generateId: () => `id-${++idCounter}`,
|
||||
onApiKeyCreated: (config, apiKey) => {
|
||||
const name = config.name.toLowerCase().replace(/\s+/g, '-')
|
||||
;(config as unknown as Record<string, unknown>).authProfile = name
|
||||
return name
|
||||
},
|
||||
onApiKeyDeleted: (config) => {
|
||||
const profile = (config as unknown as Record<string, unknown>).authProfile as string | undefined
|
||||
if (profile) deleted.push(profile)
|
||||
},
|
||||
})
|
||||
storeWithHook.addConfig({ name: 'My OpenAI', provider: 'openai', apiKey: 'sk-old' })
|
||||
const id = storeWithHook.getAllConfigs()[0].id
|
||||
storeWithHook.updateConfig(id, { name: 'Work OpenAI', apiKey: 'sk-new' })
|
||||
assert.deepEqual(deleted, ['my-openai'], 'old profile should be cleaned up when profile name changes')
|
||||
})
|
||||
|
||||
it('does not call onApiKeyDeleted when key changes but profile name stays the same', () => {
|
||||
const deleted: string[] = []
|
||||
const storeWithHook = new LLMConfigStore(storage, {
|
||||
generateId: () => `id-${++idCounter}`,
|
||||
onApiKeyCreated: (config, apiKey) => {
|
||||
const name = config.name.toLowerCase().replace(/\s+/g, '-')
|
||||
;(config as unknown as Record<string, unknown>).authProfile = name
|
||||
return name
|
||||
},
|
||||
onApiKeyDeleted: (config) => {
|
||||
const profile = (config as unknown as Record<string, unknown>).authProfile as string | undefined
|
||||
if (profile) deleted.push(profile)
|
||||
},
|
||||
})
|
||||
storeWithHook.addConfig({ name: 'My OpenAI', provider: 'openai', apiKey: 'sk-old' })
|
||||
const id = storeWithHook.getAllConfigs()[0].id
|
||||
storeWithHook.updateConfig(id, { apiKey: 'sk-new' })
|
||||
assert.deepEqual(deleted, [], 'no cleanup needed when profile name is unchanged')
|
||||
})
|
||||
|
||||
it('resolves correct key for same-provider configs with different authProfiles', () => {
|
||||
const profiles = new Map<string, string>()
|
||||
const storeWithAuth = new LLMConfigStore(storage, {
|
||||
|
||||
@@ -211,8 +211,11 @@ export class LLMConfigStore {
|
||||
return { success: false, error: this.t('llm.configNotFound') }
|
||||
}
|
||||
|
||||
const oldConfig = store.configs[index]
|
||||
const oldProfileName = (oldConfig as unknown as Record<string, unknown>).authProfile as string | undefined
|
||||
|
||||
const updated = {
|
||||
...store.configs[index],
|
||||
...oldConfig,
|
||||
...updates,
|
||||
updatedAt: Date.now(),
|
||||
}
|
||||
@@ -221,6 +224,9 @@ export class LLMConfigStore {
|
||||
if (updates.apiKey && this.onApiKeyCreated) {
|
||||
const profileName = this.onApiKeyCreated(updated, updates.apiKey)
|
||||
if (profileName) {
|
||||
if (oldProfileName && oldProfileName !== profileName) {
|
||||
this.onApiKeyDeleted?.(oldConfig)
|
||||
}
|
||||
;(store.configs[index] as unknown as Record<string, unknown>).authProfile = profileName
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user