From 4ef0517cb7f01b6afe18e6c1b693c1bb5d42cdab Mon Sep 17 00:00:00 2001 From: Keven Date: Tue, 9 Dec 2025 11:39:08 -0300 Subject: [PATCH] feat(Env): Ajusta para a api usar as varaiveis de ambiente --- Dockerfile-homologacao | 41 --------- env.bat | 12 +++ src/shared/actions/Env/EnvLoader.ts | 137 ++++++++++++++++++++++++++++ src/shared/services/api/Api.ts | 14 ++- 4 files changed, 155 insertions(+), 49 deletions(-) delete mode 100644 Dockerfile-homologacao create mode 100644 env.bat create mode 100644 src/shared/actions/Env/EnvLoader.ts diff --git a/Dockerfile-homologacao b/Dockerfile-homologacao deleted file mode 100644 index 42d7e81..0000000 --- a/Dockerfile-homologacao +++ /dev/null @@ -1,41 +0,0 @@ -# Etapa 1: Construir a aplicação -FROM node:20-alpine AS builder - -# Define o diretório de trabalho -WORKDIR /app - -# Copia os arquivos de configuração do pacote -COPY package.json package-lock.json ./ - -# Instala as dependências do projeto -RUN npm install - -# Copia todo o código da aplicação para o container -COPY . . - -# Constrói a aplicação com o output 'standalone' -RUN npm run build - -# Etapa 2: Executar a aplicação -# Usa uma imagem Node.js leve -FROM node:20-alpine AS runner - -# Define o diretório de trabalho -WORKDIR /app - -# Copia o diretório 'standalone' da etapa de build, que já contém o servidor e as dependências -# O diretório 'standalone' é a pasta .next/standalone gerada pela configuração 'output: standalone' -COPY --from=builder /app/.next/standalone ./ - -# Copia os arquivos públicos -COPY --from=builder /app/public ./public - -# Copia os arquivos estáticos gerados pelo build. É aqui que os arquivos CSS e JS ficam. -COPY --from=builder /app/.next/static ./.next/static - -# Expõe a porta padrão do Next.js -EXPOSE 3000 - -# Define o comando para iniciar a aplicação -# O 'start' do package.json não é necessário, o próprio servidor standalone já está no container -CMD ["node", "server.js"] diff --git a/env.bat b/env.bat new file mode 100644 index 0000000..b35e696 --- /dev/null +++ b/env.bat @@ -0,0 +1,12 @@ +@echo off +echo === Registrando variáveis de ambiente ORIUS_APP === + +setx ORIUS_APP_STATE "GO" +setx ORIUS_APP_API_URL "http://localhost:8000/" +setx ORIUS_APP_API_PREFIX "api/v1/" +setx ORIUS_APP_API_CONTENT_TYPE "application/json" + +echo. +echo Variáveis ORIUS_API registradas com sucesso! +echo Reinicie o terminal ou o computador para aplicar as alterações. +pause \ No newline at end of file diff --git a/src/shared/actions/Env/EnvLoader.ts b/src/shared/actions/Env/EnvLoader.ts new file mode 100644 index 0000000..92e23e8 --- /dev/null +++ b/src/shared/actions/Env/EnvLoader.ts @@ -0,0 +1,137 @@ +/** + * EnvLoader - Leitor universal de variáveis de ambiente + * Compatível com Windows, Linux e EasyPanel (Docker) + * + * Suporta prefixos (ex: ORIUS_APP_), conversão automática de tipos + * e acesso via ponto (ex: env.group("ORIUS_APP").api_url). + */ + +type EnvValue = string | number | boolean | object | null; + +class EnvLoader { + private static instance: EnvLoader; + private cache: Record = {}; + + private constructor() { + this.loadAll(); + } + + /** + * Singleton global + */ + public static getInstance(): EnvLoader { + if (!EnvLoader.instance) { + EnvLoader.instance = new EnvLoader(); + } + return EnvLoader.instance; + } + + /** + * Conversão automática de tipos + */ + private convert(value: string): EnvValue { + const trimmed = value.trim(); + + // Boolean + if (["true", "false"].includes(trimmed.toLowerCase())) { + return trimmed.toLowerCase() === "true"; + } + + // Inteiro + if (/^-?\d+$/.test(trimmed)) { + return parseInt(trimmed, 10); + } + + // Float + if (/^-?\d+\.\d+$/.test(trimmed)) { + return parseFloat(trimmed); + } + + // JSON + try { + const parsed = JSON.parse(trimmed); + if (typeof parsed === "object") return parsed; + } catch { + /* ignora */ + } + + return trimmed; + } + + /** + * Carrega todas as variáveis do sistema + */ + private loadAll(): void { + for (const [key, value] of Object.entries(process.env)) { + if (value !== undefined) { + this.cache[key] = this.convert(value); + } + } + } + + /** + * Recarrega variáveis (útil em hot reload) + */ + public reload(): void { + this.cache = {}; + this.loadAll(); + } + + /** + * Retorna todas as variáveis carregadas + */ + public all(): Record { + return this.cache; + } + + /** + * Retorna variável específica + */ + public get(key: string, required = true): EnvValue { + const value = this.cache[key]; + if (value === undefined) { + if (required) + throw new Error(`Variável de ambiente obrigatória não encontrada: ${key}`); + return null; + } + return value; + } + + /** + * Retorna variável com valor padrão + */ + public getOrDefault(key: string, defaultValue: T): T { + const value = this.get(key, false); + return (value ?? defaultValue) as T; + } + + /** + * Retorna todas as variáveis que começam com um prefixo (ex: ORIUS_APP_) + * Remove o prefixo e normaliza os nomes em minúsculo. + * Retorna um objeto acessível via ponto (Proxy). + */ + public group(prefix: string): Record { + const normalizedPrefix = prefix.toUpperCase().replace(/^_+|_+$/g, "") + "_"; + const groupData: Record = {}; + + for (const [key, value] of Object.entries(this.cache)) { + if (key.startsWith(normalizedPrefix)) { + const cleanKey = key.slice(normalizedPrefix.length).toLowerCase(); + groupData[cleanKey] = value; + } + } + + // Cria proxy para acesso via ponto, com mensagem amigável + return new Proxy(groupData, { + get(target, prop: string) { + if (prop in target) { + return target[prop]; + } + throw new Error(`Variável '${prop}' não encontrada no grupo '${prefix}'`); + }, + }); + } +} + +// Exporta instância única +export const env = EnvLoader.getInstance(); diff --git a/src/shared/services/api/Api.ts b/src/shared/services/api/Api.ts index 19e4ee6..feefdf3 100644 --- a/src/shared/services/api/Api.ts +++ b/src/shared/services/api/Api.ts @@ -1,32 +1,30 @@ -import Json from '@/shared/actions/json/Json'; import TokenGet from '@/shared/actions/token/TokenGet'; -import IConfig from '@/shared/interfaces/IConfig'; import ApiSchema from '@/shared/services/api/schemas/ApiSchema'; import ApiInterface from './interfaces/ApiInterface'; export default class API { private ApiSchema: ApiSchema; - private config: IConfig; constructor() { + // Classe validadora das informações this.ApiSchema = new ApiSchema(); - // Obtem as configurações da aplicação - this.config = Json.execute(); } public async send(data: ApiInterface) { + // Define os dados para envio const _data = data; try { + // Verifica se todos os dados estão corretos - this.ApiSchema.url = this.config.api.url; - this.ApiSchema.prefix = this.config.api.prefix; + this.ApiSchema.url = process.env.NEXT_PUBLIC_ORIUS_APP_API_URL; + this.ApiSchema.prefix = process.env.NEXT_PUBLIC_ORIUS_APP_API_PREFIX; this.ApiSchema.endpoint = _data.endpoint; - this.ApiSchema.contentType = this.config.api.content_type; + this.ApiSchema.contentType = process.env.NEXT_PUBLIC_ORIUS_APP_API_CONTENT_TYPE; this.ApiSchema.token = await TokenGet(); // Verifica se existem erros