@xec-sh/cli
Version:
Xec: The Universal Shell for TypeScript
133 lines • 4.55 kB
JavaScript
import { EnvSecretProvider } from './providers/env.js';
import { LocalSecretProvider } from './providers/local.js';
import { SecretError } from './types.js';
export class SecretManager {
constructor(config) {
this.initialized = false;
this.config = config || { type: 'local' };
this.provider = this.createProvider();
}
async initialize() {
if (this.initialized)
return;
await this.provider.initialize();
this.initialized = true;
}
async ensureInitialized() {
if (!this.initialized) {
await this.initialize();
}
}
async get(key) {
await this.ensureInitialized();
this.validateKey(key);
try {
return await this.provider.get(key);
}
catch (error) {
throw new SecretError(`Failed to get secret: ${error instanceof Error ? error.message : 'Unknown error'}`, 'GET_ERROR', key);
}
}
async getRequired(key) {
const value = await this.get(key);
if (value === null) {
throw new SecretError(`Required secret '${key}' not found`, 'SECRET_NOT_FOUND', key);
}
return value;
}
async set(key, value) {
await this.ensureInitialized();
this.validateKey(key);
this.validateValue(value);
try {
return await this.provider.set(key, value);
}
catch (error) {
throw new SecretError(`Failed to set secret: ${error instanceof Error ? error.message : 'Unknown error'}`, 'SET_ERROR', key);
}
}
async delete(key) {
await this.ensureInitialized();
this.validateKey(key);
return this.provider.delete(key);
}
async list() {
await this.ensureInitialized();
return this.provider.list();
}
async has(key) {
await this.ensureInitialized();
this.validateKey(key);
return this.provider.has(key);
}
async getMany(keys) {
const results = {};
await Promise.all(keys.map(async (key) => {
results[key] = await this.get(key);
}));
return results;
}
async setMany(secrets) {
await Promise.all(Object.entries(secrets).map(([key, value]) => this.set(key, value)));
}
async deleteMany(keys) {
await Promise.all(keys.map(key => this.delete(key)));
}
async clear() {
const keys = await this.list();
await this.deleteMany(keys);
}
getProviderType() {
return this.config.type;
}
async updateProvider(config) {
this.config = config;
this.provider = this.createProvider();
this.initialized = false;
await this.initialize();
}
createProvider() {
switch (this.config.type) {
case 'local':
return new LocalSecretProvider(this.config.config);
case 'env':
return new EnvSecretProvider(this.config.config);
case 'vault':
case 'aws-secrets':
case '1password':
throw new SecretError(`Provider '${this.config.type}' not yet implemented`, 'PROVIDER_NOT_IMPLEMENTED');
default:
throw new SecretError(`Unknown secret provider type: ${this.config.type}`, 'INVALID_PROVIDER_TYPE');
}
}
validateKey(key) {
if (!key || typeof key !== 'string') {
throw new SecretError('Secret key must be a non-empty string', 'INVALID_KEY');
}
if (!/^[a-zA-Z0-9_\-\.]+$/.test(key)) {
throw new SecretError('Secret key must contain only alphanumeric characters, underscores, dashes, and dots', 'INVALID_KEY_FORMAT', key);
}
if (key.length > 256) {
throw new SecretError('Secret key must be 256 characters or less', 'KEY_TOO_LONG', key);
}
}
validateValue(value) {
if (typeof value !== 'string') {
throw new SecretError('Secret value must be a string', 'INVALID_VALUE');
}
if (value.length === 0) {
throw new SecretError('Secret value cannot be empty', 'EMPTY_VALUE');
}
if (value.length > 64 * 1024) {
throw new SecretError('Secret value must be 64KB or less', 'VALUE_TOO_LARGE');
}
}
}
let defaultManager = null;
export function getDefaultSecretManager(config) {
if (!defaultManager) {
defaultManager = new SecretManager(config);
}
return defaultManager;
}
//# sourceMappingURL=manager.js.map