npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jamx-framework/config

v2.0.0

Published

JAMX Framework — centralized configuration

Readme

@jamx-framework/config

Descripción

Módulo de configuración centralizada para JAMX Framework. Proporciona un sistema tipado y con valores por defecto para configurar todos los aspectos de una aplicación JAMX: servidor, base de datos, autenticación, seguridad, i18n, UI y plugins. Incluye carga desde jamx.config.ts, validación de tipos, y un gestor de configuración para acceso global.

Cómo funciona

El módulo maneja la configuración en tres capas:

  1. Tipos: Definiciones TypeScript completas para todas las opciones de configuración
  2. defineConfig: Función que aplica valores por defecto y valida la estructura
  3. ConfigManager: Clase para cargar, almacenar y acceder a la configuración en runtime
  4. loadConfig: Función asíncrona que carga jamx.config.ts desde el sistema de archivos

Componentes principales

Tipos (src/index.ts)

  • Target: Plataformas de compilación ("web", "ios", "android", "desktop")
  • StylingMode: Modo de estilos ("jamx-native", "tailwind", "external", "none")
  • DatabaseDriver: Drivers de BD ("postgresql", "mysql", "sqlite")
  • SessionEngine: Motor de sesiones ("jwt", "database", "redis")
  • AuthStrategy: Estrategias de autenticación
  • JamxConfig: Interfaz principal de configuración
  • DatabaseConnection: Configuración de conexión a BD

Funciones

defineConfig

function defineConfig(config: JamxConfig): JamxConfig

Aplica defaults y retorna una configuración validada.

loadConfig

async function loadConfig(projectRoot: string): Promise<JamxConfig>

Carga jamx.config.ts desde el sistema de archivos.

Clase ConfigManager

class ConfigManager {
  async load(source?: JamxConfig | string): Promise<JamxConfig>;
  get(): JamxConfig;
  section<K extends keyof JamxConfig>(key: K): JamxConfig[K];
  readonly env: string;
  readonly isDev: boolean;
  readonly isProd: boolean;
}

Gestor de configuración con acceso por secciones y helpers de entorno.

Uso básico

Definir configuración en jamx.config.ts

import { defineConfig } from '@jamx-framework/config';

export default defineConfig({
  targets: ['web', 'ios'],
  server: {
    port: 3000,
    host: 'localhost',
    cors: {
      enabled: true,
      origins: ['https://example.com'],
    },
  },
  database: {
    primary: {
      driver: 'postgresql',
      url: 'postgresql://user:pass@localhost:5432/db',
    },
  },
  auth: {
    strategies: ['credentials', 'oauth2'],
    session: {
      engine: 'jwt',
      duration: '7d',
      secret: process.env.JWT_SECRET,
    },
    pages: {
      login: '/login',
      logout: '/logout',
      register: '/register',
    },
  },
  security: {
    csrf: true,
    rateLimit: {
      enabled: true,
      max: 100,
      window: '1m',
    },
    headers: {
      hsts: true,
      frameOptions: 'DENY',
      contentTypeSniff: true,
    },
  },
  i18n: {
    defaultLocale: 'es',
    locales: ['es', 'en', 'fr'],
    strategy: 'prefix',
  },
  ui: {
    styling: {
      mode: 'tailwind',
    },
  },
});

Usar ConfigManager en la aplicación

import { ConfigManager } from '@jamx-framework/config';

const configManager = new ConfigManager();

// Cargar desde archivo
await configManager.load('./'); // busca jamx.config.ts

// O cargar desde objeto
await configManager.load({
  targets: ['web'],
  server: { port: 8080 },
});

// Acceder a la configuración completa
const config = configManager.get();
console.log(config.server?.port); // 3000 (default) o 8080

// Acceder a una sección
const serverConfig = configManager.section('server');
console.log(serverConfig.port);

// Verificar entorno
if (configManager.isDev) {
  console.log('Modo desarrollo');
}

