From 24db804c7fb204d93cfbb4dcad1608a2f2b8d88f Mon Sep 17 00:00:00 2001 From: ChatonDeAru <823314+chatondearu@users.noreply.github.com> Date: Sun, 24 Mar 2024 00:01:09 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20use=20.env=20instead=20of=20json?= =?UTF-8?q?=20config=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 18 ++++++++++ .eslintrc.js | 1 + jest/config.js | 1 + package.json | 11 +++--- src/app/index.tsx | 20 ++++++++--- src/config/default.ts | 20 ----------- src/config/index.ts | 4 --- src/config/prod.ts | 14 -------- src/server/discordBot.ts | 61 ++++++++------------------------- src/server/gsheets/accessors.ts | 52 +++++++++------------------- src/server/index.ts | 30 ++++++++-------- src/server/secure.ts | 4 +-- src/services/accessors.ts | 35 +++++++++---------- src/types/index.d.ts | 9 +++++ webpack/base.config.ts | 2 ++ yarn.lock | 5 +++ 16 files changed, 121 insertions(+), 166 deletions(-) create mode 100644 .env.example delete mode 100755 src/config/default.ts delete mode 100755 src/config/index.ts delete mode 100755 src/config/prod.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0565f37 --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +## Google Cloud Platform Service Account +GCP_SERVICE_ACCOUNT_PRIVATE_KEY= +GCP_SERVICE_ACCOUNT_CLIENT_ID= +GCP_SERVICE_ACCOUNT_CLIENT_EMAIL= +GSHEET_ID= + +## Discord +DISCORD_TOKEN= +DISCORD_CLIENTID= +DISCORD_GUILDID= + +## Notifications +FORCE_ORANGE_PUBLIC_VAPID_KEY= +FORCE_ORANGE_PRIVATE_VAPID_KEY= + +## Environment +PORT=8080 +API_URL=http://fo.parisestludique.fr/api diff --git a/.eslintrc.js b/.eslintrc.js index 88bb4b1..e9a7d11 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -60,5 +60,6 @@ module.exports = { __LOCAL__: false, __REGISTER_DISCORD_COMMANDS__: false, __TEST__: false, + API_URL: false, }, } diff --git a/jest/config.js b/jest/config.js index 23e308f..5d25004 100644 --- a/jest/config.js +++ b/jest/config.js @@ -24,6 +24,7 @@ module.exports = { __LOCAL__: false, __REGISTER_DISCORD_COMMANDS__: false, __TEST__: true, + API_URL: "http://localhost:3000", }, maxConcurrency: 50, maxWorkers: 1, diff --git a/package.json b/package.json index d455f63..38ca4bb 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,12 @@ "npm": ">=6" }, "scripts": { - "dev": "yarn dev:build && nodemon ./public/server", - "ser": "yarn dev:build && node ./public/server", + "dev": "yarn dev:build && nodemon -r dotenv/config ./public/server", + "ser": "yarn dev:build && node -r dotenv/config ./public/server", "dev:build": "cross-env NODE_ENV=development webpack --config ./webpack/server.config.ts", - "local-start": "cross-env LOCAL=true yarn build && node ./public/server", - "discord-register": "cross-env REGISTER_DISCORD_COMMANDS=true yarn build && node ./public/server", - "start": "node ./public/server", + "local-start": "cross-env LOCAL=true yarn build && node -r dotenv/config ./public/server", + "discord-register": "cross-env REGISTER_DISCORD_COMMANDS=true yarn build && node -r dotenv/config ./public/server", + "start": "node -r dotenv/config ./public/server", "build": "run-s build:*", "build:server": "cross-env NODE_ENV=production webpack --config ./webpack/server.config.ts", "build:client": "cross-env NODE_ENV=production webpack --config ./webpack/client.config.ts", @@ -174,6 +174,7 @@ "compression-webpack-plugin": "^8.0.1", "css-loader": "^5.2.6", "css-minimizer-webpack-plugin": "^3.0.2", + "dotenv": "^16.4.5", "eslint": "^7.14.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^8.3.0", diff --git a/src/app/index.tsx b/src/app/index.tsx index f5a25bc..c2a0687 100755 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -2,7 +2,6 @@ import { RouteConfig, renderRoutes } from "react-router-config" import { Helmet } from "react-helmet" import { ToastContainer } from "react-toastify" -import config from "../config" // Import your global styles here import "normalize.css/normalize.css" import "react-toastify/dist/ReactToastify.css" @@ -24,9 +23,22 @@ const App = ({ route, location }: Route): JSX.Element => { } // else + const appInfo = { + htmlAttributes: { lang: "en" }, + title: "Force Orange", + description: "Le site des bénévoles", + titleTemplate: "Force Orange - %s", + meta: [ + { + name: "description", + content: "The best react universal starter boilerplate in the world.", + }, + ], + } + return (
- + {

- {config.APP.title} + {appInfo.title}

-
{config.APP.description}
+
{appInfo.description}
diff --git a/src/config/default.ts b/src/config/default.ts deleted file mode 100755 index aef34aa..0000000 --- a/src/config/default.ts +++ /dev/null @@ -1,20 +0,0 @@ -export default { - HOST: "localhost", - PORT: 3000, - API_URL: "http://localhost:3000", - GOOGLE_SHEET_ID: "1g-GB1NHLtUAQnQkbyo_5Lv6GzJ58DeOsUTrHlIVi01M", - APP: { - htmlAttributes: { lang: "en" }, - title: "Force Orange", - description: "Le site des bénévoles", - titleTemplate: "Force Orange - %s", - meta: [ - { - name: "description", - content: "The best react universal starter boilerplate in the world.", - }, - ], - }, - DEV_JWT_SECRET: "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!", - DEV_DISCORD_TOKEN: "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!", -} diff --git a/src/config/index.ts b/src/config/index.ts deleted file mode 100755 index dd5c122..0000000 --- a/src/config/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import defaultConfig from "./default" -import prodConfig from "./prod" - -export default __DEV__ ? defaultConfig : { ...defaultConfig, ...prodConfig } diff --git a/src/config/prod.ts b/src/config/prod.ts deleted file mode 100755 index 5c0d841..0000000 --- a/src/config/prod.ts +++ /dev/null @@ -1,14 +0,0 @@ -import isNode from "detect-node" - -const PROTOCOL = (typeof window !== "undefined" && window?.location?.protocol) || "http:" -const PORT = 4000 + (PROTOCOL === "https:" ? 2 : 0) -const API_URL = - __DEV__ || __LOCAL__ || isNode - ? `${PROTOCOL}//localhost:${PORT}` - : `${PROTOCOL}//fo.parisestludique.fr` - -export default { - PORT, - HOST: "0.0.0.0", - API_URL, -} diff --git a/src/server/discordBot.ts b/src/server/discordBot.ts index bdafc00..ffaa251 100644 --- a/src/server/discordBot.ts +++ b/src/server/discordBot.ts @@ -13,8 +13,6 @@ import { User, PartialUser, } from "discord.js" -import { promises as fs, constants } from "fs" -import path from "path" import { translationVolunteer, Volunteer, VolunteerWithoutId } from "../services/volunteers" import { @@ -23,13 +21,8 @@ import { DiscordRoleWithoutId, } from "../services/discordRoles" import { getSheet } from "./gsheets/accessors" -import config from "../config" -let cachedToken: string -// let cachedClientId: string -let cachedGuildId: string -const CREDS_PATH = path.resolve(process.cwd(), "access/discordToken.json") -getCreds() // Necessary until we can make async express middleware +const { DISCORD_TOKEN, DISCORD_CLIENTID, DISCORD_GUILDID } = process.env type Command = { data: SlashCommandBuilder @@ -52,19 +45,8 @@ const commands: Collection = new Collection() // }, // } -let hasDiscordAccessReturn: boolean | undefined -export async function hasDiscordAccess(): Promise { - if (hasDiscordAccessReturn !== undefined) { - return hasDiscordAccessReturn - } - try { - // eslint-disable-next-line no-bitwise - await fs.access(CREDS_PATH, constants.R_OK | constants.W_OK) - hasDiscordAccessReturn = true - } catch { - hasDiscordAccessReturn = false - } - return hasDiscordAccessReturn +export function hasDiscordAccess(): boolean { + return Boolean(DISCORD_TOKEN && DISCORD_CLIENTID && DISCORD_GUILDID) } // export async function discordRegisterCommands(): Promise { @@ -72,7 +54,7 @@ export async function hasDiscordAccess(): Promise { // return // } -// if (!(await hasDiscordAccess())) { +// if (!(hasDiscordAccess())) { // console.error(`Discord bot: no creds found, not running bot`) // return // } @@ -82,11 +64,11 @@ export async function hasDiscordAccess(): Promise { // const commandsToRegister = [] // commandsToRegister.push(userCommand.data.toJSON()) -// const rest = new REST({ version: '10' }).setToken(cachedToken) +// const rest = new REST({ version: '10' }).setToken(DISCORD_TOKEN) // try { // await rest.put( -// Routes.applicationGuildCommands(cachedClientId, cachedGuildId), +// Routes.applicationGuildCommands(DISCORD_CLIENTID, DISCORD_GUILDID), // { body: commandsToRegister }, // ) // } catch (error) { @@ -102,11 +84,10 @@ export async function discordBot(): Promise { return } - if (!(await hasDiscordAccess())) { + if (!hasDiscordAccess()) { console.error(`Discord bot: no creds found, not running bot`) return } - await getCreds() const client = new Client({ intents: [ @@ -158,7 +139,7 @@ export async function discordBot(): Promise { await setRolesFromEmoji(client, user, reaction, "remove") }) - client.login(cachedToken) + client.login(DISCORD_TOKEN) } catch (error) { console.error("Discord error", error) } @@ -205,6 +186,8 @@ async function setBotReactions(client: Client) { async function setAllRoles(client: Client) { try { + if (!DISCORD_GUILDID) return + const volunteerSheet = await getSheet( "Volunteers", new Volunteer(), @@ -216,8 +199,7 @@ async function setAllRoles(client: Client) { } const volunteerByDiscordId = _.mapKeys(volunteerList, (v) => v.discordId.toString()) - - const guild = await client.guilds.fetch(cachedGuildId) + const guild = await client.guilds.fetch(DISCORD_GUILDID) if (!guild || !guild.members.cache) { return @@ -356,6 +338,8 @@ async function setRolesFromEmoji( reaction: MessageReaction | PartialMessageReaction, action: "add" | "remove" ) { + if (!DISCORD_GUILDID) return + const discordRolesSheet = await getSheet( "DiscordRoles", new DiscordRole(), @@ -367,7 +351,7 @@ async function setRolesFromEmoji( } await client.guilds.fetch() - const guild = client.guilds.resolve(cachedGuildId) + const guild = client.guilds.resolve(DISCORD_GUILDID) if (!guild || !guild.members.cache) { return @@ -408,20 +392,3 @@ async function fetchPartial(reaction: MessageReaction | PartialMessageReaction): } return true } - -async function getCreds(): Promise { - if (!cachedToken) { - try { - const credsContent = await fs.readFile(CREDS_PATH) - const parsedCreds = credsContent && JSON.parse(credsContent.toString()) - if (!parsedCreds) { - return - } - cachedToken = parsedCreds.token - // cachedClientId = parsedCreds.clientId - cachedGuildId = parsedCreds.guildId - } catch (e: any) { - cachedToken = config.DEV_DISCORD_TOKEN - } - } -} diff --git a/src/server/gsheets/accessors.ts b/src/server/gsheets/accessors.ts index adb0302..4307dda 100644 --- a/src/server/gsheets/accessors.ts +++ b/src/server/gsheets/accessors.ts @@ -1,7 +1,5 @@ // eslint-disable-next-line max-classes-per-file -import path from "path" import _, { assign, pick } from "lodash" -import { promises as fs, constants } from "fs" import { GoogleSpreadsheet, GoogleSpreadsheetWorksheet } from "google-spreadsheet" import { SheetNames, saveLocalDb, loadLocalDb } from "./localDb" @@ -9,14 +7,10 @@ export { SheetNames } from "./localDb" // Test write attack with: wget --header='Content-Type:application/json' --post-data='{"prenom":"Pierre","nom":"SCELLES","email":"test@gmail.com","telephone":"0601010101","dejaBenevole":false,"commentaire":""}' http://localhost:3000/PostulantAdd -const CRED_PATH = path.resolve(process.cwd(), "access/gsheets.json") - const REMOTE_UPDATE_DELAY = 120000 const DELAY_BETWEEN_ATTEMPTS = 30000 const DELAY_BETWEEN_FIRST_LOAD = 1500 -let creds: string | undefined | null - export type ElementWithId = { id: number } & ElementNoId export const sheetNames = new SheetNames() @@ -25,23 +19,16 @@ export const sheetNames = new SheetNames() type SheetList = { [sheetName in keyof SheetNames]?: Sheet> } const sheetList: SheetList = {} -let hasGSheetsAccessReturn: boolean | undefined -export async function hasGSheetsAccess(): Promise { - if (hasGSheetsAccessReturn !== undefined) { - return hasGSheetsAccessReturn - } - try { - // eslint-disable-next-line no-bitwise - await fs.access(CRED_PATH, constants.R_OK | constants.W_OK) - hasGSheetsAccessReturn = true - } catch { - hasGSheetsAccessReturn = false - } - return hasGSheetsAccessReturn +export function hasGSheetsAccess(): boolean { + return Boolean( + process.env.GSHEET_ID && + process.env.GCP_SERVICE_ACCOUNT_CLIENT_EMAIL && + process.env.GCP_SERVICE_ACCOUNT_PRIVATE_KEY + ) } export async function checkGSheetsAccess(): Promise { - if (!(await hasGSheetsAccess())) { + if (!hasGSheetsAccess()) { console.error(`Google Sheets: no creds found, loading local database instead`) } } @@ -367,22 +354,17 @@ export class Sheet< private async getGSheet(attempts = 3): Promise { return tryNTimes( async () => { - if (creds === undefined) { - if (await hasGSheetsAccess()) { - const credsBuffer = await fs.readFile(CRED_PATH) - creds = credsBuffer?.toString() || null - } else { - creds = null - } + if (hasGSheetsAccess()) { + // Authentication + const doc = new GoogleSpreadsheet(process.env.GSHEET_ID) + await doc.useServiceAccountAuth({ + client_email: process.env.GCP_SERVICE_ACCOUNT_CLIENT_EMAIL || "", + private_key: process.env.GCP_SERVICE_ACCOUNT_PRIVATE_KEY || "", + }) + await doc.loadInfo() + return doc.sheetsByTitle[this.sheetName] } - if (creds === null) { - return null - } - // Authentication - const doc = new GoogleSpreadsheet("1g-GB1NHLtUAQnQkbyo_5Lv6GzJ58DeOsUTrHlIVi01M") - await doc.useServiceAccountAuth(JSON.parse(creds)) - await doc.loadInfo() - return doc.sheetsByTitle[this.sheetName] + return null }, () => null, attempts, diff --git a/src/server/index.ts b/src/server/index.ts index 96e32cc..22d32c2 100755 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -49,7 +49,7 @@ import { volunteerOnSiteInfo, } from "./gsheets/volunteers" import { wishListGet, wishAdd } from "./gsheets/wishes" -import config from "../config" + import { notificationsSubscribe, notificationMain } from "./notifications" import { /* discordRegisterCommands, */ discordBot, hasDiscordAccess } from "./discordBot" import checkAccess from "./checkAccess" @@ -202,7 +202,9 @@ if (validCertPath) { * Listen on provided port, on all network interfaces. */ servers.forEach(({ protocol, server }) => { - server.listen(protocol === "http" ? config.PORT : config.PORT + 2) + const port = Number(process.env.PORT) || 3000 + + server.listen(protocol === "http" ? port : port + 2) server.on("error", onError) server.on("listening", () => onListening(server)) }) @@ -227,13 +229,11 @@ function onListening(server: any) { addStatus("Server listening:", chalk.green(`✅ ${bind}`)) } -hasGSheetsAccess().then((hasApiAccess: boolean) => { - if (hasApiAccess) { - addStatus("Database:", chalk.green(`✅ online from Google Sheet`)) - } else { - addStatus("Database:", chalk.blue(`🚧 offline, simulated from local db file`)) - } -}) +if (hasGSheetsAccess()) { + addStatus("Database:", chalk.green(`✅ online from Google Sheet`)) +} else { + addStatus("Database:", chalk.blue(`🚧 offline, simulated from local db file`)) +} const hasSendGridApiAccess = !!process.env.SENDGRID_API_KEY if (hasSendGridApiAccess) { @@ -249,13 +249,11 @@ if (hasPushNotifAccess) { addStatus("Push notif:", chalk.blue(`🚧 offline, simulated`)) } -hasDiscordAccess().then((hasApiAccess: boolean) => { - if (hasApiAccess) { - addStatus("Discord bot:", chalk.green(`✅ online through discord.js`)) - } else { - addStatus("Discord bot:", chalk.blue(`🚧 no creds, disabled`)) - } -}) +if (hasDiscordAccess()) { + addStatus("Discord bot:", chalk.green(`✅ online through discord.js`)) +} else { + addStatus("Discord bot:", chalk.blue(`🚧 no creds, disabled`)) +} hasSecret().then((has: boolean) => { if (has) { diff --git a/src/server/secure.ts b/src/server/secure.ts index 4a5ddf5..8e8d354 100644 --- a/src/server/secure.ts +++ b/src/server/secure.ts @@ -3,8 +3,6 @@ import path from "path" import { constants, promises as fs } from "fs" import { verify, sign } from "jsonwebtoken" -import config from "../config" - type AuthorizedRequest = Request & { headers: { authorization: string } } let cachedSecret: string @@ -57,7 +55,7 @@ async function getSecret() { const secretContent = await fs.readFile(SECRET_PATH) cachedSecret = secretContent && JSON.parse(secretContent.toString()).secret } catch (e: any) { - cachedSecret = config.DEV_JWT_SECRET + cachedSecret = "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!" } } diff --git a/src/services/accessors.ts b/src/services/accessors.ts index 99ccc82..4739014 100644 --- a/src/services/accessors.ts +++ b/src/services/accessors.ts @@ -1,7 +1,6 @@ import axios from "axios" import _ from "lodash" -import config from "../config" import { axiosConfig } from "./auth" export type ElementWithId = unknown & { id: number } @@ -26,7 +25,7 @@ export default class ServiceAccessors< } return async (id: number): Promise => { try { - const { data } = await axios.get(`${config.API_URL}/${this.elementName}Get`, { + const { data } = await axios.get(`${API_URL}/${this.elementName}Get`, { ...axiosConfig, params: { id }, }) @@ -51,7 +50,7 @@ export default class ServiceAccessors< return async (): Promise => { try { const { data } = await axios.get( - `${config.API_URL}/${this.elementName}ListGet`, + `${API_URL}/${this.elementName}ListGet`, axiosConfig ) if (data.error) { @@ -77,7 +76,7 @@ export default class ServiceAccessors< const auth = { headers: { Authorization: `Bearer ${jwt}` } } const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig) const { data } = await axios.get( - `${config.API_URL}/${this.elementName}ListGet`, + `${API_URL}/${this.elementName}ListGet`, fullAxiosConfig ) if (data.error) { @@ -107,7 +106,7 @@ export default class ServiceAccessors< try { const auth = { headers: { Authorization: `Bearer ${jwt}` } } const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig) - const rawData = await axios.get(`${config.API_URL}/${this.elementName}${apiName}`, { + const rawData = await axios.get(`${API_URL}/${this.elementName}${apiName}`, { ...fullAxiosConfig, params, }) @@ -135,7 +134,7 @@ export default class ServiceAccessors< return async (volunteerWithoutId: ElementNoId): Promise => { try { const { data } = await axios.post( - `${config.API_URL}/${this.elementName}Add`, + `${API_URL}/${this.elementName}Add`, volunteerWithoutId, axiosConfig ) @@ -160,7 +159,7 @@ export default class ServiceAccessors< return async (volunteer: Element): Promise => { try { const { data } = await axios.post( - `${config.API_URL}/${this.elementName}Set`, + `${API_URL}/${this.elementName}Set`, volunteer, axiosConfig ) @@ -185,7 +184,7 @@ export default class ServiceAccessors< return async (): Promise => { try { const { data } = await axios.get( - `${config.API_URL}/${this.elementName}CountGet`, + `${API_URL}/${this.elementName}CountGet`, axiosConfig ) if (data.error) { @@ -210,10 +209,10 @@ export default class ServiceAccessors< } return async (...params: InputElements): Promise => { try { - const { data } = await axios.get( - `${config.API_URL}/${this.elementName}${apiName}`, - { ...axiosConfig, params } - ) + const { data } = await axios.get(`${API_URL}/${this.elementName}${apiName}`, { + ...axiosConfig, + params, + }) if (data.error) { throw Error(data.error) } @@ -237,7 +236,7 @@ export default class ServiceAccessors< return async (...params: InputElements): Promise => { try { const { data } = await axios.post( - `${config.API_URL}/${this.elementName}${apiName}`, + `${API_URL}/${this.elementName}${apiName}`, params, axiosConfig ) @@ -268,10 +267,10 @@ export default class ServiceAccessors< try { const auth = { headers: { Authorization: `Bearer ${jwt}` } } const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig) - const { data } = await axios.get( - `${config.API_URL}/${this.elementName}${apiName}`, - { ...fullAxiosConfig, params } - ) + const { data } = await axios.get(`${API_URL}/${this.elementName}${apiName}`, { + ...fullAxiosConfig, + params, + }) if (data.error) { throw Error(data.error) } @@ -300,7 +299,7 @@ export default class ServiceAccessors< const auth = { headers: { Authorization: `Bearer ${jwt}` } } const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig) const { data } = await axios.post( - `${config.API_URL}/${this.elementName}${apiName}`, + `${API_URL}/${this.elementName}${apiName}`, params, fullAxiosConfig ) diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 74fc31b..d7c7d54 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -4,6 +4,7 @@ declare const __DEV__: boolean declare const __LOCAL__: boolean declare const __REGISTER_DISCORD_COMMANDS__: boolean declare const __TEST__: boolean +declare const API_URL: string declare module "*.svg" declare module "*.gif" @@ -22,6 +23,7 @@ declare namespace NodeJS { __LOCAL__: boolean __REGISTER_DISCORD_COMMANDS__: boolean __TEST__: boolean + API_URL: string $RefreshReg$: () => void $RefreshSig$$: () => void } @@ -30,6 +32,13 @@ declare namespace NodeJS { SENDGRID_API_KEY?: string FORCE_ORANGE_PUBLIC_VAPID_KEY?: string FORCE_ORANGE_PRIVATE_VAPID_KEY?: string + PORT?: string + HOST?: string + API_URL?: string + GCP_SERVICE_ACCOUNT_CLIENT_ID?: string + GCP_SERVICE_ACCOUNT_PRIVATE_KEY?: string + GCP_SERVICE_ACCOUNT_CLIENT_EMAIL?: string + GSHEET_ID?: string } } diff --git a/webpack/base.config.ts b/webpack/base.config.ts index 1750fad..4057a42 100644 --- a/webpack/base.config.ts +++ b/webpack/base.config.ts @@ -10,6 +10,7 @@ import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer" export const isDev = process.env.NODE_ENV === "development" const isLocal = process.env.LOCAL === "true" const isRegisterDiscordCommands = process.env.REGISTER_DISCORD_COMMANDS === "true" + const getStyleLoaders = (isWeb: boolean, isSass?: boolean) => { let loaders: RuleSetUseItem[] = [ { @@ -51,6 +52,7 @@ const getPlugins = (isWeb: boolean) => { __DEV__: isDev, __LOCAL__: isLocal, __REGISTER_DISCORD_COMMANDS__: isRegisterDiscordCommands, + API_URL: process.env.API_URL || "'http://localhost:3000'", }), ] diff --git a/yarn.lock b/yarn.lock index 8963fcf..580a99a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4186,6 +4186,11 @@ domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" +dotenv@^16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + download@^6.2.2: version "6.2.5" resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714"