Full-stack Next.js 16 app with three scraping pipelines: - AirScale CSV → Anymailfinder Bulk Decision Maker search - LinkedIn Sales Navigator → Vayne → Anymailfinder email enrichment - Apify Google SERP → domain extraction → Anymailfinder bulk enrichment Includes Docker multi-stage build + docker-compose for Coolify deployment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
52 lines
1.9 KiB
TypeScript
52 lines
1.9 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { prisma } from "@/lib/db";
|
|
import { encrypt, decrypt } from "@/lib/utils/encryption";
|
|
|
|
const SERVICES = ["anymailfinder", "apify", "vayne", "airscale"] as const;
|
|
|
|
export async function GET() {
|
|
try {
|
|
const creds = await prisma.apiCredential.findMany();
|
|
const result: Record<string, boolean> = {};
|
|
for (const svc of SERVICES) {
|
|
result[svc] = creds.some(c => c.service === svc && c.value);
|
|
}
|
|
return NextResponse.json(result);
|
|
} catch (err) {
|
|
console.error("GET /api/credentials error:", err);
|
|
return NextResponse.json({ anymailfinder: false, apify: false, vayne: false, airscale: false });
|
|
}
|
|
}
|
|
|
|
export async function POST(req: NextRequest) {
|
|
try {
|
|
const body = await req.json() as Record<string, string>;
|
|
for (const [service, value] of Object.entries(body)) {
|
|
if (!SERVICES.includes(service as typeof SERVICES[number])) continue;
|
|
if (value === null || value === undefined) continue;
|
|
await prisma.apiCredential.upsert({
|
|
where: { service },
|
|
create: { service, value: value ? encrypt(value) : "" },
|
|
update: { value: value ? encrypt(value) : "" },
|
|
});
|
|
}
|
|
return NextResponse.json({ ok: true });
|
|
} catch (err) {
|
|
console.error("POST /api/credentials error:", err);
|
|
return NextResponse.json({ error: "Failed to save credentials" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
// GET a specific decrypted value (for internal API use only)
|
|
export async function PUT(req: NextRequest) {
|
|
try {
|
|
const { service } = await req.json() as { service: string };
|
|
const cred = await prisma.apiCredential.findUnique({ where: { service } });
|
|
if (!cred) return NextResponse.json({ value: null });
|
|
return NextResponse.json({ value: decrypt(cred.value) });
|
|
} catch (err) {
|
|
console.error("PUT /api/credentials error:", err);
|
|
return NextResponse.json({ error: "Failed" }, { status: 500 });
|
|
}
|
|
}
|