if (configManager.isProd) {
  console.log('Modo producción');
}

Usar defineConfig directamente

import { defineConfig } from '@jamx-framework/config';

const config = defineConfig({
  targets: ['web'],
  // solo especificamos lo que necesitamos
});

console.log(config.server?.port); // 3000 (default aplicado)
console.log(config.ui?.styling?.mode); // "jamx-native" (default)
console.log(config.security?.csrf); // true (default)

Acceder a configuración en módulos

// En un módulo de base de datos
import { ConfigManager } from '@jamx-framework/config';

const configManager = new ConfigManager();
const dbConfig = configManager.section('database');

const connection = dbConfig.primary;
if (connection?.driver === 'postgresql') {
  // conectar a PostgreSQL
}

API Reference

Tipos

Target

type Target = "web" | "ios" | "android" | "desktop";

Plataformas de compilación objetivo.

StylingMode

type StylingMode = "jamx-native" | "tailwind" | "external" | "none";

Modo de estilos de la aplicación.

DatabaseDriver

type DatabaseDriver = "postgresql" | "mysql" | "sqlite";

Drivers de base de datos soportados.

SessionEngine

type SessionEngine = "jwt" | "database" | "redis";

Motor de gestión de sesiones.

AuthStrategy

type AuthStrategy =
  | "credentials"
  | "oauth2"
  | "magic-link"
  | "passkey"
  | "saml";

Estrategias de autenticación disponibles.

JamxConfig

interface JamxConfig {
  targets: Target[];
  server?: {
    port?: number;
    host?: string;
    cors?: { enabled?: boolean; origins?: string[] };
  };
  ui?: {
    styling?: { mode?: StylingMode };
  };
  database?: {
    primary?: DatabaseConnection;
    [key: string]: DatabaseConnection | undefined;
  };
  auth?: {
    strategies?: AuthStrategy[];
    session?: { engine?: SessionEngine; duration?: string; secret?: string };
    pages?: { login?: string; logout?: string; register?: string };
  };
  security?: {
    csrf?: boolean;
    rateLimit?: { enabled?: boolean; max?: number; window?: string };
    headers?: {
      hsts?: boolean;
      frameOptions?: "DENY" | "SAMEORIGIN";
      contentTypeSniff?: boolean;
    };
  };
  i18n?: {
    defaultLocale?: string;
    locales?: string[];
    strategy?: "prefix" | "prefix-except-default" | "domain";
  };
  plugins?: unknown[];
}

DatabaseConnection

interface DatabaseConnection {
  driver: DatabaseDriver;
  url: string;
}

Funciones

defineConfig

function defineConfig(config: JamxConfig): JamxConfig

Aplica valores por defecto a la configuración y la retorna validada.

Defaults aplicados:

  • targets: Requerido, sin default
  • server.port: 3000
  • server.host: "localhost"
  • server.cors.enabled: false
  • server.cors.origins: []
  • ui.styling.mode: "jamx-native"
  • security.csrf: true
  • security.rateLimit.enabled: true
  • security.rateLimit.max: 100
  • security.rateLimit.window: "1m"

loadConfig

async function loadConfig(projectRoot: string): Promise<JamxConfig>

Carga la configuración desde jamx.config.ts en projectRoot.

Comportamiento:

  • Busca jamx.config.ts en projectRoot
  • Importa el módulo ES
  • Espera un default export o named export config
  • Lanza error si no encuentra o no es un objeto
  • Internamente llama a defineConfig para aplicar defaults

Ejemplo:

// jamx.config.ts
export default {
  targets: ['web'],
  server: { port: 8080 },
};

// En código
const config = await loadConfig('/path/to/project');
// config.server.port === 8080

Clase ConfigManager

Constructor

new ConfigManager()

Crea un gestor vacío.

load

async load(source?: JamxConfig | string): Promise<JamxConfig>

