Skip to content

Variables de Entorno

Wabot ofrece dos mecanismos para leer variables de entorno según el contexto:

  • Env — clase inyectable para leer env vars dentro de servicios y constructores.
  • Config helpers (str, num, bool, …) — funciones para pasar env vars directamente en argumentos de decoradores, donde no es posible inyectar dependencias.

Conceptos clave

  • Env: singleton que encapsula el acceso a process.env.
  • requireString(name, options?): obtiene una variable como string (lanza error si no existe y no tiene default).
  • requireNumber(name, options?): obtiene una variable como number.
  • isDevelopment(), isProduction(), isTesting(): verifican el entorno actual basándose en WABOT_ENV.

Lectura de variables

import { Env, singleton } from '@wabot-dev/framework'
@singleton()
export class AppConfig {
readonly databaseUrl: string
readonly port: number
readonly apiKey: string
readonly maxRetries: number
constructor(env: Env) {
// Requerida — lanza error si no existe
this.databaseUrl = env.requireString('DATABASE_URL')
// Con valor por defecto
this.port = env.requireNumber('PORT', { default: 3000 })
this.apiKey = env.requireString('API_KEY', { default: 'dev-key' })
this.maxRetries = env.requireNumber('MAX_RETRIES', { default: 3 })
}
}

Entornos de ejecución

La variable WABOT_ENV controla el entorno. Los valores válidos son:

ValorMétodoDescripción
developmentisDevelopment()Desarrollo local (default si no se define)
stagingPre-producción
testingisTesting()Ejecución de tests
productionisProduction()Producción
import { Env, injectable } from '@wabot-dev/framework'
@injectable()
export class LoggingService {
constructor(private env: Env) {}
log(message: string) {
if (this.env.isDevelopment()) {
console.log(`[DEV] ${message}`)
}
if (this.env.isProduction()) {
// Enviar a servicio de logging externo
this.sendToCloudLogging(message)
}
}
}

Variables del framework

Wabot usa estas variables internamente:

VariableTipoDefaultDescripción
WABOT_ENVstringdevelopmentEntorno de ejecución
PORTnumber3000Puerto del servidor HTTP
JWT_SECRETstringClave secreta para JWT (requerida si usas auth)
JWT_ALGORITHMstringHS256Algoritmo de firma JWT
JWT_ACCESS_EXPIRATION_SECONDSnumber600Expiración del access token
JWT_REFRESH_EXPIRATION_SECONDSnumber31536000Expiración del refresh token
SOCKET_CORS_ORIGINstring— (CORS deshabilitado)Orígenes CORS para WebSocket: * o lista separada por comas
DATABASE_URLstringURL de conexión a PostgreSQL

Ejemplo completo

Configurar un servicio que se comporta diferente según el entorno:

import { Env, singleton, Logger } from '@wabot-dev/framework'
@singleton()
export class PaymentGateway {
private readonly apiUrl: string
private readonly apiKey: string
private readonly sandbox: boolean
private logger = new Logger('wabot:payments')
constructor(env: Env) {
this.sandbox = !env.isProduction()
if (env.isProduction()) {
this.apiUrl = env.requireString('PAYMENT_API_URL')
this.apiKey = env.requireString('PAYMENT_API_KEY')
} else {
this.apiUrl = env.requireString('PAYMENT_API_URL', {
default: 'https://sandbox.payments.example.com',
})
this.apiKey = env.requireString('PAYMENT_API_KEY', {
default: 'sandbox-test-key',
})
}
this.logger.info('PaymentGateway inicializado', {
sandbox: this.sandbox,
url: this.apiUrl,
})
}
async charge(amount: number, currency: string) {
if (this.sandbox) {
this.logger.debug('Pago simulado (sandbox)', { amount, currency })
return { success: true, transactionId: 'sandbox-' + Date.now() }
}
// Lógica real de cobro
const response = await fetch(`${this.apiUrl}/charge`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount, currency }),
})
return await response.json()
}
}

