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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@cbm-common/module-repository

v0.0.1

Published

Biblioteca Angular para la gestión avanzada de módulos funcionales y sus detalles. Permite administrar módulos, opciones, permisos y relaciones país-módulo con una API robusta y flexible.

Readme

Module Repository

Biblioteca Angular para la gestión avanzada de módulos funcionales y sus detalles. Permite administrar módulos, opciones, permisos y relaciones país-módulo con una API robusta y flexible.

📋 Características Principales

  • Gestión de Módulos: Listado, paginación, consulta individual y CRUD completo
  • Opciones y Permisos: Control granular de opciones (crear, actualizar, eliminar, listar, ver, reversar)
  • Relación País-Módulo: Soporte para módulos generales y específicos por país
  • Control de Estados: Habilitar/deshabilitar módulos y opciones con auditoría
  • Búsqueda avanzada: Filtrado por nombre, código, país y estado
  • Arquitectura Moderna: Angular 20.1.5, inyección de dependencias, patrón Repository
  • TypeScript Tipado: Interfaces y modelos robustos

🚀 Instalación

npm install @cbm-common/module-repository

⚙️ Configuración

1. Importar el Módulo

import { CbmModuleModule } from '@cbm-common/module-repository';

@NgModule({
  imports: [
    CbmModuleModule.forRoot({
      baseUrl: 'https://api.cbm.com/modules'
    })
  ]
})
export class AppModule { }

2. Configuración Standalone (Angular 20+)

import { CbmModuleModule } from '@cbm-common/module-repository';

@Component({
  standalone: true,
  imports: [CbmModuleModule.forRoot({
    baseUrl: 'https://api.cbm.com/modules'
  })]
})
export class AppComponent { }

📚 API Reference

Interfaz del Repositorio

interface ICbmModuleRepository {
  list(params: CbmModuleModel.ListParams): Observable<CbmModuleModel.ListResponse>;
  listAll(): Observable<CbmModuleModel.ListAllResponse>;
  listPaginated(params: CbmModuleModel.ListPaginatedParams): Observable<CbmModuleModel.ListPaginatedResponse>;
  getOne(id: string): Observable<CbmModuleModel.GetOneResponse>;
  save(data: CbmModuleModel.SaveBody): Observable<CbmModuleModel.ConfirmResponse>;
  update(id: string, data: CbmModuleModel.UpdateBody): Observable<CbmModuleModel.ConfirmResponse>;
  changeStatus(id: string, data: CbmModuleModel.ChangeStatusBody): Observable<CbmModuleModel.ConfirmResponse>;
  delete(id: string): Observable<CbmModuleModel.ConfirmResponse>;
}

💡 Uso Básico

Inyección del Servicio

import { CbmModuleRepository } from '@cbm-common/module-repository';

@Component({
  selector: 'app-module-manager'
})
export class ModuleManagerComponent {
  modules: CbmModuleModel.ListPaginatedResponse.Items[] = [];

  constructor(private moduleRepository: CbmModuleRepository) {
    this.loadModules();
  }

  loadModules() {
    const params: CbmModuleModel.ListPaginatedParams = {
      page: 1,
      size: 20,
      enabled: true,
      country_id: 'ECU'
    };

    this.moduleRepository.listPaginated(params).subscribe({
      next: (response) => {
        if (response.success) {
          this.modules = response.items;
        }
      },
      error: (error) => {
        console.error('Error al cargar módulos:', error);
      }
    });
  }
}

Crear Nuevo Módulo

createNewModule() {
  const moduleData: CbmModuleModel.SaveBody = {
    name: 'Inventario',
    code: 'INV',
    description: 'Gestión de inventarios',
    host: 'inventario.cbm.com',
    country_id: 'ECU',
    type: 'country'
  };

  this.moduleRepository.save(moduleData).subscribe({
    next: (response) => {
      if (response.success) {
        console.log('Módulo creado exitosamente');
        this.loadModules();
      }
    },
    error: (error) => console.error('Error al crear módulo:', error)
  });
}

Actualizar Módulo

updateModule(moduleId: string) {
  const updateData: CbmModuleModel.UpdateBody = {
    name: 'Inventario Avanzado',
    description: 'Gestión avanzada de inventarios',
    host: 'inventario-avanzado.cbm.com'
  };

  this.moduleRepository.update(moduleId, updateData).subscribe({
    next: (response) => {
      if (response.success) {
        console.log('Módulo actualizado exitosamente');
        this.loadModules();
      }
    },
    error: (error) => console.error('Error al actualizar módulo:', error)
  });
}

Cambiar Estado de Módulo