Carga la configuración desde:

  • Objeto JamxConfig: aplica defineConfig
  • Ruta de proyecto (string): llama a loadConfig(source)
  • Sin argumentos: crea config mínima con { targets: ['web'] }

get

get(): JamxConfig

Retorna la configuración cargada. Lanza error si no se ha llamado load() antes.

section

section<K extends keyof JamxConfig>(key: K): JamxConfig[K]

Accede a una sección específica de la configuración.

Ejemplo:

const server = configManager.section('server');
const port = server?.port;

Getters de conveniencia

readonly env: string;      // NODE_ENV o "development"
readonly isDev: boolean;   // true si env === "development"
readonly isProd: boolean;  // true si env === "production"

Estructura de JamxConfig

targets

Array de plataformas a compilar:

targets: ['web'];                    // solo web
targets: ['web', 'ios', 'android']; // multiplataforma

server

Configuración del servidor de desarrollo/producción:

server: {
  port: 3000,           // puerto HTTP
  host: 'localhost',    // host para binding
  cors: {
    enabled: true,      // habilitar CORS
    origins: ['*'],     // orígenes permitidos
  },
}

ui

Configuración de interfaz de usuario:

ui: {
  styling: {
    mode: 'tailwind', // 'jamx-native' | 'tailwind' | 'external' | 'none'
  },
}

database

Configuración de bases de datos:

database: {
  primary: {
    driver: 'postgresql', // 'postgresql' | 'mysql' | 'sqlite'
    url: 'postgresql://...',
  },
  // conexiones adicionales
  analytics: {
    driver: 'mysql',
    url: 'mysql://...',
  },
}

auth

Configuración de autenticación:

auth: {
  strategies: ['credentials', 'oauth2'],
  session: {
    engine: 'jwt',      // 'jwt' | 'database' | 'redis'
    duration: '7d',     // TTL de sesión
    secret: 'secret',   // secreto para firmar tokens
  },
  pages: {
    login: '/login',
    logout: '/logout',
    register: '/register',
  },
}

security

Configuración de seguridad:

security: {
  csrf: true, // habilitar protección CSRF
  rateLimit: {
    enabled: true,
    max: 100,      // requests por ventana
    window: '1m',  // '1s', '1m', '1h', etc.
  },
  headers: {
    hsts: true,               // HTTP Strict Transport Security
    frameOptions: 'DENY',     // X-Frame-Options
    contentTypeSniff: true,   // X-Content-Type-Options
  },
}

i18n

Configuración de internacionalización:

i18n: {
  defaultLocale: 'es',
  locales: ['es', 'en', 'fr'],
  strategy: 'prefix', // 'prefix' | 'prefix-except-default' | 'domain'
}

plugins

Array de configuraciones de plugins:

plugins: [
  { name: 'my-plugin', options: { ... } },
  { name: 'another-plugin', options: { ... } },
]

Flujo de carga de configuración

1. Desde archivo (recomendado)

// jamx.config.ts
import { defineConfig } from '@jamx-framework/config';

export default defineConfig({
  targets: ['web'],
  server: { port: 3000 },
});

// En la aplicación
const manager = new ConfigManager();
await manager.load('./'); // carga desde directorio actual
const config = manager.get();

2. Desde objeto

const manager = new ConfigManager();
await manager.load({
  targets: ['web', 'ios'],
  server: { port: 8080 },
});
const config = manager.get();

3. Directo con defineConfig

import { defineConfig } from '@jamx-framework/config';

const config = defineConfig({
  targets: ['web'],
});
// config ya tiene defaults aplicados

Validación y defaults

Validación

  • defineConfig valida que targets esté presente
  • Verifica que los objetos anidados tengan la estructura correcta
  • No valida valores específicos (ej: puerto válido), solo tipos

Defaults

Los defaults se aplican en capas:

  1. Nivel raíz: targets es requerido, no tiene default
  2. Nivel objeto: Si server existe, se aplican defaults a sus propiedades
  3. Nivel propiedad: Cada propiedad tiene su propio default