Config helpers para decoradores

Los decoradores en TypeScript se evalúan cuando el módulo se carga, antes de que el contenedor DI exista. Esto significa que no puedes inyectar Env dentro de un argumento de decorador. Para ese caso existen los config helpers.

Los config helpers son funciones de template tag que crean una referencia diferida a una variable de entorno. El framework la resuelve automáticamente cuando el decorador se registra.

Sintaxis

import { str, num, bool, strArr } from '@wabot-dev/framework'
str`ruta.al.valor` // string requerido
str`ruta.al.valor:default` // string con valor por defecto
num`ruta.al.valor:3000` // número con valor por defecto
bool`ruta.al.valor:false` // boolean con valor por defecto
strArr`ruta.al.valor` // array de strings (separados por comas o JSON)

Conversión de ruta a nombre de variable

El framework convierte la ruta a mayúsculas reemplazando puntos por guiones bajos:

Config helperVariable de entorno
str\whatsapp.number“WHATSAPP_NUMBER
str\telegram.bot_token“TELEGRAM_BOT_TOKEN
str\socket.namespace“SOCKET_NAMESPACE
num\server.port:3000“SERVER_PORT
bool\feature.enabled:false“FEATURE_ENABLED

Uso en decoradores de canal

Los decoradores @whatsApp() y @socket() aceptan config helpers directamente en sus argumentos. Esto evita escribir process.env.X! y centraliza toda la configuración en variables de entorno:

import { chatController, chatBot, ChatBot, cmd, whatsApp, socket, str, type IReceivedMessage } from '@wabot-dev/framework'
import { MyMindset } from '@/mindsets/MyMindset'
@chatController()
export class MyChatController {
constructor(@chatBot(MyMindset) private bot: ChatBot) {}
// Sin config helper — funciona, pero es frágil
@whatsApp({ number: process.env.WHATSAPP_NUMBER! })
onWhatsAppMessage(ctx: IReceivedMessage) {
this.bot.sendMessage(ctx.message, (reply) => ctx.reply(reply))
}
}
import { chatController, chatBot, ChatBot, whatsApp, telegram, socket, str, type IReceivedMessage } from '@wabot-dev/framework'
import { MyMindset } from '@/mindsets/MyMindset'
@chatController()
export class MyChatController {
constructor(@chatBot(MyMindset) private bot: ChatBot) {}
// Con config helper — tipado, con mensajes de error claros si falta la variable
@whatsApp({
number: str`whatsapp.number`, // WHATSAPP_NUMBER
accessToken: str`whatsapp.access_token`, // WHATSAPP_ACCESS_TOKEN
businessNumberId: str`whatsapp.business_number_id`, // WHATSAPP_BUSINESS_NUMBER_ID
})
onWhatsAppMessage(ctx: IReceivedMessage) {
this.bot.sendMessage(ctx.message, (reply) => ctx.reply(reply))
}
@socket({
namespace: str`socket.namespace:chat`, // SOCKET_NAMESPACE, default: 'chat'
})
onSocketMessage(ctx: IReceivedMessage) {
this.bot.sendMessage(ctx.message, (reply) => ctx.reply(reply))
}
}

Nota: @telegram() también admite config helpers: @telegram({ botToken: str\telegram.bot_token` })resuelveTELEGRAM_BOT_TOKEN`.

Helpers disponibles

HelperTipo resueltoEjemplo
strstringstr\api.key“
numnumbernum\server.port:3000“
boolbooleanbool\feature.enabled:false“
objobject (JSON)obj\service.config“
strArrstring[]strArr\allowed.origins“
numArrnumber[]numArr\retry.delays“
boolArrboolean[]boolArr\feature.flags“

Para arrays, el valor en la variable de entorno puede ser JSON (["a","b"]) o valores separados por comas (a,b).


Siguiente paso

Agrega logging estructurado a tu aplicación: Logger.