153 lines
4.1 KiB
TypeScript
153 lines
4.1 KiB
TypeScript
/**
|
|
* Bot API Key Management Routes
|
|
*
|
|
* POST /api/bots/[id]/api-key - Set/update LLM API key
|
|
* DELETE /api/bots/[id]/api-key - Remove API key
|
|
*
|
|
* Requirements: 2.1, 2.2, 2.4
|
|
*/
|
|
|
|
import { NextResponse } from 'next/server';
|
|
import { requireAuth } from '@/lib/auth';
|
|
import { z } from 'zod';
|
|
import {
|
|
getBotById,
|
|
userOwnsBot,
|
|
setApiKey,
|
|
removeApiKey,
|
|
BotNotFoundError,
|
|
BotValidationError,
|
|
} from '@/lib/bots/botManager';
|
|
|
|
type RouteContext = { params: Promise<{ id: string }> };
|
|
|
|
// Schema for setting API key
|
|
const setApiKeySchema = z.object({
|
|
apiKey: z.string().min(1, 'API key is required'),
|
|
provider: z.enum(['openrouter', 'openai', 'anthropic']).optional(),
|
|
});
|
|
|
|
/**
|
|
* POST /api/bots/[id]/api-key - Set/update LLM API key
|
|
*
|
|
* Requires authentication.
|
|
* Sets or updates the API key for the bot's LLM provider.
|
|
* The API key is validated and encrypted before storage.
|
|
*
|
|
* Validates: Requirements 2.1, 2.2, 2.4
|
|
*/
|
|
export async function POST(request: Request, context: RouteContext) {
|
|
try {
|
|
const user = await requireAuth();
|
|
const { id } = await context.params;
|
|
const body = await request.json();
|
|
const data = setApiKeySchema.parse(body);
|
|
|
|
// Check if user owns the bot
|
|
const isOwner = await userOwnsBot(user.id, id);
|
|
if (!isOwner) {
|
|
// Check if bot exists at all
|
|
const bot = await getBotById(id);
|
|
if (!bot) {
|
|
return NextResponse.json({ error: 'Bot not found' }, { status: 404 });
|
|
}
|
|
return NextResponse.json({ error: 'Not authorized' }, { status: 403 });
|
|
}
|
|
|
|
// Set the API key (validates format and encrypts)
|
|
await setApiKey(id, data.apiKey, data.provider);
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: 'API key updated successfully',
|
|
});
|
|
} catch (error) {
|
|
console.error('Set API key error:', error);
|
|
|
|
if (error instanceof z.ZodError) {
|
|
return NextResponse.json(
|
|
{ error: 'Invalid input', details: error.issues },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
if (error instanceof Error && error.message === 'Authentication required') {
|
|
return NextResponse.json({ error: 'Authentication required' }, { status: 401 });
|
|
}
|
|
|
|
if (error instanceof BotNotFoundError) {
|
|
return NextResponse.json(
|
|
{ error: error.message, code: error.code },
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
if (error instanceof BotValidationError) {
|
|
return NextResponse.json(
|
|
{ error: error.message, code: error.code },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
return NextResponse.json(
|
|
{ error: 'Failed to set API key' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DELETE /api/bots/[id]/api-key - Remove API key
|
|
*
|
|
* Requires authentication.
|
|
* Removes the API key from the bot, disabling LLM functionality.
|
|
*
|
|
* Note: Since the llmApiKeyEncrypted field is NOT NULL in the schema,
|
|
* this sets the key to an empty encrypted value, effectively disabling it.
|
|
*
|
|
* Validates: Requirements 2.4
|
|
*/
|
|
export async function DELETE(_request: Request, context: RouteContext) {
|
|
try {
|
|
const user = await requireAuth();
|
|
const { id } = await context.params;
|
|
|
|
// Check if user owns the bot
|
|
const isOwner = await userOwnsBot(user.id, id);
|
|
if (!isOwner) {
|
|
// Check if bot exists at all
|
|
const bot = await getBotById(id);
|
|
if (!bot) {
|
|
return NextResponse.json({ error: 'Bot not found' }, { status: 404 });
|
|
}
|
|
return NextResponse.json({ error: 'Not authorized' }, { status: 403 });
|
|
}
|
|
|
|
// Remove the API key
|
|
await removeApiKey(id);
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: 'API key removed successfully',
|
|
});
|
|
} catch (error) {
|
|
console.error('Remove API key error:', error);
|
|
|
|
if (error instanceof Error && error.message === 'Authentication required') {
|
|
return NextResponse.json({ error: 'Authentication required' }, { status: 401 });
|
|
}
|
|
|
|
if (error instanceof BotNotFoundError) {
|
|
return NextResponse.json(
|
|
{ error: error.message, code: error.code },
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
return NextResponse.json(
|
|
{ error: 'Failed to remove API key' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|