const require_chunk = require('./chunk-CUT6urMc.cjs');
const node_fs = require_chunk.__toESM(require("node:fs"));
const node_path = require_chunk.__toESM(require("node:path"));
const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
const node_os = require_chunk.__toESM(require("node:os"));
const node_crypto = require_chunk.__toESM(require("node:crypto"));

//#region src/secrets/keystore.ts
/** Key length for AES-256 encryption */
const KEY_LENGTH = 32;
/**
* Get the keystore directory for a project.
* Keys are stored at ~/.gkm/{project-name}/
*
* @param projectName - Name of the project (defaults to current directory name)
* @returns Path to the keystore directory
*/
function getKeystoreDir(projectName) {
	const name = projectName ?? (0, node_path.basename)(process.cwd());
	return (0, node_path.join)((0, node_os.homedir)(), ".gkm", name);
}
/**
* Get the path to a stage's encryption key.
*
* @param stage - Stage name (e.g., 'development', 'production')
* @param projectName - Name of the project (defaults to current directory name)
* @returns Path to the key file
*/
function getKeyPath(stage, projectName) {
	return (0, node_path.join)(getKeystoreDir(projectName), `${stage}.key`);
}
/**
* Generate a new encryption key for a stage.
* The key is stored at ~/.gkm/{project-name}/{stage}.key with restricted permissions.
*
* @param stage - Stage name
* @param projectName - Project name (defaults to current directory name)
* @returns The generated key as a hex string
*/
async function generateKey(stage, projectName) {
	const keyDir = getKeystoreDir(projectName);
	const keyPath = getKeyPath(stage, projectName);
	await (0, node_fs_promises.mkdir)(keyDir, {
		recursive: true,
		mode: 448
	});
	const key = (0, node_crypto.randomBytes)(KEY_LENGTH).toString("hex");
	await (0, node_fs_promises.writeFile)(keyPath, key, {
		mode: 384,
		encoding: "utf-8"
	});
	await (0, node_fs_promises.chmod)(keyPath, 384);
	return key;
}
/**
* Read an encryption key for a stage.
*
* @param stage - Stage name
* @param projectName - Project name (defaults to current directory name)
* @returns The key as a hex string, or null if not found
*/
async function readKey(stage, projectName) {
	const keyPath = getKeyPath(stage, projectName);
	if (!(0, node_fs.existsSync)(keyPath)) return null;
	const key = await (0, node_fs_promises.readFile)(keyPath, "utf-8");
	return key.trim();
}
/**
* Get or create a key for a stage.
* If the key already exists, it is returned. Otherwise, a new key is generated.
*
* @param stage - Stage name
* @param projectName - Project name (defaults to current directory name)
* @returns The key as a hex string
*/
async function getOrCreateKey(stage, projectName) {
	const existingKey = await readKey(stage, projectName);
	if (existingKey) return existingKey;
	return generateKey(stage, projectName);
}