toggleModuleStatus(moduleId: string, enable: boolean) {
  const statusData: CbmModuleModel.ChangeStatusBody = {
    enabled: enable,
    disabled_reason: enable ? undefined : 'Módulo deshabilitado por mantenimiento'
  };

  this.moduleRepository.changeStatus(moduleId, statusData).subscribe({
    next: (response) => {
      if (response.success) {
        console.log(`Módulo ${enable ? 'habilitado' : 'deshabilitado'} exitosamente`);
        this.loadModules();
      }
    },
    error: (error) => console.error('Error al cambiar estado:', error)
  });
}

📊 Modelos de Datos

Parámetros de Búsqueda y Paginación

interface ListPaginatedParams {
  page: number;
  size: number;
  country_id?: string;
  enabled?: boolean;
  code?: string;
  name?: string;
}

Módulo y Detalle

interface Module {
  _id: string;
  name: string;
  code: string;
  description: string;
  host: string;
  enabled: boolean;
  country_id?: string;
  type?: 'general' | 'country';
  module_detail: ModuleDetail[];
}

interface ModuleDetail {
  _id: string;
  name: string;
  description?: string;
  option_create?: boolean;
  option_update?: boolean;
  option_delete?: boolean;
  option_list?: boolean;
  option_view?: boolean;
  option_reverse?: boolean;
  router?: string;
  icon?: string;
  enabled?: boolean;
}

Ejemplo de Datos

{
  "_id": "64f1a2b3c4d5e6f7g8h9i0j1",
  "name": "Inventario",
  "code": "INV",
  "description": "Gestión de inventarios",
  "host": "inventario.cbm.com",
  "enabled": true,
  "country_id": "ECU",
  "type": "country",
  "module_detail": [
    {
      "_id": "detail-001",
      "name": "Crear Producto",
      "option_create": true,
      "option_update": false,
      "option_delete": false,
      "option_list": true,
      "option_view": true,
      "router": "/productos/crear",
      "icon": "add_box",
      "enabled": true
    }
  ]
}

🔍 Casos de Uso Comunes

1. Selector de Módulos en Formularios

@Component({
  selector: 'app-module-selector'
})
export class ModuleSelectorComponent {
  modules: CbmModuleModel.ListResponse.Data[] = [];
  selectedModule: string = '';

  constructor(private moduleRepository: CbmModuleRepository) {
    this.loadActiveModules();
  }

  loadActiveModules() {
    const params: CbmModuleModel.ListParams = {
      enabled: true
    };

    this.moduleRepository.list(params).subscribe({
      next: (response) => {
        if (response.success) {
          this.modules = response.data;
        }
      },
      error: (error) => {
        console.error('Error al cargar módulos:', error);
      }
    });
  }

  onModuleChange(moduleId: string) {
    const selected = this.modules.find(mod => mod._id === moduleId);
    if (selected) {
      console.log('Módulo seleccionado:', selected.name);
    }
  }
}

2. Dashboard de Módulos

@Component({
  selector: 'app-module-dashboard'
})
export class ModuleDashboardComponent {
  stats = {
    totalModules: 0,
    activeModules: 0,
    inactiveModules: 0,
    modulesByCountry: new Map<string, number>()
  };

  constructor(private moduleRepository: CbmModuleRepository) {
    this.loadDashboardData();
  }

  loadDashboardData() {
    this.moduleRepository.listAll().subscribe({
      next: (response) => {
        if (response.success) {
          this.calculateStats(response.data);
        }
      }
    });
  }

  private calculateStats(modules: CbmModuleModel.ListAllResponse.Data[]) {
    this.stats.totalModules = modules.length;
    this.stats.activeModules = modules.filter(m => m.enabled).length;
    this.stats.inactiveModules = modules.filter(m => !m.enabled).length;
    modules.forEach(module => {
      const country = module.country_id || 'general';
      const current = this.stats.modulesByCountry.get(country) || 0;
      this.stats.modulesByCountry.set(country, current + 1);
    });
  }
}

🏗️ Arquitectura y Patrones

Patrón Repository

La biblioteca implementa el patrón Repository para mantener la separación entre la lógica de negocio y el acceso a datos:

// Interfaz del repositorio
export interface ICbmModuleRepository {
  list(params: CbmModuleModel.ListParams): Observable<CbmModuleModel.ListResponse>;
  // ...otros métodos
}

// Implementación del servicio
@Injectable({ providedIn: 'root' })
export class CbmModuleService implements ICbmModuleRepository {
  constructor(
    private readonly http: HttpClient,
    @Inject(MODULE_MODULE_CONFIG)
    private readonly config: ICbmModuleModuleConfig
  ) {}

  list(params: CbmModuleModel.ListParams): Observable<CbmModuleModel.ListResponse> {
    return this.http.get<CbmModuleModel.ListResponse>(this.config.baseUrl, { params: { ...params } });
  }
  // ...implementación de métodos
}

