import { b as getCredentialPool, c as addCredential } from './credential-pool-B04qO8at.js';
import { o as ok, p as parseJsonBody, i as isParseError, e as err, r as requireString } from './_lafs-C3_fBF_X.js';
import { json } from '@sveltejs/kit';
import './paths-2M_UxD_H.js';
import 'node:fs';
import 'node:path';
import 'node:os';
import 'node:events';
import 'node:diagnostics_channel';
import 'fs';
import 'events';
import 'util';
import 'path';
import 'assert';
import 'worker_threads';
import 'module';
import 'node:url';
import 'url';
import 'buffer';
import 'node:module';
import 'node:child_process';
import 'node:crypto';
import 'node:process';
import 'node:async_hooks';
import './index-IVoIz4D5.js';
import 'constants';
import 'stream';
import './config-B0nEjgSh.js';
import './json-DXl7iDYg.js';
import './lock-BoHF25mx.js';
import 'node:fs/promises';
import './index-Ca4C2M45.js';

//#region src/routes/api/credentials/+server.ts
/**
* Credential pool management endpoint for the Studio `/keys` UI.
*
* GET  /api/credentials
*   → `{ entries: SafeCredentialEntry[] }`
*
*   Returns every entry in the unified credential pool with all secret
*   material stripped (`accessToken`, `refreshToken`, `extraHeaders`,
*   `metadata` removed). Only the fields a human operator needs to
*   identify, audit, and remove a credential are exposed — provider,
*   label, source, authType, expiry, last-status, request count.
*
*   This is a deliberate write-only contract: there is NO API path
*   that returns credential values to a browser. Adding/rotating a
*   key MUST be done in-place via POST (the client sends the secret
*   in, never receives one back).
*
* POST /api/credentials
*   body: { provider: ProviderId, label: string, apiKey: string }
*   → `{ success: true, data: { provider, label } }`
*
*   Calls `@cleocode/core/llm/credentials-store#addCredential` with
*   `authType: 'api_key'` and `source: 'manual'`. The CredentialPool's
*   60s seed cache is invalidated by the underlying upsert because the
*   store mutation clears its internal Anthropic-key cache; the next
*   GET reflects the new entry immediately.
*
* SECURITY: this endpoint never returns credential values. Every
*  `SafeCredentialEntry` projection is constructed by hand so a future
*  refactor cannot accidentally spread `accessToken` into the response.
*
* @task T9426
* @epic E-CONFIG-AUTH-UNIFY (E3 §5.3 T-E3-7)
*/
/**
* Project a `StoredCredential` into the safe response shape.
*
* Implemented as an explicit field-by-field copy (rather than a `{ ...c }`
* spread minus deletions) so a future contributor adding a new secret
* field to `StoredCredential` cannot inadvertently leak it through this
* endpoint.
*
* @param c - Stored credential as returned by the pool's `list()`.
* @returns Safe projection with all secret material removed.
*
* @task T9426
*/
function toSafeEntry(c) {
	const entry = {
		provider: c.provider,
		label: c.label,
		source: c.source ?? "manual",
		authType: c.authType,
		priority: c.priority,
		expiresAt: c.expiresAt ?? null,
		disabled: c.disabled ?? false
	};
	if (c.lastStatus !== void 0) entry.lastStatus = c.lastStatus;
	if (c.lastErrorCode !== void 0) entry.lastErrorCode = c.lastErrorCode;
	if (c.lastErrorResetAt !== void 0) entry.lastErrorResetAt = c.lastErrorResetAt;
	if (c.requestCount !== void 0) entry.requestCount = c.requestCount;
	return entry;
}
/**
* Closed list of provider ids accepted by POST.
*
* Mirrors `BuiltinProviderId` from `@cleocode/contracts/llm/provider-id`.
* We do not import the type at runtime because `ProviderId` is open
* (`BuiltinProviderId | string & Record<never, never>`) — accepting an
* arbitrary string from the browser would let a caller spam the store
* with non-routable entries.
*
* @task T9426
*/
var ALLOWED_PROVIDERS = new Set([
	"anthropic",
	"openai",
	"gemini",
	"moonshot",
	"openrouter",
	"bedrock",
	"deepseek",
	"xai",
	"groq",
	"kimi-code",
	"ollama"
]);
/**
* GET /api/credentials — list pool entries (secrets stripped).
*
* @task T9426
*/
var GET = async () => {
	return json(ok({ entries: (await getCredentialPool().list()).map(toSafeEntry) }));
};
/**
* POST /api/credentials — upsert a manual API-key credential.
*
* Body: `{ provider, label, apiKey }`. The endpoint validates that
* `provider` is a recognised builtin, that `label` and `apiKey` are
* non-empty strings of reasonable length, and that `apiKey` does not
* leak whitespace. The credential is persisted with `source: 'manual'`
* and `authType: 'api_key'` so a subsequent `cleo auth remove` knows
* to dispatch to `MANUAL_REMOVAL_STEP`.
*
* @task T9426
*/
var POST = async ({ request }) => {
	const body = await parseJsonBody(request);
	if (isParseError(body)) return json(err("E_VALIDATION", body._parseError), { status: 400 });
	const providerR = requireString(body, "provider", 64);
	if (!providerR.ok) return json(err("E_VALIDATION", providerR.message), { status: 400 });
	const labelR = requireString(body, "label", 200);
	if (!labelR.ok) return json(err("E_VALIDATION", labelR.message), { status: 400 });
	const apiKeyR = requireString(body, "apiKey", 4096);
	if (!apiKeyR.ok) return json(err("E_VALIDATION", apiKeyR.message), { status: 400 });
	const provider = providerR.value.trim();
	if (!ALLOWED_PROVIDERS.has(provider)) return json(err("E_VALIDATION", `Unknown provider '${provider}'. Must be a CLEO builtin transport.`), { status: 400 });
	const label = labelR.value.trim();
	const apiKey = apiKeyR.value;
	if (apiKey !== apiKey.trim()) return json(err("E_VALIDATION", "apiKey must not have leading or trailing whitespace"), { status: 400 });
	try {
		await addCredential({
			provider,
			label,
			authType: "api_key",
			accessToken: apiKey,
			source: "manual"
		});
	} catch (e) {
		return json(err("E_WRITE_FAILED", `Failed to persist credential: ${e instanceof Error ? e.message : String(e)}`), { status: 500 });
	}
	return json(ok({
		provider,
		label
	}));
};

export { GET, POST };
//# sourceMappingURL=_server.ts-B6imN6ZX.js.map
