mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-10-04 00:37:48 +08:00
- Shared checkAccessCode for validate-diagram, validate-model, parse-url, verify-access-code - parse-url: 5 MB streamed body limit; validate-diagram: 5 MB image limit - validate-model refuses redirects when private URLs are blocked - Admin settings state shared across module instances via globalThis - Server model ids: unique slugs (non-ASCII names encoded), duplicates rejected - Panel Bedrock credentials stored as ADMIN_AWS_* so the DynamoDB client keeps its own - Locale redirect keeps basePath and query; EdgeOne function drops open CORS and checks the access code - Providers payload reports whether .env sets a default model
97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import { checkAdminAuth } from "@/lib/admin/auth"
|
|
import {
|
|
AdminProvidersSchema,
|
|
deriveEnvUpdates,
|
|
loadAdminProviders,
|
|
maskAdminProviders,
|
|
mergeSecrets,
|
|
validateAdminProviders,
|
|
} from "@/lib/admin/providers"
|
|
import {
|
|
getEnvFallback,
|
|
isSettingsWritable,
|
|
saveSettings,
|
|
} from "@/lib/admin/settings"
|
|
import { loadEnvServerModelsConfig } from "@/lib/server-model-config"
|
|
|
|
export const runtime = "nodejs"
|
|
export const dynamic = "force-dynamic"
|
|
|
|
async function payload() {
|
|
// Env-based providers (AI_MODELS_CONFIG / ai-models.json) are shown
|
|
// read-only in the panel; their credentials live in the environment
|
|
const envConfig = await loadEnvServerModelsConfig()
|
|
const adminProviders = loadAdminProviders()
|
|
// A panel default overrides any env default (matches the merge in
|
|
// loadRawServerModelsConfig), so env stars must reflect that
|
|
const adminHasDefault = adminProviders.some(
|
|
(p) => p.isDefault && p.models.length > 0,
|
|
)
|
|
return {
|
|
writable: isSettingsWritable(),
|
|
providers: maskAdminProviders(adminProviders),
|
|
envProviders:
|
|
envConfig?.providers.map((p) => ({
|
|
name: p.name,
|
|
provider: p.provider,
|
|
models: p.models,
|
|
isDefault: !!p.default && !adminHasDefault,
|
|
})) ?? [],
|
|
// Whether .env sets a default model. getEnvFallback skips the value
|
|
// the panel overlays onto process.env, so a panel default doesn't count.
|
|
envHasDefaultModel: !!getEnvFallback("AI_MODEL"),
|
|
}
|
|
}
|
|
|
|
export async function GET(req: Request) {
|
|
const authError = checkAdminAuth(req)
|
|
if (authError) return authError
|
|
return Response.json(await payload())
|
|
}
|
|
|
|
export async function PUT(req: Request) {
|
|
const authError = checkAdminAuth(req)
|
|
if (authError) return authError
|
|
|
|
if (!isSettingsWritable()) {
|
|
return Response.json(
|
|
{
|
|
error: "Settings file is not writable on this deployment. Configure via environment variables instead.",
|
|
},
|
|
{ status: 503 },
|
|
)
|
|
}
|
|
|
|
let body: unknown
|
|
try {
|
|
body = await req.json()
|
|
} catch {
|
|
return Response.json({ error: "Invalid JSON body" }, { status: 400 })
|
|
}
|
|
|
|
const parsed = AdminProvidersSchema.safeParse(
|
|
(body as { providers?: unknown })?.providers,
|
|
)
|
|
if (!parsed.success) {
|
|
return Response.json(
|
|
{
|
|
error: `Invalid providers: ${parsed.error.issues[0]?.message ?? "schema mismatch"}`,
|
|
},
|
|
{ status: 400 },
|
|
)
|
|
}
|
|
|
|
const stored = loadAdminProviders()
|
|
const merged = mergeSecrets(parsed.data, stored)
|
|
|
|
const envConfig = await loadEnvServerModelsConfig()
|
|
const validationError = validateAdminProviders(merged, envConfig)
|
|
if (validationError) {
|
|
return Response.json({ error: validationError }, { status: 400 })
|
|
}
|
|
|
|
saveSettings(deriveEnvUpdates(merged, stored))
|
|
|
|
return Response.json(await payload())
|
|
}
|