swadhinbiswas feat: implement air-gapped mode, UI fixes, and project management integrations · 7/9/2026
e3bd4a1
91 lines · 2.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import type { APIRoute } from "astro";
import { saveConfig, isConfigured } from "@/lib/config";
import { exec } from "child_process";
import { promisify } from "util";
import bcrypt from "bcryptjs";
import { getDatabase, resetDatabase, schema } from "@/db";
import { createSession } from "@/lib/auth";
import crypto from "crypto";

const execAsync = promisify(exec);

export const POST: APIRoute = async ({ request, cookies }) => {
  try {
    // If already configured, prevent re-setup
    if (isConfigured()) {
      return new Response(JSON.stringify({ error: "Already configured" }), {
        status: 403,
        headers: { "Content-Type": "application/json" }
      });
    }

    const data = await request.json();
    const { database, cache, admin } = data;

    if (!admin?.username || !admin?.email || !admin?.password) {
      return new Response(JSON.stringify({ error: "Admin credentials missing" }), { status: 400 });
    }

    // 1. Save config which sets process.env overrides
    saveConfig({
      DATABASE_URL: database.url,
      DATABASE_DRIVER: database.driver,
      REDIS_URL: cache.url
    });

    // 2. Run Drizzle migrations
    try {
      console.log("Pushing database schema...");
      await execAsync("bun run db:push", {
        env: {
          ...process.env,
          DATABASE_URL: database.url,
          DATABASE_DRIVER: database.driver
        }
      });
    } catch (pushError: any) {
      console.error("Database schema push failed", pushError);
      return new Response(JSON.stringify({ error: "Failed to initialize database: " + pushError.message }), { status: 500 });
    }

    // 3. Connect to DB and Create Admin User
    resetDatabase();
    const db = getDatabase();
    const hashedPassword = await bcrypt.hash(admin.password, 10);
    const userId = crypto.randomUUID();

    await (db as any).insert(schema.users).values({
      id: userId,
      username: admin.username,
      email: admin.email,
      passwordHash: hashedPassword,
      displayName: admin.username,
      isAdmin: true,
      isActive: true,
      emailVerified: true
    });

    // 4. Log the user in (create session)
    const sessionCookie = await createSession(userId);
    cookies.set("och_session", sessionCookie, {
      path: "/",
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "lax",
      maxAge: 60 * 60 * 24 * 30, // 30 days
    });

    return new Response(JSON.stringify({ success: true }), {
      status: 200,
      headers: { "Content-Type": "application/json" }
    });

  } catch (err: any) {
    console.error("Setup error:", err);
    return new Response(JSON.stringify({ error: err.message || "Internal server error" }), {
      status: 500,
      headers: { "Content-Type": "application/json" }
    });
  }
};