import { n as getLogger } from "./logger.js";
import { t as CredentialStoreType } from "./utility.js";
import { t as DEFAULT_NANGO_STORE_ID } from "./default-constants.js";
import { z } from "@hono/zod-openapi";
import { Nango } from "@nangohq/node";

//#region src/credential-stores/CredentialStoreRegistry.ts
/**
* Registry for managing credential stores in the application context
* Provides methods to register, retrieve, and manage credential stores
*/
var CredentialStoreRegistry = class {
	stores = /* @__PURE__ */ new Map();
	logger = getLogger("credential-store-registry");
	constructor(initialStores = []) {
		for (const store of initialStores) this.add(store);
	}
	/**
	* Add a credential store to the registry
	*/
	add(store) {
		if (this.stores.has(store.id)) this.logger.warn({ storeId: store.id }, `Credential store ${store.id} already registered, replacing`);
		this.stores.set(store.id, store);
		this.logger.info({
			storeId: store.id,
			storeType: store.type
		}, `Registered credential store: ${store.id} (type: ${store.type})`);
	}
	/**
	* Get a credential store by ID
	*/
	get(id) {
		return this.stores.get(id);
	}
	/**
	* Get all registered credential stores
	*/
	getAll() {
		return Array.from(this.stores.values());
	}
	/**
	* Get all credential store IDs
	*/
	getIds() {
		return Array.from(this.stores.keys());
	}
	/**
	* Check if a credential store is registered
	*/
	has(id) {
		return this.stores.has(id);
	}
	/**
	* Remove a credential store
	*/
	remove(id) {
		const removed = this.stores.delete(id);
		if (removed) this.logger.info({ id }, `Removed credential store: ${id}`);
		return removed;
	}
	/**
	* Get the number of registered stores
	*/
	size() {
		return this.stores.size;
	}
};

