"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_error = require('../primordials/error.js');
const require_secrets__internal = require('./_internal.js');
const require_secrets_macos = require('./macos.js');
const require_secrets_linux = require('./linux.js');
const require_secrets_windows = require('./windows.js');
let node_os = require("node:os");

//#region src/secrets/keychain.ts
/**
* @file Cross-platform secret-storage helper. Reads / writes to the native OS
*   credential store (Keychain on macOS, Secret Service via libsecret on Linux,
*   Credential Manager + DPAPI on Windows). Consumers pick their own `{
*   service, account }` pair. API shape: readSecret({ service, account }) →
*   Promise<string | undefined> readSecretSync({ service, account }) → string |
*   undefined writeSecret({ service, account, value }) → Promise<void>
*   writeSecretSync({ service, account, value }) → void deleteSecret({ service,
*   account }) → Promise<'removed' | 'absent'> deleteSecretSync({ service,
*   account }) → 'removed' | 'absent' Multi-slot helpers exist for the common
*   case of writing the same value under multiple account names (e.g.
*   SOCKET_API_TOKEN + SOCKET_API_KEY for backwards compatibility):
*   readSecretFromSlots({ service, accounts }) writeSecretToSlots({ service,
*   accounts, value }) deleteSecretFromSlots({ service, accounts }) IMPORTANT:
*   do NOT invoke these helpers from a shell rc / .zshenv file (or any other
*   always-on-startup hook). On macOS each call triggers a Keychain auth
*   prompt; piling that into per-shell startup floods the user with prompts.
*   Use `write` from `./rc` to write a one-time literal `export` block into the
*   user's shell rc file instead. (Incident memory: socket-cli session
*   2026-05-15.)
*/
/**
* Drop the in-process read cache. Tests use this between cases to force a fresh
* OS call; production code generally doesn't need it (process exit drops the
* cache anyway, and `writeSecret` / `deleteSecret` already invalidate per-key
* entries automatically).
*/
function clearCache() {
	require_secrets__internal.invalidateAll();
}
/**
* Remove a secret from the OS credential store. Idempotent — succeeds whether
* the entry exists or not. Returns the per-slot outcome so callers can log
* "actually removed X" vs "X was already absent."
*/
async function deleteSecret({ service, account }) {
	let outcome;
	switch (detectPlatform()) {
		case "darwin":
			outcome = await require_secrets_macos.deleteMacOS(service, account);
			break;
		case "linux":
			outcome = await require_secrets_linux.deleteLinux(service, account);
			break;
		case "win32":
			outcome = await require_secrets_windows.deleteWindows(service, account);
			break;
		default: outcome = "absent";
	}
	require_secrets__internal.invalidate(service, account);
	return outcome;
}
async function deleteSecretFromSlots({ service, accounts }) {
	const results = [];
	for (const account of accounts) {
		const outcome = await deleteSecret({
			service,
			account
		});
		results.push({
			account,
			outcome
		});
	}
	return results;
}
function deleteSecretFromSlotsSync({ service, accounts }) {
	const results = [];
	for (const account of accounts) {
		const outcome = deleteSecretSync({
			service,
			account
		});
		results.push({
			account,
			outcome
		});
	}
	return results;
}
function deleteSecretSync({ service, account }) {
	let outcome;
	switch (detectPlatform()) {
		case "darwin":
			outcome = require_secrets_macos.deleteMacOSSync(service, account);
			break;
		case "linux":
			outcome = require_secrets_linux.deleteLinuxSync(service, account);
			break;
		case "win32":
			outcome = require_secrets_windows.deleteWindowsSync(service, account);
			break;
		default: outcome = "absent";
	}
	require_secrets__internal.invalidate(service, account);
	return outcome;
}
/**
* Resolve the current OS to one of our four backend categories.
*
* Exported only because the fleet's `export-top-level-functions` lint rule
* requires top-level functions to be exported for testability. Not part of the
* public `secrets/keychain` API surface — consumers should call `readSecret` /
* `writeSecret` / `getBackendAvailability` instead, which handle the dispatch
* internally.
*
* @internal
*/
function detectPlatform() {
	const p = (0, node_os.platform)();
	if (p === "darwin" || p === "linux" || p === "win32") return p;
	return "other";
}
/**
* Diagnostic: tell the operator whether the OS credential backend is reachable.
* Used by installers to report up-front (before any prompt fires) when
* libsecret-tools or the CredentialManager module aren't installed.
*/
function getBackendAvailability() {
	switch (detectPlatform()) {
		case "darwin": return {
			available: require_secrets_macos.isMacOSBackendAvailable(),
			toolName: "security(1)",
			installHint: void 0
		};
		case "linux": {
			const available = require_secrets_linux.isLinuxBackendAvailable();
			return {
				available,
				toolName: "secret-tool",
				installHint: available ? void 0 : "apt install libsecret-tools  (Debian/Ubuntu) | dnf install libsecret  (Fedora/RHEL)"
			};
		}
		case "win32": return {
			available: require_secrets_windows.isWindowsBackendAvailable(),
			toolName: "PowerShell (CredentialManager / DPAPI)",
			installHint: void 0
		};
		default: return {
			available: false,
			toolName: "n/a",
			installHint: `Platform ${(0, node_os.platform)()} is not supported.`
		};
	}
}
/**
* Read a single secret value from the OS credential store. Returns `undefined`
* when the entry doesn't exist OR when the backend tool isn't available — read
* paths never throw, so callers can fall through to env / .env / prompt
* cleanly.
*/
async function readSecret({ service, account }) {
	return require_secrets__internal.dedupeRead(service, account, async () => {
		switch (detectPlatform()) {
			case "darwin": return require_secrets_macos.readMacOS(service, account);
			case "linux": return require_secrets_linux.readLinux(service, account);
			case "win32": return require_secrets_windows.readWindows(service, account);
			default: return;
		}
	});
}
/**
* Read from the first matching account. Used when multiple env-var names map to
* the same logical secret (e.g. SOCKET_API_TOKEN canonical + SOCKET_API_KEY
* legacy). Returns the value AND the account it came from so callers can warn
* on legacy hits.
*/
async function readSecretFromSlots({ service, accounts }) {
	for (const account of accounts) {
		const value = await readSecret({
			service,
			account
		});
		if (value) return {
			value,
			account
		};
	}
}
function readSecretFromSlotsSync({ service, accounts }) {
	for (const account of accounts) {
		const value = readSecretSync({
			service,
			account
		});
		if (value) return {
			value,
			account
		};
	}
}
function readSecretSync({ service, account }) {
	if (require_secrets__internal.has(service, account)) return require_secrets__internal.getCached(service, account);
	let value;
	switch (detectPlatform()) {
		case "darwin":
			value = require_secrets_macos.readMacOSSync(service, account);
			break;
		case "linux":
			value = require_secrets_linux.readLinuxSync(service, account);
			break;
		case "win32":
			value = require_secrets_windows.readWindowsSync(service, account);
			break;
		default: value = void 0;
	}
	require_secrets__internal.setCached(service, account, value);
	return value;
}
/**
* Persist a single secret to the OS credential store. Throws on write failure —
* the caller is in a setup flow and should see why persistence failed, not
* silently continue.
*
* Returns the outcome: - `'written'` — value persisted (entry was absent or
* differed). - `'unchanged'` — current stored value already matches; no OS
* write performed. Useful for idempotent flows (re-running an installer
* shouldn't show "rewrote N secrets" when nothing actually changed).
*/
async function writeSecret({ service, account, value, label }) {
	if (!value || typeof value !== "string") throw new require_primordials_error.TypeErrorCtor("writeSecret: value must be a non-empty string");
	const platform_ = detectPlatform();
	if (platform_ === "other") throw new require_primordials_error.ErrorCtor(`Unsupported platform: ${(0, node_os.platform)()}. Secret storage requires macOS, Linux, or Windows.`);
	if (await readSecret({
		service,
		account
	}) === value) return "unchanged";
	const lbl = label ?? `${service} credential`;
	switch (platform_) {
		case "darwin":
			await require_secrets_macos.writeMacOS(service, account, value, lbl);
			break;
		case "linux":
			await require_secrets_linux.writeLinux(service, account, value, lbl);
			break;
		case "win32":
			await require_secrets_windows.writeWindows(service, account, value, lbl);
			break;
	}
	require_secrets__internal.setCached(service, account, value);
	return "written";
}
function writeSecretSync({ service, account, value, label }) {
	if (!value || typeof value !== "string") throw new require_primordials_error.TypeErrorCtor("writeSecret: value must be a non-empty string");
	const platform_ = detectPlatform();
	if (platform_ === "other") throw new require_primordials_error.ErrorCtor(`Unsupported platform: ${(0, node_os.platform)()}. Secret storage requires macOS, Linux, or Windows.`);
	if (readSecretSync({
		service,
		account
	}) === value) return "unchanged";
	const lbl = label ?? `${service} credential`;
	switch (platform_) {
		case "darwin":
			require_secrets_macos.writeMacOSSync(service, account, value, lbl);
			break;
		case "linux":
			require_secrets_linux.writeLinuxSync(service, account, value, lbl);
			break;
		case "win32":
			require_secrets_windows.writeWindowsSync(service, account, value, lbl);
			break;
	}
	require_secrets__internal.setCached(service, account, value);
	return "written";
}
/**
* Persist the same value under each account name in `accounts`. Useful when a
* value needs to be reachable under several env-var names (legacy aliases,
* sibling tools). Each slot gets its own keychain entry — they all hold the
* same string.
*
* If any individual write throws, prior writes have already persisted. Failures
* aren't rolled back (the half-state is at worst a stale legacy alias, which
* the next successful write cleans up).
*/
async function writeSecretToSlots({ service, accounts, value, label }) {
	const results = [];
	for (const account of accounts) {
		const outcome = await writeSecret({
			service,
			account,
			value,
			label
		});
		results.push({
			account,
			outcome
		});
	}
	return results;
}
function writeSecretToSlotsSync({ service, accounts, value, label }) {
	const results = [];
	for (const account of accounts) {
		const outcome = writeSecretSync({
			service,
			account,
			value,
			label
		});
		results.push({
			account,
			outcome
		});
	}
	return results;
}

//#endregion
exports.clearCache = clearCache;
exports.deleteSecret = deleteSecret;
exports.deleteSecretFromSlots = deleteSecretFromSlots;
exports.deleteSecretFromSlotsSync = deleteSecretFromSlotsSync;
exports.deleteSecretSync = deleteSecretSync;
exports.detectPlatform = detectPlatform;
exports.getBackendAvailability = getBackendAvailability;
exports.readSecret = readSecret;
exports.readSecretFromSlots = readSecretFromSlots;
exports.readSecretFromSlotsSync = readSecretFromSlotsSync;
exports.readSecretSync = readSecretSync;
exports.writeSecret = writeSecret;
exports.writeSecretSync = writeSecretSync;
exports.writeSecretToSlots = writeSecretToSlots;
exports.writeSecretToSlotsSync = writeSecretToSlotsSync;