Ejemplo:

const config = defineConfig({ targets: ['web'] });

// Aplicados:
// config.server.port === 3000
// config.server.host === 'localhost'
// config.server.cors.enabled === false
// config.ui.styling.mode === 'jamx-native'
// config.security.csrf === true
// config.security.rateLimit.enabled === true
// config.security.rateLimit.max === 100
// config.security.rateLimit.window === '1m'

Configuración por entorno

Usar variables de entorno

// jamx.config.ts
export default defineConfig({
  targets: ['web'],
  server: {
    port: Number(process.env.PORT) || 3000,
    host: process.env.HOST || 'localhost',
  },
  auth: {
    session: {
      secret: process.env.JWT_SECRET,
    },
  },
  database: {
    primary: {
      url: process.env.DATABASE_URL,
    },
  },
});

Diferentes configuraciones por entorno

// jamx.config.ts
const env = process.env.NODE_ENV || 'development';

const config = defineConfig({
  targets: ['web'],
  server: {
    port: env === 'production' ? 80 : 3000,
    cors: {
      enabled: env === 'production',
      origins: env === 'production' ? ['https://example.com'] : [],
    },
  },
  security: {
    csrf: env === 'production',
    rateLimit: {
      enabled: env === 'production',
      max: env === 'production' ? 1000 : 100,
    },
  },
});

export default config;

Testing

Tests unitarios

import { defineConfig, ConfigManager } from '@jamx-framework/config';
import { describe, it, expect, beforeEach } from 'vitest';

describe('Config', () => {
  it('should apply defaults', () => {
    const cfg = defineConfig({ targets: ['web'] });
    expect(cfg.server?.port).toBe(3000);
    expect(cfg.ui?.styling?.mode).toBe('jamx-native');
    expect(cfg.security?.csrf).toBe(true);
  });

  it('should respect custom values', () => {
    const cfg = defineConfig({
      targets: ['web', 'ios'],
      server: { port: 8080 },
    });
    expect(cfg.server?.port).toBe(8080);
    expect(cfg.targets).toContain('ios');
  });

  it('ConfigManager should load from object', async () => {
    const manager = new ConfigManager();
    await manager.load({ targets: ['web'] });
    expect(manager.get().server?.port).toBe(3000);
  });

  it('ConfigManager should provide sections', async () => {
    const manager = new ConfigManager();
    await manager.load({
      targets: ['web'],
      server: { port: 5000 },
    });
    const server = manager.section('server');
    expect(server?.port).toBe(5000);
  });
});

Mock de ConfigManager en tests

import { ConfigManager } from '@jamx-framework/config';

const mockConfig = new ConfigManager();
await mockConfig.load({
  targets: ['web'],
  server: { port: 0 }, // puerto 0 para tests
  security: { csrf: false }, // deshabilitar CSRF en tests
});

Integración con otros paquetes

Con @jamx-framework/server

import { createServer } from '@jamx-framework/server';
import { ConfigManager } from '@jamx-framework/config';

const configManager = new ConfigManager();
await configManager.load('./');

const server = await createServer(configManager.get());
await server.listen();

Con @jamx-framework/cli

El CLI carga automáticamente jamx.config.ts usando loadConfig() para comandos como build, dev, db:migrate, etc.

Con @jamx-framework/compiler

El compilador lee targets y otras opciones de la configuración para determinar qué plataformas compilar y qué plugins activar.

Consideraciones

Tipos completos

Todos los tipos están definidos en TypeScript, proporcionando autocompletado en IDEs y validación en tiempo de compilación.

Inmutabilidad

defineConfig retorna un nuevo objeto, no modifica el original. ConfigManager almacena una copia.

Carga asíncrona

loadConfig y ConfigManager.load son asíncronos porque pueden importar módulos ES desde disco.