// Wrapper del repositorio
@Injectable({ providedIn: 'root' })
export class CbmModuleRepository implements ICbmModuleRepository {
  constructor(private service: CbmModuleService) {}

  list(params: CbmModuleModel.ListParams): Observable<CbmModuleModel.ListResponse> {
    return this.service.list(params);
  }
  // ...delegación a service
}

Configuración Centralizada

@NgModule({
  imports: [
    CbmModuleModule.forRoot({
      baseUrl: environment.apiUrl + '/modules'
    })
  ]
})
export class AppModule {}

🔧 Mejores Prácticas

Manejo de Errores

@Component({
  selector: 'app-safe-module-handler'
})
export class SafeModuleHandlerComponent {
  modules: CbmModuleModel.ListResponse.Data[] = [];
  loading = false;
  error: string | null = null;

  constructor(private moduleRepository: CbmModuleRepository) {}

  safeLoadModules() {
    this.loading = true;
    this.error = null;

    const params: CbmModuleModel.ListParams = {
      enabled: true
    };

    this.moduleRepository.list(params).subscribe({
      next: (response) => {
        this.loading = false;
        if (response.success && response.data) {
          this.modules = response.data;
        } else {
          this.error = 'Respuesta inválida del servidor';
        }
      },
      error: (error) => {
        this.loading = false;
        if (error.status === 404) {
          this.error = 'Servicio de módulos no disponible';
        } else if (error.status === 500) {
          this.error = 'Error interno del servidor';
        } else {
          this.error = 'Error de conexión';
        }
      }
    });
  }
}

Validación de Datos

@Injectable({ providedIn: 'root' })
export class ModuleValidationService {
  constructor(private moduleRepository: CbmModuleRepository) {}

  validateModuleData(data: CbmModuleModel.SaveBody): string[] {
    const errors: string[] = [];

    if (!data.code?.trim()) {
      errors.push('El código es obligatorio');
    }
    if (!data.name?.trim()) {
      errors.push('El nombre es obligatorio');
    }
    if (!data.description?.trim()) {
      errors.push('La descripción es obligatoria');
    }
    if (!data.host?.trim()) {
      errors.push('El host es obligatorio');
    }
    return errors;
  }

  validateAndSave(data: CbmModuleModel.SaveBody): Observable<boolean> {
    const errors = this.validateModuleData(data);
    if (errors.length > 0) {
      console.error('Errores de validación:', errors);
      return of(false);
    }
    return this.moduleRepository.save(data).pipe(
      map(response => response.success),
      catchError(() => of(false))
    );
  }
}

📋 Lista de Verificación para Implementación

  • [ ] ✅ Configurar el módulo CbmModuleModule.forRoot() en el AppModule
  • [ ] ✅ Inyectar CbmModuleRepository en los componentes que lo necesiten
  • [ ] ✅ Implementar manejo de errores para todas las operaciones CRUD
  • [ ] ✅ Validar datos antes de enviar al servidor
  • [ ] ✅ Implementar indicadores de carga durante las operaciones
  • [ ] ✅ Manejar estados de error y respuestas no exitosas
  • [ ] ✅ Probar todas las operaciones CRUD
  • [ ] ✅ Verificar funcionamiento de paginación y filtros
  • [ ] ✅ Documentar casos de uso específicos de la aplicación

🔗 Dependencias

{
  "peerDependencies": {
    "@angular/common": "20.1.5",
    "@angular/core": "20.1.5"
  },
  "dependencies": {
    "tslib": "2.3.0"
  }
}

📝 Notas de Versión

v0.0.1

  • ✅ Implementación inicial del repositorio de módulos
  • ✅ Soporte completo para operaciones CRUD
  • ✅ Gestión de opciones y permisos por módulo
  • ✅ Control de estados y auditoría
  • ✅ Paginación avanzada y filtros
  • ✅ Arquitectura basada en patrón Repository
  • ✅ Configuración simplificada con forRoot()
  • ✅ Compatibilidad con Angular 20.1.5
  • ✅ Interfaces TypeScript completamente tipadas
  • ✅ Documentación completa en español
  • ✅ Ejemplos prácticos de implementación

🤝 Contribución

Para contribuir a esta biblioteca:

  1. Fork el repositorio
  2. Crear una rama para la nueva funcionalidad
  3. Implementar los cambios siguiendo los patrones establecidos
  4. Agregar pruebas unitarias si es necesario
  5. Enviar un Pull Request con descripción detallada

📞 Soporte

Para soporte técnico o consultas sobre el uso de la biblioteca, contactar al equipo de desarrollo de CBM.


CBM (Contabilidad y Facturación Moderna) - Repositorio de Módulos v0.0.1