-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathprerequisitesCheck.ts
199 lines (182 loc) · 8.18 KB
/
prerequisitesCheck.ts
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import { createInterface } from "node:readline";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import chalk from "chalk";
import { Snowflake } from "discord.js";
// Create an interface for reading input from the command line
const rl = createInterface({
input: process.stdin,
output: process.stdout
});
// Error messages for invalid inputs
const tokenError = [
`\n${chalk.redBright("The Application Token provided is not valid.")}`,
`Please make sure you copied it correctly from the ${chalk.bold.whiteBright("Discord Developer Portal > Applications > Bot > Token.")}`,
`If you're not sure where that is, check this link - ${chalk.bold.cyanBright("https://discord.com/developers/applications")}\n`
];
const appIdError = [
`\n${chalk.redBright("The Application ID provided is not valid.")}`,
`Please make sure you copied it correctly from the ${chalk.bold.whiteBright(
"Discord Developer Portal > Applications > General Information > Application ID."
)}`,
`If you're not sure where that is, check this link - ${chalk.bold.cyanBright("https://discord.com/developers/applications")}\n`
];
const guildIdError = [
`\n${chalk.redBright("The Guild ID provided is not valid.")}`,
`Please make sure you copied it correctly from the server you want commands to be registered to.`,
`If you're not sure how to get the Guild ID, check this link - ${chalk.bold.cyanBright(
"https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-"
)}\n`
];
// Display environment variables and their current status
const envVars = [
chalk.underline.greenBright(`Environment variables:`),
`${chalk.whiteBright(`APPLICATION_TOKEN =`)} ${process.env.APPLICATION_TOKEN?.replace(process.env.APPLICATION_TOKEN, "( ͡° ͜ʖ ͡°)") || chalk.yellow("Not set")}`,
`${chalk.whiteBright(`APPLICATION_ID =`)} ${process.env.APPLICATION_ID || chalk.yellow("Not set")}`,
`${chalk.whiteBright(`GUILD_ID =`)} ${process.env.GUILD_ID || chalk.yellow("Not set")}\n`
];
/**
* Checks if the provided token matches the expected format.
* @param token - The token to validate.
* @returns True if the token is valid, false otherwise.
*/
function tokenCheck(token: string): boolean {
return /(?<snowflake>[\w-]{23,26})\.(?<timestamp>[\w-]{6})\.(?<hmac>[\w-]{27,38})/.test(token);
}
/**
* Checks if the provided parameter is a valid Snowflake ID.
* @param param - The parameter to validate.
* @returns True if the parameter is a valid Snowflake ID, false otherwise.
*/
function isSnowflake(param: Snowflake | string): param is Snowflake {
return /^(?:<@!?)?(\d{17,19})>?$/.test(param);
}
/**
* Prompts the user with a question and returns their response.
* @param question - The question to ask the user.
* @returns A promise that resolves with the user's response.
*/
async function promptUser(question: string): Promise<string> {
return new Promise((resolve, reject) => {
rl.question(question, (answer) => {
if (answer) {
resolve(answer);
} else {
reject(new Error("No answer provided"));
}
});
});
}
/**
* Checks if an environment variable is set, and if not, prompts the user to provide it.
* @param variable - The name of the environment variable to check.
* @param errorMessage - The error message to display if the variable is invalid.
* @param validationFn - An optional validation function to validate the variable's value.
* @param optional - Whether the environment variable is optional.
*/
async function checkEnvVariable(variable: string, errorMessage: string, validationFn?: (value: string) => boolean, optional = false): Promise<void> {
if (!process.env[variable]) {
if (optional) {
console.log(chalk.yellowBright(`⚠ ${variable} is not set. Skipping...`));
return;
}
try {
const value = await promptUser(`${chalk.redBright(`No ${variable} was provided.`)} \nEnter your ${variable} here to continue operation => `);
if (!value || (validationFn && !validationFn(value))) {
console.error(errorMessage);
throw new Error(errorMessage);
}
console.log(chalk.greenBright(`✅ ${variable} added.`), chalk.whiteBright("Continuing operation."));
overwriteLine(".env", variable, value);
} catch (error) {
console.error(chalk.redBright(`Failed to set ${variable}: ${error.message}`));
throw error;
}
}
}
/**
* Overwrites a line in the specified file with a new value.
* @param filePath - The path to the file.
* @param variable - The name of the variable to overwrite.
* @param newValue - The new value to set for the variable.
*/
function overwriteLine(filePath: string, variable: string, newValue: string): void {
try {
const lines = readFileSync(filePath, "utf-8").split("\n");
const index = lines.findIndex(line => line.startsWith(variable));
if (index !== -1) {
lines[index] = `${variable}=${newValue}`;
} else {
lines.push(`${variable}=${newValue}`);
}
writeFileSync(filePath, lines.join("\n"));
} catch (error) {
console.error(chalk.redBright(`Error writing to file ${filePath}: ${error.message}`));
throw error;
}
}
/**
* Creates a .env file with default values if it does not already exist.
*/
async function createEnvFile(): Promise<void> {
if (!existsSync(".env")) {
console.log(chalk.yellowBright("⚠ .env file not found."), chalk.whiteBright("Creating one now..."));
try {
writeFileSync(
".env",
`APPLICATION_TOKEN=\n# Your bot token\n\nGUILD_ID=\n# Only an ID here if you want commands to be registered in one server.\n\nAPPLICATION_ID=\n# Your bot's application ID (can be found on Discord or on the Discord Developer Portal)`
);
console.log(chalk.greenBright("✅ .env file created."));
} catch (error) {
console.error(chalk.redBright(`Failed to create .env file: ${error.message}`));
throw error;
}
} else {
console.log(chalk.yellowBright("✅ .env file already exists."), chalk.whiteBright("Continuing operation...\n"));
}
}
/**
* Asks the user if they want to register commands globally or per guild.
* If they choose per guild, prompts for the GUILD_ID.
*/
async function askForGuildId(): Promise<void> {
try {
const response = await promptUser("Do you want to register commands globally? (Y/N) ");
if (response.toLowerCase() === "y" || response.toLowerCase() === "yes") {
console.log(chalk.greenBright("✅ Commands will be registered globally. No Guild ID required.\n"));
} else if (response.toLowerCase() === "n" || response.toLowerCase() === "no") {
await checkEnvVariable("GUILD_ID", guildIdError.join("\n"), isSnowflake);
} else {
console.log(chalk.redBright("Invalid response. Please enter 'Y' or 'N'."));
await askForGuildId();
}
} catch (error) {
console.error(chalk.redBright(`Failed to get response for global commands: ${error.message}`));
throw error;
}
}
/**
* Main function to check prerequisites.
* Ensures that necessary environment variables are set and prompts the user if they are not.
*/
export async function prerequisitesCheck(): Promise<true | void> {
console.log(chalk.cyanBright("Starting prerequisites check...\n"));
try {
await createEnvFile();
} catch (error) {
console.error(chalk.redBright("Failed to create .env file. Exiting..."));
process.exit(1);
}
console.log(envVars.join("\n"));
try {
await checkEnvVariable("APPLICATION_TOKEN", tokenError.join("\n"), tokenCheck);
await checkEnvVariable("APPLICATION_ID", appIdError.join("\n"), isSnowflake);
await askForGuildId();
} catch (error) {
console.error(chalk.redBright("Prerequisite check failed. Exiting..."));
process.exit(1);
}
console.log(chalk.greenBright("✅ Prerequisite process complete. No issues were found."));
rl.close();
process.exit(0);
}
prerequisitesCheck();