//#endregion
//#region src/credential-stores/keychain-store.ts
/**
* KeyChainStore - Cross-platform system keychain credential storage
*
* Uses the native OS credential storage:
* - macOS: Keychain
* - Windows: Credential Vault
* - Linux: Secret Service API/libsecret
*
* Requires the 'keytar' npm package to be installed.
* Falls back gracefully if keytar is not available.
*
* ## macOS Permission Handling
*
* On macOS, when your Node.js app first calls keytar operations:
* - `setPassword()` creates a new Keychain item (no prompt required)
* - `getPassword()` may prompt the user for permission on first access
* - Users can click "Allow", "Always Allow", or "Deny"
* - If denied, keytar returns `null` which this implementation handles gracefully
* - The calling binary (usually `node`) will be shown in the permission prompt
* - For better UX in packaged apps, consider code signing and app bundling
*
* This implementation handles all permission scenarios gracefully:
* - Returns `null` when access is denied or credentials don't exist
* - Logs errors for debugging permission issues
* - Never throws on permission denial, only on system-level errors
*/
var KeyChainStore = class {
	id;
	type = CredentialStoreType.keychain;
	service;
	logger = getLogger("KeyChainStore");
	keytarAvailable = false;
	keytar = null;
	initializationPromise;
	constructor(id, servicePrefix = "inkeep-agent-framework") {
		this.id = id;
		this.service = `${servicePrefix}-${id}`;
		this.initializationPromise = this.initializeKeytar();
	}
	/**
	* Initialize keytar dynamically to handle optional availability
	*/
	async initializeKeytar() {
		if (this.keytar) {
			this.keytarAvailable = true;
			return;
		}
		try {
			this.keytar = (await import(
				/* webpackIgnore: true */
				"keytar"
)).default;
			this.keytarAvailable = true;
		} catch (error) {
			this.logger.warn({
				storeId: this.id,
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Keytar not available - KeyChainStore will return null for all operations");
			this.keytarAvailable = false;
		}
	}
	/**
	* Get a credential from the keychain
	*/
	async get(key) {
		await this.initializationPromise;
		if (!this.keytarAvailable || !this.keytar) {
			this.logger.debug({
				storeId: this.id,
				key
			}, "Keytar not available, returning null");
			return null;
		}
		try {
			const password = await this.keytar.getPassword(this.service, key);
			if (password === null) this.logger.debug({
				storeId: this.id,
				service: this.service,
				account: key
			}, "No credential found in keychain");
			return password;
		} catch (error) {
			this.logger.error({
				storeId: this.id,
				service: this.service,
				account: key,
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Error getting credential from keychain");
			return null;
		}
	}
	/**
	* Set a credential in the keychain
	*/
	async set(key, value, _metadata) {
		await this.initializationPromise;
		if (!this.keytarAvailable || !this.keytar) {
			this.logger.warn({
				storeId: this.id,
				key
			}, "Keytar not available, cannot set credential");
			throw new Error("Keytar not available - cannot store credentials in system keychain");
		}
		try {
			await this.keytar.setPassword(this.service, key, value);
			this.logger.debug({
				storeId: this.id,
				service: this.service,
				account: key
			}, "Credential stored in keychain");
		} catch (error) {
			this.logger.error({
				storeId: this.id,
				service: this.service,
				account: key,
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Error setting credential in keychain");
			throw new Error(`Failed to store credential in keychain: ${error instanceof Error ? error.message : "Unknown error"}`);
		}
	}
	/**
	* Check if a credential exists in the keychain
	*/
	async has(key) {
		return await this.get(key) !== null;
	}
	/**
	* Check if the credential store is available and functional
	*/
	async checkAvailability() {
		await this.initializationPromise;
		if (!this.keytarAvailable || !this.keytar) return {
			available: false,
			reason: "Keytar not available - cannot store credentials in system keychain"
		};
		return { available: true };
	}
	/**
	* Delete a credential from the keychain
	*/
	async delete(key) {
		await this.initializationPromise;
		if (!this.keytarAvailable || !this.keytar) {
			this.logger.warn({
				storeId: this.id,
				key
			}, "Keytar not available, cannot delete credential");
			return false;
		}
		try {
			const result = await this.keytar.deletePassword(this.service, key);
			if (result) this.logger.debug({
				storeId: this.id,
				service: this.service,
				account: key
			}, "Credential deleted from keychain");
			else this.logger.debug({
				storeId: this.id,
				service: this.service,
				account: key
			}, "Credential not found in keychain for deletion");
			return result;
		} catch (error) {
			this.logger.error({
				storeId: this.id,
				service: this.service,
				account: key,
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Error deleting credential from keychain");
			return false;
		}
	}
	/**
	* Find all credentials for this service
	* Useful for debugging and listing stored credentials
	*/
	async findAllCredentials() {
		await this.initializationPromise;
		if (!this.keytarAvailable || !this.keytar) return [];
		try {
			return await this.keytar.findCredentials(this.service) || [];
		} catch (error) {
			this.logger.error({
				storeId: this.id,
				service: this.service,
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Error finding credentials in keychain");
			return [];
		}
	}
	/**
	* Clear all credentials for this service
	* WARNING: This will delete all credentials stored under this service
	*/
	async clearAll() {
		const credentials = await this.findAllCredentials();
		let deletedCount = 0;
		for (const cred of credentials) if (await this.delete(cred.account)) deletedCount++;
		if (deletedCount > 0) this.logger.info({
			storeId: this.id,
			service: this.service,
			deletedCount
		}, "Cleared all credentials from keychain");
		return deletedCount;
	}
};
/**
* Factory function to create KeyChainStore
* Provides consistent initialization and optional configuration
*
* ## Usage Recommendations for macOS Permission Handling
*
* 1. **First-time setup**: Inform users that they may see permission prompts
* 2. **Error handling**: Check for `null` returns from `get()` operations
* 3. **User guidance**: If credentials can't be retrieved, guide users to:
*    - Check Keychain Access app for denied permissions
*    - Re-run the application if they accidentally clicked "Deny"
* 4. **Development**: Use a consistent `servicePrefix` to avoid permission prompt spam
* 5. **Production**: Consider code-signing your distributed app for better permission prompts
*
* Example usage with permission handling:
* ```typescript
* const store = createKeyChainStore('my-app');
*
* // Always check for null when retrieving
* const apiKey = await store.get('api-key');
* if (!apiKey) {
*   console.log('API key not found or access denied');
*   // Guide user to check permissions or re-enter credentials
* }
* ```
*/
function createKeyChainStore(id, options) {
	return new KeyChainStore(id, options?.servicePrefix);
}

//#endregion
//#region src/credential-stores/memory-store.ts
/**
* In-memory credential store implementation
* Automatically loads environment variables prefixed with CREDENTIAL_STORE_ on initialization
* Note: Runtime credentials are lost when the server restarts, but env vars are reloaded
*/
var InMemoryCredentialStore = class {
	id;
	type = CredentialStoreType.memory;
	credentials = /* @__PURE__ */ new Map();
	constructor(id = "memory-default") {
		this.id = id;
	}
	/**
	* Get a credential from the in memory store.
	* If the key is not found in the in memory store then it is loaded from environment variables.
	* If the key is not found in the environment variables or in the in memory store then returns null.
	* @param key - The key of the credential to get
	* @returns The credential value or null if not found
	*/
	async get(key) {
		const credential = this.credentials.get(key);
		if (!credential) {
			const envValue = process.env[key];
			if (envValue) {
				this.credentials.set(key, envValue);
				return envValue;
			}
			return null;
		}
		return credential;
	}
	/**
	* Set a credential in the in memory store.
	* @param key - The key of the credential to set
	* @param value - The value of the credential to set
	* @param metadata - Optional metadata (ignored by memory store)
	*/
	async set(key, value, _metadata) {
		this.credentials.set(key, value);
	}
	/**
	* Check if a credential exists in the in memory store.
	* @param key - The key of the credential to check
	* @returns True if the credential exists, false otherwise
	*/
	async has(key) {
		return this.credentials.has(key);
	}
	/**
	* Delete a credential from the in memory store.
	* @param key - The key of the credential to delete
	* @returns True if the credential was deleted, false otherwise
	*/
	async delete(key) {
		return this.credentials.delete(key);
	}
	/**
	* Check if the credential store is available and functional
	*/
	async checkAvailability() {
		return { available: true };
	}
};

//#endregion
//#region src/credential-stores/nango-store.ts
const logger = getLogger("nango-credential-store");
const CredentialKeySchema = z.object({
	connectionId: z.string().min(1, "connectionId must be a non-empty string"),
	providerConfigKey: z.string().min(1, "providerConfigKey must be a non-empty string"),
	integrationDisplayName: z.string().nullish()
});
/**
* Parse and validate a Nango credential key
* @param key - JSON string containing connectionId and providerConfigKey
* @returns Parsed credential key or null if invalid
*/
function parseCredentialKey(key) {
	try {
		const parsed = JSON.parse(key);
		return CredentialKeySchema.parse(parsed);
	} catch (error) {
		logger.warn({
			key: key.substring(0, 100),
			error: error instanceof Error ? error.message : "Unknown error"
		}, "Failed to parse credential key");
		return null;
	}
}
const SUPPORTED_AUTH_MODES = [
	"APP",
	"API_KEY",
	"BASIC",
	"CUSTOM",
	"JWT",
	"NONE",
	"OAUTH1",
	"OAUTH2",
	"OAUTH2_CC",
	"TBA"
];
function isSupportedAuthMode(mode) {
	return SUPPORTED_AUTH_MODES.includes(mode);
}
/**
* Nango-based CredentialStore that fetches OAuth credentials from Nango API
* Uses connectionId and providerConfigKey from metadata to fetch live credentials
*/
var NangoCredentialStore = class {
	id;
	type = CredentialStoreType.nango;
	nangoConfig;
	nangoClient;
	constructor(id, config) {
		this.id = id;
		this.nangoConfig = config;
		this.nangoClient = new Nango({
			secretKey: this.nangoConfig.secretKey,
			host: this.nangoConfig.apiUrl
		});
	}
	getAccessToken(credentials) {
		const { type } = credentials;
		if (!isSupportedAuthMode(type)) return null;
		const extractAccessTokenForBearerType = (tokenString) => {
			if (tokenString && typeof tokenString === "string") {
				try {
					const parsedToken = JSON.parse(tokenString);
					if (parsedToken.access_token && typeof parsedToken.access_token === "string") return parsedToken.access_token;
				} catch {}
				return tokenString;
			}
		};
		switch (type) {
			case "API_KEY": return { token: extractAccessTokenForBearerType(credentials.apiKey || credentials.api_key) };
			case "APP": return { token: extractAccessTokenForBearerType(credentials.accessToken || credentials.access_token) };
			case "BASIC": return {
				username: credentials.username,
				token: credentials.password
			};
			case "CUSTOM": return credentials.raw;
			case "JWT": return { token: extractAccessTokenForBearerType(credentials.token) };
			case "OAUTH1": return {
				token: credentials.oauth_token,
				token_secret: credentials.oauth_token_secret
			};
			case "OAUTH2": return {
				token: extractAccessTokenForBearerType(credentials.access_token),
				refresh_token: credentials.refresh_token,
				expiresAt: credentials.expires_at
			};
			case "OAUTH2_CC": return {
				token: extractAccessTokenForBearerType(credentials.token),
				client_certificate: credentials.client_certificate,
				client_id: credentials.client_id,
				client_private_key: credentials.client_private_key,
				client_secret: credentials.client_secret
			};
			case "TBA": return {
				token: credentials.token_id,
				token_secret: credentials.token_secret
			};
			default: return null;
		}
	}
	sanitizeMetadata(metadata) {
		if (!metadata || typeof metadata !== "object") return {};
		const result = {};
		for (const [key, value] of Object.entries(metadata)) {
			if (typeof key !== "string") continue;
			if (typeof value === "string") result[key] = value;
		}
		return result;
	}
	/**
	* Fetch a specific Nango integration
	*/
	async fetchNangoIntegration(uniqueKey) {
		try {
			const integration = (await this.nangoClient.getIntegration({ uniqueKey }, { include: ["credentials"] })).data;
			let areCredentialsSet = false;
			if (integration.credentials?.type === "OAUTH2" || integration.credentials?.type === "OAUTH1" || integration.credentials?.type === "TBA") areCredentialsSet = !!(integration.credentials?.client_id && integration.credentials?.client_secret);
			else if (integration.credentials?.type === "APP") areCredentialsSet = !!(integration.credentials?.app_id && integration.credentials?.app_link);
			else areCredentialsSet = true;
			const { credentials: _credentials, ...integrationWithoutCredentials } = integration;
			return {
				...integrationWithoutCredentials,
				areCredentialsSet
			};
		} catch (error) {
			if (error && typeof error === "object" && "status" in error && error.status === 404) return null;
			logger.error({
				error: error instanceof Error ? error.message : "Unknown error",
				uniqueKey
			}, `Failed to fetch integration ${uniqueKey}`);
			return null;
		}
	}
	/**
	* Create an API key credential by setting up Nango integration and importing the connection
	*/
	async createNangoApiKeyConnection({ uniqueKey, displayName, apiKeyToSet, metadata }) {
		const provider = "private-api-bearer";
		try {
			let integration;
			try {
				integration = (await this.nangoClient.createIntegration({
					provider,
					unique_key: uniqueKey,
					display_name: displayName
				})).data;
			} catch (error) {
				const existingIntegration = await this.fetchNangoIntegration(uniqueKey);
				if (existingIntegration) integration = existingIntegration;
				else console.log(`Integration creation failed for unexpected reasons`, error);
			}
			if (!integration) throw new Error(`Integration '${uniqueKey}' not found`);
			const importConnectionUrl = `${process.env.NANGO_SERVER_URL || "https://api.nango.dev"}/connections`;
			const credentials = {
				type: "API_KEY",
				apiKey: apiKeyToSet
			};
			const body = {
				provider_config_key: integration.unique_key,
				connection_id: uniqueKey,
				metadata,
				credentials
			};
			const response = await fetch(importConnectionUrl, {
				method: "POST",
				headers: {
					Authorization: `Bearer ${process.env.NANGO_SECRET_KEY}`,
					"Content-Type": "application/json"
				},
				body: JSON.stringify(body)
			});
			if (!response.ok) {
				const errorText = await response.text();
				throw new Error(`Failed to import connection: HTTP ${response.status} - ${response.statusText}. Response: ${errorText}`);
			}
		} catch (error) {
			logger.error({
				error: error instanceof Error ? error.message : "Unknown error",
				displayName
			}, `Unexpected error creating API key credential '${displayName}'`);
			throw new Error(`Failed to create API key credential '${displayName}': ${error instanceof Error ? error.message : "Unknown error"}`);
		}
	}
	/**
	* Fetch credentials from Nango API using connection information
	* @param connectionId - The connection ID for the Nango connection
	* @param providerConfigKey - The provider config key for the Nango connection
	* @returns The credential data or null if the credentials are not found
	*/
	async fetchCredentialsFromNango({ connectionId, providerConfigKey }) {
		try {
			const nangoConnection = await this.nangoClient.getConnection(providerConfigKey, connectionId);
			return {
				...this.getAccessToken(nangoConnection.credentials) ?? {},
				connectionId,
				providerConfigKey,
				provider: nangoConnection.provider || "unknown",
				secretKey: this.nangoConfig.secretKey,
				metadata: this.sanitizeMetadata(nangoConnection.metadata ?? {})
			};
		} catch (error) {
			logger.error({
				error: error instanceof Error ? error.message : "Unknown error",
				connectionId,
				providerConfigKey
			}, "Error fetching credentials from Nango");
			return null;
		}
	}
	/**
	* Get credentials by key - implements CredentialStore interface
	* Key format: JSON string with connectionId and providerConfigKey
	*/
	async get(key) {
		try {
			const parsedKey = parseCredentialKey(key);
			if (!parsedKey) return null;
			const { connectionId, providerConfigKey } = parsedKey;
			const credentials = await this.fetchCredentialsFromNango({
				connectionId,
				providerConfigKey
			});
			if (!credentials) return null;
			return JSON.stringify(credentials);
		} catch (error) {
			logger.error({
				storeId: this.id,
				key: key.substring(0, 100),
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Error getting credentials from Nango");
			return null;
		}
	}
	/**
	* Set credentials - this is used to save bearer auth
	* Key format: JSON string with connectionId and providerConfigKey
	*/
	async set(key, value, metadata = {}) {
		const parsedKey = parseCredentialKey(key);
		if (!parsedKey) throw new Error(`Invalid credential key: ${key}`);
		const { connectionId, providerConfigKey, integrationDisplayName } = parsedKey;
		await this.createNangoApiKeyConnection({
			uniqueKey: connectionId,
			displayName: integrationDisplayName ?? providerConfigKey,
			apiKeyToSet: value,
			metadata
		});
	}
	/**
	* Check if credentials exist by attempting to fetch them
	*/
	async has(key) {
		try {
			return await this.get(key) !== null;
		} catch (error) {
			logger.error({
				error: error instanceof Error ? error.message : "Unknown error",
				key
			}, "Error checking credentials existence");
			return false;
		}
	}
	/**
	* Delete credentials - not supported for Nango (revoke through Nango dashboard)
	*/
	async delete(key) {
		try {
			const parsedKey = parseCredentialKey(key);
			if (!parsedKey) return false;
			const { connectionId, providerConfigKey } = parsedKey;
			await this.nangoClient.deleteConnection(providerConfigKey, connectionId);
			return true;
		} catch (error) {
			logger.error({
				storeId: this.id,
				key: key.substring(0, 100),
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Error deleting credentials from Nango");
			return false;
		}
	}
	/**
	* Check if the credential store is available and functional
	*/
	async checkAvailability() {
		if (!this.nangoConfig.secretKey) return {
			available: false,
			reason: "Nango secret key not configured"
		};
		if (this.nangoConfig.secretKey.includes("mock") || this.nangoConfig.secretKey === "your_nango_secret_key") return {
			available: false,
			reason: "Nango secret key appears to be a placeholder or mock value"
		};
		return { available: true };
	}
};
/**
* Factory function to create NangoCredentialStore
* Automatically reads NANGO_SECRET_KEY from environment and validates it
*/
function createNangoCredentialStore(id, config) {
	const nangoSecretKey = config?.secretKey || process.env.NANGO_SECRET_KEY;
	if (!nangoSecretKey || nangoSecretKey === "your_nango_secret_key" || nangoSecretKey.includes("mock")) throw new Error("NANGO_SECRET_KEY environment variable is required and must be a real Nango secret key (not mock/placeholder)");
	return new NangoCredentialStore(id, {
		apiUrl: "https://api.nango.dev",
		...config,
		secretKey: nangoSecretKey
	});
}

//#endregion
//#region src/credential-stores/defaults.ts
/**
* Create default credential stores based on environment variables
*/
function createDefaultCredentialStores() {
	const stores = [];
	stores.push(new InMemoryCredentialStore("memory-default"));
	if (process.env.NANGO_SECRET_KEY) stores.push(createNangoCredentialStore(DEFAULT_NANGO_STORE_ID, {
		apiUrl: process.env.NANGO_SERVER_URL || "https://api.nango.dev",
		secretKey: process.env.NANGO_SECRET_KEY
	}));
	try {
		stores.push(createKeyChainStore("keychain-default"));
	} catch (error) {
		console.warn("Failed to create keychain store:", error instanceof Error ? error.message : error);
	}
	return stores;
}

//#endregion
export { KeyChainStore as a, InMemoryCredentialStore as i, NangoCredentialStore as n, createKeyChainStore as o, createNangoCredentialStore as r, CredentialStoreRegistry as s, createDefaultCredentialStores as t };
//# sourceMappingURL=credential-stores.js.map