File size: 4,651 Bytes
cd6f98e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import crypto from "crypto";
import fs from "fs";
import chalk from "chalk";

export const generateEnv = (envValues) => {
  let isDockerCompose = envValues.runOption === "docker-compose";
  let dbPort = isDockerCompose ? 3307 : 3306;
  let platformUrl = isDockerCompose
    ? "http://host.docker.internal:8000"
    : "http://localhost:8000";

  const envDefinition = getEnvDefinition(
    envValues,
    isDockerCompose,
    dbPort,
    platformUrl
  );

  const envFileContent = generateEnvFileContent(envDefinition);
  saveEnvFile(envFileContent);
};

const getEnvDefinition = (envValues, isDockerCompose, dbPort, platformUrl) => {
  return {
    "Deployment Environment": {
      NODE_ENV: "development",
      NEXT_PUBLIC_VERCEL_ENV: "${NODE_ENV}",
    },
    NextJS: {
      NEXT_PUBLIC_BACKEND_URL: "http://localhost:8000",
      NEXT_PUBLIC_MAX_LOOPS: 100,
    },
    "Next Auth config": {
      NEXTAUTH_SECRET: generateAuthSecret(),
      NEXTAUTH_URL: "http://localhost:3000",
    },
    "Auth providers (Use if you want to get out of development mode sign-in)": {
      GOOGLE_CLIENT_ID: "***",
      GOOGLE_CLIENT_SECRET: "***",
      GITHUB_CLIENT_ID: "***",
      GITHUB_CLIENT_SECRET: "***",
      DISCORD_CLIENT_SECRET: "***",
      DISCORD_CLIENT_ID: "***",
    },
    Backend: {
      REWORKD_PLATFORM_ENVIRONMENT: "${NODE_ENV}",
      REWORKD_PLATFORM_FF_MOCK_MODE_ENABLED: false,
      REWORKD_PLATFORM_MAX_LOOPS: "${NEXT_PUBLIC_MAX_LOOPS}",
      REWORKD_PLATFORM_OPENAI_API_KEY:
        envValues.OpenAIApiKey || '"<change me>"',
      REWORKD_PLATFORM_FRONTEND_URL: "http://localhost:3000",
      REWORKD_PLATFORM_RELOAD: true,
      REWORKD_PLATFORM_OPENAI_API_BASE: "https://api.openai.com/v1",
      REWORKD_PLATFORM_SERP_API_KEY: envValues.serpApiKey || '""',
      REWORKD_PLATFORM_REPLICATE_API_KEY: envValues.replicateApiKey || '""',
    },
    "Database (Backend)": {
      REWORKD_PLATFORM_DATABASE_USER: "reworkd_platform",
      REWORKD_PLATFORM_DATABASE_PASSWORD: "reworkd_platform",
      REWORKD_PLATFORM_DATABASE_HOST: "agentgpt_db",
      REWORKD_PLATFORM_DATABASE_PORT: dbPort,
      REWORKD_PLATFORM_DATABASE_NAME: "reworkd_platform",
      REWORKD_PLATFORM_DATABASE_URL:
        "mysql://${REWORKD_PLATFORM_DATABASE_USER}:${REWORKD_PLATFORM_DATABASE_PASSWORD}@${REWORKD_PLATFORM_DATABASE_HOST}:${REWORKD_PLATFORM_DATABASE_PORT}/${REWORKD_PLATFORM_DATABASE_NAME}",
    },
    "Database (Frontend)": {
      DATABASE_USER: "reworkd_platform",
      DATABASE_PASSWORD: "reworkd_platform",
      DATABASE_HOST: "agentgpt_db",
      DATABASE_PORT: dbPort,
      DATABASE_NAME: "reworkd_platform",
      DATABASE_URL:
        "mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}",
    },
  };
};

const generateEnvFileContent = (config) => {
  let configFile = "";

  Object.entries(config).forEach(([section, variables]) => {
    configFile += `# ${section}:\n`;
    Object.entries(variables).forEach(([key, value]) => {
      configFile += `${key}=${value}\n`;
    });
    configFile += "\n";
  });

  return configFile.trim();
};

const generateAuthSecret = () => {
  const length = 32;
  const buffer = crypto.randomBytes(length);
  return buffer.toString("base64");
};

const ENV_PATH = "../next/.env";
const BACKEND_ENV_PATH = "../platform/.env";

export const doesEnvFileExist = () => {
  return fs.existsSync(ENV_PATH);
};

// Read the existing env file, test if it is missing any keys or contains any extra keys
export const testEnvFile = () => {
  const data = fs.readFileSync(ENV_PATH, "utf8");

  // Make a fake definition to compare the keys of
  const envDefinition = getEnvDefinition({}, "", "", "", "");

  const lines = data
    .split("\n")
    .filter((line) => !line.startsWith("#") && line.trim() !== "");
  const envKeysFromFile = lines.map((line) => line.split("=")[0]);

  const envKeysFromDef = Object.entries(envDefinition).flatMap(
    ([section, entries]) => Object.keys(entries)
  );

  const missingFromFile = envKeysFromDef.filter(
    (key) => !envKeysFromFile.includes(key)
  );

  if (missingFromFile.length > 0) {
    let errorMessage = "\nYour ./next/.env is missing the following keys:\n";
    missingFromFile.forEach((key) => {
      errorMessage += chalk.whiteBright(`- ❌  ${key}\n`);
    });
    errorMessage += "\n";

    errorMessage += chalk.red(
      "We recommend deleting your .env file(s) and restarting this script."
    );
    throw new Error(errorMessage);
  }
};

export const saveEnvFile = (envFileContent) => {
  fs.writeFileSync(ENV_PATH, envFileContent);
  fs.writeFileSync(BACKEND_ENV_PATH, envFileContent);
};