import type { ISecretBackend, TBackendType } from './smartsecret.backends.base.js'; import { MacosKeychainBackend } from './smartsecret.backends.macos.js'; import { LinuxSecretServiceBackend } from './smartsecret.backends.linux.js'; import { FileEncryptedBackend } from './smartsecret.backends.file.js'; export interface ISmartSecretOptions { service?: string; vaultPath?: string; } export class SmartSecret { private service: string; private vaultPath?: string; private backend: ISecretBackend | null = null; constructor(options?: ISmartSecretOptions) { this.service = options?.service ?? 'smartsecret'; this.vaultPath = options?.vaultPath; } private async getBackend(): Promise { if (this.backend) return this.backend; const candidates: ISecretBackend[] = [ new MacosKeychainBackend(this.service), new LinuxSecretServiceBackend(this.service), new FileEncryptedBackend(this.service, this.vaultPath), ]; for (const candidate of candidates) { if (await candidate.isAvailable()) { this.backend = candidate; return this.backend; } } // File backend is always available, so we should never reach here this.backend = candidates[candidates.length - 1]; return this.backend; } async setSecret(account: string, secret: string): Promise { const backend = await this.getBackend(); await backend.setSecret(account, secret); } async getSecret(account: string): Promise { const backend = await this.getBackend(); return backend.getSecret(account); } async deleteSecret(account: string): Promise { const backend = await this.getBackend(); return backend.deleteSecret(account); } async listAccounts(): Promise { const backend = await this.getBackend(); return backend.listAccounts(); } async getBackendType(): Promise { const backend = await this.getBackend(); return backend.backendType; } }