mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
Some credentials cannot be configured, only obtained: getting one means a conversation — open this page, paste that code, pick an account. The new seam owns that conversation and the one-attempt-per-key lifecycle, and never the protocol, so a second authorization protocol arrives as another flow rather than as another seam. A flow is registered under the CredentialKey it writes, which is also how the seam knows which plugin answers for the format inside that record. The flow owns the write: run() resolving means the record is already committed through ctx.credentials, and the seam confirms it. That keeps a library persisting through its own store adapter the single writer instead of being copied back out and written twice. The interaction travels with the request rather than a registry, because whoever starts an authorization is the one who can talk to the human about it. A request already withdrawn never claims the key and never starts the flow — relying on each flow to check its signal before the first await would let one that does not hang holding the key.
68 lines
2.2 KiB
TypeScript
68 lines
2.2 KiB
TypeScript
import { CredentialProvider } from '@deepseek-ai/dsh-credentials'
|
|
import type {
|
|
CredentialInfo,
|
|
CredentialKey,
|
|
CredentialRecord,
|
|
CredentialRecordEntry,
|
|
CredentialRecordInfo,
|
|
CredentialRef,
|
|
ResolvedCredential,
|
|
} from '@deepseek-ai/dsh-credentials'
|
|
|
|
/**
|
|
* In-memory credentials provider for the authorization suite. Only the record
|
|
* half is exercised — the seam's whole interest in this service is whether a
|
|
* flow left a record behind — so the reference half answers "nothing stored".
|
|
*/
|
|
export class MemoryCredentials extends CredentialProvider {
|
|
private readonly records = new Map<CredentialKey, CredentialRecord>()
|
|
|
|
override resolve(_ref: CredentialRef): Promise<ResolvedCredential | undefined> {
|
|
return Promise.resolve(undefined)
|
|
}
|
|
|
|
override describe(_ref: CredentialRef): Promise<CredentialInfo> {
|
|
return Promise.resolve({ configured: false, writable: true })
|
|
}
|
|
|
|
override set(_ref: CredentialRef, _value: string): Promise<void> {
|
|
return Promise.resolve()
|
|
}
|
|
|
|
override unset(_ref: CredentialRef): Promise<void> {
|
|
return Promise.resolve()
|
|
}
|
|
|
|
override readRecord(key: CredentialKey): Promise<CredentialRecord | undefined> {
|
|
return Promise.resolve(this.records.get(key))
|
|
}
|
|
|
|
override describeRecord(key: CredentialKey): Promise<CredentialRecordInfo> {
|
|
const stored = this.records.get(key)
|
|
return Promise.resolve(stored === undefined
|
|
? { configured: false, writable: true }
|
|
: { configured: true, kind: stored.kind, writable: true })
|
|
}
|
|
|
|
override listRecords(): Promise<readonly CredentialRecordEntry[]> {
|
|
return Promise.resolve([...this.records].map(([key, record]) => ({ key, kind: record.kind })))
|
|
}
|
|
|
|
override async modifyRecord(
|
|
key: CredentialKey,
|
|
mutate: (current: CredentialRecord | undefined) => Promise<CredentialRecord | undefined>,
|
|
): Promise<CredentialRecord | undefined> {
|
|
const current = this.records.get(key)
|
|
const next = await mutate(current)
|
|
if (next === undefined) return current
|
|
this.records.set(key, next)
|
|
this.ctx.emit('credentials/record-updated', key)
|
|
return next
|
|
}
|
|
|
|
override deleteRecord(key: CredentialKey): Promise<void> {
|
|
if (this.records.delete(key)) this.ctx.emit('credentials/record-updated', key)
|
|
return Promise.resolve()
|
|
}
|
|
}
|