{"_id":"@empleado-juan/commons-backend","_rev":"6-c53c266ad1512014a50e554bf87f1c02","name":"@empleado-juan/commons-backend","dist-tags":{"latest":"1.1.4"},"versions":{"1.0.0":{"name":"@empleado-juan/commons-backend","version":"1.0.0","keywords":["backend","events","license","middleware"],"author":{"name":"Empleado Juan Team"},"license":"MIT","_id":"@empleado-juan/commons-backend@1.0.0","maintainers":[{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"}],"dist":{"shasum":"eaed407e163711a0bebcf4b8814923830e3a245a","tarball":"https://registry.npmjs.org/@empleado-juan/commons-backend/-/commons-backend-1.0.0.tgz","fileCount":32,"integrity":"sha512-xVZ9So9f1htMYnUQNc3lmcDa5DuZbFBYvk+YoyLgg41oG7Qt/jWdkFcjWwGaQ7rWn6PkcnL1FVLMylOA1WhOOw==","signatures":[{"sig":"MEUCIHHf/MO1CKRnyFtO0ViOGtdiPo7Z4we9LmE6tr3LqV+UAiEAn8HBv8CdQojeCfk2nctsPYmfHAXR5bQ7kdIE+1YRfvM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84448},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"},"_npmVersion":"11.7.0","description":"Shared backend code (event bus, license client, middlewares)","directories":{},"_nodeVersion":"20.19.4","dependencies":{"axios":"^1.6.2","amqplib":"^0.10.3","kafkajs":"^2.2.4","socket.io-client":"^4.7.2","@empleado-juan/commons":"*"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.2","@types/node":"^22.10.2","@types/amqplib":"^0.10.1"},"_npmOperationalInternal":{"tmp":"tmp/commons-backend_1.0.0_1769915509306_0.13775072254464749","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@empleado-juan/commons-backend","version":"1.1.0","keywords":["backend","events","license","middleware"],"author":{"name":"Empleado Juan Team"},"license":"MIT","_id":"@empleado-juan/commons-backend@1.1.0","maintainers":[{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"}],"dist":{"shasum":"08d68b271d822132823872d72d78a7be86c15e48","tarball":"https://registry.npmjs.org/@empleado-juan/commons-backend/-/commons-backend-1.1.0.tgz","fileCount":53,"integrity":"sha512-27n8RBB3DMjk047wbRYKlj70jEevPQpql7dZzA2iiN5rYowzq2hGpWlbBUcFmMjIXFrbrigQXvMoR7dygGynPw==","signatures":[{"sig":"MEYCIQCgngedsChc5Nk6FYdfrmEjxEhxHtch4g5IKczjlUMNcQIhANFc6eBADC1LlMbXPfMMMG6B5FRkdsTDgPlHTanfqZ1G","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104529},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"},"_npmVersion":"11.7.0","description":"Shared backend code (event bus, license client, middlewares)","directories":{},"_nodeVersion":"20.19.4","dependencies":{"axios":"^1.6.2","amqplib":"^0.10.3","express":"^5.2.1","kafkajs":"^2.2.4","jsonwebtoken":"^9.0.3","@types/express":"^5.0.6","socket.io-client":"^4.7.2","@types/jsonwebtoken":"^9.0.10","@empleado-juan/commons":"*"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.2","@types/node":"^22.10.2","@types/amqplib":"^0.10.1"},"_npmOperationalInternal":{"tmp":"tmp/commons-backend_1.1.0_1769973015528_0.040791936215819335","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@empleado-juan/commons-backend","version":"1.1.1","keywords":["backend","events","license","middleware"],"author":{"name":"Empleado Juan Team"},"license":"MIT","_id":"@empleado-juan/commons-backend@1.1.1","maintainers":[{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"}],"dist":{"shasum":"4e0539df49f8a4799f285033f6b9cb744cee9599","tarball":"https://registry.npmjs.org/@empleado-juan/commons-backend/-/commons-backend-1.1.1.tgz","fileCount":53,"integrity":"sha512-qa0lVGTlHrds2Oa3YqJC0YkH8V1+4pDcJc02cnI6Ltfo7Y8qfLYUKsvLeDri02+cVi4orTSEKsONx5tvncwysg==","signatures":[{"sig":"MEUCIEXbBPCDfUDsE/llSPftgwIvRsFzgV6O1Mr8po0gADFaAiEAincFByY1OHPAZ9a8pXbPkkbwDnchQpW9K1bfNHvWYOs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":105889},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"},"_npmVersion":"11.7.0","description":"Shared backend code (event bus, license client, middlewares)","directories":{},"_nodeVersion":"20.19.4","dependencies":{"axios":"^1.6.2","amqplib":"^0.10.3","express":"^5.2.1","kafkajs":"^2.2.4","jsonwebtoken":"^9.0.3","@types/express":"^5.0.6","socket.io-client":"^4.7.2","@types/jsonwebtoken":"^9.0.10","@empleado-juan/commons":"*"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.2","@types/node":"^22.10.2","@types/amqplib":"^0.10.1"},"_npmOperationalInternal":{"tmp":"tmp/commons-backend_1.1.1_1769973678048_0.865314524640965","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@empleado-juan/commons-backend","version":"1.1.2","keywords":["backend","events","license","middleware"],"author":{"name":"Empleado Juan Team"},"license":"MIT","_id":"@empleado-juan/commons-backend@1.1.2","maintainers":[{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"}],"dist":{"shasum":"f7c752ab41040097e17f3e2a0a9aaf38b084aa84","tarball":"https://registry.npmjs.org/@empleado-juan/commons-backend/-/commons-backend-1.1.2.tgz","fileCount":53,"integrity":"sha512-GJroPFvPa503ZaBPn09fQeGCbELh8//4a78+lFedQ9OVue4dgvx5XBjEnxfD45GkFOQD7ZqvVivoHAfrc2y5iQ==","signatures":[{"sig":"MEUCIQDx5HCu15eab1+0JoJ4WcYUPxENfCTfPJovUUTlfhXzhwIgDQBAD16TVnfM3fuuNUEG7UhC59RL72Eo+Z24nqOjiMM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":105972},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"},"_npmVersion":"11.7.0","description":"Shared backend code (event bus, license client, middlewares)","directories":{},"_nodeVersion":"20.19.4","dependencies":{"axios":"^1.6.2","amqplib":"^0.10.3","kafkajs":"^2.2.4","socket.io-client":"^4.7.2","@empleado-juan/commons":"*"},"_hasShrinkwrap":false,"devDependencies":{"express":"^5.2.1","typescript":"^5.7.2","@types/node":"^22.10.2","jsonwebtoken":"^9.0.3","@types/amqplib":"^0.10.1","@types/express":"^5.0.6","@types/jsonwebtoken":"^9.0.10"},"peerDependencies":{"express":"^5.0.0","jsonwebtoken":"^9.0.0"},"_npmOperationalInternal":{"tmp":"tmp/commons-backend_1.1.2_1769974389047_0.9003304518739954","host":"s3://npm-registry-packages-npm-production"}},"1.1.3":{"name":"@empleado-juan/commons-backend","version":"1.1.3","keywords":["backend","events","license","middleware"],"author":{"name":"Empleado Juan Team"},"license":"MIT","_id":"@empleado-juan/commons-backend@1.1.3","maintainers":[{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"}],"dist":{"shasum":"f2545fa47495de8d2858133883c89afa1c5a1e2c","tarball":"https://registry.npmjs.org/@empleado-juan/commons-backend/-/commons-backend-1.1.3.tgz","fileCount":53,"integrity":"sha512-nAoaqCghzEXKqk+wi0jaeYImeV+Kcev6ooezj1n1cdP3+kbc3gYGWRp5T0CHJnF8q0h0biHocW0wP3ysunDHYg==","signatures":[{"sig":"MEYCIQDvd7VJI/nH7SjF7lyKWm4N3WjEDUj2nCVDVt2s0iQVtwIhALFQenslnCOK7rKr/mEFdNEqzSn5OI1KNOdYW6uaDHKv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106034},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","build":"tsc","clean":"rm -rf dist"},"_npmUser":{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"},"_npmVersion":"11.7.0","description":"Shared backend code (event bus, license client, middlewares)","directories":{},"_nodeVersion":"20.19.4","dependencies":{"axios":"^1.6.2","amqplib":"^0.10.3","kafkajs":"^2.2.4","socket.io-client":"^4.7.2","@empleado-juan/commons":"*"},"_hasShrinkwrap":false,"devDependencies":{"express":"^5.2.1","typescript":"^5.7.2","@types/node":"^22.10.2","jsonwebtoken":"^9.0.3","@types/amqplib":"^0.10.1"},"peerDependencies":{"express":"^5.0.0","jsonwebtoken":"^9.0.0"},"peerDependenciesMeta":{"express":{"optional":false},"jsonwebtoken":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/commons-backend_1.1.3_1769974579012_0.8935241439128396","host":"s3://npm-registry-packages-npm-production"}},"1.1.4":{"name":"@empleado-juan/commons-backend","version":"1.1.4","description":"Shared backend code (event bus, license client, middlewares)","main":"dist/index.js","types":"dist/index.d.ts","type":"module","scripts":{"build":"tsc","dev":"tsc --watch","clean":"rm -rf dist"},"keywords":["backend","events","license","middleware"],"author":{"name":"Empleado Juan Team"},"license":"MIT","dependencies":{"@empleado-juan/commons":"*","amqplib":"^0.10.3","axios":"^1.6.2","kafkajs":"^2.2.4","socket.io-client":"^4.7.2"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0","jsonwebtoken":"^9.0.0"},"peerDependenciesMeta":{"express":{"optional":false},"jsonwebtoken":{"optional":false}},"devDependencies":{"@types/amqplib":"^0.10.1","@types/express":"^5.0.6","@types/node":"^22.10.2","express":"^5.2.1","jsonwebtoken":"^9.0.3","typescript":"^5.7.2"},"_id":"@empleado-juan/commons-backend@1.1.4","_nodeVersion":"20.19.4","_npmVersion":"11.7.0","dist":{"integrity":"sha512-zkMVnAFSRNErN4WBqW7276e5RkW5IBlunItDNnwN+BJT4LjCQ3vHbp7NcIt2I/pVpr/6E6rnrNLUqTwBbOf+xw==","shasum":"be7907c995f72749efcd4c21becde521b9aa6a77","tarball":"https://registry.npmjs.org/@empleado-juan/commons-backend/-/commons-backend-1.1.4.tgz","fileCount":53,"unpackedSize":106078,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICL0ztYXvGgQyx8JfWIbXhPrjSo5gkPuuHsu3gKU/x91AiADRaM3Jow6OrnFLaVw19pilOtuqw+306ir63kQwwe6Vg=="}]},"_npmUser":{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"},"directories":{},"maintainers":[{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/commons-backend_1.1.4_1770031886650_0.46937816432131574"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-01T03:11:49.214Z","modified":"2026-02-02T11:31:26.926Z","1.0.0":"2026-02-01T03:11:49.460Z","1.1.0":"2026-02-01T19:10:15.687Z","1.1.1":"2026-02-01T19:21:18.223Z","1.1.2":"2026-02-01T19:33:09.206Z","1.1.3":"2026-02-01T19:36:19.146Z","1.1.4":"2026-02-02T11:31:26.796Z"},"author":{"name":"Empleado Juan Team"},"license":"MIT","keywords":["backend","events","license","middleware"],"description":"Shared backend code (event bus, license client, middlewares)","maintainers":[{"name":"elempleadojuan","email":"elempleadojuan@gmail.com"}],"readme":"# @empleado-juan/commons-backend\n\n[![npm version](https://badge.fury.io/js/%40empleado-juan%2Fcommons-backend.svg)](https://www.npmjs.com/package/@empleado-juan/commons-backend)\n\nPaquete de código compartido exclusivo para backends del sistema Empleado Juan Control.\n\n## Instalación\n\n```bash\nnpm install @empleado-juan/commons-backend @empleado-juan/commons\n```\n\n**Nota**: Requiere `@empleado-juan/commons` como peer dependency.\n\n## Características\n\n- ✅ **Event Bus Adapters**: RabbitMQ y Kafka listos para usar\n- ✅ **License Client**: Cliente de licencias con cache y WebSocket\n- ✅ **Factory Pattern**: Cambio de broker sin modificar código\n- ✅ **TypeScript**: Completamente tipado\n- ✅ **Production Ready**: Manejo de errores, retry, DLQ\n\n## Contenido\n\n### 🚌 Event Bus\n\nSistema de mensajería con soporte para múltiples brokers.\n\n#### Interfaces\n\n```typescript\nimport type { IEventBus, IEventConsumer } from '@empleado-juan/commons-backend';\n```\n\n#### Factory Pattern\n\n```typescript\nimport { EventBusFactory } from '@empleado-juan/commons-backend';\n\n// Publisher\nconst publisher = EventBusFactory.createPublisher();\nawait publisher.connect();\nawait publisher.publish('my-topic', {\n  key: 'user-123',\n  value: { name: 'Juan' },\n  headers: { 'content-type': 'application/json' }\n});\n\n// Consumer\nconst consumer = EventBusFactory.createConsumer();\nawait consumer.connect();\nawait consumer.subscribe(['topic-1', 'topic-2']);\nawait consumer.start(async (topic, data) => {\n  console.log(`Received from ${topic}:`, data);\n});\n```\n\n#### Configuración\n\nEl tipo de broker se configura con variables de entorno:\n\n```bash\n# RabbitMQ (default)\nMESSAGE_BROKER=rabbitmq\nRABBITMQ_URL=amqp://localhost:5672\nRABBITMQ_QUEUE=my-queue\n\n# Kafka\nMESSAGE_BROKER=kafka\nKAFKA_BROKERS=localhost:9092\nKAFKA_GROUP_ID=my-consumer-group\n```\n\n#### Adapters Directos\n\nSi necesitas más control, puedes usar los adapters directamente:\n\n```typescript\nimport {\n  RabbitMQPublisher,\n  RabbitMQConsumer,\n  KafkaPublisher,\n  KafkaConsumer\n} from '@empleado-juan/commons-backend';\n\n// RabbitMQ\nconst rabbitmq = new RabbitMQPublisher('amqp://localhost:5672', 'my-exchange');\nawait rabbitmq.connect();\n\n// Kafka\nconst kafka = new KafkaPublisher(['localhost:9092'], 'my-client-id');\nawait kafka.connect();\n```\n\n### 🔐 License Client\n\nCliente para validación de licencias con soporte para:\n- ✅ Cache (5 min TTL)\n- ✅ Grace period (24-48 horas)\n- ✅ WebSocket para updates en tiempo real\n- ✅ Heartbeat automático\n\n```typescript\nimport { LicenseClient } from '@empleado-juan/commons-backend';\nimport type { LicenseStatus, HeartbeatMetrics } from '@empleado-juan/commons';\n\n// Crear instancia\nconst licenseClient = new LicenseClient();\n\n// Validar licencia\nconst status: LicenseStatus = await licenseClient.validateLicense();\n\nif (!status.valid) {\n  throw new Error(`License invalid: ${status.reason}`);\n}\n\n// Conectar WebSocket para updates en tiempo real\nlicenseClient.connectWebSocket();\n\nlicenseClient.on('license:deactivated', (data) => {\n  console.error('License deactivated:', data);\n  process.exit(1);\n});\n\nlicenseClient.on('license:updated', (data) => {\n  console.log('License updated:', data);\n});\n\n// Enviar heartbeat\nconst metrics: HeartbeatMetrics = {\n  employeeCount: 150,\n  clientCount: 5,\n  version: '1.0.0'\n};\nawait licenseClient.sendHeartbeat(metrics);\n\n// Verificar límites\nconst { allowed, reason } = await licenseClient.checkLimits(5);\nif (!allowed) {\n  throw new Error(reason);\n}\n\n// Verificar feature\nconst hasAdvancedReports = await licenseClient.hasFeature('advanced_reports');\n```\n\n### Configuración\n\n```bash\nLICENSE_SERVER_URL=https://license.ejemplo.com\nINSTALLATION_ID=your-installation-id\n```\n\n## Ejemplos Completos\n\n### Event Publisher (Backend Realtime)\n\n```typescript\nimport { IEventBus, EventBusFactory } from '@empleado-juan/commons-backend';\nimport { EVENT_TOPICS, type EventMessage } from '@empleado-juan/commons';\n\nclass EventPublisher {\n  private eventBus: IEventBus;\n\n  constructor() {\n    this.eventBus = EventBusFactory.createPublisher();\n  }\n\n  async connect() {\n    await this.eventBus.connect();\n  }\n\n  async publishEmployeeCreated(employee: any) {\n    await this.eventBus.publish(EVENT_TOPICS.EMPLOYEE_CREATED, {\n      key: employee.id,\n      value: {\n        id: employee.id,\n        firstName: employee.firstName,\n        lastName: employee.lastName,\n        email: employee.email,\n        isActive: employee.isActive\n      },\n      headers: {\n        'event-type': 'employee.created',\n        'timestamp': new Date().toISOString()\n      }\n    });\n  }\n}\n\nexport const eventPublisher = new EventPublisher();\n```\n\n### Event Consumer (Backend Analytics)\n\n```typescript\nimport { IEventConsumer, EventBusFactory } from '@empleado-juan/commons-backend';\nimport { EVENT_TOPICS } from '@empleado-juan/commons';\n\nclass EventConsumer {\n  private eventBus: IEventConsumer;\n\n  constructor() {\n    this.eventBus = EventBusFactory.createConsumer();\n  }\n\n  async connect() {\n    await this.eventBus.connect();\n  }\n\n  async subscribe() {\n    await this.eventBus.subscribe([\n      EVENT_TOPICS.EMPLOYEE_CREATED,\n      EVENT_TOPICS.EMPLOYEE_UPDATED,\n      EVENT_TOPICS.EMPLOYEE_DELETED\n    ]);\n  }\n\n  async start() {\n    await this.eventBus.start(async (topic, data) => {\n      switch (topic) {\n        case EVENT_TOPICS.EMPLOYEE_CREATED:\n          await this.handleEmployeeCreated(data);\n          break;\n        case EVENT_TOPICS.EMPLOYEE_UPDATED:\n          await this.handleEmployeeUpdated(data);\n          break;\n        case EVENT_TOPICS.EMPLOYEE_DELETED:\n          await this.handleEmployeeDeleted(data);\n          break;\n      }\n    });\n  }\n\n  private async handleEmployeeCreated(data: any) {\n    // Guardar en DB analytics\n    console.log('Employee created:', data);\n  }\n}\n\nexport const eventConsumer = new EventConsumer();\n```\n\n### License Validation Middleware\n\n```typescript\nimport { Request, Response, NextFunction } from 'express';\nimport { LicenseClient } from '@empleado-juan/commons-backend';\n\nconst licenseClient = new LicenseClient();\n\nexport async function requireValidLicense(\n  req: Request,\n  res: Response,\n  next: NextFunction\n) {\n  try {\n    const status = await licenseClient.checkStatus();\n\n    if (!status.valid) {\n      return res.status(403).json({\n        error: 'License invalid',\n        reason: status.reason\n      });\n    }\n\n    if (status.warning) {\n      res.setHeader('X-License-Warning', status.warning);\n    }\n\n    next();\n  } catch (error) {\n    next(error);\n  }\n}\n```\n\n## Arquitectura\n\n### Event Bus - Adapter Pattern\n\n```\nEventBusFactory\n    ↓\n    ├─→ RabbitMQPublisher (implements IEventBus)\n    ├─→ KafkaPublisher (implements IEventBus)\n    └─→ [Future: SQSPublisher, RedisPublisher, etc.]\n```\n\n**Ventajas**:\n- ✅ Cambio de broker sin modificar código de negocio\n- ✅ Testing fácil con mocks\n- ✅ Agregar nuevos brokers sin breaking changes\n\n### License Client - Singleton con Cache\n\n```\nLicenseClient\n    ├─→ HTTP: Validate license\n    ├─→ Cache: 5 min TTL\n    ├─→ WebSocket: Real-time updates\n    └─→ Grace Period: 24-48h offline tolerance\n```\n\n**Características**:\n- ✅ Cache para evitar validaciones constantes\n- ✅ Grace period si servidor de licencias está down\n- ✅ WebSocket para notificaciones instantáneas\n- ✅ EventEmitter para integración con el sistema\n\n## Features por Broker\n\n### RabbitMQ\n- ✅ Confirm mode para reliability\n- ✅ Dead Letter Queue (DLQ)\n- ✅ Retry automático (3 intentos)\n- ✅ Prefetch para backpressure\n- ✅ Topic exchange para routing\n\n### Kafka\n- ✅ Idempotent producer\n- ✅ Consumer groups para scaling\n- ✅ Partitioning por key\n- ✅ Offset management automático\n- ✅ Rebalancing support\n\n## Desarrollo\n\n### Setup\n\n```bash\ngit clone <repo>\ncd commons-backend\nnpm install\n```\n\n### Build\n\n```bash\nnpm run build\n```\n\n### Publish\n\n```bash\n# Incrementar versión\nnpm version patch|minor|major\n\n# Compilar\nnpm run build\n\n# Publicar\nnpm publish --access public\n```\n\n## Dependencias\n\n- `@empleado-juan/commons`: ^1.0.0\n- `axios`: ^1.6.2\n- `socket.io-client`: ^4.7.2\n- `amqplib`: ^0.10.3\n- `kafkajs`: ^2.2.4\n\n## License\n\nMIT © Empleado Juan Team\n","readmeFilename":"README.md"}