//#endregion
//#region src/secrets/storage.ts
/** Default secrets directory relative to project root */
const SECRETS_DIR = ".gkm/secrets";
/** AES-256-GCM configuration */
const ALGORITHM = "aes-256-gcm";
const IV_LENGTH = 12;
const AUTH_TAG_LENGTH = 16;
/**
* Get the secrets directory path.
*/
function getSecretsDir(cwd = process.cwd()) {
	return (0, node_path.join)(cwd, SECRETS_DIR);
}
/**
* Get the secrets file path for a stage.
*/
function getSecretsPath(stage, cwd = process.cwd()) {
	return (0, node_path.join)(getSecretsDir(cwd), `${stage}.json`);
}
/**
* Check if secrets exist for a stage.
*/
function secretsExist(stage, cwd = process.cwd()) {
	return (0, node_fs.existsSync)(getSecretsPath(stage, cwd));
}
/**
* Initialize an empty StageSecrets object for a stage.
*/
function initStageSecrets(stage) {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	return {
		stage,
		createdAt: now,
		updatedAt: now,
		services: {},
		urls: {},
		custom: {}
	};
}
/**
* Encrypt secrets using a key.
*/
function encryptSecretsData(secrets, keyHex) {
	const key = Buffer.from(keyHex, "hex");
	const iv = (0, node_crypto.randomBytes)(IV_LENGTH);
	const plaintext = JSON.stringify(secrets);
	const cipher = (0, node_crypto.createCipheriv)(ALGORITHM, key, iv);
	const ciphertext = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
	const authTag = cipher.getAuthTag();
	const combined = Buffer.concat([ciphertext, authTag]);
	return {
		version: 1,
		encrypted: combined.toString("base64"),
		iv: iv.toString("hex")
	};
}
/**
* Decrypt secrets using a key.
*/
function decryptSecretsData(data, keyHex) {
	const key = Buffer.from(keyHex, "hex");
	const ivBuffer = Buffer.from(data.iv, "hex");
	const combined = Buffer.from(data.encrypted, "base64");
	const ciphertext = combined.subarray(0, -AUTH_TAG_LENGTH);
	const authTag = combined.subarray(-AUTH_TAG_LENGTH);
	const decipher = (0, node_crypto.createDecipheriv)(ALGORITHM, key, ivBuffer);
	decipher.setAuthTag(authTag);
	const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
	return JSON.parse(plaintext.toString("utf-8"));
}
/**
* Read secrets for a stage (encrypted).
* Requires the decryption key to be present at ~/.gkm/{project}/{stage}.key
*
* @returns StageSecrets or null if not found
*/
async function readStageSecrets(stage, cwd = process.cwd()) {
	const path = getSecretsPath(stage, cwd);
	if (!(0, node_fs.existsSync)(path)) return null;
	const content = await (0, node_fs_promises.readFile)(path, "utf-8");
	const data = JSON.parse(content);
	if (data.version === 1 && data.encrypted && data.iv) {
		const projectName = (0, node_path.basename)(cwd);
		const key = await readKey(stage, projectName);
		if (!key) throw new Error(`Decryption key not found for stage "${stage}". Expected key at: ~/.gkm/${projectName}/${stage}.key`);
		return decryptSecretsData(data, key);
	}
	return data;
}
/**
* Write secrets for a stage (encrypted).
* Creates or uses existing encryption key at ~/.gkm/{project}/{stage}.key
*/
async function writeStageSecrets(secrets, cwd = process.cwd()) {
	const dir = getSecretsDir(cwd);
	const path = getSecretsPath(secrets.stage, cwd);
	const projectName = (0, node_path.basename)(cwd);
	await (0, node_fs_promises.mkdir)(dir, { recursive: true });
	const key = await getOrCreateKey(secrets.stage, projectName);
	const encrypted = encryptSecretsData(secrets, key);
	await (0, node_fs_promises.writeFile)(path, JSON.stringify(encrypted, null, 2), "utf-8");
}
/**
* Convert StageSecrets to embeddable format (flat key-value pairs).
* This is what gets encrypted and embedded in the bundle.
*/
function toEmbeddableSecrets(secrets) {
	return {
		...secrets.urls,
		...secrets.custom,
		...secrets.services.postgres && {
			POSTGRES_USER: secrets.services.postgres.username,
			POSTGRES_PASSWORD: secrets.services.postgres.password,
			POSTGRES_DB: secrets.services.postgres.database ?? "app",
			POSTGRES_HOST: secrets.services.postgres.host,
			POSTGRES_PORT: String(secrets.services.postgres.port)
		},
		...secrets.services.redis && {
			REDIS_PASSWORD: secrets.services.redis.password,
			REDIS_HOST: secrets.services.redis.host,
			REDIS_PORT: String(secrets.services.redis.port)
		},
		...secrets.services.rabbitmq && {
			RABBITMQ_USER: secrets.services.rabbitmq.username,
			RABBITMQ_PASSWORD: secrets.services.rabbitmq.password,
			RABBITMQ_HOST: secrets.services.rabbitmq.host,
			RABBITMQ_PORT: String(secrets.services.rabbitmq.port),
			RABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? "/"
		},
		...secrets.services.minio && {
			STORAGE_ACCESS_KEY_ID: secrets.services.minio.username,
			STORAGE_SECRET_ACCESS_KEY: secrets.services.minio.password,
			STORAGE_BUCKET: secrets.services.minio.bucket ?? "app",
			STORAGE_REGION: "eu-west-1",
			STORAGE_FORCE_PATH_STYLE: "true"
		},
		...secrets.services.mailpit && {
			SMTP_HOST: secrets.services.mailpit.host,
			SMTP_PORT: String(secrets.services.mailpit.port),
			SMTP_USER: secrets.services.mailpit.username,
			SMTP_PASS: secrets.services.mailpit.password,
			SMTP_SECURE: "false",
			MAIL_FROM: "noreply@localhost"
		},
		...secrets.services.localstack && {
			AWS_ACCESS_KEY_ID: secrets.services.localstack.accessKeyId ?? secrets.services.localstack.username,
			AWS_SECRET_ACCESS_KEY: secrets.services.localstack.password,
			AWS_REGION: secrets.services.localstack.region ?? "us-east-1",
			AWS_ENDPOINT_URL: `http://${secrets.services.localstack.host}:${secrets.services.localstack.port}`
		},
		...secrets.services.pgboss && {
			PGBOSS_DB_USER: secrets.services.pgboss.username,
			PGBOSS_DB_PASSWORD: secrets.services.pgboss.password
		}
	};
}
/**
* Update a custom secret in the secrets file.
*/
async function setCustomSecret(stage, key, value, cwd = process.cwd()) {
	const secrets = await readStageSecrets(stage, cwd);
	if (!secrets) throw new Error(`Secrets not found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
	const updated = {
		...secrets,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
		custom: {
			...secrets.custom,
			[key]: value
		}
	};
	await writeStageSecrets(updated, cwd);
	return updated;
}
/**
* Mask a password for display (show first 4 and last 2 chars).
*/
function maskPassword(password) {
	if (password.length <= 8) return "********";
	return `${password.slice(0, 4)}${"*".repeat(password.length - 6)}${password.slice(-2)}`;
}
/**
* Validate that all required environment variables are present in secrets.
*
* @param requiredVars - Array of environment variable names required by the application
* @param secrets - Stage secrets to validate against
* @returns Validation result with missing and provided variables
*
* @example
* ```typescript
* const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];
* const secrets = await readStageSecrets('production');
* const result = validateEnvironmentVariables(required, secrets);
*
* if (!result.valid) {
*   console.error(`Missing environment variables: ${result.missing.join(', ')}`);
* }
* ```
*/
function validateEnvironmentVariables(requiredVars, secrets) {
	const embeddable = toEmbeddableSecrets(secrets);
	const availableVars = new Set(Object.keys(embeddable));
	const missing = [];
	const provided = [];
	for (const varName of requiredVars) if (availableVars.has(varName)) provided.push(varName);
	else missing.push(varName);
	return {
		valid: missing.length === 0,
		missing: missing.sort(),
		provided: provided.sort(),
		required: [...requiredVars].sort()
	};
}

//#endregion
Object.defineProperty(exports, 'getKeyPath', {
  enumerable: true,
  get: function () {
    return getKeyPath;
  }
});
Object.defineProperty(exports, 'getSecretsDir', {
  enumerable: true,
  get: function () {
    return getSecretsDir;
  }
});
Object.defineProperty(exports, 'getSecretsPath', {
  enumerable: true,
  get: function () {
    return getSecretsPath;
  }
});
Object.defineProperty(exports, 'initStageSecrets', {
  enumerable: true,
  get: function () {
    return initStageSecrets;
  }
});
Object.defineProperty(exports, 'maskPassword', {
  enumerable: true,
  get: function () {
    return maskPassword;
  }
});
Object.defineProperty(exports, 'readStageSecrets', {
  enumerable: true,
  get: function () {
    return readStageSecrets;
  }
});
Object.defineProperty(exports, 'secretsExist', {
  enumerable: true,
  get: function () {
    return secretsExist;
  }
});
Object.defineProperty(exports, 'setCustomSecret', {
  enumerable: true,
  get: function () {
    return setCustomSecret;
  }
});
Object.defineProperty(exports, 'toEmbeddableSecrets', {
  enumerable: true,
  get: function () {
    return toEmbeddableSecrets;
  }
});
Object.defineProperty(exports, 'validateEnvironmentVariables', {
  enumerable: true,
  get: function () {
    return validateEnvironmentVariables;
  }
});
Object.defineProperty(exports, 'writeStageSecrets', {
  enumerable: true,
  get: function () {
    return writeStageSecrets;
  }
});
//# sourceMappingURL=storage-DLEb8Dkd.cjs.map