Thread-safety

ConfigManager no está diseñado para uso concurrente; en un servidor se recomienda crear una instancia global al startup.

Validación en runtime

La validación es mínima; se asume que el desarrollador usa TypeScript correctamente. Para validación más estricta, usar zod o yup externamente.

Ejemplo completo

// jamx.config.ts
import { defineConfig } from '@jamx-framework/config';

export default defineConfig({
  targets: ['web', 'ios', 'android'],
  server: {
    port: 3000,
    host: '0.0.0.0',
    cors: {
      enabled: true,
      origins: ['http://localhost:3000', 'https://myapp.com'],
    },
  },
  database: {
    primary: {
      driver: 'postgresql',
      url: process.env.DATABASE_URL!,
    },
  },
  auth: {
    strategies: ['credentials', 'oauth2'],
    session: {
      engine: 'jwt',
      duration: '7d',
      secret: process.env.JWT_SECRET!,
    },
  },
  security: {
    csrf: true,
    rateLimit: {
      enabled: true,
      max: 100,
      window: '1m',
    },
    headers: {
      hsts: true,
      frameOptions: 'DENY',
      contentTypeSniff: true,
    },
  },
  i18n: {
    defaultLocale: 'es',
    locales: ['es', 'en'],
    strategy: 'prefix',
  },
  ui: {
    styling: {
      mode: 'tailwind',
    },
  },
});
// src/server/index.ts
import { createServer } from '@jamx-framework/server';
import { ConfigManager } from '@jamx-framework/config';

async function start() {
  const configManager = new ConfigManager();
  await configManager.load('./'); // carga jamx.config.ts

  const config = configManager.get();
  const server = await createServer(config);

  const port = config.server?.port ?? 3000;
  await server.listen({ port, host: config.server?.host });
  console.log(`Server running on http://${config.server?.host}:${port}`);
}

start().catch(console.error);

Referencia rápida de defaults

| Propiedad | Default | |-----------|---------| | server.port | 3000 | | server.host | "localhost" | | server.cors.enabled | false | | server.cors.origins | [] | | ui.styling.mode | "jamx-native" | | security.csrf | true | | security.rateLimit.enabled | true | | security.rateLimit.max | 100 | | security.rateLimit.window | "1m" | | security.headers.hsts | undefined | | security.headers.frameOptions | undefined | | security.headers.contentTypeSniff | undefined |

Preguntas frecuentes

¿Puedo usar defineConfig en el navegador?

No, defineConfig es para build time. En el navegador usa ConfigManager con configuración pre-cargada.

¿Cómo sobreescribir configuración en producción?

Usa variables de entorno en jamx.config.ts o carga un archivo diferente con ConfigManager.load('/path/to/prod-config.ts').

¿La configuración es validada en runtime?

Solo se validan tipos TypeScript. Para validación estricta, usa librerías externas como Zod.

¿Puedo tener múltiples instancias de ConfigManager?

Sí, pero usualmente se usa una instancia global. Cada instancia mantiene su propia configuración.

¿Qué pasa si loadConfig no encuentra el archivo?

Lanza un error. Asegúrate de que jamx.config.ts exista en el directorio del proyecto.

Scripts del paquete

  • pnpm build - Compila TypeScript a JavaScript
  • pnpm dev - Compilación en watch mode
  • pnpm test - Ejecuta tests unitarios
  • pnpm test:watch - Tests en watch mode
  • pnpm type-check - Verifica tipos sin compilar
  • pnpm clean - Limpia archivos compilados

Dependencias

  • @types/node - Tipos de Node.js para desarrollo
  • typescript - Compilador TypeScript
  • vitest - Framework de testing
  • rimraf - Limpieza de directorios

Archivos importantes

  • src/index.ts - Punto de entrada, contiene todos los tipos y exportaciones
  • tests/unit/config.test.ts - Tests unitarios de defineConfig y ConfigManager