@gzl10/nexus-backend 0.12.2 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.js +63 -40
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engine/store.ts","../src/engine/registry.ts","../src/engine/queries.ts","../src/modules/logger/logger.config.ts","../src/modules/logger/logger.service.ts","../src/modules/logger/logger.entity.ts","../src/modules/logger/logger.routes.ts","../src/core/logger.ts","../src/modules/logger/index.ts","../src/modules/system/system.controller.ts","../src/modules/system/system.routes.ts","../src/modules/system/system.entity.ts","../src/modules/system/index.ts","../src/modules/storage/drivers/filesystem.driver.ts","../src/modules/storage/drivers/s3.driver.ts","../src/modules/storage/storage.config.ts","../src/db/helpers.ts","../src/core/errors/app-error.ts","../src/modules/storage/storage.service.ts","../src/core/middleware/rate-limit.middleware.ts","../src/modules/storage/storage.entity.ts","../src/modules/storage/storage.routes.ts","../src/modules/storage/storage.seed.ts","../src/modules/storage/index.ts","../src/core/crypto/hash.ts","../src/core/crypto/index.ts","../src/modules/users/users.entity.ts","../src/modules/users/users.routes.ts","../src/modules/users/users.service.ts","../src/modules/users/users.seed.ts","../src/modules/users/index.ts","../src/core/startup-logger.ts","../src/modules/auth/auth.config.ts","../src/modules/auth/jwt.utils.ts","../src/modules/auth/auth.entity.ts","../src/modules/auth/auth.service.ts","../src/modules/auth/auth.controller.ts","../src/modules/auth/auth.routes.ts","../src/modules/auth/auth.middleware.ts","../src/modules/auth/auth.seed.ts","../src/modules/auth/index.ts","../src/modules/ui/ui.entity.ts","../src/modules/ui/index.ts","../src/modules/mail/mail.config.ts","../src/modules/mail/mail.service.ts","../src/modules/mail/mail.entity.ts","../src/modules/mail/mail.routes.ts","../src/modules/mail/mail.seed.ts","../src/modules/mail/index.ts","../src/modules/notifications/notifications.service.ts","../src/modules/notifications/notifications.entity.ts","../src/modules/notifications/notifications.routes.ts","../src/modules/notifications/notifications.socket.ts","../src/modules/notifications/index.ts","../src/modules/schedules/schedules.executor.ts","../src/modules/schedules/schedules.service.ts","../src/modules/schedules/schedules.entity.ts","../src/modules/schedules/schedules.routes.ts","../src/modules/schedules/index.ts","../src/engine/loader.ts","../src/engine/utils.ts","../src/engine/index.ts","../src/runtime/services/base.service.ts","../src/runtime/services/collection.service.ts","../src/runtime/services/single.service.ts","../src/runtime/services/reference.service.ts","../src/runtime/services/event.service.ts","../src/runtime/services/config.service.ts","../src/runtime/services/temp.service.ts","../src/runtime/services/view.service.ts","../src/runtime/types.ts","../src/core/cache/lru-cache.ts","../src/core/events/emitter.ts","../src/core/cache/cache-invalidator.ts","../src/core/cache/index.ts","../src/runtime/services/external.service.ts","../src/runtime/services/virtual.service.ts","../src/runtime/services/computed.service.ts","../src/runtime/services/action.service.ts","../src/runtime/validation/schema-builder.ts","../src/runtime/validation/index.ts","../src/runtime/controllers/entity.controller.ts","../src/runtime/routes/entity.routes.ts","../src/runtime/entity-factory.ts","../src/core/openapi/schema-builder.ts","../src/core/openapi/path-builder.ts","../src/core/openapi/generator.ts","../src/core/openapi/index.ts","../src/config/env.ts","../src/db/query-interceptor.ts","../src/core/paths.ts","../src/db/boolean-registry.ts","../src/config/database.ts","../src/core/utils/id.ts","../src/core/middleware/validate.middleware.ts","../src/core/abilities/ability.factory.ts","../src/core/socket/index.ts","../src/modules/context.ts","../src/core/middleware/error.middleware.ts","../src/core/app.ts","../src/core/utils/net.ts","../src/db/generated-migrate.ts","../src/db/ensure-system-tables.ts","../src/core/server.ts","../src/env-loader.ts","../src/index.ts","../src/runtime/index.ts"],"sourcesContent":["import type { ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\n\n/**\n * Estado en memoria del engine\n * IMPORTANTE: Este archivo NO importa módulos para evitar dependencias circulares\n */\nexport const moduleStore = {\n /** Módulos registrados */\n modules: [] as ModuleManifest[],\n\n /** Plugins registrados (por name) */\n plugins: new Map<string, PluginManifest>(),\n\n /** Tablas registradas (para validar unicidad) */\n tables: new Set<string>(),\n\n /** Subjects registrados (para validar unicidad) */\n subjects: new Set<string>(['all'])\n}\n\n/**\n * Resetea el store a su estado inicial\n * Usado por stop() para permitir restart limpio\n */\nexport function resetStore(): void {\n moduleStore.modules.length = 0\n moduleStore.plugins.clear()\n moduleStore.tables.clear()\n moduleStore.subjects.clear()\n moduleStore.subjects.add('all')\n}\n","import type { ModuleManifest, PluginManifest, EntityDefinition } from '@gzl10/nexus-sdk'\nimport { moduleStore } from './store.js'\n\n/**\n * Obtiene tabla y subject de una definition.\n * Subject solo se retorna si está explícitamente definido en casl.subject.\n */\nfunction getTableAndSubject(def: EntityDefinition): { table?: string; subject?: string } {\n const typesWithTable = ['collection', 'reference', 'event', 'config', 'temp', 'view', undefined]\n const caslSubject = (def as { casl?: { subject?: string } }).casl?.subject\n\n if (!typesWithTable.includes(def.type)) {\n // computed, action, external, virtual no tienen tabla\n return { subject: caslSubject }\n }\n\n const table = (def as { table: string }).table\n return { table, subject: caslSubject }\n}\n\n/**\n * Valida unicidad de tablas y subjects al registrar un módulo\n */\nfunction validateUniqueness(mod: ModuleManifest): void {\n const errors: string[] = []\n\n // Validar label requerido\n if (!mod.label) {\n throw new Error(`Módulo '${mod.name}': label es requerido`)\n }\n\n for (const def of mod.definitions ?? []) {\n const { table, subject } = getTableAndSubject(def)\n\n if (table && moduleStore.tables.has(table)) {\n errors.push(`tabla '${table}' ya está registrada`)\n }\n if (subject && moduleStore.subjects.has(subject)) {\n errors.push(`subject '${subject}' ya está registrado`)\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Módulo '${mod.name}' tiene conflictos:\\n - ${errors.join('\\n - ')}`)\n }\n}\n\n/**\n * Registra tablas y subjects de un módulo\n */\nfunction registerTablesAndSubjects(mod: ModuleManifest): void {\n for (const def of mod.definitions ?? []) {\n const { table, subject } = getTableAndSubject(def)\n if (table) moduleStore.tables.add(table)\n if (subject) moduleStore.subjects.add(subject)\n }\n}\n\n/**\n * Registrar módulo dinámicamente\n */\nexport function registerModule(mod: ModuleManifest): void {\n validateUniqueness(mod)\n registerTablesAndSubjects(mod)\n moduleStore.modules.push(mod)\n}\n\n/**\n * Registrar un plugin completo (todos sus módulos)\n * Hereda del plugin: label e icon (si el módulo no los define)\n */\nexport function registerPlugin(plugin: PluginManifest): void {\n // Registrar plugin para lookup\n moduleStore.plugins.set(plugin.name, plugin)\n\n for (const mod of plugin.modules) {\n // Inyectar propiedades del plugin al módulo (solo si no están definidas)\n const moduleWithPluginProps = {\n ...mod,\n label: mod.label ?? plugin.label,\n icon: mod.icon ?? plugin.icon,\n category: plugin.category,\n }\n registerModule(moduleWithPluginProps)\n }\n}\n","import type { ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\nimport { moduleStore } from './store.js'\n\n/**\n * Obtener todos los módulos registrados\n */\nexport function getModules(): ModuleManifest[] {\n return [...moduleStore.modules]\n}\n\n/**\n * Ordenar módulos por dependencias (topological sort)\n * Garantiza que un módulo se procese después de sus dependencias\n */\nexport function getOrderedModules(): ModuleManifest[] {\n const sorted: ModuleManifest[] = []\n const visited = new Set<string>()\n const moduleMap = new Map(moduleStore.modules.map(m => [m.name, m]))\n\n function visit(mod: ModuleManifest) {\n if (visited.has(mod.name)) return\n visited.add(mod.name)\n\n for (const dep of mod.dependencies ?? []) {\n const depMod = moduleMap.get(dep)\n if (depMod) visit(depMod)\n }\n sorted.push(mod)\n }\n\n moduleStore.modules.forEach(visit)\n return sorted\n}\n\n/**\n * Obtener módulo por nombre\n */\nexport function getModule(name: string): ModuleManifest | undefined {\n return moduleStore.modules.find(m => m.name === name)\n}\n\n/**\n * Obtener plugin por nombre\n */\nexport function getPlugin(name: string): PluginManifest | undefined {\n return moduleStore.plugins.get(name)\n}\n\n/**\n * Obtener todos los plugins registrados\n */\nexport function getPlugins(): PluginManifest[] {\n return [...moduleStore.plugins.values()]\n}\n\n/**\n * Obtener todos los subjects registrados en módulos\n * Incluye 'all' que siempre está disponible\n */\nexport function getRegisteredSubjects(): string[] {\n return [...moduleStore.subjects]\n}\n\n/**\n * Validar que un subject existe en algún módulo registrado\n */\nexport function isValidSubject(subject: string): boolean {\n return moduleStore.subjects.has(subject)\n}\n","import { z } from 'zod'\nimport type { LoggerConfig } from './logger.types.js'\n\n/**\n * Schema de variables de entorno para logger\n * Completamente independiente de la configuración global\n */\nconst loggerEnvSchema = z.object({\n LOG_LEVEL: z.enum(['silent', 'fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n LOG_FORMAT: z.enum(['json', 'pretty']).default('pretty'),\n // Sentry opcional - solo se activa si DSN está definido\n SENTRY_DSN: z.string().url().optional(),\n SENTRY_ENVIRONMENT: z.string().default('development'),\n SENTRY_SAMPLE_RATE: z.coerce.number().min(0).max(1).default(1.0)\n})\n\nexport const loggerEnv = loggerEnvSchema.parse(process.env)\n\n/**\n * Obtiene la configuración de logger desde las variables de entorno\n */\nexport function getLoggerConfig(): LoggerConfig {\n return {\n level: loggerEnv.LOG_LEVEL,\n format: loggerEnv.LOG_FORMAT,\n // Sentry solo si DSN está definido\n sentry: loggerEnv.SENTRY_DSN\n ? {\n dsn: loggerEnv.SENTRY_DSN,\n environment: loggerEnv.SENTRY_ENVIRONMENT,\n sampleRate: loggerEnv.SENTRY_SAMPLE_RATE\n }\n : undefined\n }\n}\n","import pino from 'pino'\nimport * as Sentry from '@sentry/node'\nimport type { LoggerConfig, LoggerService } from './logger.types.js'\n\nlet loggerInstance: LoggerService | null = null\nlet pinoInstance: pino.Logger | null = null\nlet sentryEnabled = false\n\n/**\n * Inicializa el servicio de logger con Pino y opcionalmente Sentry\n */\nexport function initLoggerService(config: LoggerConfig): LoggerService {\n // Si ya está inicializado, retornar instancia existente (idempotente)\n if (loggerInstance) {\n return loggerInstance\n }\n\n // Inicializar Pino\n const pinoLogger = pino({\n level: config.level,\n transport: config.format === 'pretty'\n ? { target: 'pino-pretty', options: { colorize: true, sync: true } }\n : undefined\n })\n\n // Inicializar Sentry solo si DSN está configurado\n sentryEnabled = !!config.sentry\n if (sentryEnabled && config.sentry) {\n Sentry.init({\n dsn: config.sentry.dsn,\n environment: config.sentry.environment,\n sampleRate: config.sentry.sampleRate\n })\n pinoLogger.info({ sentry: config.sentry.environment }, 'Sentry initialized')\n }\n\n // Guardar instancia de pino para shared/logger.ts\n pinoInstance = pinoLogger\n\n loggerInstance = {\n fatal: pinoLogger.fatal.bind(pinoLogger),\n error: pinoLogger.error.bind(pinoLogger),\n warn: pinoLogger.warn.bind(pinoLogger),\n info: pinoLogger.info.bind(pinoLogger),\n debug: pinoLogger.debug.bind(pinoLogger),\n trace: pinoLogger.trace.bind(pinoLogger),\n child: pinoLogger.child.bind(pinoLogger),\n\n // Sentry helpers (no-op si no está habilitado)\n captureException: (error: Error, context?: Record<string, unknown>) => {\n if (sentryEnabled) {\n Sentry.captureException(error, { extra: context })\n }\n },\n captureMessage: (msg: string, level: 'info' | 'warning' | 'error' = 'info') => {\n if (sentryEnabled) {\n Sentry.captureMessage(msg, level)\n }\n },\n setUser: (user: { id: string; email?: string }) => {\n if (sentryEnabled) {\n Sentry.setUser(user)\n }\n },\n isSentryEnabled: () => sentryEnabled\n }\n\n return loggerInstance\n}\n\n/**\n * Obtiene la instancia del LoggerService (singleton)\n */\nexport function getLoggerService(): LoggerService {\n if (!loggerInstance) {\n throw new Error('Logger not initialized. Call initLoggerService() first.')\n }\n return loggerInstance\n}\n\n/**\n * Resetea el logger service (solo para tests)\n */\nexport function resetLoggerService(): void {\n loggerInstance = null\n pinoInstance = null\n sentryEnabled = false\n}\n\n/**\n * Obtiene la instancia de pino.Logger (para ctx.logger)\n */\nexport function getPinoLogger(): pino.Logger {\n if (!pinoInstance) {\n throw new Error('Logger not initialized. Call initLoggerService() first.')\n }\n return pinoInstance\n}\n\nexport function captureExceptionSafe(error: Error, context?: Record<string, unknown>): void {\n if (loggerInstance?.isSentryEnabled()) {\n loggerInstance.captureException(error, context)\n }\n}\n\nexport function captureMessageSafe(msg: string, level?: 'info' | 'warning' | 'error'): void {\n if (loggerInstance?.isSentryEnabled()) {\n loggerInstance.captureMessage(msg, level)\n }\n}\n\nexport function setUserSafe(user: { id: string; email?: string }): void {\n if (loggerInstance?.isSentryEnabled()) {\n loggerInstance.setUser(user)\n }\n}\n","import type { ComputedEntityDefinition } from '@gzl10/nexus-sdk'\nimport { getLoggerConfig } from './logger.config.js'\n\n/**\n * Computed Entity: config\n * Muestra la configuración del logger actual (read-only)\n */\nexport const loggerConfigEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Logger Config',\n routePrefix: '/config',\n\n fields: {\n level: {\n name: 'level',\n label: 'Log Level',\n input: 'select',\n hint: 'Env: LOG_LEVEL (default: info)',\n db: { type: 'string', size: 10, nullable: false },\n options: {\n static: [\n { value: 'silent', label: 'Silent (sin logs)' },\n { value: 'fatal', label: 'Fatal' },\n { value: 'error', label: 'Error' },\n { value: 'warn', label: 'Warn' },\n { value: 'info', label: 'Info' },\n { value: 'debug', label: 'Debug' },\n { value: 'trace', label: 'Trace' }\n ]\n }\n },\n format: {\n name: 'format',\n label: 'Formato',\n input: 'select',\n hint: 'Env: LOG_FORMAT (default: pretty)',\n db: { type: 'string', size: 10, nullable: false },\n options: {\n static: [\n { value: 'pretty', label: 'Pretty (desarrollo)' },\n { value: 'json', label: 'JSON (producción)' }\n ]\n }\n },\n sentry_enabled: {\n name: 'sentry_enabled',\n label: 'Sentry Habilitado',\n input: 'switch',\n hint: 'Env: SENTRY_DSN (opcional)',\n db: { type: 'boolean', nullable: false }\n },\n sentry_environment: {\n name: 'sentry_environment',\n label: 'Sentry Environment',\n input: 'text',\n hint: 'Env: SENTRY_ENVIRONMENT (default: development)',\n db: { type: 'string', size: 50, nullable: true }\n },\n sentry_sample_rate: {\n name: 'sentry_sample_rate',\n label: 'Sentry Sample Rate',\n input: 'number',\n hint: 'Env: SENTRY_SAMPLE_RATE (default: 1.0)',\n db: { type: 'decimal', nullable: true }\n }\n },\n\n compute: async () => {\n const config = getLoggerConfig()\n return [{\n level: config.level,\n format: config.format,\n sentry_enabled: !!config.sentry,\n sentry_environment: config.sentry?.environment ?? null,\n sentry_sample_rate: config.sentry?.sampleRate ?? null\n }]\n },\n\n cache: { ttl: 0 },\n\n casl: {\n subject: 'LoggerConfig',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { getLoggerConfig } from './logger.config.js'\nimport { getLoggerService } from './logger.service.js'\n\n/**\n * Crea las rutas del módulo logger\n */\nexport function createLoggerRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { optionalAuth } = ctx.middleware\n\n /**\n * GET /logger/health\n * Estado del servicio de logging\n *\n * - Sin auth: solo status básico (para healthchecks externos)\n * - Con auth ADMIN: información completa de configuración\n */\n router.get('/health', optionalAuth!, (_req, res) => {\n const config = getLoggerConfig()\n const logger = getLoggerService()\n\n // Info básica para todos (healthchecks)\n const basicInfo = {\n status: 'ok',\n level: config.level\n }\n\n // Info completa solo para admins autenticados\n if (_req.user && _req.ability?.can('manage', 'all')) {\n res.json({\n ...basicInfo,\n format: config.format,\n sentry: {\n enabled: logger.isSentryEnabled(),\n environment: config.sentry?.environment ?? null\n }\n })\n return\n }\n\n res.json(basicInfo)\n })\n\n return router\n}\n","import pino from 'pino'\n\n/**\n * Logger global con fallback durante bootstrap\n *\n * Inicialmente crea un pino logger básico.\n * Cuando el módulo logger se inicializa, reemplaza la instancia.\n */\n\nconst isDev = process.env['NODE_ENV'] !== 'production'\n\n// Logger inicial (fallback durante bootstrap, antes de que el módulo se inicialice)\nlet loggerInstance: pino.Logger = pino({\n level: process.env['LOG_LEVEL'] || 'info',\n transport: isDev\n ? { target: 'pino-pretty', options: { colorize: true, sync: true } }\n : undefined\n})\n\n/**\n * Reemplaza la instancia del logger\n * Llamado desde el init() del módulo logger\n */\nexport function setLoggerInstance(instance: pino.Logger): void {\n loggerInstance = instance\n}\n\n/**\n * Proxy que delega al logger actual\n * Permite hot-swap del logger cuando el módulo se inicializa\n */\nexport const logger = new Proxy({} as pino.Logger, {\n get(_, prop) {\n const target = loggerInstance as unknown as Record<string | symbol, unknown>\n const value = target[prop]\n // Bind methods para preservar `this`\n return typeof value === 'function' ? value.bind(loggerInstance) : value\n }\n})\n\nexport const createChildLogger = (context: string) => logger.child({ context })\n","import type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { getLoggerConfig } from './logger.config.js'\nimport { initLoggerService, getPinoLogger } from './logger.service.js'\nimport { loggerConfigEntity } from './logger.entity.js'\nimport { createLoggerRoutes } from './logger.routes.js'\nimport { setLoggerInstance } from '../../core/logger.js'\n\n// Re-export types del módulo\nexport type { LoggerConfig, LoggerService } from './logger.types.js'\n\nexport const loggerModule: ModuleManifest = {\n name: 'logger',\n label: 'Logger',\n icon: 'mdi:text-box-outline',\n description: 'Centralized logging with Pino and optional Sentry integration',\n type: 'core',\n category: 'analytics',\n dependencies: [], // Sin dependencias - debe cargar primero\n definitions: [loggerConfigEntity],\n init: (ctx: ModuleContext) => {\n const config = getLoggerConfig()\n const service = initLoggerService(config)\n // Registrar servicio en ctx.services\n ctx.services['logger'] = service\n // Actualizar el logger global de shared/logger.ts\n setLoggerInstance(getPinoLogger())\n service.debug('Logger module initialized')\n },\n routes: createLoggerRoutes,\n routePrefix: '/logger'\n}\n\nexport default loggerModule\n","import { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Request, Response, ModuleContext, ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\nimport type { FieldDefinitionDTO, ModuleDTO, PluginDTO } from './system.types.js'\n\nfunction moduleHasSeedWithPath(mod: ModuleManifest, libPath: string): boolean {\n if (mod.seed) return true\n const seedPath = join(libPath, 'dist', 'modules', mod.name, `${mod.name}.seed.js`)\n return existsSync(seedPath)\n}\n\n/**\n * Convierte FieldDefinition a DTO serializable (sin funciones)\n */\nfunction toFieldDTO(name: string, field: Record<string, unknown>): FieldDefinitionDTO {\n const db = field['db'] as Record<string, unknown> | undefined\n const relation = field['relation'] as Record<string, unknown> | undefined\n const validation = field['validation'] as Record<string, unknown> | undefined\n const options = field['options'] as Record<string, unknown> | undefined\n const storage = field['storage'] as Record<string, unknown> | undefined\n const meta = field['meta'] as Record<string, unknown> | undefined\n\n return {\n name,\n label: field['label'] as string,\n input: field['input'] as string,\n placeholder: field['placeholder'] as string | undefined,\n hint: field['hint'] as string | undefined,\n hidden: field['hidden'] as boolean | undefined,\n disabled: field['disabled'] as boolean | undefined,\n db: {\n type: String(db?.['type'] ?? 'text'),\n nullable: db?.['nullable'] as boolean | undefined,\n default: db?.['default'],\n unique: db?.['unique'] as boolean | undefined,\n index: db?.['index'] as boolean | undefined\n },\n relation: relation ? {\n table: String(relation['table']),\n column: relation['column'] as string | undefined,\n labelField: relation['labelField'] as string | undefined,\n onDelete: relation['onDelete'] as string | undefined\n } : undefined,\n validation: validation ? {\n required: validation['required'] as boolean | undefined,\n min: validation['min'] as number | undefined,\n max: validation['max'] as number | undefined,\n pattern: validation['pattern'] as string | undefined,\n format: validation['format'] as string | undefined,\n enum: validation['enum'] as string[] | undefined\n } : undefined,\n options: options ? {\n endpoint: options['endpoint'] as string | undefined,\n valueField: options['valueField'] as string | undefined,\n labelField: options['labelField'] as string | undefined,\n static: options['static'] as Array<{ value: string; label: string }> | undefined\n } : undefined,\n storage: storage ? {\n accept: storage['accept'] as string | undefined,\n maxSize: storage['maxSize'] as number | undefined,\n maxFiles: storage['maxFiles'] as number | undefined,\n folder: storage['folder'] as string | undefined\n } : undefined,\n meta: meta ? {\n sortable: meta['sortable'] as boolean | undefined,\n searchable: meta['searchable'] as boolean | undefined\n } : undefined\n }\n}\n\nexport function createSystemController(ctx: ModuleContext) {\n const { errors, engine } = ctx\n\n function toModuleDTO(mod: ModuleManifest, libPath: string): ModuleDTO {\n return {\n name: mod.name,\n label: mod.label!,\n icon: mod.icon,\n description: mod.description,\n type: mod.type ?? 'core',\n dependencies: mod.dependencies ?? [],\n routePrefix: mod.routePrefix ?? `/${mod.name}`,\n subjects: engine.getModuleSubjects(mod),\n definitions: (mod.definitions ?? []).map(def => {\n const typesWithoutTable = ['action', 'external', 'virtual', 'computed', 'single']\n const hasTable = !typesWithoutTable.includes(def.type ?? 'collection')\n\n const fields: Record<string, FieldDefinitionDTO> = {}\n for (const [name, field] of Object.entries(def.fields)) {\n fields[name] = toFieldDTO(name, field as unknown as Record<string, unknown>)\n }\n\n return {\n table: hasTable ? (def as { table: string }).table : '',\n key: def.type === 'single' ? (def as { key: string }).key : undefined,\n type: def.type ?? 'collection',\n label: def.label,\n labelField: 'labelField' in def ? def.labelField : undefined,\n icon: 'icon' in def ? (def.icon as string) : undefined,\n routePrefix: 'routePrefix' in def ? (def.routePrefix as string) : undefined,\n order: 'order' in def ? (def.order as number) : undefined,\n fields,\n fieldsCount: Object.keys(fields).length,\n hasTimestamps: 'timestamps' in def ? !!def.timestamps : false,\n hasAudit: 'audit' in def ? !!def.audit : false,\n caslSubject: 'casl' in def ? def.casl?.subject : undefined\n }\n }),\n hasRoutes: !!mod.routes,\n hasMigrate: !!mod.migrate,\n hasSeed: moduleHasSeedWithPath(mod, libPath),\n hasInit: !!mod.init\n }\n }\n\n function toPluginDTO(plugin: PluginManifest): PluginDTO {\n return {\n name: plugin.name,\n code: plugin.code,\n label: plugin.label,\n icon: plugin.icon,\n category: plugin.category,\n version: plugin.version,\n description: plugin.description\n }\n }\n\n return {\n /**\n * GET /system/modules\n * Lista todos los módulos registrados\n */\n listModules(_req: Request, res: Response) {\n const libPath = ctx.helpers.getLibPath()\n const modules = engine.getModules().map(mod => toModuleDTO(mod, libPath))\n res.json({\n items: modules,\n total: modules.length,\n page: 1,\n limit: modules.length,\n totalPages: 1,\n hasNext: false\n })\n },\n\n /**\n * GET /system/modules/:name\n * Obtiene un módulo por nombre\n */\n getModule(req: Request<{ name: string }>, res: Response) {\n const { name } = req.params\n const mod = engine.getModules().find((m) => m.name === name)\n\n if (!mod) {\n throw new errors.NotFoundError('Módulo no encontrado')\n }\n\n res.json(toModuleDTO(mod, ctx.helpers.getLibPath()))\n },\n\n /**\n * GET /system/plugins\n * Lista todos los plugins registrados\n */\n listPlugins(_req: Request, res: Response) {\n const plugins = engine.getPlugins().map(toPluginDTO)\n res.json({\n items: plugins,\n total: plugins.length,\n page: 1,\n limit: plugins.length,\n totalPages: 1,\n hasNext: false\n })\n },\n\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { createSystemController } from './system.controller.js'\n\n/**\n * System Routes\n *\n * Auto-montaje desde definitions:\n * - moduleEntity, pluginEntity, osEntity (computed)\n */\nexport function createSystemRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const controller = createSystemController(ctx)\n\n // Rutas públicas - Información del sistema (sin auth)\n router.get('/modules', controller.listModules)\n router.get('/modules/:name', controller.getModule)\n router.get('/plugins', controller.listPlugins)\n\n // osEntity se auto-monta desde definitions (computed con routePrefix)\n\n return router\n}\n","import * as os from 'node:os'\nimport type { ComputedEntityDefinition, ModuleContext } from '@gzl10/nexus-sdk'\nimport type { ModuleComputedDTO, PluginComputedDTO, OsComputedDTO } from './system.types.js'\n\n/**\n * EntityDefinition para Módulos del sistema (computed)\n * Datos calculados en runtime desde el engine\n */\nexport const moduleEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Modules',\n labelField: 'name',\n routePrefix: '/modules',\n\n fields: {\n name: {\n name: 'name',\n label: 'Nombre',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false },\n meta: { sortable: true, searchable: true }\n },\n label: {\n name: 'label',\n label: 'Etiqueta',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false },\n meta: { sortable: true }\n },\n icon: {\n name: 'icon',\n label: 'Icono',\n input: 'text',\n db: { type: 'string', size: 50, nullable: true }\n },\n type: {\n name: 'type',\n label: 'Tipo',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n validation: { enum: ['core', 'plugin', 'auth-plugin', 'custom'] },\n options: {\n static: [\n { value: 'core', label: 'Core' },\n { value: 'plugin', label: 'Plugin' },\n { value: 'auth-plugin', label: 'Auth Plugin' },\n { value: 'custom', label: 'Custom' }\n ]\n },\n meta: { sortable: true }\n }\n },\n\n // Sin CASL - módulos son públicos\n casl: {\n subject: 'Module',\n permissions: {\n // Vacío = acceso público a lectura\n }\n },\n\n // Función que calcula los módulos desde el engine\n compute: async (ctx: ModuleContext): Promise<ModuleComputedDTO[]> => {\n return ctx.engine.getModules().map(mod => ({\n name: mod.name,\n label: mod.label!,\n icon: mod.icon,\n description: mod.description,\n type: mod.type ?? 'core',\n dependencies: mod.dependencies ?? [],\n routePrefix: mod.routePrefix ?? `/${mod.name}`,\n subjects: ctx.engine.getModuleSubjects(mod),\n definitionsCount: mod.definitions?.length ?? 0,\n hasRoutes: !!mod.routes,\n hasMigrate: !!mod.migrate,\n hasInit: !!mod.init\n }))\n },\n\n cache: {\n ttl: 60 // Cache de 60 segundos (módulos no cambian en runtime)\n }\n}\n\n/**\n * EntityDefinition para Plugins del sistema (computed)\n * Datos calculados en runtime desde el engine\n */\nexport const pluginEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Plugins',\n labelField: 'name',\n routePrefix: '/plugins',\n\n fields: {\n name: {\n name: 'name',\n label: 'Nombre',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false },\n meta: { sortable: true, searchable: true }\n },\n code: {\n name: 'code',\n label: 'Código',\n input: 'text',\n db: { type: 'string', size: 10, nullable: false },\n meta: { sortable: true }\n },\n label: {\n name: 'label',\n label: 'Etiqueta',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false },\n meta: { sortable: true }\n },\n version: {\n name: 'version',\n label: 'Versión',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false }\n },\n category: {\n name: 'category',\n label: 'Categoría',\n input: 'select',\n db: { type: 'string', size: 20, nullable: true },\n options: {\n static: [\n { value: 'content', label: 'Content' },\n { value: 'data', label: 'Data' },\n { value: 'storage', label: 'Storage' },\n { value: 'messaging', label: 'Messaging' },\n { value: 'jobs', label: 'Jobs' },\n { value: 'ai', label: 'AI' },\n { value: 'analytics', label: 'Analytics' },\n { value: 'integrations', label: 'Integrations' },\n { value: 'commerce', label: 'Commerce' },\n { value: 'security', label: 'Security' }\n ]\n },\n meta: { sortable: true }\n }\n },\n\n // Sin CASL - plugins son públicos\n casl: {\n subject: 'Plugin',\n permissions: {\n // Vacío = acceso público a lectura\n }\n },\n\n // Función que calcula los plugins desde el engine\n compute: async (ctx: ModuleContext): Promise<PluginComputedDTO[]> => {\n return ctx.engine.getPlugins().map(plugin => ({\n name: plugin.name,\n code: plugin.code,\n label: plugin.label,\n icon: plugin.icon,\n category: plugin.category,\n version: plugin.version,\n description: plugin.description\n }))\n },\n\n cache: {\n ttl: 60 // Cache de 60 segundos\n }\n}\n\n/**\n * EntityDefinition para información del Sistema Operativo (computed)\n * Datos calculados en runtime desde node:os\n */\nexport const osEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'OS Info',\n labelField: 'hostname',\n routePrefix: '/os',\n\n fields: {\n hostname: {\n name: 'hostname',\n label: 'Hostname',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false }\n },\n platform: {\n name: 'platform',\n label: 'Platform',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false },\n meta: { sortable: true }\n },\n arch: {\n name: 'arch',\n label: 'Architecture',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false }\n },\n release: {\n name: 'release',\n label: 'Release',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false }\n },\n type: {\n name: 'type',\n label: 'Type',\n input: 'text',\n db: { type: 'string', size: 30, nullable: false }\n },\n uptime: {\n name: 'uptime',\n label: 'Uptime (s)',\n input: 'number',\n db: { type: 'integer', nullable: false },\n meta: { sortable: true }\n },\n totalMemory: {\n name: 'totalMemory',\n label: 'Total Memory',\n input: 'number',\n db: { type: 'integer', nullable: false }\n },\n freeMemory: {\n name: 'freeMemory',\n label: 'Free Memory',\n input: 'number',\n db: { type: 'integer', nullable: false }\n },\n cpuCount: {\n name: 'cpuCount',\n label: 'CPU Count',\n input: 'number',\n db: { type: 'integer', nullable: false }\n },\n cpuModel: {\n name: 'cpuModel',\n label: 'CPU Model',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false }\n },\n loadAverage: {\n name: 'loadAverage',\n label: 'Load Average',\n input: 'hidden',\n db: { type: 'json', nullable: false }\n }\n },\n\n // Solo ADMIN - info del sistema es sensible\n casl: {\n subject: 'OsInfo',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n },\n\n compute: async (_ctx: ModuleContext): Promise<OsComputedDTO[]> => {\n const cpus = os.cpus()\n return [{\n hostname: os.hostname(),\n platform: os.platform(),\n arch: os.arch(),\n release: os.release(),\n type: os.type(),\n uptime: os.uptime(),\n totalMemory: os.totalmem(),\n freeMemory: os.freemem(),\n cpuCount: cpus.length,\n cpuModel: cpus[0]?.model ?? 'Unknown',\n loadAverage: os.loadavg()\n }]\n },\n\n cache: {\n ttl: 5 // Cache corto (5s) porque uptime/memory cambian\n }\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { createSystemRoutes } from './system.routes.js'\nimport { moduleEntity, pluginEntity, osEntity } from './system.entity.js'\n\n// Re-exports\nexport { createSystemController } from './system.controller.js'\nexport { moduleEntity, pluginEntity, osEntity } from './system.entity.js'\nexport type {\n Module,\n Plugin,\n OSInfo,\n Setting,\n FieldDefinitionDTO,\n EntityDefinitionDTO,\n ModuleDTO,\n PluginDTO,\n ModuleComputedDTO,\n PluginComputedDTO,\n OsComputedDTO\n} from './system.types.js'\n\nexport const systemModule: ModuleManifest = {\n name: 'system',\n label: 'System',\n icon: 'mdi:cog-outline',\n description: 'System configuration, module registry, and platform metadata',\n type: 'core',\n category: 'data',\n dependencies: ['logger'],\n definitions: [moduleEntity, pluginEntity, osEntity],\n // migrate: usa migración generada desde definitions\n routes: createSystemRoutes,\n routePrefix: '/system'\n}\n\nexport default systemModule\n","/**\n * Filesystem Storage Driver\n *\n * Almacena archivos en el sistema de archivos local.\n */\n\nimport { createReadStream, createWriteStream, existsSync, unlinkSync, mkdirSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { join, dirname, extname } from 'node:path'\nimport { createHash } from 'node:crypto'\nimport type { StorageDriver, StorageFile, PutOptions } from './driver.interface.js'\nimport type { StorageConfig } from '../storage.config.js'\n\nexport class FilesystemDriver implements StorageDriver {\n private basePath: string\n private baseUrl: string | undefined\n private generateId: () => string\n\n constructor(config: StorageConfig) {\n this.basePath = config.basePath\n this.baseUrl = config.baseUrl\n this.generateId = config.generateId\n\n // Crear directorio base si no existe\n if (!existsSync(this.basePath)) {\n mkdirSync(this.basePath, { recursive: true })\n }\n }\n\n async put(buffer: Buffer, filename: string, options?: PutOptions): Promise<StorageFile> {\n const id = this.generateId()\n const ext = extname(filename) || ''\n const diskFilename = `${id}${ext}`\n const folder = options?.folder || ''\n const relativePath = folder ? `${folder}/${diskFilename}` : diskFilename\n const fullPath = join(this.basePath, relativePath)\n\n // Crear subdirectorio si es necesario\n const dir = dirname(fullPath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n\n // Calcular hash SHA256\n const hash = createHash('sha256').update(buffer).digest('hex')\n\n // Escribir archivo\n await new Promise<void>((resolve, reject) => {\n const stream = createWriteStream(fullPath)\n stream.on('finish', resolve)\n stream.on('error', reject)\n stream.write(buffer)\n stream.end()\n })\n\n return {\n id,\n filename,\n diskFilename,\n mimetype: options?.mimetype || 'application/octet-stream',\n size: buffer.length,\n folder: folder || undefined,\n path: relativePath,\n url: this.getUrl(relativePath) || undefined,\n hash\n }\n }\n\n async get(path: string): Promise<NodeJS.ReadableStream> {\n const fullPath = join(this.basePath, path)\n if (!existsSync(fullPath)) {\n throw new Error(`File not found: ${path}`)\n }\n return createReadStream(fullPath)\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const fullPath = join(this.basePath, path)\n return readFile(fullPath)\n }\n\n async delete(path: string): Promise<void> {\n const fullPath = join(this.basePath, path)\n if (existsSync(fullPath)) {\n unlinkSync(fullPath)\n }\n }\n\n async exists(path: string): Promise<boolean> {\n const fullPath = join(this.basePath, path)\n return existsSync(fullPath)\n }\n\n getUrl(path: string): string | null {\n if (!this.baseUrl) return null\n return `${this.baseUrl}/files/${path}`\n }\n}\n","/**\n * S3 Storage Driver\n *\n * Almacena archivos en AWS S3 o compatible (MinIO, DigitalOcean Spaces, etc.)\n */\n\nimport { Readable } from 'node:stream'\nimport { createHash } from 'node:crypto'\nimport { extname } from 'node:path'\nimport {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n HeadObjectCommand\n} from '@aws-sdk/client-s3'\nimport type { StorageDriver, StorageFile, PutOptions } from './driver.interface.js'\nimport type { StorageConfig } from '../storage.config.js'\n\nexport class S3Driver implements StorageDriver {\n private client: S3Client\n private bucket: string\n private baseUrl: string | undefined\n private generateId: () => string\n\n constructor(config: StorageConfig) {\n if (!config.s3) {\n throw new Error('S3 configuration is required for S3Driver')\n }\n\n const { bucket, region, accessKeyId, secretAccessKey, endpoint } = config.s3\n\n this.bucket = bucket\n this.baseUrl = config.baseUrl\n this.generateId = config.generateId\n\n this.client = new S3Client({\n region,\n credentials: {\n accessKeyId,\n secretAccessKey\n },\n ...(endpoint && {\n endpoint,\n forcePathStyle: true // Necesario para MinIO\n })\n })\n }\n\n async put(buffer: Buffer, filename: string, options?: PutOptions): Promise<StorageFile> {\n const id = this.generateId()\n const ext = extname(filename) || ''\n const diskFilename = `${id}${ext}`\n const folder = options?.folder || ''\n const key = folder ? `${folder}/${diskFilename}` : diskFilename\n\n // Calcular hash SHA256\n const hash = createHash('sha256').update(buffer).digest('hex')\n\n // Subir a S3\n await this.client.send(new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: buffer,\n ContentType: options?.mimetype || 'application/octet-stream',\n ContentLength: buffer.length,\n Metadata: {\n 'original-filename': filename,\n 'sha256': hash\n }\n }))\n\n return {\n id,\n filename,\n diskFilename,\n mimetype: options?.mimetype || 'application/octet-stream',\n size: buffer.length,\n folder: folder || undefined,\n path: key,\n url: this.getUrl(key) || undefined,\n hash\n }\n }\n\n async get(path: string): Promise<NodeJS.ReadableStream> {\n const response = await this.client.send(new GetObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n\n if (!response.Body) {\n throw new Error(`File not found: ${path}`)\n }\n\n // El Body de S3 es un Readable stream\n return response.Body as Readable\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const response = await this.client.send(new GetObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n\n if (!response.Body) {\n throw new Error(`File not found: ${path}`)\n }\n\n // Convertir stream a buffer\n const stream = response.Body as Readable\n const chunks: Buffer[] = []\n\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk))\n }\n\n return Buffer.concat(chunks)\n }\n\n async delete(path: string): Promise<void> {\n await this.client.send(new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await this.client.send(new HeadObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n return true\n } catch {\n return false\n }\n }\n\n getUrl(path: string): string | null {\n if (this.baseUrl) {\n return `${this.baseUrl}/files/${path}`\n }\n // URL pública de S3 (si el bucket tiene permisos públicos)\n return `https://${this.bucket}.s3.amazonaws.com/${path}`\n }\n}\n","/**\n * Storage Module Configuration\n *\n * Configuración para el sistema de almacenamiento de archivos.\n * Soporta filesystem local y S3 (AWS/MinIO).\n * Lee configuración desde BD (storage_config) con fallback a env vars.\n */\n\nimport { join, isAbsolute } from 'node:path'\nimport { existsSync, mkdirSync } from 'node:fs'\nimport type { Knex } from 'knex'\nimport type { FilesystemMetadata, S3Metadata } from './storage.types.js'\n\nconst TABLE = 'storage_config'\n\nexport interface StorageConfig {\n /** Scope de configuración (identificador único) */\n scope: string\n\n /** Driver de almacenamiento */\n driver: 'filesystem' | 's3'\n\n /** Ruta base para filesystem (default: ./storage) */\n basePath: string\n\n /** URL pública base para generar URLs de archivos */\n baseUrl?: string\n\n /** Tamaño máximo de archivo en bytes (default: 10MB) */\n maxFileSize: number\n\n /** Tipos MIME permitidos globalmente (opcional) */\n allowedMimeTypes?: string[]\n\n /** Generador de IDs (inyectado desde ctx.helpers) */\n generateId: () => string\n\n /** Configuración S3 */\n s3?: {\n bucket: string\n region: string\n accessKeyId: string\n secretAccessKey: string\n /** Endpoint personalizado para MinIO/otros proveedores */\n endpoint?: string\n }\n}\n\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\n\n/** Scope por defecto para filesystem */\nexport const DEFAULT_FILESYSTEM_SCOPE = 'default_filesystem'\n\n/** Scope por defecto para S3 */\nexport const DEFAULT_S3_SCOPE = 'default_s3'\n\n/** Scope por defecto según driver */\nfunction getDefaultScope(driver: 'filesystem' | 's3'): string {\n return driver === 's3' ? DEFAULT_S3_SCOPE : DEFAULT_FILESYSTEM_SCOPE\n}\n\n/** Config singleton para compatibilidad con código existente */\nlet defaultConfig: StorageConfig | null = null\n\n/** Project path para resolver rutas relativas */\nlet projectPath: string = process.cwd()\n\n/** GenerateId function */\nlet generateIdFn: (() => string) | null = null\n\n/**\n * Obtiene la configuración de storage por defecto (singleton)\n */\nexport function getStorageConfig(): StorageConfig {\n if (!defaultConfig) {\n throw new Error('StorageConfig not initialized. Call initStorageConfig() first.')\n }\n return defaultConfig\n}\n\n/**\n * Resuelve una ruta de storage:\n * - Rutas absolutas: se usan directamente\n * - Rutas relativas (./storage): se resuelven a projectPath/data/{path}\n */\nfunction resolveStoragePath(path: string, projPath: string): string {\n if (isAbsolute(path)) {\n return path\n }\n // Rutas relativas van dentro de data/\n const cleanPath = path.startsWith('./') ? path.slice(2) : path\n return join(projPath, 'data', cleanPath)\n}\n\n/**\n * Registro de BD para storage_config\n */\ninterface StorageConfigRow {\n scope: string\n driver: 'filesystem' | 's3'\n base_url: string | null\n max_file_size: number\n allowed_mime_types: string | null\n metadata: string | null\n}\n\n/**\n * Obtiene configuración de storage por scope desde BD\n * Fallback a variables de entorno si no existe en BD\n */\nexport async function getConfigByScope(\n db: Knex,\n scope: string\n): Promise<StorageConfig> {\n if (!generateIdFn) {\n throw new Error('StorageConfig not initialized. Call initStorageConfig() first.')\n }\n\n const row = await db(TABLE).where({ scope }).first<StorageConfigRow>()\n\n if (row) {\n return buildConfigFromRow(row)\n }\n\n // Fallback a env vars (usa config por defecto según driver esperado)\n const isS3Scope = scope.includes('s3')\n return buildConfigFromEnv(isS3Scope ? 's3' : 'filesystem')\n}\n\n/**\n * Construye StorageConfig desde un registro de BD\n */\nfunction buildConfigFromRow(row: StorageConfigRow): StorageConfig {\n const metadata = row.metadata ? JSON.parse(row.metadata) : {}\n\n const config: StorageConfig = {\n scope: row.scope,\n driver: row.driver,\n basePath: '',\n baseUrl: row.base_url || undefined,\n maxFileSize: row.max_file_size,\n allowedMimeTypes: row.allowed_mime_types?.split(',').map(t => t.trim()),\n generateId: generateIdFn!\n }\n\n if (row.driver === 'filesystem') {\n const fsMeta = metadata as FilesystemMetadata\n config.basePath = resolveStoragePath(fsMeta.basePath || './storage', projectPath)\n\n // Crear directorio si no existe\n if (!existsSync(config.basePath)) {\n mkdirSync(config.basePath, { recursive: true })\n }\n } else if (row.driver === 's3') {\n const s3Meta = metadata as S3Metadata\n config.basePath = '' // No aplica para S3\n config.s3 = {\n bucket: s3Meta.bucket,\n region: s3Meta.region,\n accessKeyId: s3Meta.accessKeyId,\n secretAccessKey: s3Meta.secretAccessKey,\n endpoint: s3Meta.endpoint\n }\n }\n\n return config\n}\n\n/**\n * Construye StorageConfig desde variables de entorno\n */\nfunction buildConfigFromEnv(driver: 'filesystem' | 's3'): StorageConfig {\n const config: StorageConfig = {\n scope: getDefaultScope(driver),\n driver,\n basePath: '',\n baseUrl: process.env['STORAGE_URL'],\n maxFileSize: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowedMimeTypes: process.env['STORAGE_ALLOWED_TYPES']?.split(',').map(t => t.trim()),\n generateId: generateIdFn!\n }\n\n if (driver === 'filesystem') {\n const rawPath = process.env['STORAGE_PATH'] || './storage'\n config.basePath = resolveStoragePath(rawPath, projectPath)\n\n if (!existsSync(config.basePath)) {\n mkdirSync(config.basePath, { recursive: true })\n }\n } else if (driver === 's3') {\n const bucket = process.env['S3_BUCKET']\n const region = process.env['S3_REGION']\n const accessKeyId = process.env['S3_ACCESS_KEY']\n const secretAccessKey = process.env['S3_SECRET_KEY']\n\n if (!bucket || !region || !accessKeyId || !secretAccessKey) {\n throw new Error('S3 configuration incomplete. Required: S3_BUCKET, S3_REGION, S3_ACCESS_KEY, S3_SECRET_KEY')\n }\n\n config.s3 = {\n bucket,\n region,\n accessKeyId,\n secretAccessKey,\n endpoint: process.env['S3_ENDPOINT']\n }\n }\n\n return config\n}\n\nexport interface InitStorageConfigOptions {\n projectPath?: string\n generateId: () => string\n}\n\n/**\n * Inicializa la configuración de storage (singleton por defecto)\n * Usa scope 'default_filesystem' desde BD si existe, sino env vars\n */\nexport function initStorageConfig(options: InitStorageConfigOptions): StorageConfig {\n projectPath = options.projectPath ?? process.cwd()\n generateIdFn = options.generateId\n\n // Config por defecto desde env vars (sync, para init rápido)\n const driver = (process.env['STORAGE_DRIVER'] as 'filesystem' | 's3') || 'filesystem'\n defaultConfig = buildConfigFromEnv(driver)\n\n return defaultConfig\n}\n","import type { Knex } from 'knex'\nimport { logger } from '../core/logger.js'\n\n/**\n * Get the database client type\n * Returns 'sqlite' as default when client type cannot be determined (e.g., in mocks)\n */\nexport function getDbClient(db: Knex): 'postgres' | 'mysql' | 'sqlite' {\n const client = (db.client?.config?.client ?? 'sqlite') as string\n if (client === 'pg' || client === 'postgresql') return 'postgres'\n if (client === 'mysql' || client === 'mysql2') return 'mysql'\n return 'sqlite'\n}\n\n/**\n * Format timestamp for database insert/update\n * - PostgreSQL: accepts ISO strings directly\n * - MySQL: requires 'YYYY-MM-DD HH:MM:SS' format\n * - SQLite: accepts ISO strings (stored as TEXT)\n *\n * @param db Knex instance to detect driver\n * @param date Date object (defaults to now)\n * @returns Formatted timestamp string\n */\nexport function formatTimestamp(db: Knex, date: Date = new Date()): string {\n const client = getDbClient(db)\n\n if (client === 'mysql') {\n // MySQL requires YYYY-MM-DD HH:MM:SS format\n return date.toISOString().slice(0, 19).replace('T', ' ')\n }\n\n // PostgreSQL and SQLite accept ISO strings\n return date.toISOString()\n}\n\n/**\n * Get current timestamp formatted for the database\n */\nexport function nowTimestamp(db: Knex): string {\n return formatTimestamp(db, new Date())\n}\n\n/**\n * Añade campos de timestamp a una tabla durante su creación\n * - PostgreSQL: usa timestamptz (timestamp with time zone)\n * - MySQL: usa timestamp estándar\n * - SQLite: usa TEXT con datetime('now') para consistencia con ISO strings\n */\nexport function addTimestamps(table: Knex.CreateTableBuilder, db: Knex) {\n const client = (db.client?.config?.client ?? 'sqlite3') as string\n const isPostgres = client === 'pg' || client === 'postgresql'\n const isSqlite = client === 'better-sqlite3' || client === 'sqlite3' || client === 'sqlite'\n\n if (isPostgres) {\n // PostgreSQL: usar timestamp with time zone\n table.timestamp('created_at', { useTz: true }).defaultTo(db.fn.now())\n table.timestamp('updated_at', { useTz: true }).defaultTo(db.fn.now())\n } else if (isSqlite) {\n // SQLite: usar datetime('now') que genera strings ISO directamente\n // Nota: SQLite requiere paréntesis extra para funciones en DEFAULT\n table.text('created_at').defaultTo(db.raw(\"(datetime('now'))\"))\n table.text('updated_at').defaultTo(db.raw(\"(datetime('now'))\"))\n } else {\n // MySQL: timestamp estándar\n table.timestamp('created_at').defaultTo(db.fn.now())\n table.timestamp('updated_at').defaultTo(db.fn.now())\n }\n}\n\n/**\n * Añade campos de auditoría (created_by, updated_by) a una tabla existente si no existen\n * Nota: SQLite no soporta ALTER TABLE ADD COLUMN con default no constante\n */\nexport async function addAuditFieldsIfMissing(db: Knex, tableName: string): Promise<void> {\n if (!(await db.schema.hasColumn(tableName, 'created_by'))) {\n await db.schema.alterTable(tableName, (table) => {\n // Sin FK para evitar dependencias circulares entre módulos\n table.string('created_by').nullable()\n table.string('updated_by').nullable()\n })\n logger.info(`Added audit fields to: ${tableName}`)\n }\n}\n\n/**\n * Añade campo is_default a tablas de tipo config\n * Permite marcar cuál configuración es la default en runtime\n */\nexport async function addConfigDefaultField(db: Knex, tableName: string): Promise<void> {\n if (!(await db.schema.hasColumn(tableName, 'is_default'))) {\n await db.schema.alterTable(tableName, (table) => {\n table.boolean('is_default').defaultTo(false).nullable()\n })\n logger.info(`Added is_default field to config table: ${tableName}`)\n }\n}\n\n/**\n * Añade una columna si no existe\n */\nexport async function addColumnIfMissing(\n db: Knex,\n tableName: string,\n columnName: string,\n columnBuilder: (table: Knex.AlterTableBuilder) => void\n): Promise<boolean> {\n if (!(await db.schema.hasColumn(tableName, columnName))) {\n await db.schema.alterTable(tableName, columnBuilder)\n logger.info(`Added column: ${tableName}.${columnName}`)\n return true\n }\n return false\n}\n","export class AppError extends Error {\n public readonly statusCode: number\n public readonly details?: unknown\n\n constructor(message: string, statusCode: number = 400, details?: unknown) {\n super(message)\n this.statusCode = statusCode\n this.details = details\n this.name = 'AppError'\n Error.captureStackTrace(this, this.constructor)\n }\n}\n\nexport class NotFoundError extends AppError {\n constructor(resource: string = 'Recurso') {\n super(`${resource} no encontrado`, 404)\n this.name = 'NotFoundError'\n }\n}\n\nexport class UnauthorizedError extends AppError {\n constructor(message: string = 'No autorizado') {\n super(message, 401)\n this.name = 'UnauthorizedError'\n }\n}\n\nexport class ForbiddenError extends AppError {\n constructor(message: string = 'Acceso denegado') {\n super(message, 403)\n this.name = 'ForbiddenError'\n }\n}\n\nexport class ConflictError extends AppError {\n constructor(message: string = 'Conflicto') {\n super(message, 409)\n this.name = 'ConflictError'\n }\n}\n\nexport class ValidationError extends AppError {\n public readonly errors: unknown[]\n\n constructor(message: string = 'Error de validación', errors: unknown[] = []) {\n super(message, 400)\n this.name = 'ValidationError'\n this.errors = errors\n }\n}\n","/**\n * Storage Service\n *\n * Servicio para gestión de archivos con soporte para thumbnails.\n * Soporta múltiples configuraciones de storage (scopes) desde BD.\n */\n\nimport type { Logger } from 'pino'\nimport type { Knex } from 'knex'\nimport sharp from 'sharp'\nimport type { StorageDriver, StorageFile } from './drivers/driver.interface.js'\nimport { FilesystemDriver } from './drivers/filesystem.driver.js'\nimport { S3Driver } from './drivers/s3.driver.js'\nimport { initStorageConfig, getConfigByScope, type StorageConfig } from './storage.config.js'\nimport type { UploadedFile, UploadOptions, StorageFileRecord } from './storage.types.js'\nimport type { LoggerReporter } from '@gzl10/nexus-sdk'\nimport { nowTimestamp } from '../../db/helpers.js'\nimport { ValidationError, NotFoundError } from '../../core/errors/app-error.js'\n\n// Re-export types for backwards compatibility\nexport type { UploadedFile, UploadOptions, StorageFileRecord } from './storage.types.js'\n\nconst TABLE = 'storage_files'\n\nlet storageServiceInstance: StorageService | null = null\n\n/**\n * Obtiene la instancia del servicio de storage\n */\nexport function getStorageService(): StorageService {\n if (!storageServiceInstance) {\n throw new Error('StorageService not initialized. Call initStorageService() first.')\n }\n return storageServiceInstance\n}\n\nexport interface InitStorageServiceOptions {\n db: Knex\n logger: Logger\n generateId: () => string\n loggerService?: LoggerReporter\n projectPath?: string\n}\n\n/**\n * Inicializa el servicio de storage\n */\nexport function initStorageService(options: InitStorageServiceOptions): StorageService {\n const { db, logger, generateId, loggerService, projectPath } = options\n const config = initStorageConfig({ projectPath, generateId })\n storageServiceInstance = new StorageService(db, config, logger, loggerService)\n return storageServiceInstance\n}\n\nexport class StorageService {\n private driver: StorageDriver\n private config: StorageConfig\n private db: Knex\n private logger: Logger\n private loggerService?: LoggerReporter\n /** Cache de drivers por scope */\n private driverCache: Map<string, StorageDriver> = new Map()\n\n constructor(db: Knex, config: StorageConfig, logger: Logger, loggerService?: LoggerReporter) {\n this.db = db\n this.config = config\n this.logger = logger.child({ service: 'storage' })\n this.loggerService = loggerService\n\n // Inicializar driver por defecto según configuración\n this.driver = this.createDriver(config)\n this.logger.debug({ driver: config.driver }, 'Storage driver initialized')\n }\n\n /**\n * Crea un driver según la configuración\n */\n private createDriver(config: StorageConfig): StorageDriver {\n switch (config.driver) {\n case 's3':\n return new S3Driver(config)\n case 'filesystem':\n default:\n return new FilesystemDriver(config)\n }\n }\n\n /**\n * Obtiene un driver por scope (con cache)\n */\n private async getDriverByScope(scope: string): Promise<{ driver: StorageDriver; config: StorageConfig }> {\n // Revisar cache primero\n const cached = this.driverCache.get(scope)\n if (cached) {\n // Obtener config para validaciones\n const config = await getConfigByScope(this.db, scope)\n return { driver: cached, config }\n }\n\n // Obtener config desde BD\n const config = await getConfigByScope(this.db, scope)\n const driver = this.createDriver(config)\n\n // Guardar en cache\n this.driverCache.set(scope, driver)\n this.logger.debug({ scope, driver: config.driver }, 'Driver created for scope')\n\n return { driver, config }\n }\n\n /**\n * Subir un archivo\n */\n async upload(file: UploadedFile, options?: UploadOptions): Promise<StorageFileRecord> {\n // Obtener driver y config según scope (o usar defaults)\n let driver = this.driver\n let config = this.config\n\n if (options?.scope) {\n const scoped = await this.getDriverByScope(options.scope)\n driver = scoped.driver\n config = scoped.config\n }\n\n // Validar tamaño\n if (file.size > config.maxFileSize) {\n throw new ValidationError(`File size ${file.size} exceeds limit ${config.maxFileSize}`)\n }\n\n // Validar tipo MIME\n if (config.allowedMimeTypes?.length) {\n const allowed = config.allowedMimeTypes.some(type => {\n if (type.endsWith('/*')) {\n return file.mimetype.startsWith(type.slice(0, -1))\n }\n return type === file.mimetype\n })\n if (!allowed) {\n throw new ValidationError(`File type ${file.mimetype} not allowed`)\n }\n }\n\n // Guardar archivo principal\n const storageFile = await driver.put(file.buffer, file.originalname, {\n folder: options?.folder,\n mimetype: file.mimetype\n })\n\n // Generar thumbnails si es imagen y se solicitan\n let thumbnailUrl: string | undefined\n if (options?.thumbnails?.length && this.isImage(file.mimetype)) {\n thumbnailUrl = await this.generateThumbnails(\n file.buffer,\n storageFile,\n options.thumbnails,\n options.folder,\n driver\n )\n }\n\n // Guardar metadatos en BD\n const now = nowTimestamp(this.db)\n const record: StorageFileRecord = {\n ...storageFile,\n url: storageFile.url || driver.getUrl(storageFile.path) || undefined,\n created_at: now,\n updated_at: now,\n created_by: options?.userId || null,\n updated_by: options?.userId || null\n }\n\n await this.db(TABLE).insert({\n id: record.id,\n filename: record.filename,\n disk_filename: record.diskFilename,\n mimetype: record.mimetype,\n size: record.size,\n folder: record.folder || null,\n scope: config.scope,\n path: record.path,\n url: record.url || null,\n thumbnail_url: thumbnailUrl || null,\n hash: record.hash || null,\n metadata: null,\n created_at: now,\n updated_at: now,\n created_by: record.created_by,\n updated_by: record.updated_by\n })\n\n this.logger.info({ id: record.id, filename: record.filename, size: record.size }, 'File uploaded')\n\n return {\n ...record,\n url: record.url,\n thumbnail_url: thumbnailUrl\n } as StorageFileRecord & { thumbnail_url?: string }\n }\n\n /**\n * Genera thumbnails para una imagen\n */\n private async generateThumbnails(\n buffer: Buffer,\n originalFile: StorageFile,\n sizes: Array<{ width: number; height: number }>,\n folder: string | undefined,\n driver: StorageDriver\n ): Promise<string | undefined> {\n // Generar el primer thumbnail como principal\n const firstSize = sizes[0]\n if (!firstSize) return undefined\n\n try {\n const thumbnailBuffer = await sharp(buffer)\n .resize(firstSize.width, firstSize.height, {\n fit: 'cover',\n position: 'center'\n })\n .jpeg({ quality: 80 })\n .toBuffer()\n\n const thumbnailFolder = folder\n ? `${folder}/thumbnails/${firstSize.width}x${firstSize.height}`\n : `thumbnails/${firstSize.width}x${firstSize.height}`\n\n const thumbnail = await driver.put(\n thumbnailBuffer,\n originalFile.filename.replace(/\\.[^.]+$/, '.jpg'),\n { folder: thumbnailFolder, mimetype: 'image/jpeg' }\n )\n\n this.logger.debug(\n { originalId: originalFile.id, size: `${firstSize.width}x${firstSize.height}` },\n 'Thumbnail generated'\n )\n\n // Generar thumbnails adicionales en background (no bloqueante)\n if (sizes.length > 1) {\n this.generateAdditionalThumbnails(buffer, originalFile, sizes.slice(1), folder, driver)\n .catch(err => {\n const error = err instanceof Error ? err : new Error('Error generating additional thumbnails')\n this.logger.error({ err }, 'Error generating additional thumbnails')\n this.loggerService?.captureException(error, { service: 'storage', action: 'thumbnail', originalId: originalFile.id })\n })\n }\n\n return thumbnail.url || driver.getUrl(thumbnail.path) || undefined\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Error generating thumbnail')\n this.logger.error({ err, originalId: originalFile.id }, 'Error generating thumbnail')\n this.loggerService?.captureException(error, { service: 'storage', action: 'thumbnail', originalId: originalFile.id })\n return undefined\n }\n }\n\n /**\n * Genera thumbnails adicionales en background\n */\n private async generateAdditionalThumbnails(\n buffer: Buffer,\n originalFile: StorageFile,\n sizes: Array<{ width: number; height: number }>,\n folder: string | undefined,\n driver: StorageDriver\n ): Promise<void> {\n for (const size of sizes) {\n try {\n const thumbnailBuffer = await sharp(buffer)\n .resize(size.width, size.height, {\n fit: 'cover',\n position: 'center'\n })\n .jpeg({ quality: 80 })\n .toBuffer()\n\n const thumbnailFolder = folder\n ? `${folder}/thumbnails/${size.width}x${size.height}`\n : `thumbnails/${size.width}x${size.height}`\n\n await driver.put(\n thumbnailBuffer,\n originalFile.filename.replace(/\\.[^.]+$/, '.jpg'),\n { folder: thumbnailFolder, mimetype: 'image/jpeg' }\n )\n\n this.logger.debug(\n { originalId: originalFile.id, size: `${size.width}x${size.height}` },\n 'Additional thumbnail generated'\n )\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Error generating additional thumbnail')\n this.logger.error({ err, size }, 'Error generating additional thumbnail')\n this.loggerService?.captureException(error, { service: 'storage', action: 'thumbnail', size })\n }\n }\n }\n\n /**\n * Verifica si un mimetype es de imagen\n */\n private isImage(mimetype: string): boolean {\n return mimetype.startsWith('image/')\n }\n\n /**\n * Obtener archivo por ID\n */\n async getById(id: string): Promise<StorageFileRecord | null> {\n const record = await this.db(TABLE).where('id', id).first()\n if (!record) return null\n\n return this.mapRecord(record)\n }\n\n /**\n * Obtener múltiples archivos por IDs\n */\n async getByIds(ids: string[]): Promise<StorageFileRecord[]> {\n if (ids.length === 0) return []\n\n const records = await this.db(TABLE).whereIn('id', ids)\n return records.map((r: unknown) => this.mapRecord(r))\n }\n\n /**\n * Obtener el driver apropiado para un scope\n * Si el scope coincide con el default, usa this.driver\n */\n private async getDriverForScope(scope: string | undefined): Promise<StorageDriver> {\n // Si no hay scope o es el scope por defecto, usar driver default\n if (!scope || scope === this.config.scope) {\n return this.driver\n }\n return (await this.getDriverByScope(scope)).driver\n }\n\n /**\n * Obtener stream de archivo\n */\n async getStream(id: string): Promise<NodeJS.ReadableStream> {\n const record = await this.getById(id)\n if (!record) {\n throw new NotFoundError(`File not found: ${id}`)\n }\n\n const driver = await this.getDriverForScope(record.scope)\n return driver.get(record.path)\n }\n\n /**\n * Obtener buffer de archivo\n */\n async getBuffer(id: string): Promise<Buffer> {\n const record = await this.getById(id)\n if (!record) {\n throw new NotFoundError(`File not found: ${id}`)\n }\n\n const driver = await this.getDriverForScope(record.scope)\n return driver.getBuffer(record.path)\n }\n\n /**\n * Eliminar archivo\n */\n async delete(id: string): Promise<void> {\n const record = await this.getById(id)\n if (!record) return\n\n const driver = await this.getDriverForScope(record.scope)\n\n // Eliminar de storage\n await driver.delete(record.path)\n\n // Eliminar de BD\n await this.db(TABLE).where('id', id).delete()\n\n this.logger.info({ id, filename: record.filename }, 'File deleted')\n }\n\n /**\n * Listar archivos con paginación\n */\n async findAll(params: {\n page: number\n limit: number\n folder?: string\n mimetype?: string\n }): Promise<{\n items: StorageFileRecord[]\n total: number\n page: number\n limit: number\n totalPages: number\n hasNext: boolean\n }> {\n const { page, limit, folder, mimetype } = params\n const offset = (page - 1) * limit\n\n let query = this.db(TABLE)\n\n if (folder) {\n query = query.where('folder', folder)\n }\n if (mimetype) {\n query = query.where('mimetype', 'like', `${mimetype}%`)\n }\n\n const [countResult, items] = await Promise.all([\n query.clone().count('* as count').first<{ count: string | number }>(),\n query.clone().orderBy('created_at', 'desc').limit(limit).offset(offset)\n ])\n\n const total = Number(countResult?.count ?? 0)\n const totalPages = Math.ceil(total / limit)\n\n return {\n items: items.map((r: unknown) => this.mapRecord(r)),\n total,\n page,\n limit,\n totalPages,\n hasNext: page < totalPages\n }\n }\n\n /**\n * Mapea un registro de BD a StorageFileRecord\n */\n private mapRecord(record: unknown): StorageFileRecord {\n const r = record as Record<string, unknown>\n return {\n id: r['id'] as string,\n filename: r['filename'] as string,\n diskFilename: r['disk_filename'] as string,\n mimetype: r['mimetype'] as string,\n size: r['size'] as number,\n folder: r['folder'] as string | undefined,\n scope: r['scope'] as string | undefined,\n path: r['path'] as string,\n url: r['url'] as string | undefined,\n hash: r['hash'] as string | undefined,\n created_at: r['created_at'] as string,\n updated_at: r['updated_at'] as string,\n created_by: r['created_by'] as string | null,\n updated_by: r['updated_by'] as string | null\n }\n }\n}\n","import rateLimit, { type Options } from 'express-rate-limit'\n\nexport interface RateLimitOptions {\n /** Time window in milliseconds (default: 60000 = 1 minute) */\n windowMs?: number\n /** Max requests per window (default: 100) */\n max?: number\n /** Message when limit is reached */\n message?: string\n}\n\n/**\n * Creates a rate limit middleware\n *\n * @example\n * // 100 requests per minute (default)\n * router.use(createRateLimit())\n *\n * @example\n * // 5 requests per 15 minutes for login\n * router.post('/login', createRateLimit({ windowMs: 15 * 60 * 1000, max: 5 }), handler)\n */\nexport function createRateLimit(options: RateLimitOptions = {}) {\n const {\n windowMs = 60 * 1000,\n max = 100,\n message = 'Too many requests, please try again later'\n } = options\n\n return rateLimit({\n windowMs,\n max,\n message: { error: message },\n standardHeaders: 'draft-7',\n legacyHeaders: false,\n // Skip trust proxy validation - we handle this at app level\n validate: { trustProxy: false }\n } satisfies Partial<Options>)\n}\n","import type { CollectionEntityDefinition, ConfigEntityDefinition, ActionEntityDefinition, ModuleContext, Request, Response } from '@gzl10/nexus-sdk'\nimport multer from 'multer'\nimport { getStorageService } from './storage.service.js'\nimport { getStorageConfig } from './storage.config.js'\nimport type { UploadedFile } from './storage.types.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\n// Re-export types for backwards compatibility\nexport type { FilesystemMetadata, S3Metadata, StorageDriverMetadata } from './storage.types.js'\n\n// ============================================================================\n// CONFIG ENTITY\n// ============================================================================\n\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\n\n/**\n * Config Entity: storage_config\n *\n * Campos comunes + metadata JSON para especialización por driver.\n */\nexport const storageConfigEntity: ConfigEntityDefinition = {\n type: 'config',\n table: 'storage_config',\n label: 'Storage Config',\n routePrefix: '/config',\n scopeField: 'scope',\n timestamps: true,\n\n // Defaults desde variables de entorno\n get defaults() {\n return {\n driver: process.env['STORAGE_DRIVER'] || 'filesystem',\n base_url: process.env['STORAGE_URL'] || '',\n max_file_size: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowed_mime_types: process.env['STORAGE_ALLOWED_TYPES'] || '',\n metadata: {}\n }\n },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n scope: {\n name: 'scope',\n label: 'Scope',\n disabled: true,\n input: 'text',\n hint: 'Identificador único (ej: default_filesystem, default_s3)',\n db: { type: 'string', size: 100, nullable: false, unique: true }\n },\n driver: {\n name: 'driver',\n label: 'Driver',\n input: 'select',\n hint: 'Backend de almacenamiento',\n db: { type: 'string', size: 20, nullable: false },\n validation: { required: true, enum: ['filesystem', 's3'] },\n options: {\n static: [\n { value: 'filesystem', label: 'Filesystem (local)' },\n { value: 's3', label: 'S3 (AWS/MinIO)' }\n ]\n }\n },\n base_url: {\n name: 'base_url',\n label: 'Base URL',\n input: 'url',\n hint: 'URL pública para generar enlaces a archivos',\n db: { type: 'string', size: 500, nullable: true }\n },\n max_file_size: {\n name: 'max_file_size',\n label: 'Max File Size (bytes)',\n input: 'number',\n hint: 'Tamaño máximo en bytes (default: 10MB = 10485760)',\n db: { type: 'integer', nullable: false }\n },\n allowed_mime_types: {\n name: 'allowed_mime_types',\n label: 'Allowed MIME Types',\n input: 'text',\n hint: 'Tipos permitidos separados por coma (ej: image/*,application/pdf)',\n db: { type: 'string', size: 1000, nullable: true }\n },\n metadata: {\n name: 'metadata',\n label: 'Driver Config',\n input: 'json',\n hint: 'Configuración específica del driver (filesystem: basePath, s3: bucket/region/keys)',\n db: { type: 'json', nullable: true }\n }\n },\n\n casl: {\n subject: 'StorageConfig',\n permissions: {\n ADMIN: { actions: ['read', 'update'] }\n }\n }\n}\n\n// ============================================================================\n// COLLECTION ENTITY\n// ============================================================================\n\n/**\n * EntityDefinition para Storage Files\n *\n * Almacena metadatos de archivos subidos al sistema.\n * Los archivos físicos se guardan en el driver configurado (filesystem/S3).\n */\nexport const storageFilesEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'storage_files',\n label: 'Storage Files',\n labelField: 'filename',\n timestamps: true,\n audit: true,\n routePrefix: '/files',\n\n actions: [\n {\n key: 'download',\n label: 'Download File',\n icon: 'mdi:download',\n method: 'GET',\n select: ['id', 'filename', 'mimetype', 'size'],\n handler: async (ctx: ModuleContext, input: unknown, _req?: Request, res?: Response) => {\n if (!res) {\n throw new ctx.errors.AppError('Response required for download', 500)\n }\n\n const { _record: file } = input as {\n _record: { id: string; filename: string; mimetype: string; size: number }\n }\n\n const storageService = getStorageService()\n const stream = await storageService.getStream(file.id)\n\n res.setHeader('Content-Type', file.mimetype)\n res.setHeader('Content-Disposition', `attachment; filename=\"${encodeURIComponent(file.filename)}\"`)\n res.setHeader('Content-Length', file.size.toString())\n\n stream.pipe(res)\n },\n casl: { action: 'read' }\n },\n {\n key: 'inline',\n label: 'View File',\n icon: 'mdi:eye',\n method: 'GET',\n select: ['id', 'filename', 'mimetype', 'size'],\n handler: async (ctx: ModuleContext, input: unknown, _req?: Request, res?: Response) => {\n if (!res) {\n throw new ctx.errors.AppError('Response required for inline view', 500)\n }\n\n const { _record: file } = input as {\n _record: { id: string; filename: string; mimetype: string; size: number }\n }\n\n const storageService = getStorageService()\n const stream = await storageService.getStream(file.id)\n\n res.setHeader('Content-Type', file.mimetype)\n res.setHeader('Content-Disposition', `inline; filename=\"${encodeURIComponent(file.filename)}\"`)\n res.setHeader('Content-Length', file.size.toString())\n\n stream.pipe(res)\n },\n casl: { action: 'read' }\n }\n ],\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n filename: {\n name: 'filename',\n label: 'Nombre original',\n input: 'text',\n db: { type: 'string', size: 255, nullable: false },\n validation: { required: true },\n meta: { sortable: true, searchable: true }\n },\n disk_filename: {\n name: 'disk_filename',\n label: 'Nombre en disco',\n input: 'hidden',\n db: { type: 'string', size: 255, nullable: false },\n validation: { required: true }\n },\n mimetype: {\n name: 'mimetype',\n label: 'Tipo MIME',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false, index: true },\n validation: { required: true },\n meta: { sortable: true, searchable: true }\n },\n size: {\n name: 'size',\n label: 'Tamaño (bytes)',\n input: 'number',\n db: { type: 'integer', nullable: false },\n validation: { required: true, min: 0 },\n meta: { sortable: true }\n },\n folder: {\n name: 'folder',\n label: 'Carpeta',\n input: 'text',\n db: { type: 'string', size: 100, nullable: true, index: true },\n meta: { searchable: true }\n },\n scope: {\n name: 'scope',\n label: 'Storage Scope',\n input: 'hidden',\n db: { type: 'string', size: 50, nullable: true, index: true },\n hint: 'Storage configuration scope used for this file'\n },\n path: {\n name: 'path',\n label: 'Ruta completa',\n input: 'hidden',\n db: { type: 'string', size: 500, nullable: false },\n validation: { required: true }\n },\n url: {\n name: 'url',\n label: 'URL pública',\n input: 'url',\n db: { type: 'string', size: 500, nullable: true },\n meta: { exportable: true }\n },\n thumbnail_url: {\n name: 'thumbnail_url',\n label: 'URL thumbnail',\n input: 'url',\n db: { type: 'string', size: 500, nullable: true }\n },\n hash: {\n name: 'hash',\n label: 'Hash SHA256',\n input: 'hidden',\n db: { type: 'string', size: 64, nullable: true, index: true }\n },\n metadata: {\n name: 'metadata',\n label: 'Metadata',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n }\n },\n\n indexes: [\n { columns: ['folder', 'filename'] }\n ],\n\n casl: {\n subject: 'StorageFile',\n permissions: {\n ADMIN: {\n actions: ['manage']\n },\n EDITOR: {\n actions: ['create', 'read', 'delete'],\n conditions: { created_by: '${user.id}' }\n },\n VIEWER: {\n actions: ['read']\n }\n }\n }\n}\n\n// ============================================================================\n// ACTION ENTITIES\n// ============================================================================\n\n/**\n * Action: Upload File\n *\n * POST /storage/upload\n * Content-Type: multipart/form-data\n */\nexport const storageUploadAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Upload File',\n icon: 'mdi:upload',\n routePrefix: '/upload',\n successStatus: 201,\n\n fields: {\n file: {\n name: 'file',\n label: 'File',\n input: 'file',\n validation: { required: true }\n },\n folder: {\n name: 'folder',\n label: 'Folder',\n input: 'text',\n hint: 'Optional folder path'\n },\n scope: {\n name: 'scope',\n label: 'Storage Scope',\n input: 'text',\n hint: 'Storage config scope (default: uses default config)'\n }\n },\n\n middleware: (_ctx) => {\n const rateLimit = createRateLimit({ windowMs: 60 * 1000, max: 20, message: 'Demasiados uploads, intenta en 1 minuto' })\n const config = getStorageConfig()\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: config.maxFileSize }\n })\n return [rateLimit, upload.single('file')]\n },\n\n handler: async (ctx, _input, req, res) => {\n if (!req || !res) {\n throw new ctx.errors.AppError('Request and response required for upload', 500)\n }\n\n const authReq = req as AuthRequest\n const file = authReq.file as UploadedFile | undefined\n\n if (!file) {\n res.status(400).json({ error: 'No file provided' })\n return\n }\n\n const folder = req.body?.folder as string | undefined\n const scope = req.body?.scope as string | undefined\n\n const storageService = getStorageService()\n const result = await storageService.upload(\n {\n fieldname: file.fieldname,\n originalname: file.originalname,\n mimetype: file.mimetype,\n buffer: file.buffer,\n size: file.size\n },\n {\n folder,\n scope,\n userId: authReq.user?.id\n }\n )\n\n return result\n },\n\n casl: {\n subject: 'StorageFile',\n permissions: {\n ADMIN: { actions: ['execute'] },\n EDITOR: { actions: ['execute'] }\n }\n }\n}\n\n// NOTE: storageDownloadAction ha sido migrado a storageFilesEntity.actions[]\n// Ruta: GET /storage/files/download/:id\n","/**\n * Storage Routes\n *\n * Rutas adicionales para storage (upload multiple).\n * Las rutas principales (upload, download, inline) se manejan via EntityActions.\n */\n\nimport type { ModuleContext, Request, Response } from '@gzl10/nexus-sdk'\nimport multer from 'multer'\nimport { getStorageConfig } from './storage.config.js'\nimport { getStorageService, type UploadedFile } from './storage.service.js'\nimport { storageFilesEntity, storageConfigEntity } from './storage.entity.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\nexport function createStorageRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { auth } = ctx.middleware\n const config = getStorageConfig()\n\n // Configurar multer para almacenamiento en memoria\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: config.maxFileSize }\n })\n\n // ============================================================================\n // UPLOAD MULTIPLE (no hay action para esto aún)\n // ============================================================================\n\n const uploadMultiple = async (req: Request, res: Response): Promise<void> => {\n const authReq = req as AuthRequest\n const files = (req as { files?: Express.Multer.File[] }).files\n\n if (!files?.length) {\n res.status(400).json({ error: 'No files uploaded' })\n return\n }\n\n const folder = req.body?.['folder'] as string | undefined\n const storageService = getStorageService()\n const results = []\n\n for (const f of files) {\n const file: UploadedFile = {\n fieldname: f.fieldname,\n originalname: f.originalname,\n mimetype: f.mimetype,\n buffer: f.buffer,\n size: f.size\n }\n const result = await storageService.upload(file, {\n folder,\n userId: authReq.user?.id\n })\n results.push(result)\n }\n\n res.status(201).json(results)\n }\n\n // Rate limit para prevenir abuso de uploads\n const uploadRateLimit = createRateLimit({ windowMs: 60 * 1000, max: 20, message: 'Demasiados uploads, intenta en 1 minuto' })\n\n if (auth) {\n router.post('/upload/multiple', uploadRateLimit, auth, upload.array('files', 10), uploadMultiple)\n } else {\n router.post('/upload/multiple', uploadRateLimit, upload.array('files', 10), uploadMultiple)\n }\n\n // ============================================================================\n // CRUD para storage_files (runtime)\n // Las EntityActions 'download' e 'inline' se montan automáticamente\n // ============================================================================\n\n const filesService = ctx.createEntityService(storageFilesEntity)\n const filesController = ctx.createEntityController(filesService, storageFilesEntity)\n\n // Deshabilitar create y update via API REST estándar\n // Los archivos solo se crean via upload action\n delete filesController.create\n delete filesController.update\n\n // Sobrescribir delete para eliminar también el archivo físico\n filesController.delete = async (req: Request, res: Response): Promise<void> => {\n const id = req.params['id']\n if (!id) {\n res.status(400).json({ error: 'File ID required' })\n return\n }\n\n const storageService = getStorageService()\n const file = await storageService.getById(id)\n if (!file) {\n res.status(404).json({ error: 'File not found' })\n return\n }\n\n await storageService.delete(id)\n res.status(204).send()\n }\n\n const filesRouter = ctx.createEntityRouter(filesController, storageFilesEntity)\n router.use(storageFilesEntity.routePrefix ?? '/files', filesRouter)\n\n // ============================================================================\n // CONFIG (runtime)\n // ============================================================================\n\n const configService = ctx.createEntityService(storageConfigEntity)\n const configController = ctx.createEntityController(configService, storageConfigEntity)\n const configRouter = ctx.createEntityRouter(configController, storageConfigEntity)\n router.use(storageConfigEntity.routePrefix ?? '/config', configRouter)\n\n return router\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport type { FilesystemMetadata, S3Metadata } from './storage.entity.js'\nimport { DEFAULT_FILESYSTEM_SCOPE, DEFAULT_S3_SCOPE } from './storage.config.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nconst TABLE = 'storage_config'\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\n\n/**\n * Seed para storage: crea configuraciones iniciales desde variables de entorno\n *\n * Scopes creados:\n * - default_filesystem: siempre se crea con config filesystem\n * - default_s3: solo si S3_BUCKET está configurado\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n const now = nowTimestamp(db)\n\n // ============================================================================\n // FILESYSTEM CONFIG (siempre)\n // ============================================================================\n\n const existingFs = await db(TABLE).where({ scope: DEFAULT_FILESYSTEM_SCOPE }).first()\n if (!existingFs) {\n const fsMetadata: FilesystemMetadata = {\n basePath: process.env['STORAGE_PATH'] || './storage'\n }\n\n await db(TABLE).insert({\n id: generateId(),\n scope: DEFAULT_FILESYSTEM_SCOPE,\n driver: 'filesystem',\n base_url: process.env['STORAGE_URL'] || null,\n max_file_size: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowed_mime_types: process.env['STORAGE_ALLOWED_TYPES'] || null,\n metadata: JSON.stringify(fsMetadata),\n is_default: true,\n created_at: now,\n updated_at: now\n })\n logger.info(`Storage config seeded: ${DEFAULT_FILESYSTEM_SCOPE}`)\n } else {\n logger.debug(`Storage config ${DEFAULT_FILESYSTEM_SCOPE} already exists`)\n }\n\n // ============================================================================\n // S3 CONFIG (solo si hay bucket configurado)\n // ============================================================================\n\n const s3Bucket = process.env['S3_BUCKET']\n if (s3Bucket) {\n const existingS3 = await db(TABLE).where({ scope: DEFAULT_S3_SCOPE }).first()\n if (!existingS3) {\n const s3Region = process.env['S3_REGION']\n const s3AccessKey = process.env['S3_ACCESS_KEY']\n const s3SecretKey = process.env['S3_SECRET_KEY']\n\n if (!s3Region || !s3AccessKey || !s3SecretKey) {\n logger.warn('S3_BUCKET defined but missing S3_REGION, S3_ACCESS_KEY or S3_SECRET_KEY - skipping S3 seed')\n return\n }\n\n const s3Metadata: S3Metadata = {\n bucket: s3Bucket,\n region: s3Region,\n accessKeyId: s3AccessKey,\n secretAccessKey: s3SecretKey,\n endpoint: process.env['S3_ENDPOINT'] || undefined\n }\n\n await db(TABLE).insert({\n id: generateId(),\n scope: DEFAULT_S3_SCOPE,\n driver: 's3',\n base_url: process.env['STORAGE_URL'] || null,\n max_file_size: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowed_mime_types: process.env['STORAGE_ALLOWED_TYPES'] || null,\n metadata: JSON.stringify(s3Metadata),\n is_default: false,\n created_at: now,\n updated_at: now\n })\n logger.info(`Storage config seeded: ${DEFAULT_S3_SCOPE}`)\n } else {\n logger.debug(`Storage config ${DEFAULT_S3_SCOPE} already exists`)\n }\n }\n}\n","/**\n * Storage Module\n *\n * Gestión de archivos con soporte para filesystem y S3.\n */\n\nimport type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { storageConfigEntity, storageFilesEntity, storageUploadAction } from './storage.entity.js'\nimport { initStorageService } from './storage.service.js'\nimport { createStorageRoutes } from './storage.routes.js'\n\n// Re-exports\nexport { StorageService, getStorageService } from './storage.service.js'\nexport { getStorageConfig, type StorageConfig } from './storage.config.js'\nexport type { StorageDriver, StorageFile, PutOptions } from './drivers/driver.interface.js'\nexport { FilesystemDriver } from './drivers/filesystem.driver.js'\nexport { S3Driver } from './drivers/s3.driver.js'\nexport { storageConfigEntity, storageFilesEntity, storageUploadAction } from './storage.entity.js'\n\n// Types from storage.types.ts\nexport type {\n FilesystemMetadata,\n S3Metadata,\n StorageDriverMetadata,\n UploadedFile,\n UploadOptions,\n StorageFileRecord\n} from './storage.types.js'\n\nexport const storageModule: ModuleManifest = {\n name: 'storage',\n label: 'Storage',\n icon: 'mdi:cloud-upload-outline',\n description: 'File storage and management',\n type: 'core',\n category: 'storage',\n dependencies: ['logger'],\n\n definitions: [storageConfigEntity, storageFilesEntity, storageUploadAction],\n\n routePrefix: '/storage',\n\n init: (ctx: ModuleContext) => {\n // Inicializar y registrar el servicio de storage\n const storageService = initStorageService({\n db: ctx.db,\n logger: ctx.logger,\n generateId: ctx.helpers.generateId,\n loggerService: ctx.services['logger'],\n projectPath: ctx.helpers.getProjectPath()\n })\n ctx.services['storage'] = storageService\n ctx.logger.debug('Storage service registered')\n },\n\n routes: (ctx: ModuleContext) => createStorageRoutes(ctx),\n\n // Import dinámico para evitar ciclos\n seed: async (ctx) => {\n const { seed } = await import('./storage.seed.js')\n await seed(ctx)\n }\n}\n\nexport default storageModule\n","import bcrypt from 'bcryptjs'\n\nconst SALT_ROUNDS = 10\n\n/**\n * Hash dummy para timing-safe login.\n * Se usa cuando el usuario no existe para evitar timing attacks.\n */\nexport const DUMMY_HASH = '$2a$10$N9qo8uLOickgx2ZMRZoMyeUv9rT7dRVqTMtKYzOYQVxZi1qU2cFaW'\n\n/**\n * Hashea un password con bcrypt\n */\nexport function hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, SALT_ROUNDS)\n}\n\n/**\n * Verifica un password contra su hash\n */\nexport function verifyPassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash)\n}\n","/**\n * Crypto utilities - shared across modules\n */\nexport { hashPassword, verifyPassword, DUMMY_HASH } from './hash.js'\n","import type { CollectionEntityDefinition, ModuleContext } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { nowTimestamp } from '../../db/helpers.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\n/**\n * EntityDefinition para Users\n *\n * Single source of truth para:\n * - Migraciones Knex (generateMigration)\n * - Schemas Zod (generateZodSchema)\n * - Tipos TypeScript (generateModel)\n * - Permisos CASL (generateCaslPermissions)\n */\nexport const userEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: \"users\",\n label: \"Users\",\n labelField: \"name\",\n timestamps: true,\n audit: true,\n order: 1,\n routePrefix: '/', // Monta en raíz del módulo: /users/*\n\n fields: {\n id: {\n name: \"id\",\n label: \"ID\",\n input: \"hidden\",\n db: { type: \"string\", size: 26, nullable: false },\n meta: { sortable: false },\n },\n email: {\n name: \"email\",\n label: \"Email\",\n input: \"email\",\n placeholder: \"usuario@ejemplo.com\",\n db: { type: \"string\", size: 255, nullable: false, unique: true },\n validation: { required: true, format: \"email\" },\n meta: { sortable: true, searchable: true },\n },\n password: {\n name: \"password\",\n label: \"Contraseña\",\n input: \"password\",\n placeholder: \"••••••••\",\n db: { type: \"string\", size: 255, nullable: false },\n validation: { required: true, min: 6 },\n meta: { exportable: false },\n },\n name: {\n name: \"name\",\n label: \"Nombre\",\n input: \"text\",\n placeholder: \"Nombre completo\",\n db: { type: \"string\", size: 255, nullable: false },\n validation: { required: true, min: 1 },\n meta: { sortable: true, searchable: true },\n },\n role_id: {\n name: \"role_id\",\n label: \"Rol\",\n input: \"select\",\n db: { type: \"string\", size: 26, nullable: false },\n relation: { table: \"roles\", column: \"id\" },\n validation: { required: true },\n options: {\n endpoint: \"/users/roles\",\n valueField: \"id\",\n labelField: \"name\",\n },\n meta: {\n searchable: true,\n // Solo ADMIN puede modificar el rol\n casl: { writeRoles: [\"ADMIN\"] },\n },\n },\n metadata: {\n name: \"metadata\",\n label: \"Metadata\",\n input: \"hidden\",\n db: { type: \"json\", nullable: true },\n meta: {\n exportable: false,\n // Solo ADMIN puede ver/modificar metadata\n casl: { readRoles: [\"ADMIN\"], writeRoles: [\"ADMIN\"] },\n },\n },\n avatar: {\n name: \"avatar\",\n label: \"Avatar\",\n input: \"image\",\n db: { type: \"string\", size: 26, nullable: true },\n relation: { table: \"storage_files\", column: \"id\", onDelete: \"SET NULL\" },\n storage: {\n accept: \"image/*\",\n maxSize: 2 * 1024 * 1024, // 2MB\n folder: \"avatars\",\n thumbnails: [{ width: 128, height: 128 }],\n },\n meta: { exportable: false },\n },\n },\n\n // Entity Actions\n actions: [\n {\n key: 'change-password',\n label: 'Change Password',\n icon: 'mdi:lock-reset',\n method: 'POST',\n select: ['id', 'password'],\n inputSchema: z.object({\n currentPassword: z.string().min(1, 'Current password is required'),\n newPassword: z.string().min(6, 'Password must be at least 6 characters')\n }),\n middleware: () => createRateLimit({ windowMs: 15 * 60 * 1000, max: 5, message: 'Demasiados intentos, intenta en 15 minutos' }),\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { _record: user, currentPassword, newPassword } = input as {\n _record: { id: string; password: string }\n currentPassword: string\n newPassword: string\n }\n const { verifyPassword, hashPassword } = await import('../../core/crypto/index.js')\n\n // Verificar password actual\n const isValid = await verifyPassword(currentPassword, user.password)\n if (!isValid) {\n throw new ctx.errors.UnauthorizedError('Current password is incorrect')\n }\n\n // Hash y actualizar\n const hashedPassword = await hashPassword(newPassword)\n await ctx.db('users').where('id', user.id).update({\n password: hashedPassword,\n updated_at: nowTimestamp(ctx.db)\n })\n\n return { updated: true }\n },\n casl: { action: 'update' }\n }\n ],\n\n // Autorización CASL\n casl: {\n subject: \"User\",\n sensitiveFields: [\"password\"],\n permissions: {\n ADMIN: {\n actions: [\"manage\"],\n },\n EDITOR: {\n actions: [\"read\"],\n },\n VIEWER: {\n // Solo puede ver su propio perfil\n actions: [\"read\", \"update\"],\n conditions: { id: \"${user.id}\" },\n },\n },\n },\n};\n\n/**\n * EntityDefinition para Roles\n */\nexport const roleEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'roles',\n label: 'Roles',\n labelField: 'name',\n timestamps: true,\n audit: true,\n order: 10,\n routePrefix: '/roles', // Monta en /users/roles/*\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n name: {\n name: 'name',\n label: 'Nombre',\n input: 'text',\n placeholder: 'ROLE_NAME',\n db: { type: 'string', size: 50, nullable: false, unique: true },\n validation: { required: true, min: 2, max: 50, pattern: '^[A-Z_]+$' },\n meta: { sortable: true, searchable: true }\n },\n description: {\n name: 'description',\n label: 'Descripción',\n input: 'text',\n db: { type: 'string', size: 255, nullable: true },\n meta: { sortable: false }\n },\n is_system: {\n name: 'is_system',\n label: 'Sistema',\n input: 'checkbox',\n disabled: true,\n db: { type: 'boolean', nullable: false, default: false },\n meta: { sortable: true }\n }\n },\n\n casl: {\n subject: 'Role',\n permissions: {\n ADMIN: {\n actions: ['manage']\n }\n }\n }\n}\n\n/**\n * EntityDefinition para Role Permissions\n */\nexport const rolePermissionEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'role_permissions',\n label: 'Permissions',\n labelField: 'action',\n timestamps: true,\n order: 20,\n audit: true,\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n role_id: {\n name: 'role_id',\n label: 'Rol',\n input: 'select',\n db: { type: 'string', size: 26, nullable: false },\n relation: { table: 'roles', column: 'id', onDelete: 'CASCADE' },\n validation: { required: true },\n options: { endpoint: '/users/roles', valueField: 'id', labelField: 'name' },\n meta: { searchable: true }\n },\n action: {\n name: 'action',\n label: 'Acción',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n validation: { required: true, enum: ['manage', 'create', 'read', 'update', 'delete'] },\n options: {\n static: [\n { value: 'manage', label: 'Manage (all)' },\n { value: 'create', label: 'Create' },\n { value: 'read', label: 'Read' },\n { value: 'update', label: 'Update' },\n { value: 'delete', label: 'Delete' }\n ]\n },\n meta: { sortable: true }\n },\n subject: {\n name: 'subject',\n label: 'Subject',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false },\n validation: { required: true },\n meta: { sortable: true, searchable: true }\n },\n conditions: {\n name: 'conditions',\n label: 'Condiciones',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n },\n fields: {\n name: 'fields',\n label: 'Campos',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n },\n inverted: {\n name: 'inverted',\n label: 'Invertido',\n input: 'checkbox',\n db: { type: 'boolean', nullable: false, default: false }\n }\n },\n\n indexes: [\n { columns: ['role_id', 'action', 'subject'], unique: true }\n ],\n\n casl: {\n subject: 'RolePermission',\n permissions: {\n ADMIN: {\n actions: ['manage']\n }\n }\n }\n}\n\n","/**\n * Users Routes - Uses runtime with custom services\n *\n * Estructura:\n * - /users/* → CRUD Users (runtime auto-generado)\n * - /users/roles/* → CRUD Roles (runtime auto-generado)\n * - /users/roles/permissions → List all permissions\n * - /users/roles/permissions/:id → Update role permissions\n * - /users/change-password/:id → Change user password (entity action)\n */\n\nimport type { Request, Response, ModuleContext, Router } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { userEntity, roleEntity } from './users.entity.js'\nimport type { createUsersService } from './users.service.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\n\n// ============================================================================\n// Schemas para endpoints especiales\n// ============================================================================\n\nexport const permissionSchema = z.object({\n action: z.enum(['manage', 'create', 'read', 'update', 'delete']),\n subject: z.string().min(1),\n conditions: z.record(z.unknown()).optional(),\n fields: z.array(z.string()).optional(),\n inverted: z.boolean().default(false)\n})\n\nexport const updatePermissionsSchema = z.object({\n permissions: z.array(permissionSchema)\n})\n\nconst roleParamsSchema = z.object({\n id: z.string().min(1)\n})\n\nexport type PermissionInput = z.infer<typeof permissionSchema>\nexport type UpdatePermissionsInput = z.infer<typeof updatePermissionsSchema>\n\n// ============================================================================\n// Routes Factory\n// ============================================================================\n\nexport function createUsersRoutes(ctx: ModuleContext): Router {\n const router = ctx.createRouter()\n const { auth, validate } = ctx.middleware\n const { ForbiddenError: CASLForbiddenError } = ctx.abilities\n\n // Obtener servicio registrado en init() via createUsersService()\n const users = ctx.services['users'] as ReturnType<typeof createUsersService>\n const usersService = users\n const rolesService = users.roles\n\n // ============================================================================\n // USERS ROUTES (runtime auto-generado con CASL)\n // ============================================================================\n\n const usersController = ctx.createEntityController(usersService, userEntity)\n\n // Interceptar delete para añadir validación \"no puedes eliminarte a ti mismo\"\n const originalUsersDelete = usersController.delete\n if (originalUsersDelete) {\n usersController.delete = async (req: Request, res: Response) => {\n const authReq = req as AuthRequest\n const id = req.params['id'] ?? ''\n\n if (authReq.user?.id === id) {\n throw new ctx.errors.ForbiddenError('No puedes eliminarte a ti mismo')\n }\n\n return originalUsersDelete(req, res)\n }\n }\n\n // ============================================================================\n // ROLES ROUTES (montar ANTES de users para evitar que /:id capture /roles)\n // ============================================================================\n\n const rolesController = ctx.createEntityController(rolesService, roleEntity)\n const rolesRouter = ctx.createEntityRouter(rolesController, roleEntity)\n const rolesPrefix = roleEntity.routePrefix ?? '/roles'\n\n // Endpoints especiales (montar ANTES de las rutas CRUD para evitar conflictos con :id)\n\n // --- GET /roles/permissions (listar todos los permisos) ---\n router.get(`${rolesPrefix}/permissions`,\n auth!,\n async (req: Request, res: Response) => {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('read', 'Permission')\n\n const result = await rolesService.findAllPermissions(req.query as Record<string, unknown>)\n // result ya es PaginatedResult { data, total, page, limit }\n res.json(result)\n }\n )\n\n // --- PUT /roles/permissions/:id ---\n router.put(`${rolesPrefix}/permissions/:id`,\n auth!,\n validate({ params: roleParamsSchema, body: updatePermissionsSchema }),\n async (req: Request, res: Response) => {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('update', 'Role')\n\n const { id } = req.validated?.params as { id: string }\n const { permissions } = req.body as UpdatePermissionsInput\n\n const role = await rolesService.updatePermissions(id, permissions, authReq.user?.id)\n res.json(role)\n }\n )\n\n // Montar rutas CRUD de roles\n router.use(rolesPrefix, rolesRouter)\n\n // ============================================================================\n // USERS ROUTES (montar DESPUÉS de roles para que /roles no sea capturado por /:id)\n // ============================================================================\n\n const usersRouter = ctx.createEntityRouter(usersController, userEntity)\n router.use(userEntity.routePrefix ?? '/', usersRouter)\n\n return router\n}\n","/**\n * Users Service - Composición con createEntityService + hooks\n *\n * Usa ctx.createEntityService en lugar de herencia para:\n * - Password hashing en beforeCreate/beforeUpdate\n * - Email uniqueness validation\n * - System roles protection\n * - User-role joins en findAll/findById\n */\n\nimport type { ModuleContext, PaginatedResult, CollectionEntityService, EntityQuery } from '@gzl10/nexus-sdk'\nimport type {\n User,\n Role,\n Permission,\n UserWithoutPassword,\n UserPresence,\n UserWithRole,\n RoleWithPermissions,\n RoleWithCounts,\n PermissionInput,\n PermissionWithRole\n} from './users.types.js'\nimport { userEntity, roleEntity } from './users.entity.js'\n\n// Re-export types for backwards compatibility\nexport type {\n UserWithoutPassword,\n UserPresence,\n UserWithRole,\n RoleWithPermissions,\n RoleWithCounts,\n PermissionInput,\n PermissionWithRole\n} from './users.types.js'\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/** Parse JSON fields from permission rows */\nfunction parsePermission(p: Record<string, unknown>): Permission {\n return {\n ...p,\n conditions: typeof p['conditions'] === 'string' ? JSON.parse(p['conditions']) : p['conditions'],\n fields: typeof p['fields'] === 'string' ? JSON.parse(p['fields']) : p['fields']\n } as Permission\n}\n\n// ============================================================================\n// FACTORY FUNCTION\n// ============================================================================\n\n/**\n * Factory function para crear servicio de usuarios\n * Usa composición con createEntityService + hooks\n */\nexport function createUsersService(ctx: ModuleContext) {\n const { db, errors, helpers: { generateId, nowTimestamp }, crypto: { hashPassword }, socket } = ctx\n const { isUserConnected, getUserSocketCount } = socket\n const USERS_TABLE = 'users'\n const ROLES_TABLE = 'roles'\n const PERMISSIONS_TABLE = 'role_permissions'\n\n // ============================================================================\n // USERS SERVICE (composición)\n // ============================================================================\n\n const baseUsersService = ctx.createEntityService<User>(userEntity, {\n hooks: {\n beforeCreate: async (data) => {\n const processed = { ...data }\n\n // 1. Hash password\n if (processed.password) {\n processed.password = await hashPassword(processed.password)\n }\n\n // 2. Validar email único\n if (processed.email) {\n const existing = await db(USERS_TABLE).where({ email: processed.email }).first()\n if (existing) {\n throw new errors.ConflictError('El email ya está en uso')\n }\n }\n\n // 3. Validar rol existe\n if (processed.role_id) {\n const role = await db(ROLES_TABLE).where({ id: processed.role_id }).first()\n if (!role) {\n throw new errors.NotFoundError('Rol')\n }\n }\n\n return processed\n },\n\n beforeUpdate: async (id, data) => {\n const processed = { ...data }\n\n // 1. Hash password si cambia\n if (processed.password) {\n processed.password = await hashPassword(processed.password)\n }\n\n // 2. Validar email único (excluyendo actual)\n if (processed.email) {\n const existing = await db(USERS_TABLE)\n .where({ email: processed.email })\n .whereNot({ id })\n .first()\n if (existing) {\n throw new errors.ConflictError('El email ya está en uso')\n }\n }\n\n // 3. Validar rol existe\n if (processed.role_id) {\n const role = await db(ROLES_TABLE).where({ id: processed.role_id }).first()\n if (!role) {\n throw new errors.NotFoundError('Rol')\n }\n }\n\n return processed\n }\n }\n }) as CollectionEntityService<User>\n\n // Helpers para mapear rows\n function excludePassword(user: User): UserWithoutPassword {\n const { password: _, ...rest } = user\n return rest\n }\n\n function mapRowToUserWithRole(row: Record<string, unknown>): UserWithRole {\n const {\n password: _,\n role_name,\n role_description,\n role_is_system,\n role_created_at,\n role_updated_at,\n ...user\n } = row\n\n const userId = user['id'] as string\n\n return {\n ...user,\n role: user['role_id']\n ? {\n id: user['role_id'] as string,\n name: role_name as string,\n description: role_description as string | null,\n is_system: role_is_system as boolean,\n created_at: role_created_at as Date,\n updated_at: role_updated_at as Date\n }\n : null,\n presence: {\n isOnline: isUserConnected(userId),\n socketCount: getUserSocketCount(userId)\n }\n } as UserWithRole\n }\n\n // Métodos de usuarios con lógica personalizada\n const usersService = {\n /**\n * findAll con JOIN de roles\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<UserWithRole>> {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n\n const selectColumns = [\n `${USERS_TABLE}.*`,\n `${ROLES_TABLE}.name as role_name`,\n `${ROLES_TABLE}.description as role_description`,\n `${ROLES_TABLE}.is_system as role_is_system`,\n `${ROLES_TABLE}.created_at as role_created_at`,\n `${ROLES_TABLE}.updated_at as role_updated_at`\n ]\n\n let qb = db(USERS_TABLE)\n .select(...selectColumns)\n .leftJoin(ROLES_TABLE, `${USERS_TABLE}.role_id`, `${ROLES_TABLE}.id`)\n\n // Apply role_id filter\n let countQb = db(USERS_TABLE).count('* as count')\n const roleIdFilter = (query as Record<string, unknown>)?.['role_id'] ?? query?.filters?.['role_id']\n if (roleIdFilter) {\n qb = qb.where(`${USERS_TABLE}.role_id`, roleIdFilter)\n countQb = countQb.where('role_id', roleIdFilter)\n }\n\n const countResult = await countQb.first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n qb = qb.orderBy(`${USERS_TABLE}.created_at`, 'desc')\n qb = qb.limit(limit).offset(offset)\n\n const rows = await qb as Record<string, unknown>[]\n const items = rows.map(mapRowToUserWithRole)\n\n const totalPages = Math.ceil(total / limit)\n return { items, total, page, limit, totalPages, hasNext: page < totalPages }\n },\n\n /**\n * findById sin password\n */\n async findById(id: string): Promise<UserWithoutPassword> {\n const user = await baseUsersService.findById(id)\n if (!user) throw new errors.NotFoundError('Usuario')\n return excludePassword(user)\n },\n\n /**\n * findByIdWithRole - usuario con rol incluido\n */\n async findByIdWithRole(id: string): Promise<UserWithRole | null> {\n const selectColumns = [\n `${USERS_TABLE}.*`,\n `${ROLES_TABLE}.name as role_name`,\n `${ROLES_TABLE}.description as role_description`,\n `${ROLES_TABLE}.is_system as role_is_system`,\n `${ROLES_TABLE}.created_at as role_created_at`,\n `${ROLES_TABLE}.updated_at as role_updated_at`\n ]\n\n const row = await db(USERS_TABLE)\n .select(...selectColumns)\n .leftJoin(ROLES_TABLE, `${USERS_TABLE}.role_id`, `${ROLES_TABLE}.id`)\n .where(`${USERS_TABLE}.id`, id)\n .first() as Record<string, unknown> | undefined\n\n if (!row) return null\n return mapRowToUserWithRole(row)\n },\n\n /**\n * findByIdWithPassword - para autenticación\n */\n async findByIdWithPassword(id: string): Promise<User | null> {\n return baseUsersService.findById(id)\n },\n\n /**\n * create con userId para audit (retorna sin password)\n */\n async create(data: Record<string, unknown>, userId?: string): Promise<UserWithoutPassword> {\n const user = await baseUsersService.create({ ...data, created_by: userId ?? null })\n return excludePassword(user)\n },\n\n /**\n * update con userId para audit (retorna sin password)\n */\n async update(id: string, data: Record<string, unknown>, userId?: string): Promise<UserWithoutPassword> {\n const user = await baseUsersService.update(id, { ...data, updated_by: userId ?? null })\n return excludePassword(user)\n },\n\n /**\n * delete\n */\n async delete(id: string) {\n return baseUsersService.delete(id)\n }\n }\n\n // ============================================================================\n // ROLES SERVICE (composición)\n // ============================================================================\n\n const baseRolesService = ctx.createEntityService<Role>(roleEntity, {\n hooks: {\n beforeCreate: async (data) => {\n if (data.name) {\n const existing = await db(ROLES_TABLE).where({ name: data.name }).first()\n if (existing) {\n throw new errors.ConflictError('Ya existe un rol con ese nombre')\n }\n }\n return data\n },\n\n beforeUpdate: async (id, data) => {\n const role = await db(ROLES_TABLE).where({ id }).first() as Role | undefined\n\n if (role?.is_system) {\n throw new errors.ForbiddenError('No se pueden modificar roles del sistema')\n }\n\n if (data.name && data.name !== role?.name) {\n const existing = await db(ROLES_TABLE).where({ name: data.name }).first()\n if (existing) {\n throw new errors.ConflictError('Ya existe un rol con ese nombre')\n }\n }\n\n return data\n },\n\n beforeDelete: async (id) => {\n const role = await db(ROLES_TABLE).where({ id }).first() as Role | undefined\n\n if (role?.is_system) {\n throw new errors.ForbiddenError('No se pueden eliminar roles del sistema')\n }\n\n const usersCount = await db(USERS_TABLE)\n .where({ role_id: id })\n .count('* as count')\n .first<{ count: string | number }>()\n\n if (Number(usersCount?.count ?? 0) > 0) {\n throw new errors.ConflictError('No se puede eliminar un rol con usuarios asignados')\n }\n }\n }\n }) as CollectionEntityService<Role>\n\n const rolesService = {\n /**\n * findAll con conteos\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<RoleWithCounts>> {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n\n const permissionsCountSubquery = db(PERMISSIONS_TABLE)\n .count('*')\n .whereRaw(`${PERMISSIONS_TABLE}.role_id = ${ROLES_TABLE}.id`)\n .as('permissions_count')\n\n const usersCountSubquery = db(USERS_TABLE)\n .count('*')\n .whereRaw(`${USERS_TABLE}.role_id = ${ROLES_TABLE}.id`)\n .as('users_count')\n\n const baseQuery = db(ROLES_TABLE)\n .select(`${ROLES_TABLE}.*`, permissionsCountSubquery, usersCountSubquery)\n\n const [roles, countResult] = await Promise.all([\n baseQuery.clone().orderBy('name', 'asc').limit(limit).offset(offset),\n db(ROLES_TABLE).count('* as count').first<{ count: string | number }>()\n ])\n\n const total = Number(countResult?.count ?? 0)\n const items = (roles as Record<string, unknown>[]).map((role) => ({\n ...role,\n permissions_count: Number(role['permissions_count'] ?? 0),\n users_count: Number(role['users_count'] ?? 0)\n })) as RoleWithCounts[]\n\n const totalPages = Math.ceil(total / limit)\n return { items, total, page, limit, totalPages, hasNext: page < totalPages }\n },\n\n /**\n * findById con permisos\n */\n async findById(id: string): Promise<RoleWithPermissions> {\n const role = await baseRolesService.findById(id)\n if (!role) throw new errors.NotFoundError('Rol')\n\n const permissions = await db(PERMISSIONS_TABLE)\n .where({ role_id: id })\n .orderBy('subject', 'asc')\n .orderBy('action', 'asc') as Record<string, unknown>[]\n\n return { ...role, permissions: permissions.map(parsePermission) }\n },\n\n /**\n * findByName\n */\n async findByName(name: string): Promise<Role | undefined> {\n return db(ROLES_TABLE).where({ name }).first() as Promise<Role | undefined>\n },\n\n /**\n * getPermissionsByRoleId\n */\n async getPermissionsByRoleId(roleId: string): Promise<Permission[]> {\n const permissions = await db(PERMISSIONS_TABLE).where({ role_id: roleId }) as Record<string, unknown>[]\n return permissions.map(parsePermission)\n },\n\n /**\n * findAllPermissions\n */\n async findAllPermissions(query?: EntityQuery): Promise<PaginatedResult<PermissionWithRole>> {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n\n const baseQuery = db(PERMISSIONS_TABLE)\n .select(`${PERMISSIONS_TABLE}.*`, `${ROLES_TABLE}.name as role_name`)\n .leftJoin(ROLES_TABLE, `${PERMISSIONS_TABLE}.role_id`, `${ROLES_TABLE}.id`)\n\n const [permissions, countResult] = await Promise.all([\n baseQuery.clone().orderBy(`${ROLES_TABLE}.name`, 'asc').orderBy('subject', 'asc').limit(limit).offset(offset),\n db(PERMISSIONS_TABLE).count('* as count').first<{ count: string | number }>()\n ])\n\n const total = Number(countResult?.count ?? 0)\n const items = (permissions as Record<string, unknown>[]).map((p) => ({\n ...parsePermission(p),\n role: { name: p['role_name'] as string }\n }))\n\n const totalPages = Math.ceil(total / limit)\n return { items, total, page, limit, totalPages, hasNext: page < totalPages }\n },\n\n /**\n * create con userId para audit\n */\n async create(data: Record<string, unknown>, userId?: string) {\n return baseRolesService.create({ ...data, created_by: userId ?? null })\n },\n\n /**\n * update con userId para audit\n */\n async update(id: string, data: Record<string, unknown>, userId?: string) {\n return baseRolesService.update(id, { ...data, updated_by: userId ?? null })\n },\n\n /**\n * delete\n */\n async delete(id: string) {\n return baseRolesService.delete(id)\n },\n\n /**\n * updatePermissions - actualizar permisos de un rol (transacción)\n */\n async updatePermissions(id: string, permissions: PermissionInput[], userId?: string): Promise<RoleWithPermissions> {\n return db.transaction(async (trx) => {\n const role = await trx(ROLES_TABLE).where({ id }).first() as Role | undefined\n if (!role) throw new errors.NotFoundError('Rol')\n\n if (role.is_system && role.name === 'ADMIN') {\n throw new errors.ForbiddenError('No se pueden modificar los permisos del rol ADMIN')\n }\n\n // Eliminar permisos existentes\n await trx(PERMISSIONS_TABLE).where({ role_id: id }).delete()\n\n // Insertar nuevos permisos\n if (permissions.length > 0) {\n const permissionsData = permissions.map((p) => ({\n id: generateId(),\n role_id: id,\n action: p.action,\n subject: p.subject,\n conditions: p.conditions ? JSON.stringify(p.conditions) : null,\n fields: p.fields ? JSON.stringify(p.fields) : null,\n inverted: p.inverted ?? false,\n created_by: userId ?? null\n }))\n await trx(PERMISSIONS_TABLE).insert(permissionsData)\n }\n\n // Actualizar timestamp del rol\n await trx(ROLES_TABLE).where({ id }).update({\n updated_at: nowTimestamp(db),\n updated_by: userId ?? null\n })\n\n // Retornar rol con permisos\n const updatedRole = await trx(ROLES_TABLE).where({ id }).first() as Role\n const updatedPermissions = await trx(PERMISSIONS_TABLE)\n .where({ role_id: id })\n .orderBy('subject', 'asc')\n .orderBy('action', 'asc') as Record<string, unknown>[]\n\n return { ...updatedRole, permissions: updatedPermissions.map(parsePermission) }\n })\n }\n }\n\n // ============================================================================\n // RETURN\n // ============================================================================\n\n return {\n // Definition para compatibilidad con BaseEntityService (requerido por createEntityController)\n definition: userEntity,\n\n // Users methods\n findAll: usersService.findAll,\n findById: usersService.findById,\n findByIdWithRole: usersService.findByIdWithRole,\n findByIdWithPassword: usersService.findByIdWithPassword,\n create: usersService.create,\n update: usersService.update,\n delete: usersService.delete,\n\n // Roles nested service (con definition para createEntityController)\n roles: {\n definition: roleEntity,\n ...rolesService\n }\n }\n}\n","import type { ModuleContext, CollectionEntityDefinition } from '@gzl10/nexus-sdk'\nimport { userEntity, roleEntity, rolePermissionEntity } from './users.entity.js'\n\n// Table names from EntityDefinition\nconst USERS = (userEntity as CollectionEntityDefinition).table\nconst ROLES = (roleEntity as CollectionEntityDefinition).table\nconst PERMISSIONS = (rolePermissionEntity as CollectionEntityDefinition).table\n\n/**\n * Seed para users: crea roles de sistema y usuario admin\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n await seedRoles(ctx)\n await seedAdminUser(ctx)\n}\n\n/**\n * Crea los roles de sistema y sus permisos si no existen\n */\nasync function seedRoles(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n\n // Solo crear roles si la tabla está vacía\n const existingRoles = await db(ROLES).count('* as count').first<{ count: string | number }>()\n if (Number(existingRoles?.count ?? 0) > 0) return\n\n // Insertar roles de sistema\n const systemRoles = [\n { id: generateId(), name: 'ADMIN', description: 'Administrador con control total', is_system: true },\n { id: generateId(), name: 'EDITOR', description: 'Puede crear y editar contenido propio', is_system: true },\n { id: generateId(), name: 'VIEWER', description: 'Solo lectura', is_system: true }\n ]\n await db(ROLES).insert(systemRoles)\n logger.info('Inserted system roles: ADMIN, EDITOR, VIEWER')\n\n // Insertar permisos para roles de sistema\n const roles = await db(ROLES).select('id', 'name')\n const roleMap = Object.fromEntries(roles.map((r: { id: string; name: string }) => [r.name, r.id]))\n\n const permissions = [\n // ADMIN: manage all\n { id: generateId(), role_id: roleMap['ADMIN'], action: 'manage', subject: 'all', conditions: null, inverted: false },\n // EDITOR: read users, CRUD posts (own for update/delete)\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'read', subject: 'User', conditions: null, inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'create', subject: 'PstPost', conditions: null, inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'read', subject: 'PstPost', conditions: null, inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'update', subject: 'PstPost', conditions: JSON.stringify({ author_id: '${user.id}' }), inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'delete', subject: 'PstPost', conditions: JSON.stringify({ author_id: '${user.id}' }), inverted: false },\n // VIEWER: read published posts, read own profile\n { id: generateId(), role_id: roleMap['VIEWER'], action: 'read', subject: 'PstPost', conditions: JSON.stringify({ status: 'PUBLISHED' }), inverted: false },\n { id: generateId(), role_id: roleMap['VIEWER'], action: 'read', subject: 'User', conditions: JSON.stringify({ id: '${user.id}' }), inverted: false }\n ]\n await db(PERMISSIONS).insert(permissions)\n logger.info('Inserted permissions for system roles')\n}\n\n/**\n * Crea el usuario administrador inicial si no existe\n */\nasync function seedAdminUser(ctx: ModuleContext): Promise<void> {\n const { db, logger, config, helpers: { generateId }, crypto: { hashPassword } } = ctx\n\n const email = (config['adminEmail'] as string) || 'admin@example.com'\n const password = (config['adminPassword'] as string) || 'admin123'\n\n const existing = await db(USERS).where({ email }).first()\n if (existing) {\n logger.info({ email }, 'Admin user already exists')\n return\n }\n\n // Get ADMIN role ID\n const adminRole = await db(ROLES).where({ name: 'ADMIN' }).first()\n if (!adminRole) {\n logger.error('ADMIN role not found. Run migrations first.')\n throw new Error('ADMIN role not found')\n }\n\n const hashedPassword = await hashPassword(password)\n\n await db(USERS).insert({\n id: generateId(),\n email,\n password: hashedPassword,\n name: 'Administrador',\n role_id: adminRole.id\n })\n\n logger.info({ email }, 'Admin user created')\n}\n","import type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { createUsersRoutes } from './users.routes.js'\nimport { createUsersService } from './users.service.js'\nimport { userEntity, roleEntity, rolePermissionEntity } from './users.entity.js'\n\n// Re-exports\nexport { createUsersService } from './users.service.js'\nexport { userEntity, roleEntity, rolePermissionEntity } from './users.entity.js'\n\n// Types from users.types.ts\nexport type {\n User,\n Role,\n Permission,\n UserWithoutPassword,\n UserPresence,\n UserWithRole,\n RoleWithPermissions,\n RoleWithCounts,\n PermissionInput,\n PermissionWithRole\n} from './users.types.js'\n\nexport const usersModule: ModuleManifest = {\n name: 'users',\n label: 'Users & Roles',\n icon: 'mdi:account-group-outline',\n description: 'User accounts, authentication profiles, roles and permissions',\n type: 'core',\n category: 'data',\n dependencies: ['logger'],\n // Import dinámico para evitar posibles ciclos\n seed: async (ctx) => {\n const { seed } = await import('./users.seed.js')\n await seed(ctx)\n },\n\n init: (ctx: ModuleContext) => {\n // Registrar servicio de usuarios en ctx.services\n ctx.services['users'] = createUsersService(ctx)\n ctx.logger.debug('Users service registered')\n },\n\n routes: createUsersRoutes,\n routePrefix: '/users',\n // Orden importante: roles primero (FK de users.role_id → roles.id)\n // changePassword es entity action dentro de userEntity\n definitions: [roleEntity, rolePermissionEntity, userEntity]\n}\n\nexport default usersModule\n","/**\n * Startup Logger\n *\n * Logger simple para errores de configuración que ocurren\n * antes de que el logger principal esté inicializado.\n *\n * Usa pino directamente con pino-pretty para formato legible.\n */\nimport pino from 'pino'\n\nconst startupLogger = pino({\n level: 'error',\n transport: {\n target: 'pino-pretty',\n options: {\n colorize: true,\n sync: true,\n messageFormat: '{msg}'\n }\n }\n})\n\n/**\n * Muestra un error de configuración formateado y termina el proceso\n */\nexport function configError(module: string, errors: string[]): never {\n startupLogger.error(`\\n${'═'.repeat(60)}`)\n startupLogger.error(`NEXUS BACKEND - Configuration Error [${module}]`)\n startupLogger.error('═'.repeat(60))\n errors.forEach((err) => startupLogger.error(` ${err}`))\n startupLogger.error('═'.repeat(60) + '\\n')\n\n process.exit(1)\n}\n\nexport { startupLogger }\n","import { z } from 'zod'\nimport { configError } from '../../core/startup-logger.js'\n\n/**\n * Schema de variables de entorno para auth\n * Completamente independiente de la configuración global\n */\nconst authEnvSchema = z.object({\n AUTH_SECRET: z.string().min(32, 'AUTH_SECRET must be at least 32 characters'),\n AUTH_ACCESS_EXPIRES: z.string().default('15m'),\n AUTH_REFRESH_EXPIRES: z.string().default('7d'),\n // Rate limiting (default: 5 requests per 15 minutes)\n AUTH_RATE_LIMIT_MAX: z.coerce.number().default(5),\n AUTH_RATE_LIMIT_WINDOW: z.coerce.number().default(900), // seconds\n // Cookie domain for SSO across subdomains (e.g., '.example.com')\n AUTH_COOKIE_DOMAIN: z.string().optional()\n})\n\nfunction parseAuthEnv() {\n const result = authEnvSchema.safeParse(process.env)\n\n if (!result.success) {\n const errors = result.error.issues.map((issue) => {\n const path = issue.path.join('.')\n if (path === 'AUTH_SECRET' && issue.code === 'invalid_type') {\n return 'AUTH_SECRET is required. Set it in your .env file or environment.'\n }\n if (path === 'AUTH_SECRET' && issue.code === 'too_small') {\n return `AUTH_SECRET must be at least 32 characters (current: ${String(process.env['AUTH_SECRET']).length})`\n }\n return `${path}: ${issue.message}`\n })\n configError('auth', errors)\n }\n\n return result.data\n}\n\nexport const authEnv = parseAuthEnv()\n\n/**\n * Configuración Auth tipada\n */\nexport interface AuthConfig {\n secret: string\n accessExpires: string\n refreshExpires: string\n rateLimitMax: number\n rateLimitWindowMs: number\n /** Cookie domain for SSO across subdomains (e.g., '.example.com') */\n cookieDomain?: string\n}\n\n/**\n * Obtiene la configuración de auth desde las variables de entorno\n */\nexport function getAuthConfig(): AuthConfig {\n return {\n secret: authEnv.AUTH_SECRET,\n accessExpires: authEnv.AUTH_ACCESS_EXPIRES,\n refreshExpires: authEnv.AUTH_REFRESH_EXPIRES,\n rateLimitMax: authEnv.AUTH_RATE_LIMIT_MAX,\n rateLimitWindowMs: authEnv.AUTH_RATE_LIMIT_WINDOW * 1000, // convert to ms\n cookieDomain: authEnv.AUTH_COOKIE_DOMAIN\n }\n}\n","import jwt from 'jsonwebtoken'\nimport crypto from 'crypto'\nimport { getAuthConfig } from './auth.config.js'\n\nexport interface JwtPayload {\n userId: string\n email: string\n roleId: string\n}\n\nexport interface TokenPair {\n accessToken: string\n refreshToken: string\n}\n\nfunction parseExpiration(exp: string): number {\n const match = exp.match(/^(\\d+)([smhd])$/)\n if (!match) return 900 // 15 min default\n\n const value = parseInt(match[1]!, 10)\n const unit = match[2]\n\n switch (unit) {\n case 's': return value\n case 'm': return value * 60\n case 'h': return value * 60 * 60\n case 'd': return value * 60 * 60 * 24\n default: return 900\n }\n}\n\nexport function generateAccessToken(payload: JwtPayload): string {\n const config = getAuthConfig()\n return jwt.sign(payload, config.secret, {\n expiresIn: config.accessExpires as jwt.SignOptions['expiresIn']\n })\n}\n\nexport function generateRefreshToken(): string {\n return crypto.randomBytes(64).toString('hex')\n}\n\nexport function getRefreshTokenExpiration(): Date {\n const seconds = parseExpiration(getAuthConfig().refreshExpires)\n return new Date(Date.now() + seconds * 1000)\n}\n\nexport function generateTokenPair(payload: JwtPayload): TokenPair {\n return {\n accessToken: generateAccessToken(payload),\n refreshToken: generateRefreshToken()\n }\n}\n\nexport function verifyAccessToken(token: string): JwtPayload {\n return jwt.verify(token, getAuthConfig().secret) as JwtPayload\n}\n","import type { TempEntityDefinition, EventEntityDefinition, SingleEntityDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * EntityDefinition para Refresh Tokens\n *\n * Usa tipo 'temp' para limpieza automática de tokens expirados.\n * TTL: 7 días (604800 segundos) - mismo que jwtRefreshExpires default\n */\nexport const refreshTokenEntity: TempEntityDefinition = {\n type: 'temp',\n table: 'auth_refresh_tokens',\n label: 'Refresh Tokens',\n labelField: 'id',\n routePrefix: '/tokens',\n ttl: 604800, // 7 días en segundos\n ttlField: 'expires_at',\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n token: {\n name: 'token',\n label: 'Token',\n input: 'hidden',\n db: { type: 'string', size: 255, nullable: false, unique: true },\n meta: { exportable: false }\n },\n user_id: {\n name: 'user_id',\n label: 'Usuario',\n input: 'select',\n db: { type: 'string', size: 26, nullable: false, index: true },\n relation: { table: 'users', column: 'id', onDelete: 'CASCADE' },\n validation: { required: true },\n options: { endpoint: '/users', valueField: 'id', labelField: 'name' },\n meta: { searchable: true }\n },\n expires_at: {\n name: 'expires_at',\n label: 'Expira',\n input: 'datetime',\n db: { type: 'datetime', nullable: false, index: true },\n validation: { required: true },\n meta: { sortable: true }\n },\n device_id: {\n name: 'device_id',\n label: 'Device ID',\n input: 'text',\n db: { type: 'string', size: 64, nullable: true, index: true },\n meta: { searchable: true }\n },\n device_name: {\n name: 'device_name',\n label: 'Dispositivo',\n input: 'text',\n db: { type: 'string', size: 100, nullable: true },\n hint: 'Nombre legible del dispositivo (ej: iPhone de Juan)'\n },\n created_at: {\n name: 'created_at',\n label: 'Creado',\n input: 'datetime',\n disabled: true,\n db: { type: 'datetime', nullable: true, defaultFn: 'now' },\n meta: { sortable: true }\n }\n },\n\n casl: {\n subject: 'AuthRefreshToken',\n permissions: {\n ADMIN: { actions: ['manage'] }\n }\n }\n}\n\n/**\n * EntityDefinition para Auth Audit\n *\n * Eventos de autenticación persistidos (append-only).\n * Retención: 90 días por defecto.\n */\nexport const authAuditEntity: EventEntityDefinition = {\n type: 'event',\n table: 'auth_audit',\n label: 'Auth Audit',\n labelField: 'event_type',\n routePrefix: '/audit',\n // timestamps: false - created_at está definido explícitamente en fields para metadata extra\n retention: {\n days: 90\n },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n event_type: {\n name: 'event_type',\n label: 'Tipo',\n input: 'select',\n db: { type: 'string', size: 50, nullable: false, index: true },\n validation: {\n required: true,\n enum: ['login', 'logout', 'failed', 'refresh', 'password_reset']\n },\n options: {\n static: [\n { value: 'login', label: 'Login' },\n { value: 'logout', label: 'Logout' },\n { value: 'failed', label: 'Failed' },\n { value: 'refresh', label: 'Refresh' },\n { value: 'password_reset', label: 'Password Reset' }\n ]\n },\n meta: { sortable: true, searchable: true }\n },\n user_id: {\n name: 'user_id',\n label: 'Usuario',\n input: 'select',\n db: { type: 'string', size: 26, nullable: true, index: true },\n relation: { table: 'users', column: 'id', onDelete: 'SET NULL' },\n options: { endpoint: '/users', valueField: 'id', labelField: 'name' },\n meta: { searchable: true }\n },\n email: {\n name: 'email',\n label: 'Email',\n input: 'email',\n db: { type: 'string', size: 255, nullable: true },\n validation: { format: 'email' },\n meta: { searchable: true }\n },\n ip_address: {\n name: 'ip_address',\n label: 'IP',\n input: 'text',\n db: { type: 'string', size: 45, nullable: true },\n meta: { searchable: true }\n },\n user_agent: {\n name: 'user_agent',\n label: 'User Agent',\n input: 'textarea',\n db: { type: 'text', nullable: true },\n meta: { exportable: false }\n },\n details: {\n name: 'details',\n label: 'Detalles',\n input: 'hidden',\n db: { type: 'json', nullable: true },\n meta: { exportable: false }\n },\n created_at: {\n name: 'created_at',\n label: 'Fecha',\n input: 'datetime',\n disabled: true,\n db: { type: 'datetime', nullable: false, defaultFn: 'now', index: true },\n meta: { sortable: true }\n }\n },\n\n casl: {\n subject: 'AuthAudit',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n\n/**\n * Single Entity: Auth Config\n *\n * Configuración de autenticación persistida en DB.\n * AUTH_SECRET siempre viene de env por seguridad.\n */\nexport const authConfigEntity: SingleEntityDefinition = {\n type: 'single',\n key: 'auth_config',\n label: 'Auth Config',\n routePrefix: '/config',\n\n // Defaults desde variables de entorno\n get defaults() {\n return {\n access_expires: process.env['AUTH_ACCESS_EXPIRES'] || '15m',\n refresh_expires: process.env['AUTH_REFRESH_EXPIRES'] || '7d',\n rate_limit_max: parseInt(process.env['AUTH_RATE_LIMIT_MAX'] || '') || 5,\n rate_limit_window: parseInt(process.env['AUTH_RATE_LIMIT_WINDOW'] || '') || 900,\n cookie_domain: process.env['AUTH_COOKIE_DOMAIN'] || null\n }\n },\n\n fields: {\n access_expires: {\n name: 'access_expires',\n label: 'Access Token Expira',\n input: 'text',\n hint: 'Duración del access token (ej: 15m, 1h, 1d)',\n db: { type: 'string', size: 20, nullable: false, default: '15m' }\n },\n refresh_expires: {\n name: 'refresh_expires',\n label: 'Refresh Token Expira',\n input: 'text',\n hint: 'Duración del refresh token (ej: 7d, 30d)',\n db: { type: 'string', size: 20, nullable: false, default: '7d' }\n },\n rate_limit_max: {\n name: 'rate_limit_max',\n label: 'Rate Limit (intentos)',\n input: 'number',\n hint: 'Máximo de intentos de login por ventana',\n db: { type: 'integer', nullable: false, default: 5 }\n },\n rate_limit_window: {\n name: 'rate_limit_window',\n label: 'Rate Limit (segundos)',\n input: 'number',\n hint: 'Ventana de tiempo para rate limit en segundos',\n db: { type: 'integer', nullable: false, default: 900 }\n },\n cookie_domain: {\n name: 'cookie_domain',\n label: 'Cookie Domain',\n input: 'text',\n hint: 'Dominio para SSO entre subdominios (ej: .example.com)',\n db: { type: 'string', size: 100, nullable: true }\n }\n },\n\n casl: {\n subject: 'AuthConfig',\n permissions: {\n ADMIN: { actions: ['read', 'update'] }\n }\n }\n}\n","import type { ModuleContext, TempEntityDefinition, EventEntityDefinition } from '@gzl10/nexus-sdk'\nimport { generateTokenPair, getRefreshTokenExpiration } from './jwt.utils.js'\nimport type { LoginInput, RegisterInput } from './auth.routes.js'\nimport { refreshTokenEntity, authAuditEntity } from './auth.entity.js'\nimport type { UsersService } from '../../types/services.js'\nimport type { TypedEventEmitter } from '../../core/events/emitter.js'\nimport type { RequestInfo, UserSession } from './auth.types.js'\n\n// Table names (hardcoded for module isolation - auth depends on users via ctx.services)\nconst USERS = 'users'\nconst ROLES = 'roles'\nconst REFRESH_TOKENS = (refreshTokenEntity as TempEntityDefinition).table\nconst AUTH_AUDIT = (authAuditEntity as EventEntityDefinition).table\n\n/**\n * Tipo local para datos de usuario - auth no importa de users module\n * Define los campos que auth necesita para autenticación y CASL\n */\nexport interface AuthUserRecord {\n id: string\n email: string\n password: string\n name: string\n role_id: string\n created_at: Date\n updated_at: Date\n created_by: string | null\n updated_by: string | null\n [key: string]: unknown\n}\n\nexport function createAuthService(ctx: ModuleContext) {\n const { db, errors, helpers: { generateId, nowTimestamp }, abilities, crypto } = ctx\n const { verifyPassword, DUMMY_HASH } = crypto\n const events = ctx.events as TypedEventEmitter\n const { defineAbilityFor, packRules } = abilities\n\n // Obtener servicio de usuarios desde ctx.services (registrado en users.init())\n const usersService = ctx.services['users'] as UsersService\n if (!usersService) {\n throw new Error('UsersService not initialized. Ensure users module loads before auth.')\n }\n const { roles: rolesService } = usersService\n\n /** Persiste evento de audit en base de datos */\n async function persistAuditEvent(\n eventType: 'login' | 'logout' | 'failed' | 'refresh' | 'password_reset',\n data: {\n userId?: string\n email?: string\n requestInfo?: RequestInfo\n details?: Record<string, unknown>\n }\n ): Promise<void> {\n try {\n await db(AUTH_AUDIT).insert({\n id: generateId(),\n event_type: eventType,\n user_id: data.userId ?? null,\n email: data.email ?? null,\n ip_address: data.requestInfo?.ip ?? null,\n user_agent: data.requestInfo?.userAgent ?? null,\n details: data.details ? JSON.stringify(data.details) : null,\n created_at: nowTimestamp(db)\n })\n } catch {\n // No fallar el flujo principal si audit falla\n ctx.logger.warn(`Failed to persist audit event: ${eventType}`)\n }\n }\n\n async function getUserWithRole(userId: string) {\n const user = await db<AuthUserRecord & { role_name: string; role_description: string | null; role_is_system: boolean }>(USERS)\n .leftJoin(ROLES, `${USERS}.role_id`, `${ROLES}.id`)\n .where(`${USERS}.id`, userId)\n .select(\n `${USERS}.*`,\n `${ROLES}.name as role_name`,\n `${ROLES}.description as role_description`,\n `${ROLES}.is_system as role_is_system`\n )\n .first()\n\n if (!user) return null\n\n const { role_name, role_description, role_is_system, password: _, ...userWithoutPassword } = user\n\n return {\n ...userWithoutPassword,\n role: {\n id: user.role_id,\n name: role_name,\n description: role_description,\n is_system: role_is_system\n }\n }\n }\n\n return {\n async login(input: LoginInput, requestInfo?: RequestInfo) {\n const user = await db<AuthUserRecord>(USERS).where({ email: input.email }).first()\n\n // Timing-safe: siempre ejecutar bcrypt aunque usuario no exista\n const hashToCheck = user?.password ?? DUMMY_HASH\n const validPassword = await verifyPassword(input.password, hashToCheck)\n\n if (!user || !validPassword) {\n const reason = user ? 'invalid_password' : 'user_not_found'\n events.emitEvent('auth.failed', { email: input.email, reason })\n\n // Persistir evento de fallo\n await persistAuditEvent('failed', {\n email: input.email,\n requestInfo,\n details: { reason }\n })\n\n throw new errors.UnauthorizedError('Credenciales inválidas')\n }\n\n const tokens = generateTokenPair({\n userId: user.id,\n email: user.email,\n roleId: user.role_id\n })\n\n // Guardar refresh token en DB\n await db(REFRESH_TOKENS).insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration(),\n device_id: requestInfo?.deviceId ?? null,\n device_name: requestInfo?.deviceName ?? null\n })\n\n // Cargar permisos del rol\n const permissions = await rolesService.getPermissionsByRoleId(user.role_id)\n const ability = defineAbilityFor(user, permissions)\n\n // Obtener usuario con rol\n const userWithRole = await getUserWithRole(user.id)\n\n events.emitEvent('auth.login', { userId: user.id, email: user.email })\n\n // Persistir evento de login exitoso\n await persistAuditEvent('login', {\n userId: user.id,\n email: user.email,\n requestInfo\n })\n\n return {\n user: userWithRole,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n abilities: packRules(ability)\n }\n },\n\n async register(input: RegisterInput, requestInfo?: RequestInfo) {\n // Buscar rol por defecto (VIEWER)\n const defaultRole = await rolesService.findByName('VIEWER')\n if (!defaultRole) {\n throw new errors.AppError('Rol VIEWER no encontrado. Ejecuta las migraciones.', 500)\n }\n\n // Crear usuario (usersService hace hash de password y valida email único)\n const user = await usersService.create({\n email: input.email,\n password: input.password,\n name: input.name,\n role_id: defaultRole.id\n })\n\n // Generar tokens\n const tokens = generateTokenPair({\n userId: user.id,\n email: user.email,\n roleId: defaultRole.id\n })\n\n // Guardar refresh token en DB\n await db(REFRESH_TOKENS).insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration(),\n device_id: requestInfo?.deviceId ?? null,\n device_name: requestInfo?.deviceName ?? null\n })\n\n // Cargar permisos del rol\n const permissions = await rolesService.getPermissionsByRoleId(defaultRole.id)\n // User siempre tiene role_id en registro (acabamos de asignarlo)\n const ability = defineAbilityFor({ ...user, role_id: defaultRole.id }, permissions)\n\n // Obtener usuario con rol\n const userWithRole = await getUserWithRole(user.id)\n\n events.emitEvent('auth.login', { userId: user.id, email: user.email })\n\n // Persistir evento de registro\n await persistAuditEvent('login', {\n userId: user.id,\n email: user.email,\n requestInfo,\n details: { isRegistration: true }\n })\n\n return {\n user: userWithRole,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n abilities: packRules(ability)\n }\n },\n\n async refresh(refreshToken: string, requestInfo?: RequestInfo) {\n // Toda la lógica de refresh dentro de transacción para evitar race conditions\n const result = await db.transaction(async (trx) => {\n // Buscar token con bloqueo (forUpdate solo en PostgreSQL/MySQL)\n let query = trx(REFRESH_TOKENS).where({ token: refreshToken })\n const client = db.client.config.client as string\n if (!client.includes('sqlite')) {\n query = query.forUpdate()\n }\n const storedToken = await query.first()\n\n if (!storedToken) {\n throw new errors.UnauthorizedError('Refresh token inválido')\n }\n\n if (new Date(storedToken.expires_at) < new Date()) {\n await trx(REFRESH_TOKENS).where({ id: storedToken.id }).delete()\n throw new errors.UnauthorizedError('Refresh token expirado')\n }\n\n const user = await trx<AuthUserRecord>(USERS).where({ id: storedToken.user_id }).first()\n if (!user) {\n throw new errors.UnauthorizedError('Usuario no encontrado')\n }\n\n const tokens = generateTokenPair({\n userId: user.id,\n email: user.email,\n roleId: user.role_id\n })\n\n // Rotar refresh token atómicamente (preservando device info)\n await trx(REFRESH_TOKENS).where({ id: storedToken.id }).delete()\n await trx(REFRESH_TOKENS).insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration(),\n device_id: storedToken.device_id ?? null,\n device_name: storedToken.device_name ?? null\n })\n\n return { user, tokens }\n })\n\n // Cargar permisos del rol (fuera de transacción, solo lectura)\n const permissions = await rolesService.getPermissionsByRoleId(result.user.role_id)\n const ability = defineAbilityFor(result.user, permissions)\n\n events.emitEvent('auth.refresh', { userId: result.user.id })\n\n // Persistir evento de refresh\n await persistAuditEvent('refresh', {\n userId: result.user.id,\n requestInfo\n })\n\n return {\n accessToken: result.tokens.accessToken,\n refreshToken: result.tokens.refreshToken,\n abilities: packRules(ability)\n }\n },\n\n async logout(refreshToken: string, userId?: string, requestInfo?: RequestInfo) {\n const deleted = await db(REFRESH_TOKENS).where({ token: refreshToken }).delete()\n if (deleted > 0 && userId) {\n events.emitEvent('auth.logout', { userId })\n\n // Persistir evento de logout\n await persistAuditEvent('logout', {\n userId,\n requestInfo\n })\n }\n return deleted > 0\n },\n\n async logoutAll(userId: string, requestInfo?: RequestInfo) {\n const deleted = await db(REFRESH_TOKENS).where({ user_id: userId }).delete()\n\n events.emitEvent('auth.logout', { userId })\n\n // Persistir evento de logout-all con detalles\n await persistAuditEvent('logout', {\n userId,\n requestInfo,\n details: { allDevices: true, sessionsRevoked: deleted }\n })\n\n return deleted\n },\n\n async me(userId: string) {\n const userWithRole = await getUserWithRole(userId)\n\n if (!userWithRole) {\n throw new errors.NotFoundError('Usuario')\n }\n\n // Cargar permisos del rol\n const permissions = await rolesService.getPermissionsByRoleId(userWithRole.role_id)\n const ability = defineAbilityFor(userWithRole, permissions)\n\n return {\n user: userWithRole,\n abilities: packRules(ability)\n }\n },\n\n async cleanupExpiredTokens() {\n const deleted = await db(REFRESH_TOKENS)\n .where('expires_at', '<', nowTimestamp(db))\n .delete()\n return deleted\n },\n\n async getSessions(userId: string, currentToken?: string): Promise<UserSession[]> {\n const tokens = await db(REFRESH_TOKENS)\n .where({ user_id: userId })\n .where('expires_at', '>', new Date())\n .select('id', 'device_id', 'device_name', 'token', 'created_at', 'expires_at')\n .orderBy('created_at', 'desc')\n\n return tokens.map(t => ({\n id: t.id,\n device_id: t.device_id ?? null,\n device_name: t.device_name ?? null,\n created_at: t.created_at,\n expires_at: t.expires_at,\n is_current: currentToken ? t.token === currentToken : false\n }))\n },\n\n async revokeSession(userId: string, sessionId: string, requestInfo?: RequestInfo): Promise<boolean> {\n // Solo permite revocar sesiones del propio usuario\n const deleted = await db(REFRESH_TOKENS)\n .where({ id: sessionId, user_id: userId })\n .delete()\n\n if (deleted > 0) {\n await persistAuditEvent('logout', {\n userId,\n requestInfo,\n details: { sessionId, revokedByUser: true }\n })\n }\n\n return deleted > 0\n }\n }\n}\n","import type { Request, Response, CookieOptions, ModuleContext } from '@gzl10/nexus-sdk'\nimport { createAuthService } from './auth.service.js'\nimport { getAuthConfig } from './auth.config.js'\nimport type { LoginInput, RegisterInput } from './auth.routes.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport type { RequestInfo } from './auth.types.js'\n\nexport function createAuthController(ctx: ModuleContext) {\n const { errors } = ctx\n const authService = createAuthService(ctx)\n\n function getCookieOptions(req: Request): CookieOptions {\n const config = getAuthConfig()\n const isSecure = req.secure || req.get('x-forwarded-proto') === 'https'\n return {\n httpOnly: true,\n secure: isSecure,\n sameSite: isSecure ? 'strict' : 'lax',\n path: '/api/v1',\n maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days\n ...(config.cookieDomain && { domain: config.cookieDomain })\n }\n }\n\n /** Extrae información del request para audit */\n function getRequestInfo(req: Request, deviceInfo?: { deviceId?: string, deviceName?: string }): RequestInfo {\n return {\n ip: req.ip ?? req.socket?.remoteAddress,\n userAgent: req.get('user-agent'),\n deviceId: deviceInfo?.deviceId,\n deviceName: deviceInfo?.deviceName\n }\n }\n\n return {\n async login(req: Request, res: Response) {\n const body = req.body as LoginInput\n const result = await authService.login(body, getRequestInfo(req, { deviceId: body.deviceId, deviceName: body.deviceName }))\n\n // Refresh token in HttpOnly cookie\n res.cookie('refreshToken', result.refreshToken, getCookieOptions(req))\n\n // Access token in body (client stores in localStorage)\n res.json({\n user: result.user,\n accessToken: result.accessToken,\n abilities: result.abilities\n })\n },\n\n async register(req: Request, res: Response) {\n const body = req.body as RegisterInput\n const result = await authService.register(body, getRequestInfo(req, { deviceId: body.deviceId, deviceName: body.deviceName }))\n\n // Refresh token in HttpOnly cookie (auto-login after register)\n res.cookie('refreshToken', result.refreshToken, getCookieOptions(req))\n\n res.status(201).json({\n user: result.user,\n accessToken: result.accessToken,\n abilities: result.abilities\n })\n },\n\n async refresh(req: Request, res: Response) {\n const refreshToken = req.cookies?.['refreshToken'] as string | undefined\n if (!refreshToken) {\n throw new errors.UnauthorizedError('Refresh token required')\n }\n\n const result = await authService.refresh(refreshToken, getRequestInfo(req))\n\n res.cookie('refreshToken', result.refreshToken, getCookieOptions(req))\n res.json({\n accessToken: result.accessToken,\n abilities: result.abilities\n })\n },\n\n async logout(req: Request, res: Response) {\n const refreshToken = req.cookies?.['refreshToken'] as string | undefined\n const authReq = req as AuthRequest\n\n if (refreshToken) {\n await authService.logout(refreshToken, authReq.user?.id, getRequestInfo(req))\n }\n\n res.clearCookie('refreshToken', { path: '/api/v1' })\n res.status(204).send()\n },\n\n async me(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const result = await authService.me(authReq.user.id)\n res.json(result)\n },\n\n async logoutAll(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const sessionsRevoked = await authService.logoutAll(authReq.user.id, getRequestInfo(req))\n\n res.clearCookie('refreshToken', { path: '/api/v1' })\n res.json({ sessionsRevoked })\n },\n\n async getSessions(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const currentToken = req.cookies?.['refreshToken'] as string | undefined\n const sessions = await authService.getSessions(authReq.user.id, currentToken)\n res.json(sessions)\n },\n\n async revokeSession(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const sessionId = req.params['id']\n if (!sessionId) {\n throw new errors.AppError('ID de sesión requerido', 400)\n }\n\n const currentToken = req.cookies?.['refreshToken'] as string | undefined\n\n // No permitir revocar la sesión actual (usar logout para eso)\n const sessions = await authService.getSessions(authReq.user.id, currentToken)\n const targetSession = sessions.find(s => s.id === sessionId)\n\n if (targetSession?.is_current) {\n throw new errors.AppError('No puedes revocar tu sesión actual. Usa logout.', 400)\n }\n\n const revoked = await authService.revokeSession(authReq.user.id, sessionId, getRequestInfo(req))\n\n if (!revoked) {\n throw new errors.NotFoundError('Sesión')\n }\n\n res.status(204).send()\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { createAuthController } from './auth.controller.js'\nimport { refreshTokenEntity, authConfigEntity } from './auth.entity.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\nimport { getAuthConfig } from './auth.config.js'\n\n// Schemas para rutas manuales\nexport const loginSchema = z.object({\n email: z.string().email('Email inválido'),\n password: z.string().min(1, 'Password requerido'),\n deviceId: z.string().max(64).optional(),\n deviceName: z.string().max(100).optional()\n})\n\nexport type LoginInput = z.infer<typeof loginSchema>\n\nexport const registerSchema = z.object({\n email: z.string().email('Email inválido'),\n password: z.string().min(8, 'Password debe tener al menos 8 caracteres'),\n name: z.string().min(2, 'Nombre debe tener al menos 2 caracteres'),\n deviceId: z.string().max(64).optional(),\n deviceName: z.string().max(100).optional()\n})\n\nexport type RegisterInput = z.infer<typeof registerSchema>\n\n/**\n * Auth Routes\n *\n * Auto-montaje desde definitions:\n * - authAuditEntity (event) - read-only por diseño\n *\n * Aquí montamos:\n * - Rutas de autenticación (login, refresh, logout, me)\n * - refreshTokenEntity (temp con personalización: sin create/update vía API)\n * - authConfigEntity (single - configuración de auth)\n */\nexport function createAuthRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { validate, auth } = ctx.middleware\n const controller = createAuthController(ctx)\n\n if (!auth) {\n throw new Error('Auth middleware not initialized. Ensure auth.init() runs before routes.')\n }\n\n // ============================================================================\n // RUTAS DE AUTENTICACIÓN (manuales - lógica específica)\n // ============================================================================\n\n // Rate limits desde configuración (AUTH_RATE_LIMIT_MAX, AUTH_RATE_LIMIT_WINDOW)\n const authConfig = getAuthConfig()\n const loginRateLimit = createRateLimit({\n windowMs: authConfig.rateLimitWindowMs,\n max: authConfig.rateLimitMax,\n message: 'Demasiados intentos de login, intenta más tarde'\n })\n const refreshRateLimit = createRateLimit({\n windowMs: 60 * 1000,\n max: authConfig.rateLimitMax * 2,\n message: 'Demasiadas solicitudes de refresh'\n })\n const logoutRateLimit = createRateLimit({\n windowMs: 60 * 1000,\n max: authConfig.rateLimitMax,\n message: 'Demasiadas solicitudes de logout'\n })\n\n router.post('/login', loginRateLimit, validate({ body: loginSchema }), controller.login)\n router.post('/register', loginRateLimit, validate({ body: registerSchema as z.ZodSchema }), controller.register)\n router.post('/refresh', refreshRateLimit, controller.refresh)\n router.post('/logout', auth, logoutRateLimit, controller.logout)\n router.post('/logout-all', auth, logoutRateLimit, controller.logoutAll)\n router.get('/me', auth, controller.me)\n\n // Gestión de sesiones/dispositivos\n router.get('/sessions', auth, controller.getSessions)\n router.delete('/sessions/:id', auth, controller.revokeSession)\n\n // ============================================================================\n // TOKENS (temp - personalización: sin create/update vía API)\n // ============================================================================\n\n const tokensService = ctx.createEntityService(refreshTokenEntity)\n const tokensController = ctx.createEntityController(tokensService, refreshTokenEntity)\n\n // Tokens solo se crean/rotan internamente\n delete tokensController.create\n delete tokensController.update\n\n const tokensRouter = ctx.createEntityRouter(tokensController, refreshTokenEntity)\n router.use(refreshTokenEntity.routePrefix ?? '/tokens', tokensRouter)\n\n ctx.services['refreshTokens'] = tokensService\n\n // ============================================================================\n // CONFIG (single - configuración de auth)\n // ============================================================================\n\n const configService = ctx.createEntityService(authConfigEntity)\n const configController = ctx.createEntityController(configService, authConfigEntity)\n const configRouter = ctx.createEntityRouter(configController, authConfigEntity)\n router.use(authConfigEntity.routePrefix ?? '/config', configRouter)\n\n return router\n}\n","import jwt from 'jsonwebtoken'\nimport type { Request, Response, NextFunction, RequestHandler, ModuleContext } from '@gzl10/nexus-sdk'\nimport type { JwtPayload } from './jwt.utils.js'\nimport type { AuthUserRecord } from './auth.service.js'\nimport type { UsersService } from '../../types/services.js'\nimport { getAuthConfig } from './auth.config.js'\n\n// Table name (hardcoded for module isolation)\nconst USERS = 'users'\n\n/**\n * Crea el middleware de autenticación requerida\n * Falla si no hay token válido\n */\nexport function createAuthMiddleware(ctx: ModuleContext): RequestHandler {\n const { errors, abilities } = ctx\n const { defineAbilityFor } = abilities\n const { secret } = getAuthConfig()\n\n // Obtener servicio de usuarios desde ctx.services\n const usersService = ctx.services['users'] as UsersService\n if (!usersService) {\n throw new Error('UsersService not initialized. Ensure users module loads before auth.')\n }\n const { roles: rolesService } = usersService\n\n return async (req: Request, _res: Response, next: NextFunction) => {\n const authHeader = req.headers.authorization\n\n if (!authHeader?.startsWith('Bearer ')) {\n throw new errors.UnauthorizedError('Token no proporcionado')\n }\n\n const token = authHeader.slice(7)\n\n try {\n const decoded = jwt.verify(token, secret) as unknown as JwtPayload\n\n const user = await ctx.db<AuthUserRecord>(USERS).where({ id: decoded.userId }).first()\n\n if (!user) {\n throw new errors.UnauthorizedError('Usuario no encontrado')\n }\n\n // Cargar permisos del rol desde BD\n const permissions = await rolesService.getPermissionsByRoleId(user.role_id)\n\n req.user = user\n req.ability = defineAbilityFor(user, permissions) as Request['ability']\n next()\n } catch (error) {\n if (error instanceof jwt.JsonWebTokenError) {\n throw new errors.UnauthorizedError('Token inválido')\n }\n if (error instanceof jwt.TokenExpiredError) {\n throw new errors.UnauthorizedError('Token expirado')\n }\n throw error\n }\n }\n}\n\n/**\n * Crea el middleware de autenticación opcional\n * No falla si no hay token, simplemente continúa sin user\n */\nexport function createOptionalAuthMiddleware(ctx: ModuleContext): RequestHandler {\n const { abilities } = ctx\n const { defineAbilityFor } = abilities\n const { secret } = getAuthConfig()\n\n // Obtener servicio de usuarios desde ctx.services\n const usersService = ctx.services['users'] as UsersService\n if (!usersService) {\n throw new Error('UsersService not initialized. Ensure users module loads before auth.')\n }\n const { roles: rolesService } = usersService\n\n return async (req: Request, _res: Response, next: NextFunction) => {\n const authHeader = req.headers.authorization\n\n if (!authHeader?.startsWith('Bearer ')) {\n return next()\n }\n\n const token = authHeader.slice(7)\n\n try {\n const decoded = jwt.verify(token, secret) as unknown as JwtPayload\n\n const user = await ctx.db<AuthUserRecord>(USERS).where({ id: decoded.userId }).first()\n\n if (user) {\n const permissions = await rolesService.getPermissionsByRoleId(user.role_id)\n req.user = user\n req.ability = defineAbilityFor(user, permissions) as Request['ability']\n }\n } catch {\n // Token inválido, continuar sin autenticación\n }\n\n next()\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { authConfigEntity } from './auth.entity.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nconst SINGLE_RECORDS = 'single_records'\n\n/**\n * Seed para auth: crea configuración inicial desde variables de entorno\n *\n * AUTH_SECRET nunca se persiste en DB (siempre desde env por seguridad)\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n\n const key = authConfigEntity.key\n\n // Verificar si ya existe\n const existing = await db(SINGLE_RECORDS).where({ key }).first()\n if (existing) {\n logger.debug('Auth config already seeded')\n return\n }\n\n const now = nowTimestamp(db)\n const defaults = authConfigEntity.defaults\n\n // Crear config inicial desde variables de entorno\n await db(SINGLE_RECORDS).insert({\n id: generateId(),\n key,\n value: JSON.stringify(defaults),\n created_at: now,\n updated_at: now\n })\n\n logger.info('Auth config seeded from environment variables')\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { createAuthRoutes } from './auth.routes.js'\nimport { createAuthMiddleware, createOptionalAuthMiddleware } from './auth.middleware.js'\nimport { refreshTokenEntity, authAuditEntity, authConfigEntity } from './auth.entity.js'\n\n// Re-export types del módulo\nexport type { RefreshToken, AuthAudit } from './auth.types.js'\n\nexport const authModule: ModuleManifest = {\n name: 'auth',\n label: 'Authentication',\n icon: 'mdi:lock-outline',\n description: 'JWT authentication with refresh tokens, session management, and password security',\n type: 'core',\n category: 'security',\n dependencies: ['logger', 'users'],\n definitions: [refreshTokenEntity, authAuditEntity, authConfigEntity],\n // migrate: usa migración generada desde definitions\n init: (ctx) => {\n // Registrar middlewares para uso de otros módulos\n ctx.middleware['auth'] = createAuthMiddleware(ctx)\n ctx.middleware['optionalAuth'] = createOptionalAuthMiddleware(ctx)\n },\n routes: createAuthRoutes,\n routePrefix: '/auth',\n\n // Import dinámico para evitar ciclos\n seed: async (ctx) => {\n const { seed } = await import('./auth.seed.js')\n await seed(ctx)\n }\n}\n\nexport default authModule\n","import type { ComputedEntityDefinition, ModuleContext, ModuleManifest, PluginManifest, Category } from '@gzl10/nexus-sdk'\nimport { CATEGORIES, CATEGORY_ORDER } from '@gzl10/nexus-sdk'\n\n/**\n * Tipos de items del sidebar\n */\nexport type SidebarItemType = 'item' | 'divider' | 'group'\n\n/**\n * Item del sidebar para la UI\n */\nexport interface SidebarItem {\n type: SidebarItemType\n key: string\n label?: string\n icon?: string\n to?: string\n children?: SidebarItem[]\n}\n\n/**\n * Respuesta del sidebar con metadata\n */\nexport interface SidebarDTO {\n items: SidebarItem[]\n version: string\n}\n\n/**\n * Agrupa módulos por categoría (del módulo o heredada del plugin)\n */\ninterface ModuleWithCategory {\n module: ModuleManifest\n category: string\n pluginIcon?: string\n}\n\nfunction groupModulesByCategory(\n plugins: PluginManifest[],\n coreModules: ModuleManifest[]\n): Map<string, ModuleWithCategory[]> {\n const groups = new Map<string, ModuleWithCategory[]>()\n\n // Core modules usan su propia category\n for (const mod of coreModules) {\n if (!mod.routes) continue\n const category = mod.category || 'other'\n if (!groups.has(category)) {\n groups.set(category, [])\n }\n groups.get(category)!.push({ module: mod, category })\n }\n\n // Plugin modules: usar category del módulo, o heredar del plugin\n for (const plugin of plugins) {\n for (const mod of plugin.modules) {\n if (!mod.routes) continue\n const category = mod.category || plugin.category || 'other'\n if (!groups.has(category)) {\n groups.set(category, [])\n }\n groups.get(category)!.push({\n module: mod,\n category,\n pluginIcon: plugin.icon\n })\n }\n }\n\n return groups\n}\n\n/**\n * Convierte un módulo a item del sidebar\n */\nfunction moduleToSidebarItem(\n mod: ModuleManifest,\n getModuleSubjects: (mod: ModuleManifest) => string[],\n userSubjects?: string[]\n): SidebarItem | null {\n // Solo módulos con rutas\n if (!mod.routes) return null\n\n // Verificar permisos si se proporcionan subjects del usuario\n if (userSubjects) {\n const moduleSubjects = getModuleSubjects(mod)\n // Si el módulo tiene subjects y el usuario no tiene acceso a ninguno, ocultar\n if (moduleSubjects.length > 0) {\n const hasAccess = moduleSubjects.some((s: string) => userSubjects.includes(s))\n if (!hasAccess) return null\n }\n }\n\n return {\n type: 'item',\n key: `module-${mod.name}`,\n label: mod.label || mod.name,\n icon: mod.icon || 'mdi:cube-outline',\n to: `/admin/module/${mod.name}`\n }\n}\n\n/**\n * Fallback para categoría 'other' (no definida en CATEGORIES)\n */\nconst OTHER_CATEGORY = { label: 'Other', icon: 'mdi:package-variant', order: 99 }\n\n/**\n * EntityDefinition para Sidebar (computed)\n * Calcula el contenido del sidebar desde módulos y plugins\n */\nexport const sidebarEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Sidebar',\n labelField: 'version',\n routePrefix: '/sidebar',\n\n fields: {\n items: {\n name: 'items',\n label: 'Items',\n input: 'hidden',\n db: { type: 'json', nullable: false }\n },\n version: {\n name: 'version',\n label: 'Version',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false }\n }\n },\n\n // Sin restricciones CASL - sidebar es público\n // El filtrado de items se hace según abilities del usuario\n casl: {\n subject: 'Sidebar',\n permissions: {}\n },\n\n compute: async (ctx: ModuleContext): Promise<SidebarDTO[]> => {\n const items: SidebarItem[] = []\n const modules = ctx.engine.getModules()\n const plugins = ctx.engine.getPlugins()\n\n // 1. Dashboard (siempre visible)\n items.push({\n type: 'item',\n key: 'dashboard',\n label: 'Dashboard',\n icon: 'mdi:view-dashboard-outline',\n to: '/admin'\n })\n\n // Separador entre Dashboard y categorías\n items.push({\n type: 'divider',\n key: 'divider-main'\n })\n\n // 2. Agrupar todos los módulos por category\n const coreModules = modules.filter(m => m.type === 'core')\n const modulesByCategory = groupModulesByCategory(plugins, coreModules)\n\n // Orden de categorías en sidebar (CATEGORY_ORDER + 'other' como fallback)\n const categoryOrder = [...CATEGORY_ORDER, 'other' as Category]\n\n for (const category of categoryOrder) {\n const categoryModules = modulesByCategory.get(category)\n if (!categoryModules || categoryModules.length === 0) continue\n\n const categoryItems = categoryModules\n .map(({ module, pluginIcon }) => {\n const item = moduleToSidebarItem(module, ctx.engine.getModuleSubjects)\n if (item && pluginIcon) {\n item.icon = pluginIcon\n }\n return item\n })\n .filter((item): item is SidebarItem => item !== null)\n\n if (categoryItems.length > 0) {\n const meta = CATEGORIES[category] || OTHER_CATEGORY\n\n items.push({\n type: 'group',\n key: `category-${category}`,\n label: meta.label,\n icon: meta.icon,\n children: categoryItems\n })\n }\n }\n\n return [{\n items,\n version: new Date().toISOString()\n }]\n },\n\n cache: {\n ttl: 60 // Cache 60s - estructura no cambia frecuentemente\n }\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { sidebarEntity } from './ui.entity.js'\n\n/**\n * UI Module\n *\n * sidebarEntity (computed) se auto-monta desde definitions.\n * No necesita routes custom.\n */\nexport const uiModule: ModuleManifest = {\n name: 'ui',\n label: 'UI',\n icon: 'mdi:view-dashboard',\n description: 'UI configuration and sidebar structure',\n type: 'core',\n category: 'content',\n dependencies: ['logger'],\n definitions: [sidebarEntity],\n routePrefix: '/ui'\n}\n\nexport default uiModule\n","import { z } from 'zod'\nimport type { MailConfig } from './mail.types.js'\n\n// Re-export type for backwards compatibility\nexport type { MailConfig } from './mail.types.js'\n\n/**\n * Schema de variables de entorno para mail\n * Completamente independiente de la configuración global\n */\nconst mailEnvSchema = z.object({\n SMTP_HOST: z.string().default('localhost'),\n SMTP_PORT: z.coerce.number().default(1025),\n SMTP_SECURE: z.string().default('false').transform(v => v === 'true' || v === '1'),\n SMTP_USER: z.string().optional(),\n SMTP_PASS: z.string().optional(),\n SMTP_FROM: z.string().default('noreply@nexus.local')\n})\n\nexport const mailEnv = mailEnvSchema.parse(process.env)\n\n/**\n * Obtiene la configuración de mail desde las variables de entorno\n */\nexport function getMailConfig(): MailConfig {\n return {\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n auth: mailEnv.SMTP_USER\n ? { user: mailEnv.SMTP_USER, pass: mailEnv.SMTP_PASS! }\n : undefined,\n from: mailEnv.SMTP_FROM\n }\n}\n","import nodemailer, { type Transporter } from 'nodemailer'\nimport { readFileSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport type { Logger } from 'pino'\nimport { getMailConfig } from './mail.config.js'\nimport type { LoggerReporter } from '@gzl10/nexus-sdk'\nimport type { MailConfig, MailAction, SendMailOptions, SendMailResult } from './mail.types.js'\n\n// Re-export types for backwards compatibility\nexport type { MailAction, SendMailOptions, SendMailResult } from './mail.types.js'\n\n// Assets en public/ para que se publiquen con el paquete npm\nconst TEMPLATE_REL_PATH = join('public', 'mail', 'base.html')\n// Logo blanco para header azul (fondo #3B82F6)\nconst LOGO_REL_PATH = join('public', 'nexus', 'nexus-light-512.png')\n\n/**\n * Servicio de mail singleton\n */\nlet mailServiceInstance: MailService | null = null\n\nexport function getMailService(): MailService {\n if (!mailServiceInstance) {\n throw new Error('MailService not initialized. Call initMailService() first.')\n }\n return mailServiceInstance\n}\n\nexport function initMailService(\n logger: Logger,\n loggerService?: LoggerReporter,\n options?: { libPath?: string }\n): MailService {\n const config = getMailConfig()\n mailServiceInstance = new MailService(config, logger, loggerService, options)\n return mailServiceInstance\n}\n\nexport class MailService {\n private transporter: Transporter\n private defaultFrom: string\n private defaultLogoUrl: string\n private logger: Logger\n private template: string\n private loggerService?: LoggerReporter\n\n constructor(\n config: MailConfig,\n logger: Logger,\n loggerService?: LoggerReporter,\n options?: { libPath?: string }\n ) {\n this.defaultFrom = config.from\n this.logger = logger.child({ service: 'mail' })\n this.loggerService = loggerService\n\n const libPath = options?.libPath ?? process.cwd()\n this.template = readFileSync(join(libPath, TEMPLATE_REL_PATH), 'utf-8')\n\n // Cargar logo como base64 data URI\n const logoPath = join(libPath, LOGO_REL_PATH)\n if (existsSync(logoPath)) {\n const logoBase64 = readFileSync(logoPath).toString('base64')\n this.defaultLogoUrl = `data:image/png;base64,${logoBase64}`\n } else {\n this.defaultLogoUrl = ''\n }\n\n this.transporter = nodemailer.createTransport({\n host: config.host,\n port: config.port,\n secure: config.secure,\n auth: config.auth,\n // MailHog y servidores dev no necesitan TLS\n ...(config.auth ? {} : { ignoreTLS: true })\n })\n }\n\n async send(options: SendMailOptions): Promise<SendMailResult | null> {\n const from = options.from ?? this.defaultFrom\n const to = Array.isArray(options.to) ? options.to.join(', ') : options.to\n\n // Si hay title o message, usar template; si no, usar html raw\n const html = (options.title || options.message)\n ? this.renderTemplate(options)\n : options.html\n\n this.logger.info({ to, subject: options.subject }, 'Sending email')\n\n try {\n const result = await this.transporter.sendMail({\n from,\n to,\n subject: options.subject,\n text: options.text,\n html,\n replyTo: options.replyTo,\n attachments: options.attachments\n })\n\n this.logger.info(\n { messageId: result.messageId, accepted: result.accepted },\n 'Email sent'\n )\n\n return {\n messageId: result.messageId,\n accepted: result.accepted as string[],\n rejected: result.rejected as string[]\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Failed to send email')\n this.logger.warn({ error, to, subject: options.subject }, 'Failed to send email (continuing)')\n this.loggerService?.captureException(err, { service: 'mail', action: 'send', toCount: options.to?.length ?? 0 })\n return null\n }\n }\n\n private renderTemplate(options: SendMailOptions): string {\n let html = this.template\n\n // Reemplazar variables simples\n html = html.replace(/\\{\\{subject\\}\\}/g, options.subject)\n html = html.replace(/\\{\\{logoUrl\\}\\}/g, options.logoUrl ?? this.defaultLogoUrl)\n html = html.replace(/\\{\\{year\\}\\}/g, new Date().getFullYear().toString())\n\n // Procesar bloques condicionales con patrón específico\n html = this.processConditionalBlock(html, 'title', options.title)\n html = this.processConditionalBlock(html, 'message', options.message)\n\n // Actions (botones) - Nexus Blue (#3B82F6)\n if (options.actions?.length) {\n const actionsHtml = options.actions.map(a =>\n `<a href=\"${a.url}\" style=\"display:inline-block; background-color:#3B82F6; color:#ffffff; padding:12px 24px; text-decoration:none; border-radius:6px; margin:4px; font-weight:500;\">${a.label}</a>`\n ).join('')\n html = html.replace(/\\{\\{#if actions\\}\\}([\\s\\S]*?)\\{\\{\\/if\\}\\}/g, (_, content) =>\n content.replace(/\\{\\{actions\\}\\}/g, actionsHtml)\n )\n } else {\n html = html.replace(/\\{\\{#if actions\\}\\}[\\s\\S]*?\\{\\{\\/if\\}\\}/g, '')\n }\n\n return html\n }\n\n private processConditionalBlock(html: string, name: string, value?: string): string {\n const pattern = new RegExp(`\\\\{\\\\{#if ${name}\\\\}\\\\}([\\\\s\\\\S]*?)\\\\{\\\\{\\\\/if\\\\}\\\\}`, 'g')\n if (value) {\n return html.replace(pattern, (_, content) =>\n content.replace(new RegExp(`\\\\{\\\\{${name}\\\\}\\\\}`, 'g'), value)\n )\n }\n return html.replace(pattern, '')\n }\n\n async verify(): Promise<boolean> {\n try {\n await this.transporter.verify()\n this.logger.info('SMTP connection verified')\n return true\n } catch (error) {\n const err = error instanceof Error ? error : new Error('SMTP connection failed')\n this.logger.warn({ error }, 'SMTP connection failed (emails may not work)')\n this.loggerService?.captureException(err, { service: 'mail', action: 'verify' })\n return false\n }\n }\n}\n","import type {\n ConfigEntityDefinition,\n ActionEntityDefinition,\n EventEntityDefinition,\n ModuleContext\n} from '@gzl10/nexus-sdk'\nimport nodemailer from 'nodemailer'\nimport { mailEnv } from './mail.config.js'\nimport { getMailService } from './mail.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\nimport type { SendMailInput, SendMailOptions, MailConfigRow } from './mail.types.js'\n\n/**\n * Get mail config from DB by scope, fallback to env vars\n */\nasync function getConfigByScope(ctx: ModuleContext, scope: string): Promise<MailConfigRow> {\n const row = await ctx.db('mail_config').where({ scope }).first<MailConfigRow>()\n\n if (row) {\n return {\n ...row,\n // Coerce SQLite 0/1 to boolean\n secure: row.secure === true || row.secure === 1\n }\n }\n\n // Fallback to env vars\n return {\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n from: mailEnv.SMTP_FROM,\n auth_user: mailEnv.SMTP_USER ?? null,\n auth_pass: mailEnv.SMTP_PASS ?? null\n }\n}\n\n/**\n * Create nodemailer transporter from config\n */\nfunction createTransporter(config: MailConfigRow) {\n const auth = config.auth_user\n ? { user: config.auth_user, pass: config.auth_pass! }\n : undefined\n\n return nodemailer.createTransport({\n host: config.host,\n port: config.port,\n secure: config.secure as boolean,\n auth,\n ...(auth ? {} : { ignoreTLS: true })\n })\n}\n\n/** Normalize to to array */\nfunction normalizeRecipients(to: string | string[]): string[] {\n if (Array.isArray(to)) return to\n return to.split(',').map(s => s.trim()).filter(Boolean)\n}\n\n/**\n * Config Entity: config\n * Configuración SMTP persistida en BD con scope\n */\nexport const mailConfigEntity: ConfigEntityDefinition = {\n type: 'config',\n table: 'mail_config',\n label: 'Mail Config',\n routePrefix: '/config',\n scopeField: 'scope',\n timestamps: true,\n\n // Defaults desde variables de entorno\n defaults: {\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n from: mailEnv.SMTP_FROM,\n auth_user: mailEnv.SMTP_USER ?? '',\n auth_pass: ''\n },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n scope: {\n name: 'scope',\n label: 'Scope',\n disabled: true,\n input: 'text',\n hint: 'Identificador de scope (ej: default, tenant-123)',\n db: { type: 'string', size: 100, nullable: false, unique: true }\n },\n host: {\n name: 'host',\n label: 'SMTP Host',\n input: 'text',\n hint: 'Default: SMTP_HOST env var',\n db: { type: 'string', size: 255, nullable: false }\n },\n port: {\n name: 'port',\n label: 'Port',\n input: 'number',\n hint: 'Default: SMTP_PORT env var',\n db: { type: 'integer', nullable: false }\n },\n secure: {\n name: 'secure',\n label: 'TLS/SSL',\n input: 'switch',\n hint: 'Default: SMTP_SECURE env var',\n db: { type: 'boolean', nullable: false }\n },\n from: {\n name: 'from',\n label: 'Sender',\n input: 'email',\n hint: 'Default: SMTP_FROM env var',\n db: { type: 'string', size: 255, nullable: false }\n },\n auth_user: {\n name: 'auth_user',\n label: 'Auth User',\n input: 'text',\n hint: 'SMTP username (optional)',\n db: { type: 'string', size: 255, nullable: true }\n },\n auth_pass: {\n name: 'auth_pass',\n label: 'Auth Password',\n input: 'password',\n hint: 'SMTP password (optional)',\n db: { type: 'string', size: 255, nullable: true }\n }\n },\n\n casl: {\n subject: 'MailConfig',\n permissions: {\n ADMIN: { actions: ['read', 'update'] }\n }\n }\n}\n\n/**\n * Action Entity: send\n * Endpoint para enviar emails\n */\nexport const mailSendAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Send Email',\n routePrefix: '/send',\n\n fields: {\n scope: {\n name: 'scope',\n label: 'Config Scope',\n input: 'select',\n hint: 'Which mail config to use',\n options: { endpoint: '/mail/config', valueField: 'scope', labelField: 'scope' }\n },\n to: {\n name: 'to',\n label: 'Recipient(s)',\n input: 'tags',\n placeholder: 'Add email address',\n validation: { required: true, format: 'email' }\n },\n subject: {\n name: 'subject',\n label: 'Subject',\n input: 'text',\n validation: { required: true, min: 1, max: 255 }\n },\n title: {\n name: 'title',\n label: 'Title',\n input: 'text',\n hint: 'Large title in email header'\n },\n message: {\n name: 'message',\n label: 'Message',\n input: 'markdown',\n hint: 'Email body (supports markdown)'\n },\n html: {\n name: 'html',\n label: 'HTML',\n input: 'hidden',\n hint: 'Alternative HTML (ignores title/message if provided)'\n }\n },\n\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { to: rawTo, subject, title, message, html, scope = 'default' } = input as SendMailInput\n const recipients = normalizeRecipients(rawTo)\n\n // Get config from DB by scope\n const config = await getConfigByScope(ctx, scope)\n const transporter = createTransporter(config)\n\n // Use MailService for template rendering if available\n const mailService = getMailService()\n\n // Build email options\n const mailOptions: SendMailOptions = {\n to: recipients,\n subject,\n title,\n message,\n html,\n from: config.from\n }\n\n // Send using dynamic transporter but delegate to service for template\n let result: { messageId: string; accepted: string[]; rejected: string[] } | null = null\n try {\n // If using title/message, let service render template\n if (title || message) {\n result = await mailService.send(mailOptions)\n } else {\n // Direct send with raw html\n const sendResult = await transporter.sendMail({\n from: config.from,\n to: recipients.join(', '),\n subject,\n html\n })\n result = {\n messageId: sendResult.messageId,\n accepted: sendResult.accepted as string[],\n rejected: sendResult.rejected as string[]\n }\n }\n } catch (error) {\n ctx.logger.warn({ error, scope }, 'Failed to send email')\n\n // Log del fallo\n await ctx.db('mail_log').insert({\n id: ctx.helpers.generateId(),\n to: recipients.join(', '),\n subject,\n status: 'failed',\n message_id: null,\n error: error instanceof Error ? error.message : 'Failed to send email',\n created_at: nowTimestamp(ctx.db)\n })\n\n throw new ctx.errors.AppError('Failed to send email', 500)\n }\n\n // Guard: result siempre definido si llegamos aquí\n if (!result) {\n throw new ctx.errors.AppError('Failed to send email', 500)\n }\n\n // Log del éxito\n await ctx.db('mail_log').insert({\n id: ctx.helpers.generateId(),\n to: recipients.join(', '),\n subject,\n status: 'sent',\n message_id: result.messageId,\n error: null,\n created_at: nowTimestamp(ctx.db)\n })\n\n const acceptedCount = result.accepted.length\n const rejectedCount = result.rejected.length\n let resultMessage = `Email sent to ${acceptedCount} recipient${acceptedCount !== 1 ? 's' : ''}`\n if (rejectedCount > 0) {\n resultMessage += ` (${rejectedCount} rejected)`\n }\n\n return {\n message: resultMessage,\n messageId: result.messageId,\n accepted: result.accepted,\n rejected: result.rejected\n }\n },\n\n casl: {\n subject: 'MailSend',\n permissions: {\n ADMIN: { actions: ['execute'] }\n }\n }\n}\n\n/**\n * Action Entity: test\n * Probar conexión SMTP\n */\nexport const mailTestAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Test Connection',\n order: 1, \n routePrefix: '/test',\n\n fields: {\n scope: {\n name: 'scope',\n label: 'Config Scope',\n input: 'select',\n hint: 'Which mail config to test',\n options: { endpoint: '/mail/config', valueField: 'scope', labelField: 'scope' }\n }\n },\n\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { scope = 'default' } = input as { scope?: string }\n\n // Get config from DB by scope\n const config = await getConfigByScope(ctx, scope)\n const transporter = createTransporter(config)\n\n try {\n await transporter.verify()\n ctx.logger.info({ scope, host: config.host, port: config.port }, 'SMTP connection verified')\n } catch (error) {\n ctx.logger.warn({ error, scope }, 'SMTP connection failed')\n throw new ctx.errors.AppError(\n `Failed to connect to SMTP server ${config.host}:${config.port}`,\n 500\n )\n }\n\n return {\n scope,\n host: config.host,\n port: config.port,\n message: `SMTP connection to ${config.host}:${config.port} verified successfully`\n }\n },\n\n casl: {\n subject: 'MailTest',\n permissions: {\n ADMIN: { actions: ['execute'] }\n }\n }\n}\n\n/**\n * Event Entity: log\n * Log append-only de emails enviados\n */\nexport const mailLogEntity: EventEntityDefinition = {\n type: 'event',\n table: 'mail_log',\n label: 'Mail Log',\n labelField: 'subject',\n routePrefix: '/log',\n // timestamps: false - created_at está definido explícitamente en fields\n retention: { days: 90 },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n created_at: {\n name: 'created_at',\n label: 'Date',\n input: 'datetime',\n disabled: true,\n db: { type: 'datetime', nullable: false, defaultFn: 'now', index: true },\n meta: { sortable: true }\n },\n to: {\n name: 'to',\n label: 'Recipient(s)',\n input: 'text',\n db: { type: 'string', size: 1000, nullable: false },\n meta: { searchable: true }\n },\n subject: {\n name: 'subject',\n label: 'Subject',\n input: 'text',\n db: { type: 'string', size: 255, nullable: false },\n meta: { searchable: true, sortable: true }\n },\n status: {\n name: 'status',\n label: 'Status',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false, index: true },\n validation: { enum: ['pending', 'sent', 'failed', 'bounced'] },\n options: {\n static: [\n { value: 'pending', label: 'Pending' },\n { value: 'sent', label: 'Sent' },\n { value: 'failed', label: 'Failed' },\n { value: 'bounced', label: 'Bounced' }\n ]\n },\n meta: { sortable: true }\n },\n message_id: {\n name: 'message_id',\n label: 'Message ID',\n input: 'hidden',\n db: { type: 'string', size: 255, nullable: true }\n },\n error: {\n name: 'error',\n label: 'Error',\n input: 'text',\n db: { type: 'text', nullable: true }\n },\n sent_by: {\n name: 'sent_by',\n label: 'Sent by',\n input: 'select',\n db: { type: 'string', size: 26, nullable: true, index: true },\n relation: { table: 'users', column: 'id', onDelete: 'SET NULL' },\n options: { endpoint: '/users', valueField: 'id', labelField: 'name' }\n }\n },\n\n casl: {\n subject: 'MailLog',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { mailConfigEntity } from './mail.entity.js'\n\n/**\n * Mail Routes\n *\n * Auto-montaje desde definitions:\n * - mailSendAction, mailTestAction (action)\n * - mailLogEntity (event)\n *\n * Aquí solo montamos mailConfigEntity (config - no auto-monta).\n */\nexport function createMailRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n\n // ============================================================================\n // CONFIG (config entity - no auto-monta)\n // ============================================================================\n\n const configService = ctx.createEntityService(mailConfigEntity)\n const configController = ctx.createEntityController(configService, mailConfigEntity)\n const configRouter = ctx.createEntityRouter(configController, mailConfigEntity)\n\n router.use(mailConfigEntity.routePrefix ?? '/config', configRouter)\n\n ctx.services['mail-config'] = configService\n\n return router\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { mailEnv } from './mail.config.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\n/**\n * Seed para mail: crea configuración inicial desde variables de entorno\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n\n // Verificar si ya existe config 'default'\n const existing = await db('mail_config').where({ scope: 'default' }).first()\n if (existing) {\n logger.debug('Mail config already seeded')\n return\n }\n\n const now = nowTimestamp(db)\n\n // Crear config inicial desde variables de entorno\n const configData = {\n id: generateId(),\n scope: 'default',\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n from: mailEnv.SMTP_FROM,\n auth_user: mailEnv.SMTP_USER ?? null,\n auth_pass: mailEnv.SMTP_PASS ?? null,\n is_default: true,\n created_at: now,\n updated_at: now\n }\n\n await db('mail_config').insert(configData)\n logger.info('Mail config seeded from environment variables')\n}\n","import type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { mailConfigEntity, mailSendAction, mailTestAction, mailLogEntity } from './mail.entity.js'\nimport { initMailService } from './mail.service.js'\nimport { createMailRoutes } from './mail.routes.js'\n\nexport { MailService, getMailService } from './mail.service.js'\nexport { getMailConfig } from './mail.config.js'\nexport type {\n MailConfig,\n MailConfigRow,\n MailAction,\n SendMailInput,\n SendMailOptions,\n SendMailResult\n} from './mail.types.js'\n\nexport const mailModule: ModuleManifest = {\n name: 'mail',\n label: 'Mail',\n icon: 'mdi:email-outline',\n description: 'Email sending and logging',\n type: 'core',\n category: 'messaging',\n dependencies: ['logger'],\n\n definitions: [\n mailConfigEntity,\n mailSendAction,\n mailTestAction,\n mailLogEntity\n ],\n\n routePrefix: '/mail',\n routes: createMailRoutes,\n\n init: (ctx: ModuleContext) => {\n // Inicializar y registrar el servicio de mail\n const mailService = initMailService(ctx.logger, ctx.services['logger'], { libPath: ctx.helpers.getLibPath() })\n ctx.services['mail'] = mailService\n ctx.logger.debug('Mail service registered')\n },\n\n // Import dinámico para evitar ciclos\n seed: async (ctx) => {\n const { seed } = await import('./mail.seed.js')\n await seed(ctx)\n }\n}\n\nexport default mailModule\n","import type { Knex } from 'knex'\nimport type { Logger } from 'pino'\nimport type { ModuleContext } from '@gzl10/nexus-sdk'\nimport type {\n NotificationType,\n NotificationPriority,\n NotificationTarget,\n SendNotificationInput\n} from './notifications.entity.js'\n\n/**\n * Notificación en BD\n */\nexport interface Notification {\n id: string\n title: string\n message: string\n type: NotificationType\n priority: NotificationPriority\n target_type: NotificationTarget\n target_value: string | null\n link: string | null\n read_by: string[] | null\n expires_at: Date | null\n created_at: Date\n}\n\n/**\n * Payload enviado por Socket.IO\n */\nexport interface NotificationPayload {\n id: string\n title: string\n message: string\n type: NotificationType\n priority: NotificationPriority\n link?: string\n timestamp: string\n}\n\n/**\n * Servicio de notificaciones\n */\nexport class NotificationService {\n private db: Knex\n private logger: Logger\n private generateId: () => string\n private nowTimestamp: (db: Knex) => string\n private formatTimestamp: (db: Knex, date?: Date) => string\n private socket: ModuleContext['socket']\n private events: ModuleContext['events']\n\n constructor(ctx: ModuleContext) {\n this.db = ctx.db\n this.logger = ctx.logger.child({ service: 'notifications' })\n this.generateId = ctx.helpers.generateId\n this.nowTimestamp = ctx.helpers.nowTimestamp\n this.formatTimestamp = ctx.helpers.formatTimestamp\n this.socket = ctx.socket\n this.events = ctx.events\n }\n\n /**\n * Envía una notificación\n */\n async send(options: SendNotificationInput): Promise<{ id: string; sent: number }> {\n const { target_type, target_value } = options\n let sent = 0\n\n const type = options.type || 'info'\n const priority = options.priority || 'normal'\n\n // 1. Persistir notificación\n const id = this.generateId()\n const now = this.nowTimestamp(this.db)\n\n await this.db('notifications').insert({\n id,\n title: options.title,\n message: options.message,\n type,\n priority,\n target_type,\n target_value: target_value || null,\n link: options.link || null,\n read_by: JSON.stringify([]),\n expires_at: options.expires_at ? this.formatTimestamp(this.db, new Date(options.expires_at)) : null,\n created_at: now\n })\n\n // 2. Emitir por Socket.IO si está inicializado\n if (this.socket.isInitialized()) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const io = this.socket.getIO() as any\n\n const payload: NotificationPayload = {\n id,\n title: options.title,\n message: options.message,\n type,\n priority,\n link: options.link || undefined,\n timestamp: now\n }\n\n switch (target_type) {\n case 'all':\n io.to('all').emit('notification', payload)\n sent = io.sockets.sockets.size\n break\n\n case 'authenticated':\n io.to('authenticated').emit('notification', payload)\n sent = (await io.in('authenticated').fetchSockets()).length\n break\n\n case 'role':\n if (target_value) {\n io.to(`role:${target_value}`).emit('notification', payload)\n sent = (await io.in(`role:${target_value}`).fetchSockets()).length\n }\n break\n\n case 'users':\n if (target_value) {\n try {\n const userIds = JSON.parse(target_value) as string[]\n for (const userId of userIds) {\n io.to(`user:${userId}`).emit('notification', payload)\n }\n sent = userIds.length\n } catch {\n this.logger.warn({ target_value }, 'Invalid user IDs JSON')\n }\n }\n break\n\n case 'user':\n if (target_value) {\n io.to(`user:${target_value}`).emit('notification', payload)\n sent = this.socket.isUserConnected(target_value) ? 1 : 0\n }\n break\n }\n\n this.logger.debug({ id, target_type, sent }, 'Notification sent')\n }\n\n // 3. Emitir evento interno\n this.events.emit('notifications.sent', { id, target_type, target_value, sent })\n\n return { id, sent }\n }\n\n /**\n * Marca una notificación como leída por un usuario\n */\n async markAsRead(notificationId: string, userId: string): Promise<boolean> {\n const notification = await this.db('notifications')\n .where('id', notificationId)\n .first()\n\n if (!notification) {\n return false\n }\n\n // Actualizar read_by (append userId si no existe)\n const readBy: string[] = JSON.parse(notification.read_by || '[]')\n if (!readBy.includes(userId)) {\n readBy.push(userId)\n await this.db('notifications')\n .where('id', notificationId)\n .update({ read_by: JSON.stringify(readBy) })\n\n // Insertar en notification_reads (event log)\n await this.db('notification_reads').insert({\n id: this.generateId(),\n notification_id: notificationId,\n user_id: userId,\n read_at: this.nowTimestamp(this.db)\n })\n\n // Emitir por Socket.IO para sync entre tabs\n if (this.socket.isInitialized()) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const io = this.socket.getIO() as any\n io.to(`user:${userId}`).emit('notification:read', { notificationId })\n }\n\n this.logger.debug({ notificationId, userId }, 'Notification marked as read')\n }\n\n return true\n }\n\n /**\n * Marca todas las notificaciones como leídas por un usuario\n */\n async markAllAsRead(userId: string, roleId?: string): Promise<number> {\n const unread = await this.getUnread(userId, roleId)\n let count = 0\n\n for (const notification of unread) {\n await this.markAsRead(notification.id, userId)\n count++\n }\n\n return count\n }\n\n /**\n * Obtiene notificaciones no leídas para un usuario\n */\n async getUnread(userId: string, roleId?: string): Promise<Notification[]> {\n const now = this.nowTimestamp(this.db)\n\n const query = this.db('notifications')\n .where(function () {\n // No expiradas\n this.whereNull('expires_at').orWhere('expires_at', '>', now)\n })\n .orderBy('created_at', 'desc')\n\n const notifications = await query\n\n // Filtrar por target y read_by en memoria (más flexible)\n return notifications.filter((n: Notification) => {\n // Verificar si ya fue leída\n const readBy: string[] = JSON.parse(n.read_by as unknown as string || '[]')\n if (readBy.includes(userId)) {\n return false\n }\n\n // Verificar target\n switch (n.target_type) {\n case 'all':\n case 'authenticated':\n return true\n\n case 'role':\n return n.target_value === roleId\n\n case 'users':\n try {\n const userIds = JSON.parse(n.target_value || '[]') as string[]\n return userIds.includes(userId)\n } catch {\n return false\n }\n\n case 'user':\n return n.target_value === userId\n\n default:\n return false\n }\n })\n }\n\n /**\n * Obtiene una notificación por ID\n */\n async findById(id: string): Promise<Notification | null> {\n const notification = await this.db('notifications').where('id', id).first()\n return notification || null\n }\n\n /**\n * Elimina una notificación\n */\n async delete(id: string): Promise<boolean> {\n const deleted = await this.db('notifications').where('id', id).delete()\n return deleted > 0\n }\n\n /**\n * Limpia notificaciones expiradas\n */\n async cleanupExpired(): Promise<number> {\n const deleted = await this.db('notifications')\n .where('expires_at', '<', this.nowTimestamp(this.db))\n .whereNotNull('expires_at')\n .delete()\n\n if (deleted > 0) {\n this.logger.info({ deleted }, 'Cleaned up expired notifications')\n }\n\n return deleted\n }\n}\n\nlet serviceInstance: NotificationService | null = null\n\n/**\n * Inicializa el servicio de notificaciones\n */\nexport function initNotificationService(ctx: ModuleContext): NotificationService {\n serviceInstance = new NotificationService(ctx)\n return serviceInstance\n}\n\n/**\n * Obtiene la instancia del servicio\n */\nexport function getNotificationService(): NotificationService {\n if (!serviceInstance) {\n throw new Error('NotificationService not initialized')\n }\n return serviceInstance\n}\n","import type { EventEntityDefinition, ActionEntityDefinition } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { getNotificationService } from './notifications.service.js'\n\n/**\n * Tipos de notificación\n */\nexport type NotificationType = 'info' | 'warning' | 'error' | 'success'\n\n/**\n * Prioridad de notificación\n */\nexport type NotificationPriority = 'low' | 'normal' | 'high' | 'urgent'\n\n/**\n * Tipos de target para notificaciones\n */\nexport type NotificationTarget = 'all' | 'authenticated' | 'role' | 'users' | 'user'\n\n/**\n * Notification (event) - Notificaciones efímeras con TTL\n */\nexport const notificationEntity: EventEntityDefinition = {\n type: 'event',\n table: 'notifications',\n label: 'Notifications',\n labelField: 'title',\n timestamps: true,\n retention: { days: 30 },\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n title: {\n name: 'title',\n label: 'Title',\n input: 'text',\n db: { type: 'string', size: 255, nullable: false }\n },\n message: {\n name: 'message',\n label: 'Message',\n input: 'textarea',\n db: { type: 'text', nullable: false }\n },\n type: {\n name: 'type',\n label: 'Type',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false, default: 'info' },\n options: {\n static: [\n { value: 'info', label: 'Info' },\n { value: 'success', label: 'Success' },\n { value: 'warning', label: 'Warning' },\n { value: 'error', label: 'Error' }\n ]\n }\n },\n priority: {\n name: 'priority',\n label: 'Priority',\n input: 'select',\n db: { type: 'string', size: 10, nullable: false, default: 'normal' },\n options: {\n static: [\n { value: 'low', label: 'Low' },\n { value: 'normal', label: 'Normal' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' }\n ]\n }\n },\n target_type: {\n name: 'target_type',\n label: 'Target Type',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n options: {\n static: [\n { value: 'user', label: 'User' },\n { value: 'role', label: 'Role' },\n { value: 'all', label: 'All users' }\n ]\n }\n },\n target_value: {\n name: 'target_value',\n label: 'Target Value',\n input: 'text',\n db: { type: 'string', size: 255, nullable: true }\n },\n link: {\n name: 'link',\n label: 'Link',\n input: 'url',\n db: { type: 'string', size: 500, nullable: true }\n },\n read_by: {\n name: 'read_by',\n label: 'Read By',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n },\n expires_at: {\n name: 'expires_at',\n label: 'Expires At',\n input: 'datetime',\n db: { type: 'datetime', nullable: true }\n }\n },\n casl: {\n subject: 'Notification',\n permissions: {\n ADMIN: { actions: ['manage'] },\n EDITOR: { actions: ['read'] },\n VIEWER: { actions: ['read'] }\n }\n }\n}\n\n/**\n * NotificationRead (event) - Log de lecturas\n */\nexport const notificationReadEntity: EventEntityDefinition = {\n type: 'event',\n table: 'notification_reads',\n label: 'Notification Reads',\n labelField: 'notification_id',\n retention: { days: 90 },\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n notification_id: {\n name: 'notification_id',\n label: 'Notification ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n user_id: {\n name: 'user_id',\n label: 'User ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n read_at: {\n name: 'read_at',\n label: 'Read At',\n input: 'datetime',\n db: { type: 'datetime', nullable: false }\n }\n },\n casl: {\n subject: 'NotificationRead',\n permissions: {\n ADMIN: { actions: ['manage'] }\n }\n }\n}\n\n/**\n * Schema de input para enviar notificación\n */\nexport const sendNotificationInputSchema = z.object({\n title: z.string().min(1, 'Title is required'),\n message: z.string().min(1, 'Message is required'),\n type: z.enum(['info', 'warning', 'error', 'success']).optional().default('info'),\n priority: z.enum(['low', 'normal', 'high', 'urgent']).optional().default('normal'),\n target_type: z.enum(['all', 'authenticated', 'role', 'users', 'user']),\n target_value: z.string().optional(),\n link: z.string().url().optional().or(z.literal('')),\n expires_at: z.string().datetime().optional()\n})\n\nexport type SendNotificationInput = z.input<typeof sendNotificationInputSchema>\n\n/**\n * Schema de output\n */\nexport const sendNotificationOutputSchema = z.object({\n id: z.string(),\n sent: z.number()\n})\n\n/**\n * SendNotification (action) - Enviar notificación\n */\nexport const sendNotificationAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Send Notification',\n routePrefix: '/send',\n inputSchema: sendNotificationInputSchema,\n outputSchema: sendNotificationOutputSchema,\n handler: async (_ctx, input: unknown) => {\n // Usar getNotificationService() directamente, no ctx.services\n // porque createModuleRouters() sobrescribe ctx.services['notifications']\n // con el EventEntityService de notificationEntity\n const service = getNotificationService()\n return service.send(input as SendNotificationInput)\n },\n fields: {\n title: {\n name: 'title',\n label: 'Title',\n input: 'text',\n validation: { required: true }\n },\n message: {\n name: 'message',\n label: 'Message',\n input: 'textarea',\n validation: { required: true }\n },\n type: {\n name: 'type',\n label: 'Type',\n input: 'select',\n options: {\n static: [\n { value: 'info', label: 'Info' },\n { value: 'success', label: 'Success' },\n { value: 'warning', label: 'Warning' },\n { value: 'error', label: 'Error' }\n ]\n }\n },\n priority: {\n name: 'priority',\n label: 'Priority',\n input: 'select',\n options: {\n static: [\n { value: 'low', label: 'Low' },\n { value: 'normal', label: 'Normal' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' }\n ]\n }\n },\n target_type: {\n name: 'target_type',\n label: 'Target Type',\n input: 'select',\n options: {\n static: [\n { value: 'user', label: 'User' },\n { value: 'role', label: 'Role' },\n { value: 'all', label: 'All users' }\n ]\n },\n validation: { required: true }\n },\n target_value: {\n name: 'target_value',\n label: 'Target Value',\n input: 'text'\n },\n link: {\n name: 'link',\n label: 'Link',\n input: 'url'\n },\n expires_at: {\n name: 'expires_at',\n label: 'Expires At',\n input: 'datetime'\n }\n },\n casl: {\n subject: 'Notification',\n permissions: {\n ADMIN: { actions: ['execute'] }\n }\n }\n}\n","import type { Request, Response, ModuleContext, Router } from '@gzl10/nexus-sdk'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { getNotificationService } from './notifications.service.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\n/**\n * Notifications Routes\n *\n * La action sendNotificationAction se monta automáticamente desde definitions.\n * Aquí solo definimos rutas especiales que no son actions (unread, read, etc).\n */\nexport function createNotificationsRoutes(ctx: ModuleContext): Router {\n const router = ctx.createRouter()\n const { auth } = ctx.middleware\n\n if (!auth) {\n throw new Error('Auth middleware not found. Ensure auth module loads before notifications.')\n }\n\n // Crear middleware requireAdmin inline\n const requireAdmin = (req: Request, res: Response, next: () => void) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n // Verificar si es ADMIN por roleId o por abilities\n const ability = (req as AuthRequest).ability\n if (!ability?.can('manage', 'all')) {\n res.status(403).json({ error: 'Forbidden: Admin role required' })\n return\n }\n next()\n }\n\n /**\n * GET /notifications/unread\n * Obtiene notificaciones no leídas del usuario autenticado\n */\n router.get('/unread', auth, async (req: Request, res: Response) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const service = getNotificationService()\n const notifications = await service.getUnread(user.id, user.role_id)\n\n res.json({\n items: notifications,\n total: notifications.length,\n page: 1,\n limit: notifications.length,\n totalPages: 1,\n hasNext: false\n })\n })\n\n /**\n * POST /notifications/:id/read\n * Marca una notificación como leída\n */\n router.post('/:id/read', auth, async (req: Request, res: Response) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const id = req.params['id']\n if (!id) {\n res.status(400).json({ error: 'Missing notification ID' })\n return\n }\n\n const service = getNotificationService()\n const success = await service.markAsRead(id, user.id)\n\n if (!success) {\n res.status(404).json({ error: 'Notification not found' })\n return\n }\n\n res.status(204).send()\n })\n\n /**\n * POST /notifications/read-all\n * Marca todas las notificaciones como leídas\n */\n router.post('/read-all', auth, async (req: Request, res: Response) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const service = getNotificationService()\n const count = await service.markAllAsRead(user.id, user.role_id)\n\n res.json({ count })\n })\n\n /**\n * DELETE /notifications/:id\n * Elimina una notificación (solo admin)\n */\n router.delete('/:id', auth, requireAdmin, async (req: Request, res: Response) => {\n const id = req.params['id']\n if (!id) {\n res.status(400).json({ error: 'Missing notification ID' })\n return\n }\n\n const service = getNotificationService()\n const success = await service.delete(id)\n\n if (!success) {\n res.status(404).json({ error: 'Notification not found' })\n return\n }\n\n res.status(204).send()\n })\n\n /**\n * GET /notifications\n * Lista notificaciones (solo admin)\n */\n router.get('/', auth, requireAdmin, async (req: Request, res: Response) => {\n const limit = parseInt(req.query['limit'] as string) || 50\n const page = parseInt(req.query['page'] as string) || 1\n const offset = (page - 1) * limit\n\n const notifications = await ctx.db('notifications')\n .orderBy('created_at', 'desc')\n .limit(limit)\n .offset(offset)\n\n const countResult = await ctx.db('notifications').count('* as count').first<{ count: string | number }>()\n const total = parseInt(String(countResult?.count || 0))\n const totalPages = Math.ceil(total / limit)\n\n res.json({\n items: notifications,\n total,\n page,\n limit,\n totalPages,\n hasNext: page < totalPages\n })\n })\n\n /**\n * POST /notifications/cleanup\n * Limpia notificaciones expiradas (solo admin)\n */\n const cleanupRateLimit = createRateLimit({ windowMs: 60 * 1000, max: 1, message: 'Cleanup solo puede ejecutarse 1 vez por minuto' })\n router.post('/cleanup', cleanupRateLimit, auth, requireAdmin, async (_req: Request, res: Response) => {\n const service = getNotificationService()\n const deleted = await service.cleanupExpired()\n\n res.json({ deleted })\n })\n\n return router\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { getNotificationService } from './notifications.service.js'\n\n/**\n * Registra handlers de Socket.IO para notificaciones\n */\nexport function registerNotificationSocketHandlers(ctx: ModuleContext): void {\n if (!ctx.socket.isInitialized()) {\n ctx.logger.debug('Socket.IO not initialized, skipping notification handlers')\n return\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const io = ctx.socket.getIO() as any\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n io.on('connection', (socket: any) => {\n const { userId, roleId, authenticated } = socket.data\n\n if (!authenticated || !userId) {\n return\n }\n\n /**\n * notification:read - Marcar notificación como leída\n */\n socket.on('notification:read', async (data: { notificationId: string }) => {\n try {\n const service = getNotificationService()\n await service.markAsRead(data.notificationId, userId)\n } catch (err) {\n ctx.logger.error({ err, userId, notificationId: data.notificationId }, 'Error marking notification as read')\n }\n })\n\n /**\n * notifications:read-all - Marcar todas como leídas\n */\n socket.on('notifications:read-all', async () => {\n try {\n const service = getNotificationService()\n await service.markAllAsRead(userId, roleId)\n } catch (err) {\n ctx.logger.error({ err, userId }, 'Error marking all notifications as read')\n }\n })\n })\n\n ctx.logger.debug('Notification socket handlers registered')\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport {\n notificationEntity,\n notificationReadEntity,\n sendNotificationAction\n} from './notifications.entity.js'\nimport { createNotificationsRoutes } from './notifications.routes.js'\nimport { initNotificationService, getNotificationService, NotificationService } from './notifications.service.js'\nimport { registerNotificationSocketHandlers } from './notifications.socket.js'\n\nexport {\n NotificationService,\n getNotificationService,\n initNotificationService\n}\n\nexport type {\n NotificationType,\n NotificationPriority,\n NotificationTarget,\n SendNotificationInput\n} from './notifications.entity.js'\n\nexport type {\n Notification,\n NotificationPayload\n} from './notifications.service.js'\n\n/**\n * Módulo de notificaciones en tiempo real\n */\nexport const notificationsModule: ModuleManifest = {\n name: 'notifications',\n label: 'Notifications',\n icon: 'mdi:bell-outline',\n description: 'Real-time notifications via Socket.IO',\n type: 'core',\n category: 'messaging',\n dependencies: ['logger', 'users'],\n\n definitions: [\n notificationEntity,\n notificationReadEntity,\n sendNotificationAction\n ],\n\n routePrefix: '/notifications',\n routes: createNotificationsRoutes,\n\n init: (ctx) => {\n const service = initNotificationService(ctx)\n ctx.services['notifications'] = service\n\n // Registrar handlers Socket.IO (después de que el servidor inicie)\n // Se ejecuta de forma diferida porque Socket.IO puede no estar listo\n setTimeout(() => {\n registerNotificationSocketHandlers(ctx)\n }, 0)\n\n ctx.logger.debug('Notifications module initialized')\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport type {\n Schedule,\n ServiceActionConfig,\n HttpInternalConfig,\n HttpExternalConfig,\n FunctionRegistryConfig,\n RegisteredFunction,\n ExecutionResult\n} from './schedules.types.js'\n\n/**\n * Registry de funciones para function_registry target\n */\nconst functionRegistry = new Map<string, RegisteredFunction>()\n\n/**\n * Registra una función para usar con function_registry\n */\nexport function registerFunction(key: string, fn: RegisteredFunction): void {\n functionRegistry.set(key, fn)\n}\n\n/**\n * Desregistra una función\n */\nexport function unregisterFunction(key: string): void {\n functionRegistry.delete(key)\n}\n\n/**\n * Obtiene una función registrada\n */\nexport function getRegisteredFunction(key: string): RegisteredFunction | undefined {\n return functionRegistry.get(key)\n}\n\n/**\n * Lista todas las funciones registradas\n */\nexport function listRegisteredFunctions(): string[] {\n return Array.from(functionRegistry.keys())\n}\n\n/**\n * Ejecuta un service_action target\n */\nasync function executeServiceAction(\n ctx: ModuleContext,\n config: ServiceActionConfig\n): Promise<unknown> {\n const { service, action, input, recordId } = config\n\n // Obtener el servicio del registro\n const targetService = ctx.services[service]\n if (!targetService) {\n throw new Error(`Service '${service}' not found in ctx.services`)\n }\n\n // Verificar que el servicio tiene executeAction\n if (typeof (targetService as { executeAction?: unknown }).executeAction !== 'function') {\n throw new Error(`Service '${service}' does not support executeAction()`)\n }\n\n // Ejecutar la action\n const result = await (targetService as {\n executeAction: (action: string, input?: Record<string, unknown>, recordId?: string) => Promise<unknown>\n }).executeAction(action, input ?? {}, recordId)\n\n return result\n}\n\n/**\n * Ejecuta un http_internal target (endpoint del propio backend)\n */\nasync function executeHttpInternal(\n _ctx: ModuleContext,\n config: HttpInternalConfig\n): Promise<unknown> {\n const { method, path, body, headers } = config\n\n // Usar fetch contra el propio servidor\n const port = process.env['PORT'] ?? 3000\n const baseUrl = `http://127.0.0.1:${port}`\n const url = `${baseUrl}${path}`\n\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...headers\n },\n body: body ? JSON.stringify(body) : undefined\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`HTTP ${response.status}: ${errorText}`)\n }\n\n // Intentar parsear como JSON, si falla devolver texto\n const contentType = response.headers.get('content-type')\n if (contentType?.includes('application/json')) {\n return response.json()\n }\n\n return response.text()\n}\n\n/**\n * Ejecuta un http_external target (webhook externo)\n */\nasync function executeHttpExternal(config: HttpExternalConfig): Promise<unknown> {\n const { method, url, body, headers, timeout = 30000 } = config\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...headers\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`HTTP ${response.status}: ${errorText}`)\n }\n\n const contentType = response.headers.get('content-type')\n if (contentType?.includes('application/json')) {\n return response.json()\n }\n\n return response.text()\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Ejecuta un function_registry target\n */\nasync function executeFunctionRegistry(config: FunctionRegistryConfig): Promise<unknown> {\n const { functionKey, args } = config\n\n const fn = functionRegistry.get(functionKey)\n if (!fn) {\n throw new Error(`Function '${functionKey}' not found in registry. Available: ${listRegisteredFunctions().join(', ') || 'none'}`)\n }\n\n return fn(args)\n}\n\n/**\n * Ejecuta el target de un schedule\n */\nexport async function executeTarget(\n ctx: ModuleContext,\n schedule: Schedule\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n\n try {\n let data: unknown\n\n switch (schedule.target_type) {\n case 'service_action':\n data = await executeServiceAction(ctx, schedule.target_config as ServiceActionConfig)\n break\n\n case 'http_internal':\n data = await executeHttpInternal(ctx, schedule.target_config as HttpInternalConfig)\n break\n\n case 'http_external':\n data = await executeHttpExternal(schedule.target_config as HttpExternalConfig)\n break\n\n case 'function_registry':\n data = await executeFunctionRegistry(schedule.target_config as FunctionRegistryConfig)\n break\n\n default:\n throw new Error(`Unknown target_type: ${schedule.target_type}`)\n }\n\n return {\n success: true,\n data,\n duration_ms: Date.now() - startTime\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n duration_ms: Date.now() - startTime\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport cron from 'node-cron'\nimport type { ScheduledTask } from 'node-cron'\nimport { CronExpressionParser } from 'cron-parser'\nimport type {\n Schedule,\n ScheduleJob,\n ScheduleStatus,\n CreateScheduleInput,\n UpdateScheduleInput,\n RegisteredFunction,\n ExecutionResult,\n NextRunInfo\n} from './schedules.types.js'\nimport {\n executeTarget,\n registerFunction as registerFn,\n unregisterFunction as unregisterFn,\n listRegisteredFunctions\n} from './schedules.executor.js'\n\nlet schedulesService: SchedulesService | null = null\n\n/**\n * Servicio de schedules con node-cron\n */\nexport class SchedulesService {\n private ctx: ModuleContext\n private jobs: Map<string, ScheduleJob> = new Map()\n private initialized = false\n private generateId: () => string\n\n constructor(ctx: ModuleContext) {\n this.ctx = ctx\n this.generateId = ctx.helpers.generateId\n }\n\n /**\n * Inicializa el servicio cargando schedules activos de BD\n */\n async init(): Promise<void> {\n if (this.initialized) return\n\n this.ctx.logger.debug('Initializing schedules service...')\n\n // Cargar schedules activos de la BD\n const schedules = await this.ctx.db<Schedule>('schedules')\n .where('enabled', true)\n .whereNot('status', 'paused')\n .select('*')\n\n for (const schedule of schedules) {\n this.scheduleJob(schedule)\n }\n\n this.initialized = true\n this.ctx.logger.info(`Schedules service initialized with ${schedules.length} active jobs`)\n }\n\n /**\n * Detiene todos los jobs\n */\n shutdown(): void {\n this.ctx.logger.debug('Shutting down schedules service...')\n\n for (const [id, job] of this.jobs) {\n job.task.stop()\n this.ctx.logger.debug(`Stopped job: ${id}`)\n }\n\n this.jobs.clear()\n this.initialized = false\n this.ctx.logger.info('Schedules service shut down')\n }\n\n /**\n * Crea un nuevo schedule\n */\n async create(data: CreateScheduleInput, userId?: string): Promise<Schedule> {\n // Validar expresión cron\n if (!cron.validate(data.cron_expression)) {\n throw new this.ctx.errors.ValidationError(`Invalid cron expression: ${data.cron_expression}`)\n }\n\n // Validar timezone\n if (data.timezone && data.timezone !== 'UTC') {\n try {\n Intl.DateTimeFormat(undefined, { timeZone: data.timezone })\n } catch {\n throw new this.ctx.errors.ValidationError(`Invalid timezone: ${data.timezone}`)\n }\n }\n\n const now = new Date().toISOString()\n const schedule: Schedule = {\n id: this.generateId(),\n name: data.name,\n description: data.description ?? null,\n cron_expression: data.cron_expression,\n timezone: data.timezone ?? 'UTC',\n target_type: data.target_type,\n target_config: data.target_config,\n enabled: data.enabled ?? true,\n status: 'idle',\n last_run_at: null,\n last_error: null,\n run_count: 0,\n created_at: now,\n updated_at: now,\n created_by: userId ?? null,\n updated_by: userId ?? null\n }\n\n // Insertar en BD\n await this.ctx.db('schedules').insert({\n ...schedule,\n target_config: JSON.stringify(schedule.target_config)\n })\n\n // Programar job si está habilitado\n if (schedule.enabled) {\n this.scheduleJob(schedule)\n }\n\n this.ctx.logger.info(`Schedule created: ${schedule.name} (${schedule.id})`)\n return schedule\n }\n\n /**\n * Actualiza un schedule existente\n */\n async update(id: string, data: UpdateScheduleInput, userId?: string): Promise<Schedule> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n // Validar expresión cron si se actualiza\n if (data.cron_expression && !cron.validate(data.cron_expression)) {\n throw new this.ctx.errors.ValidationError(`Invalid cron expression: ${data.cron_expression}`)\n }\n\n // Validar timezone si se actualiza\n if (data.timezone && data.timezone !== 'UTC') {\n try {\n Intl.DateTimeFormat(undefined, { timeZone: data.timezone })\n } catch {\n throw new this.ctx.errors.ValidationError(`Invalid timezone: ${data.timezone}`)\n }\n }\n\n const updated: Partial<Schedule> = {\n ...data,\n updated_at: new Date().toISOString(),\n updated_by: userId ?? null\n }\n\n // Actualizar en BD\n await this.ctx.db('schedules')\n .where('id', id)\n .update({\n ...updated,\n target_config: data.target_config ? JSON.stringify(data.target_config) : undefined\n })\n\n // Obtener schedule actualizado\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found after update: ${id}`)\n }\n\n // Reprogramar job\n this.cancelJob(id)\n if (schedule.enabled && schedule.status !== 'paused') {\n this.scheduleJob(schedule)\n }\n\n this.ctx.logger.info(`Schedule updated: ${schedule.name} (${id})`)\n return schedule\n }\n\n /**\n * Elimina un schedule\n */\n async delete(id: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n // Cancelar job\n this.cancelJob(id)\n\n // Eliminar de BD\n await this.ctx.db('schedules').where('id', id).delete()\n\n this.ctx.logger.info(`Schedule deleted: ${existing.name} (${id})`)\n }\n\n /**\n * Busca un schedule por ID\n */\n async findById(id: string): Promise<Schedule | null> {\n const row = await this.ctx.db<Schedule>('schedules')\n .where('id', id)\n .first()\n\n if (!row) return null\n\n return {\n ...row,\n target_config: typeof row.target_config === 'string'\n ? JSON.parse(row.target_config)\n : row.target_config\n }\n }\n\n /**\n * Lista todos los schedules\n */\n async findAll(): Promise<Schedule[]> {\n const rows = await this.ctx.db<Schedule>('schedules')\n .orderBy('created_at', 'desc')\n .select('*')\n\n return rows.map(row => ({\n ...row,\n target_config: typeof row.target_config === 'string'\n ? JSON.parse(row.target_config)\n : row.target_config\n }))\n }\n\n /**\n * Pausa un schedule\n */\n async pause(id: string): Promise<void> {\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n // Cancelar job\n this.cancelJob(id)\n\n // Actualizar status en BD\n await this.ctx.db('schedules')\n .where('id', id)\n .update({ status: 'paused', updated_at: new Date().toISOString() })\n\n this.ctx.logger.info(`Schedule paused: ${schedule.name} (${id})`)\n }\n\n /**\n * Reanuda un schedule pausado\n */\n async resume(id: string): Promise<void> {\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n if (!schedule.enabled) {\n throw new this.ctx.errors.ValidationError(`Cannot resume disabled schedule: ${id}`)\n }\n\n // Actualizar status en BD\n await this.ctx.db('schedules')\n .where('id', id)\n .update({ status: 'idle', updated_at: new Date().toISOString() })\n\n // Reprogramar job\n const updated = await this.findById(id)\n if (updated) {\n this.scheduleJob(updated)\n }\n\n this.ctx.logger.info(`Schedule resumed: ${schedule.name} (${id})`)\n }\n\n /**\n * Ejecuta un schedule inmediatamente (trigger manual)\n */\n async trigger(id: string): Promise<ExecutionResult> {\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n this.ctx.logger.info(`Manual trigger: ${schedule.name} (${id})`)\n return this.executeSchedule(schedule)\n }\n\n /**\n * Obtiene las próximas ejecuciones\n */\n async getNextRuns(limit = 10): Promise<NextRunInfo[]> {\n const schedules = await this.ctx.db<Schedule>('schedules')\n .where('enabled', true)\n .whereNot('status', 'paused')\n .select('id', 'name', 'cron_expression', 'timezone')\n .limit(limit)\n\n const result: NextRunInfo[] = []\n\n for (const schedule of schedules) {\n const nextDate = this.getNextRunDate(schedule.cron_expression, schedule.timezone)\n if (nextDate) {\n result.push({\n id: schedule.id,\n name: schedule.name,\n cron_expression: schedule.cron_expression,\n next_run: nextDate.toISOString()\n })\n }\n }\n\n // Ordenar por próxima ejecución\n return result.sort((a, b) => new Date(a.next_run).getTime() - new Date(b.next_run).getTime())\n }\n\n /**\n * Sincroniza un job con la BD (para usar con eventos de CRUD auto-montado)\n */\n async syncJob(id: string): Promise<void> {\n const schedule = await this.findById(id)\n if (!schedule) {\n // Schedule fue eliminado, cancelar job si existe\n this.cancelJob(id)\n return\n }\n\n // Cancelar job existente\n this.cancelJob(id)\n\n // Reprogramar si está habilitado y no pausado\n if (schedule.enabled && schedule.status !== 'paused') {\n this.scheduleJob(schedule)\n }\n }\n\n /**\n * Cancela un job por ID (público para uso desde eventos)\n */\n cancelJobById(id: string): void {\n this.cancelJob(id)\n }\n\n /**\n * Registra una función para function_registry\n */\n registerFunction(key: string, fn: RegisteredFunction): void {\n registerFn(key, fn)\n this.ctx.logger.debug(`Function registered: ${key}`)\n }\n\n /**\n * Desregistra una función\n */\n unregisterFunction(key: string): void {\n unregisterFn(key)\n this.ctx.logger.debug(`Function unregistered: ${key}`)\n }\n\n /**\n * Lista funciones registradas\n */\n getRegisteredFunctions(): string[] {\n return listRegisteredFunctions()\n }\n\n // --- Private methods ---\n\n /**\n * Programa un job con node-cron\n */\n private scheduleJob(schedule: Schedule): void {\n if (this.jobs.has(schedule.id)) {\n this.ctx.logger.warn(`Job already scheduled: ${schedule.id}`)\n return\n }\n\n const task: ScheduledTask = cron.schedule(\n schedule.cron_expression,\n async () => {\n await this.executeSchedule(schedule)\n },\n {\n timezone: schedule.timezone\n }\n )\n\n this.jobs.set(schedule.id, { id: schedule.id, task, schedule })\n this.ctx.logger.debug(`Job scheduled: ${schedule.name} (${schedule.cron_expression})`)\n }\n\n /**\n * Cancela un job\n */\n private cancelJob(id: string): void {\n const job = this.jobs.get(id)\n if (job) {\n job.task.stop()\n this.jobs.delete(id)\n this.ctx.logger.debug(`Job cancelled: ${id}`)\n }\n }\n\n /**\n * Ejecuta un schedule\n */\n private async executeSchedule(schedule: Schedule): Promise<ExecutionResult> {\n // Verificar si ya está corriendo (skip concurrencia)\n const current = await this.findById(schedule.id)\n if (current?.status === 'running') {\n this.ctx.logger.warn(`Skipping execution, already running: ${schedule.name}`)\n await this.logExecution(schedule.id, {\n success: false,\n error: 'Skipped: previous execution still running',\n duration_ms: 0\n }, 'skipped')\n return { success: false, error: 'Skipped: already running', duration_ms: 0 }\n }\n\n // Marcar como running\n await this.ctx.db('schedules')\n .where('id', schedule.id)\n .update({ status: 'running' })\n\n // Ejecutar\n const result = await executeTarget(this.ctx, schedule)\n\n // Actualizar estado\n const newStatus: ScheduleStatus = result.success ? 'idle' : 'error'\n await this.ctx.db('schedules')\n .where('id', schedule.id)\n .update({\n status: newStatus,\n last_run_at: new Date().toISOString(),\n last_error: result.error ?? null,\n run_count: this.ctx.db.raw('run_count + 1')\n })\n\n // Log de ejecución\n await this.logExecution(schedule.id, result, result.success ? 'success' : 'error')\n\n if (result.success) {\n this.ctx.logger.info(`Schedule executed: ${schedule.name} (${result.duration_ms}ms)`)\n } else {\n this.ctx.logger.error(`Schedule failed: ${schedule.name} - ${result.error}`)\n }\n\n return result\n }\n\n /**\n * Registra log de ejecución\n */\n private async logExecution(\n scheduleId: string,\n result: ExecutionResult,\n status: 'success' | 'error' | 'skipped'\n ): Promise<void> {\n const now = new Date()\n const startedAt = new Date(now.getTime() - result.duration_ms)\n\n await this.ctx.db('schedule_logs').insert({\n id: this.generateId(),\n schedule_id: scheduleId,\n started_at: startedAt.toISOString(),\n finished_at: now.toISOString(),\n duration_ms: result.duration_ms,\n status,\n result: result.data ? JSON.stringify(result.data) : null,\n error: result.error ?? null,\n created_at: now.toISOString()\n })\n }\n\n /**\n * Calcula la próxima fecha de ejecución usando cron-parser\n */\n private getNextRunDate(cronExpression: string, timezone: string): Date | null {\n try {\n const interval = CronExpressionParser.parse(cronExpression, {\n tz: timezone\n })\n return interval.next().toDate()\n } catch {\n return null\n }\n }\n}\n\n/**\n * Inicializa el servicio de schedules\n */\nexport function initSchedulesService(ctx: ModuleContext): SchedulesService {\n schedulesService = new SchedulesService(ctx)\n return schedulesService\n}\n\n/**\n * Obtiene el servicio de schedules\n */\nexport function getSchedulesService(): SchedulesService {\n if (!schedulesService) {\n throw new Error('Schedules service not initialized. Call initSchedulesService() first.')\n }\n return schedulesService\n}\n","import type {\n CollectionEntityDefinition,\n EventEntityDefinition,\n ModuleContext\n} from '@gzl10/nexus-sdk'\nimport type { Request, Response } from 'express'\nimport { z } from 'zod'\nimport type { Schedule } from './schedules.types.js'\nimport { getSchedulesService } from './schedules.service.js'\n\n/**\n * Schema de validación para target_config según tipo\n */\nconst serviceActionConfigSchema = z.object({\n service: z.string().min(1),\n action: z.string().min(1),\n input: z.record(z.unknown()).optional(),\n recordId: z.string().optional()\n})\n\nconst httpInternalConfigSchema = z.object({\n method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']),\n path: z.string().startsWith('/'),\n body: z.record(z.unknown()).optional(),\n headers: z.record(z.string()).optional()\n})\n\nconst httpExternalConfigSchema = z.object({\n method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']),\n url: z.string().url(),\n body: z.record(z.unknown()).optional(),\n headers: z.record(z.string()).optional(),\n timeout: z.number().positive().optional()\n})\n\nconst functionRegistryConfigSchema = z.object({\n functionKey: z.string().min(1),\n args: z.record(z.unknown()).optional()\n})\n\n/**\n * Schema base para crear/actualizar schedule\n */\nexport const scheduleInputSchema = z.object({\n name: z.string().min(1).max(100),\n description: z.string().max(500).optional(),\n cron_expression: z.string().min(1).max(50),\n timezone: z.string().max(50).default('UTC'),\n target_type: z.enum(['service_action', 'http_internal', 'http_external', 'function_registry']),\n target_config: z.union([\n serviceActionConfigSchema,\n httpInternalConfigSchema,\n httpExternalConfigSchema,\n functionRegistryConfigSchema\n ]),\n enabled: z.boolean().default(true)\n})\n\nexport type ScheduleInput = z.infer<typeof scheduleInputSchema>\n\n/**\n * Schedule Entity (collection)\n */\nexport const scheduleEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'schedules',\n label: 'Schedules',\n labelField: 'name',\n timestamps: true,\n audit: true,\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n name: {\n name: 'name',\n label: 'Name',\n input: 'text',\n validation: { required: true },\n db: { type: 'string', size: 100, nullable: false }\n },\n description: {\n name: 'description',\n label: 'Description',\n input: 'textarea',\n db: { type: 'text', nullable: true }\n },\n cron_expression: {\n name: 'cron_expression',\n label: 'Cron Expression',\n input: 'text',\n validation: { required: true },\n db: { type: 'string', size: 50, nullable: false }\n },\n timezone: {\n name: 'timezone',\n label: 'Timezone',\n input: 'select',\n db: { type: 'string', size: 50, nullable: false, default: 'UTC' },\n options: {\n static: [\n { value: 'UTC', label: 'UTC' },\n { value: 'Europe/Madrid', label: 'Europe/Madrid (CET/CEST)' },\n { value: 'Europe/London', label: 'Europe/London (GMT/BST)' },\n { value: 'Europe/Paris', label: 'Europe/Paris (CET/CEST)' },\n { value: 'Europe/Berlin', label: 'Europe/Berlin (CET/CEST)' },\n { value: 'America/New_York', label: 'America/New_York (EST/EDT)' },\n { value: 'America/Chicago', label: 'America/Chicago (CST/CDT)' },\n { value: 'America/Denver', label: 'America/Denver (MST/MDT)' },\n { value: 'America/Los_Angeles', label: 'America/Los_Angeles (PST/PDT)' },\n { value: 'America/Sao_Paulo', label: 'America/Sao_Paulo (BRT)' },\n { value: 'Asia/Tokyo', label: 'Asia/Tokyo (JST)' },\n { value: 'Asia/Shanghai', label: 'Asia/Shanghai (CST)' },\n { value: 'Asia/Singapore', label: 'Asia/Singapore (SGT)' },\n { value: 'Australia/Sydney', label: 'Australia/Sydney (AEST/AEDT)' }\n ],\n allowCreate: true\n }\n },\n target_type: {\n name: 'target_type',\n label: 'Target Type',\n input: 'select',\n validation: { required: true },\n db: { type: 'string', size: 20, nullable: false },\n options: {\n static: [\n { value: 'webhook', label: 'Webhook (HTTP)' },\n { value: 'event', label: 'Event (internal)' }\n ]\n }\n },\n target_config: {\n name: 'target_config',\n label: 'Target Configuration',\n input: 'json',\n validation: { required: true },\n db: { type: 'json', nullable: false }\n },\n enabled: {\n name: 'enabled',\n label: 'Enabled',\n input: 'switch',\n db: { type: 'boolean', nullable: false, default: true }\n },\n status: {\n name: 'status',\n label: 'Status',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false, default: 'idle' },\n options: {\n static: [\n { value: 'idle', label: 'Idle' },\n { value: 'running', label: 'Running' },\n { value: 'error', label: 'Error' }\n ]\n }\n },\n last_run_at: {\n name: 'last_run_at',\n label: 'Last Run',\n input: 'datetime',\n db: { type: 'datetime', nullable: true }\n },\n last_error: {\n name: 'last_error',\n label: 'Last Error',\n input: 'textarea',\n db: { type: 'text', nullable: true }\n },\n run_count: {\n name: 'run_count',\n label: 'Run Count',\n input: 'number',\n db: { type: 'integer', nullable: false, default: 0 }\n }\n },\n\n actions: [\n {\n key: 'pause',\n label: 'Pause Schedule',\n icon: 'mdi:pause',\n method: 'POST',\n select: ['id', 'name', 'status', 'enabled'],\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { _record } = input as { _record: Schedule }\n const service = getSchedulesService()\n await service.pause(_record.id)\n return { success: true, status: 'paused' }\n },\n casl: { action: 'update' }\n },\n {\n key: 'resume',\n label: 'Resume Schedule',\n icon: 'mdi:play',\n method: 'POST',\n select: ['id', 'name', 'status', 'enabled', 'cron_expression', 'timezone'],\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { _record } = input as { _record: Schedule }\n const service = getSchedulesService()\n await service.resume(_record.id)\n return { success: true, status: 'idle' }\n },\n casl: { action: 'update' }\n },\n {\n key: 'trigger',\n label: 'Run Now',\n icon: 'mdi:play-circle',\n method: 'POST',\n select: ['id', 'name', 'status', 'target_type', 'target_config'],\n handler: async (ctx: ModuleContext, input: unknown, _req?: Request, res?: Response) => {\n const { _record } = input as { _record: Schedule }\n const service = getSchedulesService()\n const result = await service.trigger(_record.id)\n return result\n },\n casl: { action: 'execute' }\n }\n ],\n\n casl: {\n subject: 'Schedule',\n permissions: {\n ADMIN: { actions: ['manage'] }\n }\n }\n}\n\n/**\n * Schedule Log Entity (event - append-only)\n */\nexport const scheduleLogEntity: EventEntityDefinition = {\n type: 'event',\n table: 'schedule_logs',\n label: 'Schedule Logs',\n labelField: 'schedule_id',\n timestamps: true,\n retention: { days: 30 },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n schedule_id: {\n name: 'schedule_id',\n label: 'Schedule ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n started_at: {\n name: 'started_at',\n label: 'Started At',\n input: 'datetime',\n db: { type: 'datetime', nullable: false }\n },\n finished_at: {\n name: 'finished_at',\n label: 'Finished At',\n input: 'datetime',\n db: { type: 'datetime', nullable: true }\n },\n duration_ms: {\n name: 'duration_ms',\n label: 'Duration (ms)',\n input: 'number',\n db: { type: 'integer', nullable: true }\n },\n status: {\n name: 'status',\n label: 'Status',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n options: {\n static: [\n { value: 'pending', label: 'Pending' },\n { value: 'running', label: 'Running' },\n { value: 'success', label: 'Success' },\n { value: 'failed', label: 'Failed' }\n ]\n }\n },\n result: {\n name: 'result',\n label: 'Result',\n input: 'json',\n db: { type: 'json', nullable: true }\n },\n error: {\n name: 'error',\n label: 'Error',\n input: 'textarea',\n db: { type: 'text', nullable: true }\n }\n },\n\n casl: {\n subject: 'ScheduleLog',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n","import type { Request, Response, ModuleContext, Router } from '@gzl10/nexus-sdk'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { getSchedulesService } from './schedules.service.js'\n\n/**\n * Schedules Routes\n *\n * Las Entity Actions (pause, resume, trigger) se montan automáticamente.\n * Aquí solo definimos rutas adicionales.\n */\nexport function createSchedulesRoutes(ctx: ModuleContext): Router {\n const router = ctx.createRouter()\n const { auth } = ctx.middleware\n\n if (!auth) {\n throw new Error('Auth middleware not found. Ensure auth module loads before schedules.')\n }\n\n // Middleware para verificar ADMIN\n const requireAdmin = (req: Request, res: Response, next: () => void) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const ability = (req as AuthRequest).ability\n if (!ability?.can('manage', 'all')) {\n res.status(403).json({ error: 'Forbidden: Admin role required' })\n return\n }\n next()\n }\n\n /**\n * GET /schedules/next-runs\n * Obtiene las próximas ejecuciones programadas\n */\n router.get('/next-runs', auth, requireAdmin, async (req: Request, res: Response) => {\n const limit = Math.min(parseInt(req.query['limit'] as string) || 10, 100)\n\n const service = getSchedulesService()\n const nextRuns = await service.getNextRuns(limit)\n\n res.json({\n items: nextRuns,\n total: nextRuns.length\n })\n })\n\n /**\n * GET /schedules/functions\n * Lista las funciones registradas para function_registry\n */\n router.get('/functions', auth, requireAdmin, async (_req: Request, res: Response) => {\n const service = getSchedulesService()\n const functions = service.getRegisteredFunctions()\n\n res.json({\n items: functions,\n total: functions.length\n })\n })\n\n return router\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { scheduleEntity, scheduleLogEntity } from './schedules.entity.js'\nimport { createSchedulesRoutes } from './schedules.routes.js'\nimport { initSchedulesService, getSchedulesService, SchedulesService } from './schedules.service.js'\nimport { registerFunction, unregisterFunction } from './schedules.executor.js'\n\n// Re-exports\nexport {\n SchedulesService,\n getSchedulesService,\n initSchedulesService,\n registerFunction,\n unregisterFunction\n}\n\nexport type {\n Schedule,\n ScheduleLog,\n ScheduleTargetType,\n ScheduleStatus,\n ScheduleLogStatus,\n CreateScheduleInput,\n UpdateScheduleInput,\n ServiceActionConfig,\n HttpInternalConfig,\n HttpExternalConfig,\n FunctionRegistryConfig,\n TargetConfig,\n RegisteredFunction,\n ExecutionResult,\n NextRunInfo\n} from './schedules.types.js'\n\n/**\n * Módulo de schedules (tareas programadas con cron)\n */\nexport const schedulesModule: ModuleManifest = {\n name: 'schedules',\n label: 'Schedules',\n icon: 'mdi:clock-outline',\n description: 'Scheduled tasks with cron expressions',\n type: 'core',\n category: 'jobs',\n dependencies: ['logger'],\n\n definitions: [\n scheduleEntity,\n scheduleLogEntity\n ],\n\n routePrefix: '/schedules',\n routes: createSchedulesRoutes,\n\n init: async (ctx) => {\n const service = initSchedulesService(ctx)\n ctx.services['schedules'] = service\n\n // Handler para sincronizar jobs cuando el CRUD auto-montado modifica schedules\n const handleScheduleChange = async (...args: unknown[]) => {\n try {\n const payload = args[0] as { data?: unknown; id?: string } | undefined\n if (payload?.id) {\n await service.syncJob(payload.id)\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n ctx.logger.error(`Failed to sync schedule job: ${message}`)\n }\n }\n\n const handleScheduleDelete = (...args: unknown[]) => {\n const payload = args[0] as { id?: string } | undefined\n if (payload?.id) {\n service.cancelJobById(payload.id)\n }\n }\n\n // Escuchar eventos de BD para sincronizar jobs\n ctx.events.on('db.schedules.created', handleScheduleChange)\n ctx.events.on('db.schedules.updated', handleScheduleChange)\n ctx.events.on('db.schedules.deleted', handleScheduleDelete)\n\n // Handler de shutdown\n const shutdownHandler = () => {\n // Remover listeners de eventos\n ctx.events.off('db.schedules.created', handleScheduleChange)\n ctx.events.off('db.schedules.updated', handleScheduleChange)\n ctx.events.off('db.schedules.deleted', handleScheduleDelete)\n // Detener jobs\n service.shutdown()\n }\n\n // Registrar shutdown handlers\n process.on('SIGTERM', shutdownHandler)\n process.on('SIGINT', shutdownHandler)\n\n // Inicializar jobs activos (diferido para que BD esté lista)\n setTimeout(async () => {\n try {\n await service.init()\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n ctx.logger.error(`Failed to initialize schedules: ${message}`)\n }\n }, 100)\n\n ctx.logger.debug('Schedules module initialized')\n }\n}\n\nexport default schedulesModule\n","import { registerModule } from './registry.js'\n\n// Imports de módulos core\nimport { loggerModule } from '../modules/logger/index.js'\nimport { systemModule } from '../modules/system/index.js'\nimport { storageModule } from '../modules/storage/index.js'\nimport { usersModule } from '../modules/users/index.js'\nimport { authModule } from '../modules/auth/index.js'\nimport { uiModule } from '../modules/ui/index.js'\nimport { mailModule } from '../modules/mail/index.js'\nimport { notificationsModule } from '../modules/notifications/index.js'\nimport { schedulesModule } from '../modules/schedules/index.js'\n\n/**\n * Carga los módulos core del backend\n * Esta es la única función que importa módulos directamente\n */\nexport function loadCoreModules(): void {\n // Logger primero - sin dependencias, otros módulos lo necesitan\n registerModule(loggerModule)\n registerModule(systemModule)\n registerModule(storageModule) // Antes de users para FK de avatar\n registerModule(usersModule)\n registerModule(authModule)\n registerModule(uiModule)\n registerModule(mailModule)\n registerModule(notificationsModule)\n registerModule(schedulesModule)\n}\n","import type { ModuleManifest, EntityDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * Obtiene tabla y subject de una definition.\n * Subject solo se retorna si está explícitamente definido en casl.subject.\n */\nfunction getTableAndSubject(def: EntityDefinition): { table?: string; subject?: string } {\n const typesWithTable = ['collection', 'reference', 'event', 'config', 'temp', 'view', undefined]\n const caslSubject = (def as { casl?: { subject?: string } }).casl?.subject\n\n if (!typesWithTable.includes(def.type)) {\n // computed, action, external, virtual no tienen tabla\n return { subject: caslSubject }\n }\n\n const table = (def as { table: string }).table\n return { table, subject: caslSubject }\n}\n\n/**\n * Obtener todos los subjects de un módulo (desde definitions)\n */\nexport function getModuleSubjects(mod: ModuleManifest): string[] {\n const subjects = new Set<string>()\n for (const def of mod.definitions ?? []) {\n const { subject } = getTableAndSubject(def)\n if (subject) subjects.add(subject)\n }\n return [...subjects]\n}\n","// Escritura\nexport { registerModule, registerPlugin } from './registry.js'\n\n// Lectura\nexport {\n getModules,\n getOrderedModules,\n getModule,\n getPlugins,\n getPlugin,\n getRegisteredSubjects,\n isValidSubject\n} from './queries.js'\n\n// Loader\nexport { loadCoreModules } from './loader.js'\n\n// Store reset\nexport { resetStore } from './store.js'\n\n// Utilidades\nexport { getModuleSubjects } from './utils.js'\n\n// Re-export types\nexport type { ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\n","/**\n * Base Entity Service - Abstract class for all entity services\n */\n\nimport type { Knex } from 'knex'\nimport type {\n EntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks,\n EntityAction\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery, EntityService } from '../types.js'\nimport type { LoggerServiceInterface, ModuleServices } from '../../types/services.js'\n\n/**\n * Abstract base class for entity services\n *\n * Provides common functionality:\n * - Access to ModuleContext (db, logger, etc.)\n * - Entity definition\n * - Default pagination\n * - Hook system for lifecycle events (internos + externos via createEntityService)\n */\nexport abstract class BaseEntityService<T = unknown> implements EntityService<T> {\n protected readonly db: Knex\n protected readonly logger: ModuleContext['logger']\n protected readonly generateId: () => string\n protected readonly errors: ModuleContext['errors']\n /** Hooks externos inyectados via createEntityService */\n protected readonly externalHooks?: EntityServiceHooks<T>\n\n constructor(\n protected readonly ctx: ModuleContext,\n public readonly definition: EntityDefinition,\n hooks?: EntityServiceHooks<T>\n ) {\n this.db = ctx.db\n this.logger = ctx.logger\n this.generateId = ctx.helpers.generateId\n this.errors = ctx.errors\n this.externalHooks = hooks\n }\n\n /**\n * Get table name for persistent entities\n */\n protected get table(): string {\n if ('table' in this.definition && this.definition.table) {\n return this.definition.table\n }\n throw new Error(`Entity ${this.definition.label} has no table`)\n }\n\n protected get loggerService(): LoggerServiceInterface | undefined {\n return (this.ctx.services as Partial<ModuleServices>).logger\n }\n\n /**\n * Get all entities with pagination\n */\n abstract findAll(query?: EntityQuery): Promise<PaginatedResult<T>>\n\n /**\n * Get entity by ID\n */\n abstract findById(id: string): Promise<T | null>\n\n // ============================================================================\n // Hooks - Llaman primero a hooks externos, luego internos (subclases)\n // ============================================================================\n\n /**\n * Called before creating an entity\n * Ejecuta hook externo (si existe) y luego permite override en subclases\n * @returns Modified data\n */\n protected async beforeCreate(data: Partial<T>): Promise<Partial<T>> {\n let result = data\n if (this.externalHooks?.beforeCreate) {\n result = await this.externalHooks.beforeCreate(result)\n }\n return this.internalBeforeCreate(result)\n }\n\n /** Override en subclases para lógica personalizada de beforeCreate */\n protected async internalBeforeCreate(data: Partial<T>): Promise<Partial<T>> {\n return data\n }\n\n /**\n * Called after creating an entity\n */\n protected async afterCreate(entity: T): Promise<void> {\n await this.internalAfterCreate(entity)\n if (this.externalHooks?.afterCreate) {\n await this.externalHooks.afterCreate(entity)\n }\n }\n\n /** Override en subclases para lógica personalizada de afterCreate */\n protected async internalAfterCreate(_entity: T): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called before updating an entity\n * @returns Modified data\n */\n protected async beforeUpdate(id: string, data: Partial<T>): Promise<Partial<T>> {\n let result = data\n if (this.externalHooks?.beforeUpdate) {\n result = await this.externalHooks.beforeUpdate(id, result)\n }\n return this.internalBeforeUpdate(id, result)\n }\n\n /** Override en subclases para lógica personalizada de beforeUpdate */\n protected async internalBeforeUpdate(_id: string, data: Partial<T>): Promise<Partial<T>> {\n return data\n }\n\n /**\n * Called after updating an entity\n */\n protected async afterUpdate(entity: T): Promise<void> {\n await this.internalAfterUpdate(entity)\n if (this.externalHooks?.afterUpdate) {\n await this.externalHooks.afterUpdate(entity)\n }\n }\n\n /** Override en subclases para lógica personalizada de afterUpdate */\n protected async internalAfterUpdate(_entity: T): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called before deleting an entity\n */\n protected async beforeDelete(id: string): Promise<void> {\n if (this.externalHooks?.beforeDelete) {\n await this.externalHooks.beforeDelete(id)\n }\n await this.internalBeforeDelete(id)\n }\n\n /** Override en subclases para lógica personalizada de beforeDelete */\n protected async internalBeforeDelete(_id: string): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called after deleting an entity\n */\n protected async afterDelete(id: string): Promise<void> {\n await this.internalAfterDelete(id)\n if (this.externalHooks?.afterDelete) {\n await this.externalHooks.afterDelete(id)\n }\n }\n\n /** Override en subclases para lógica personalizada de afterDelete */\n protected async internalAfterDelete(_id: string): Promise<void> {\n // Override in subclasses\n }\n\n // ============================================================================\n // Helpers\n // ============================================================================\n\n /**\n * Build paginated result from items and count\n */\n protected buildPaginatedResult(\n items: T[],\n total: number,\n page: number,\n limit: number\n ): PaginatedResult<T> {\n const totalPages = Math.ceil(total / limit)\n return {\n items,\n total,\n page,\n limit,\n totalPages,\n hasNext: page < totalPages\n }\n }\n\n /**\n * Get pagination params with defaults\n */\n protected getPagination(query?: EntityQuery): { page: number; limit: number; offset: number } {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n return { page, limit, offset }\n }\n\n /**\n * Apply sorting to query builder\n */\n protected applySorting(qb: Knex.QueryBuilder, query?: EntityQuery): Knex.QueryBuilder {\n if (query?.sort) {\n const order = query.order ?? 'asc'\n qb.orderBy(query.sort, order)\n } else if ('labelField' in this.definition && this.definition.labelField) {\n // Default sort by label field\n qb.orderBy(this.definition.labelField as string, 'asc')\n }\n return qb\n }\n\n /**\n * Apply search filter to query builder\n * Override in subclasses for entity-specific search\n */\n protected applySearch(qb: Knex.QueryBuilder, search: string): Knex.QueryBuilder {\n if ('labelField' in this.definition && this.definition.labelField) {\n const labelField = this.definition.labelField as string\n qb.where(labelField, 'like', `%${search}%`)\n }\n return qb\n }\n\n /**\n * Apply filters to query builder\n * Override in subclasses for entity-specific filters\n */\n protected applyFilters(qb: Knex.QueryBuilder, filters: Record<string, unknown>): Knex.QueryBuilder {\n for (const [key, value] of Object.entries(filters)) {\n if (value !== undefined && value !== null && value !== '') {\n qb.where(key, value)\n }\n }\n return qb\n }\n\n // ============================================================================\n // CASL Helpers\n // ============================================================================\n\n /**\n * Get sensitive fields from CASL config\n */\n protected get sensitiveFields(): string[] {\n return this.definition.casl?.sensitiveFields ?? []\n }\n\n /**\n * Exclude sensitive fields from entity data\n * Uses definition.casl.sensitiveFields if configured\n *\n * @example\n * // In entity definition:\n * casl: { sensitiveFields: ['password', 'secret'] }\n *\n * // In service:\n * return this.excludeSensitiveFields(user)\n */\n protected excludeSensitiveFields<D extends Record<string, unknown>>(data: D): Partial<D> {\n if (this.sensitiveFields.length === 0) return data\n\n const result = { ...data }\n for (const field of this.sensitiveFields) {\n delete result[field]\n }\n return result\n }\n\n /**\n * Exclude sensitive fields from array of entities\n */\n protected excludeSensitiveFieldsFromArray<D extends Record<string, unknown>>(items: D[]): Partial<D>[] {\n if (this.sensitiveFields.length === 0) return items\n return items.map(item => this.excludeSensitiveFields(item))\n }\n\n // ============================================================================\n // Action Execution\n // ============================================================================\n\n /**\n * Execute an action defined in this entity programmatically\n *\n * Allows invoking EntityActions from other services without HTTP context.\n * NOTE: Does NOT verify CASL permissions - caller is responsible for authorization.\n *\n * @param actionKey - Key of the action to execute\n * @param input - Input for the handler (without _record if recordId is provided)\n * @param recordId - ID of the record (optional, loads automatically)\n * @param options - Additional options\n * @returns Result from the action handler\n *\n * @example\n * // From another service\n * const storageService = ctx.services['storage_files'] as CollectionService\n * const result = await storageService.executeAction('thumbnail', { width: 200 }, fileId)\n */\n async executeAction(\n actionKey: string,\n input: Record<string, unknown> = {},\n recordId?: string,\n options?: { userId?: string; skipValidation?: boolean }\n ): Promise<unknown> {\n // 1. Find action in definition.actions\n const actions = (this.definition as { actions?: EntityAction[] }).actions\n if (!actions?.length) {\n throw new this.errors.NotFoundError('Entity has no actions')\n }\n\n const action = actions.find(a => a.key === actionKey)\n if (!action) {\n throw new this.errors.NotFoundError(`Action \"${actionKey}\" not found`)\n }\n\n // 2. Load record if recordId provided\n let record: Record<string, unknown> | undefined = input['_record'] as Record<string, unknown>\n if (recordId && !record) {\n let query = this.db(this.table).where('id', recordId)\n if (action.select?.length) {\n query = query.select(action.select)\n }\n record = await query.first()\n if (!record) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n }\n\n // 3. Validate input if schema exists and not skipped\n let validatedInput = input\n if (action.inputSchema && !options?.skipValidation) {\n validatedInput = action.inputSchema.parse(input) as Record<string, unknown>\n }\n\n // 4. Extend input with _record and _authUserId\n const extendedInput: Record<string, unknown> = { ...validatedInput }\n if (record) {\n extendedInput['_record'] = record\n }\n if (options?.userId) {\n extendedInput['_authUserId'] = options.userId\n }\n\n // 5. Execute handler (without req/res)\n return action.handler(this.ctx, extendedInput)\n }\n}\n","/**\n * Collection Service - Full CRUD for collection entities\n *\n * Supports:\n * - Full CRUD operations (create, read, update, delete)\n * - Soft delete (optional)\n * - Timestamps (created_at, updated_at)\n * - Audit fields (created_by, updated_by)\n * - Pagination, sorting, search, filters\n */\n\nimport type {\n CollectionEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class CollectionService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: CollectionEntityDefinition\n\n constructor(ctx: ModuleContext, definition: CollectionEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all entities with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n // Build base query\n let qb = this.db(this.table)\n\n // Apply soft delete filter\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting and pagination\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get entity by ID\n */\n async findById(id: string): Promise<T | null> {\n let qb = this.db(this.table).where('id', id)\n\n // Apply soft delete filter\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n const entity = await qb.first<T>()\n return entity ?? null\n }\n\n /**\n * Create new entity\n */\n async create(data: Partial<T>): Promise<T> {\n // Generate ID if not provided\n const dataRecord = data as Record<string, unknown>\n const entityData: Record<string, unknown> = {\n ...data,\n id: dataRecord['id'] ?? this.generateId()\n }\n\n // Add timestamps\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n }\n\n // Run beforeCreate hook\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n\n // Insert\n await this.db(this.table).insert(processedData)\n\n // Fetch created entity\n const entity = await this.findById((processedData as Record<string, unknown>)['id'] as string)\n if (!entity) {\n throw new this.errors.AppError(`${this.definition.label} no encontrado tras crear`, 404)\n }\n\n // Run afterCreate hook\n await this.afterCreate(entity)\n\n return entity\n }\n\n /**\n * Update entity\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n // Check entity exists\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(this.definition.label)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n\n // Update timestamp\n if (this.definition.timestamps) {\n updateData['updated_at'] = nowTimestamp(this.db)\n }\n\n // Run beforeUpdate hook\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n\n // Update\n await this.db(this.table).where('id', id).update(processedData)\n\n // Fetch updated entity\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.AppError(`${this.definition.label} no encontrado tras actualizar`, 404)\n }\n\n // Run afterUpdate hook\n await this.afterUpdate(entity)\n\n return entity\n }\n\n /**\n * Delete entity (soft delete if enabled)\n */\n async delete(id: string): Promise<void> {\n // Check entity exists\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(this.definition.label)\n }\n\n // Run beforeDelete hook\n await this.beforeDelete(id)\n\n if (this.definition.softDelete) {\n // Soft delete\n await this.db(this.table).where('id', id).update({\n deleted_at: nowTimestamp(this.db)\n })\n } else {\n // Hard delete\n await this.db(this.table).where('id', id).delete()\n }\n\n // Run afterDelete hook\n await this.afterDelete(id)\n }\n\n /**\n * Restore soft-deleted entity\n */\n async restore(id: string): Promise<T> {\n if (!this.definition.softDelete) {\n throw new this.errors.AppError('Soft delete not enabled for this entity', 400)\n }\n\n // Find including deleted\n const entity = await this.db(this.table).where('id', id).first<T>()\n if (!entity) {\n throw new this.errors.NotFoundError(this.definition.label)\n }\n\n // Restore\n await this.db(this.table).where('id', id).update({\n deleted_at: null,\n updated_at: nowTimestamp(this.db)\n })\n\n const restored = await this.findById(id)\n if (!restored) {\n throw new this.errors.AppError(`${this.definition.label} no encontrado tras restaurar`, 404)\n }\n\n return restored\n }\n\n /**\n * Find multiple entities by IDs\n */\n async findByIds(ids: string[]): Promise<T[]> {\n if (ids.length === 0) return []\n\n let qb = this.db(this.table).whereIn('id', ids)\n\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n return qb as Promise<T[]>\n }\n\n /**\n * Count entities matching filters\n */\n async count(filters?: Record<string, unknown>): Promise<number> {\n let qb = this.db(this.table)\n\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n if (filters) {\n qb = this.applyFilters(qb, filters)\n }\n\n const result = await qb.count('* as count').first<{ count: string | number }>()\n return Number(result?.count ?? 0)\n }\n\n /**\n * Check if entity exists\n */\n async exists(id: string): Promise<boolean> {\n const entity = await this.findById(id)\n return entity !== null\n }\n}\n","/**\n * Single Service - Singleton entities stored in single_records\n *\n * Supports:\n * - Read single config\n * - Update config\n * - Defaults on first read\n *\n * Uses single_records table with key-value storage:\n * { key: 'site_config', value: { siteName: '...', logo: '...' } }\n */\n\nimport type {\n SingleEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nconst SINGLE_RECORDS_TABLE = 'single_records'\n\nexport class SingleService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: SingleEntityDefinition\n\n constructor(ctx: ModuleContext, definition: SingleEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get table - overridden since single entities use sys_settings\n */\n protected override get table(): string {\n return SINGLE_RECORDS_TABLE\n }\n\n /**\n * Get the setting key\n */\n private get key(): string {\n return this.definition.key\n }\n\n /**\n * Get all - returns single item in paginated format\n */\n async findAll(_query?: EntityQuery): Promise<PaginatedResult<T>> {\n const value = await this.findById(this.key)\n\n return {\n items: value ? [value] : [],\n total: value ? 1 : 0,\n page: 1,\n limit: 1,\n totalPages: value ? 1 : 0,\n hasNext: false\n }\n }\n\n /**\n * Get the singleton value\n * @param _id - Ignored, uses definition.key\n */\n async findById(_id: string): Promise<T | null> {\n const row = await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .first<{ key: string; value: string }>()\n\n if (!row) {\n // Return defaults if available\n if (this.definition.defaults) {\n return this.definition.defaults as T\n }\n return null\n }\n\n try {\n const value = JSON.parse(row.value)\n // Merge with defaults\n if (this.definition.defaults) {\n return { ...this.definition.defaults, ...value } as T\n }\n return value as T\n } catch {\n this.logger.warn({ key: this.key }, 'Failed to parse setting value')\n return this.definition.defaults as T ?? null\n }\n }\n\n /**\n * Get the setting - alias for findById\n */\n async get(): Promise<T | null> {\n return this.findById(this.key)\n }\n\n /**\n * Update the singleton value\n */\n async update(_id: string, data: Partial<T>): Promise<T> {\n // Get current value\n const current = await this.get() ?? {}\n\n // Merge with new data\n const newValue = { ...current, ...data }\n\n // Run beforeUpdate hook\n const processedData = await this.beforeUpdate(this.key, newValue as Partial<T>)\n\n // Check if exists\n const exists = await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .first()\n\n const now = nowTimestamp(this.db)\n\n if (exists) {\n // Update\n await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .update({\n value: JSON.stringify(processedData),\n updated_at: now\n })\n } else {\n // Insert\n await this.db(SINGLE_RECORDS_TABLE).insert({\n id: this.generateId(),\n key: this.key,\n value: JSON.stringify(processedData),\n created_at: now,\n updated_at: now\n })\n }\n\n const result = await this.get()\n if (!result) {\n throw new this.errors.AppError('Failed to save setting', 500)\n }\n\n // Run afterUpdate hook\n await this.afterUpdate(result)\n\n return result\n }\n\n /**\n * Set the setting - alias for update\n */\n async set(data: Partial<T>): Promise<T> {\n return this.update(this.key, data)\n }\n\n /**\n * Reset to defaults\n */\n async reset(): Promise<T | null> {\n if (!this.definition.defaults) {\n // Delete if no defaults\n await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .delete()\n return null\n }\n\n // Set to defaults\n return this.update(this.key, this.definition.defaults as Partial<T>)\n }\n}\n","/**\n * Reference Service - Read-only catalog entities with optional admin CRUD\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - Seed initial data\n * - Optional admin CRUD (allowAdminEdit)\n */\n\nimport type {\n ReferenceEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class ReferenceService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ReferenceEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ReferenceEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all reference items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting and pagination\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get reference item by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table).where('id', id).first<T>()\n return entity ?? null\n }\n\n /**\n * Create reference item (only if allowAdminEdit)\n */\n async create(data: Partial<T>): Promise<T> {\n if (!this.definition.allowAdminEdit) {\n throw new this.errors.ForbiddenError('Reference entities are read-only')\n }\n\n const entityData = {\n ...data,\n id: (data as Record<string, unknown>)['id'] ?? this.generateId()\n } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n }\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Entity not found after creation')\n }\n\n await this.afterCreate(entity)\n return entity\n }\n\n /**\n * Update reference item (only if allowAdminEdit)\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n if (!this.definition.allowAdminEdit) {\n throw new this.errors.ForbiddenError('Reference entities are read-only')\n }\n\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n if (this.definition.timestamps) {\n updateData['updated_at'] = nowTimestamp(this.db)\n }\n\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n await this.db(this.table).where('id', id).update(processedData)\n\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found after update`)\n }\n\n await this.afterUpdate(entity)\n return entity\n }\n\n /**\n * Delete reference item (only if allowAdminEdit)\n */\n async delete(id: string): Promise<void> {\n if (!this.definition.allowAdminEdit) {\n throw new this.errors.ForbiddenError('Reference entities are read-only')\n }\n\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n await this.beforeDelete(id)\n await this.db(this.table).where('id', id).delete()\n await this.afterDelete(id)\n }\n\n /**\n * Seed initial data from definition\n */\n async seed(): Promise<number> {\n if (!this.definition.seed || this.definition.seed.length === 0) {\n return 0\n }\n\n let seeded = 0\n\n for (const item of this.definition.seed) {\n const id = item['id'] as string | undefined\n if (!id) continue\n\n const exists = await this.findById(id)\n if (!exists) {\n const data = {\n ...item,\n id\n } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n data['created_at'] = now\n data['updated_at'] = now\n }\n\n await this.db(this.table).insert(data)\n seeded++\n }\n }\n\n this.logger.info({ table: this.table, seeded }, 'Reference data seeded')\n return seeded\n }\n}\n","/**\n * Event Service - Append-only entities for audit logs\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - Append (create) only - no update/delete\n * - Retention policy (cleanup old events)\n */\n\nimport type {\n EventEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class EventService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: EventEntityDefinition\n\n constructor(ctx: ModuleContext, definition: EventEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all events with pagination (newest first by default)\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Events default to newest first\n if (!query?.sort) {\n qb = qb.orderBy('created_at', 'desc')\n } else {\n qb = this.applySorting(qb, query)\n }\n\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get event by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table).where('id', id).first<T>()\n return entity ?? null\n }\n\n /**\n * Append new event (create)\n */\n async create(data: Partial<T>): Promise<T> {\n const entityData = {\n ...data,\n id: (data as Record<string, unknown>)['id'] ?? this.generateId()\n } as Record<string, unknown>\n\n // Events always have timestamps\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Event not found after creation')\n }\n\n await this.afterCreate(entity)\n\n // Run retention cleanup asynchronously\n this.runRetentionCleanup().catch(err => {\n const error = err instanceof Error ? err : new Error('Event retention cleanup failed')\n this.logger.error({ err }, 'Retention cleanup failed')\n this.loggerService?.captureException(error, { table: this.table, type: 'event', action: 'retention' })\n })\n\n return entity\n }\n\n /**\n * Append event - alias for create\n */\n async append(data: Partial<T>): Promise<T> {\n return this.create(data)\n }\n\n /**\n * Update is NOT allowed for events\n */\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Events are immutable and cannot be updated')\n }\n\n /**\n * Delete is NOT allowed for events (use retention policy)\n */\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Events cannot be deleted. Use retention policy.')\n }\n\n /**\n * Run retention cleanup based on definition\n */\n async runRetentionCleanup(): Promise<number> {\n const retention = this.definition.retention\n if (!retention) return 0\n\n let deleted = 0\n\n // Delete by age\n if (retention.days) {\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() - retention.days)\n\n const result = await this.db(this.table)\n .where('created_at', '<', cutoff)\n .delete()\n\n deleted += result\n }\n\n // Delete by max rows (keep newest)\n if (retention.maxRows) {\n const countResult = await this.db(this.table)\n .count('* as count')\n .first<{ count: string | number }>()\n\n const total = Number(countResult?.count ?? 0)\n const toDelete = total - retention.maxRows\n\n if (toDelete > 0) {\n // Get IDs of oldest events to delete\n const oldestIds = await this.db(this.table)\n .select('id')\n .orderBy('created_at', 'asc')\n .limit(toDelete)\n\n if (oldestIds.length > 0) {\n const result = await this.db(this.table)\n .whereIn('id', oldestIds.map(r => r.id))\n .delete()\n\n deleted += result\n }\n }\n }\n\n if (deleted > 0) {\n this.logger.info({ table: this.table, deleted }, 'Event retention cleanup completed')\n }\n\n return deleted\n }\n\n /**\n * Get events in date range\n */\n async findByDateRange(startDate: Date, endDate: Date, query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n .where('created_at', '>=', startDate)\n .where('created_at', '<=', endDate)\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting (default newest first)\n if (!query?.sort) {\n qb = qb.orderBy('created_at', 'desc')\n } else {\n qb = this.applySorting(qb, query)\n }\n\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n}\n","/**\n * Config Service - Scoped configuration entities\n *\n * Supports:\n * - Read config by scope (module, tenant, user)\n * - Update config\n * - Defaults on first read\n */\n\nimport type {\n ConfigEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class ConfigService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ConfigEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ConfigEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all configs with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n\n // Apply filters (scope filtering)\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n // Merge with defaults\n const mergedItems = items.map(item => this.mergeWithDefaults(item))\n\n return this.buildPaginatedResult(mergedItems, total, page, limit)\n }\n\n /**\n * Get config by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table).where('id', id).first<T>()\n if (!entity) {\n return null\n }\n return this.mergeWithDefaults(entity)\n }\n\n /**\n * Get config by scope key (e.g., module name, tenant id)\n */\n async findByScope(scopeValue: string): Promise<T | null> {\n const scopeField = this.definition.scopeField ?? 'scope_key'\n\n const entity = await this.db(this.table)\n .where(scopeField, scopeValue)\n .first<T>()\n\n if (!entity) {\n // Return defaults if available\n if (this.definition.defaults) {\n return this.definition.defaults as T\n }\n return null\n }\n\n return this.mergeWithDefaults(entity)\n }\n\n /**\n * Update config\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n const existing = await this.db(this.table).where('id', id).first<T>()\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n updateData['updated_at'] = nowTimestamp(this.db)\n }\n\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n await this.db(this.table).where('id', id).update(processedData)\n\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found after update`)\n }\n\n await this.afterUpdate(entity)\n return entity\n }\n\n /**\n * Update or create config by scope\n */\n async upsertByScope(scopeValue: string, data: Partial<T>): Promise<T> {\n const scopeField = this.definition.scopeField ?? 'scope_key'\n const existing = await this.db(this.table)\n .where(scopeField, scopeValue)\n .first<T>()\n\n if (existing) {\n const id = (existing as Record<string, unknown>)['id'] as string\n return this.update(id, data)\n } else {\n // Create new config\n const entityData = {\n ...this.definition.defaults,\n ...data,\n [scopeField]: scopeValue,\n id: this.generateId()\n } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n }\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Config not found after creation')\n }\n\n await this.afterCreate(entity)\n return entity\n }\n }\n\n /**\n * Reset config to defaults\n */\n async resetToDefaults(id: string): Promise<T | null> {\n if (!this.definition.defaults) {\n await this.db(this.table).where('id', id).delete()\n return null\n }\n\n return this.update(id, this.definition.defaults as Partial<T>)\n }\n\n /**\n * Set a config as the default (only one can be default at a time)\n */\n async setAsDefault(id: string): Promise<void> {\n // Verify record exists\n const existing = await this.db(this.table).where('id', id).first()\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n await this.db.transaction(async (trx) => {\n // 1. Unset all is_default\n await trx(this.table).update({ is_default: false })\n\n // 2. Set the selected one as default\n await trx(this.table).where('id', id).update({ is_default: true })\n })\n }\n\n /**\n * Get the default config record\n * Fallback: first record ordered by created_at if no is_default: true\n */\n async getDefault(): Promise<T | null> {\n // 1. Look for the one marked as default\n const defaultRecord = await this.db(this.table)\n .where('is_default', true)\n .first<T>()\n\n if (defaultRecord) {\n return this.mergeWithDefaults(defaultRecord)\n }\n\n // 2. Fallback: first record by created_at\n const firstRecord = await this.db(this.table)\n .orderBy('created_at', 'asc')\n .first<T>()\n\n if (firstRecord) {\n return this.mergeWithDefaults(firstRecord)\n }\n\n // 3. No records: return defaults if available\n if (this.definition.defaults) {\n return this.definition.defaults as T\n }\n\n return null\n }\n\n /**\n * Merge entity with defaults\n */\n private mergeWithDefaults(entity: T): T {\n if (!this.definition.defaults) {\n return entity\n }\n return { ...this.definition.defaults, ...entity } as T\n }\n}\n","/**\n * Temp Service - Temporary entities with TTL auto-cleanup\n *\n * Supports:\n * - Full CRUD\n * - Automatic TTL field management\n * - Cleanup of expired records\n */\n\nimport type {\n TempEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp, formatTimestamp } from '../../db/helpers.js'\n\nexport class TempService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: TempEntityDefinition\n\n constructor(ctx: ModuleContext, definition: TempEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get the TTL field name\n */\n private get ttlField(): string {\n return this.definition.ttlField ?? 'expires_at'\n }\n\n /**\n * Get all non-expired items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n // Only return non-expired items\n let qb = this.db(this.table)\n .where(this.ttlField, '>', new Date())\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n // Run cleanup asynchronously\n this.cleanup().catch(err => {\n const error = err instanceof Error ? err : new Error('Temp cleanup failed')\n this.logger.error({ err }, 'Temp cleanup failed')\n this.loggerService?.captureException(error, { table: this.table, type: 'temp', action: 'cleanup' })\n })\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get non-expired item by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table)\n .where('id', id)\n .where(this.ttlField, '>', new Date())\n .first<T>()\n\n return entity ?? null\n }\n\n /**\n * Create with auto TTL\n */\n async create(data: Partial<T>): Promise<T> {\n const now = new Date()\n const expiresAt = new Date(now.getTime() + this.definition.ttl * 1000)\n\n const entityData = {\n ...data,\n id: (data as Record<string, unknown>)['id'] ?? this.generateId(),\n [this.ttlField]: formatTimestamp(this.db, expiresAt),\n ['created_at']: nowTimestamp(this.db)\n } as Record<string, unknown>\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Entity not found after creation')\n }\n\n await this.afterCreate(entity)\n return entity\n }\n\n /**\n * Update and optionally extend TTL\n */\n async update(id: string, data: Partial<T>, extendTtl = false): Promise<T> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found or expired`)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n\n if (extendTtl) {\n const expiresAt = new Date(Date.now() + this.definition.ttl * 1000)\n updateData[this.ttlField] = expiresAt\n }\n\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n await this.db(this.table).where('id', id).update(processedData)\n\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found after update`)\n }\n\n await this.afterUpdate(entity)\n return entity\n }\n\n /**\n * Delete item\n */\n async delete(id: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found or expired`)\n }\n\n await this.beforeDelete(id)\n await this.db(this.table).where('id', id).delete()\n await this.afterDelete(id)\n }\n\n /**\n * Extend TTL for an item\n */\n async extendTtl(id: string, additionalSeconds?: number): Promise<T> {\n const ttl = additionalSeconds ?? this.definition.ttl\n const expiresAt = new Date(Date.now() + ttl * 1000)\n\n return this.update(id, { [this.ttlField]: expiresAt } as Partial<T>)\n }\n\n /**\n * Cleanup expired items\n */\n async cleanup(): Promise<number> {\n const result = await this.db(this.table)\n .where(this.ttlField, '<=', new Date())\n .delete()\n\n if (result > 0) {\n this.logger.info({ table: this.table, deleted: result }, 'Temp cleanup completed')\n }\n\n return result\n }\n\n /**\n * Get remaining TTL for an item (in seconds)\n */\n async getRemainingTtl(id: string): Promise<number | null> {\n const entity = await this.db(this.table)\n .select(this.ttlField)\n .where('id', id)\n .first<Record<string, unknown>>()\n\n if (!entity) return null\n\n const expiresAt = entity[this.ttlField] as Date\n const remaining = Math.max(0, (expiresAt.getTime() - Date.now()) / 1000)\n\n return Math.floor(remaining)\n }\n\n /**\n * Check if item exists and is not expired\n */\n async isValid(id: string): Promise<boolean> {\n const entity = await this.findById(id)\n return entity !== null\n }\n}\n","/**\n * View Service - Read-only views with custom queries\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - Custom query builder or SQL VIEW\n */\n\nimport type {\n ViewEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\n\nexport class ViewService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ViewEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ViewEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get the base query builder\n */\n private getBaseQuery() {\n const query = this.definition.query\n\n if (!query) {\n // Use table directly if no custom query\n return this.db(this.table)\n }\n\n if (typeof query === 'string') {\n // Raw SQL query\n return this.db.raw(query)\n }\n\n // Query builder function\n return query(this.db)\n }\n\n /**\n * Get all items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n // For views, we need to handle counting differently\n if (this.definition.query && typeof this.definition.query !== 'string') {\n // Use query builder\n let baseQuery = this.definition.query(this.db)\n\n // Apply search\n if (query?.search && this.definition.labelField) {\n baseQuery = baseQuery.where(this.definition.labelField, 'like', `%${query.search}%`)\n }\n\n // Apply filters\n if (query?.filters) {\n for (const [key, value] of Object.entries(query.filters)) {\n if (value !== undefined && value !== null && value !== '') {\n baseQuery = baseQuery.where(key, value)\n }\n }\n }\n\n // Get count\n const countQuery = this.definition.query(this.db)\n const countResult = await countQuery.count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting\n if (query?.sort) {\n baseQuery = baseQuery.orderBy(query.sort, query.order ?? 'asc')\n } else if (this.definition.labelField) {\n baseQuery = baseQuery.orderBy(this.definition.labelField, 'asc')\n }\n\n // Apply pagination\n baseQuery = baseQuery.limit(limit).offset(offset)\n\n const items = await baseQuery as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n } else {\n // Use table (SQL VIEW or regular table)\n let qb = this.db(this.table)\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n }\n\n /**\n * Get item by ID\n */\n async findById(id: string): Promise<T | null> {\n if (this.definition.query && typeof this.definition.query !== 'string') {\n // Use query builder\n const entity = await this.definition.query(this.db)\n .where('id', id)\n .first<T>()\n\n return entity ?? null\n } else {\n // Use table\n const entity = await this.db(this.table).where('id', id).first<T>()\n return entity ?? null\n }\n }\n\n /**\n * Create SQL VIEW from definition (for migrations)\n */\n async createView(): Promise<void> {\n const query = this.definition.query\n\n if (!query) {\n this.logger.warn({ table: this.table }, 'No query defined for view')\n return\n }\n\n let sql: string\n\n if (typeof query === 'string') {\n sql = query\n } else {\n // Build query and convert to SQL\n const qb = query(this.db)\n sql = qb.toQuery()\n }\n\n // Create or replace view\n await this.db.raw(`CREATE OR REPLACE VIEW ?? AS ${sql}`, [this.table])\n\n this.logger.info({ table: this.table }, 'View created')\n }\n\n /**\n * Drop SQL VIEW\n */\n async dropView(): Promise<void> {\n await this.db.raw('DROP VIEW IF EXISTS ??', [this.table])\n this.logger.info({ table: this.table }, 'View dropped')\n }\n\n /**\n * Views are read-only\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Views are read-only')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Views are read-only')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Views are read-only')\n }\n}\n","/**\n * Runtime types for entity services\n */\n\nimport type { Router, Request, Response, NextFunction, RequestHandler } from 'express'\nimport type {\n EntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityQuery\n} from '@gzl10/nexus-sdk'\n\nexport type { Request, Response, NextFunction, RequestHandler }\n\n// Re-export EntityQuery from SDK for backwards compatibility\nexport type { EntityQuery }\n\n/**\n * Entity service interface - base contract for all entity services\n */\nexport interface EntityService<T = unknown> {\n /** Get all entities with pagination */\n findAll(query?: EntityQuery): Promise<PaginatedResult<T>>\n\n /** Get single entity by ID */\n findById(id: string): Promise<T | null>\n\n /** Create new entity (optional - throws if not supported) */\n create?(data: Partial<T>): Promise<T>\n\n /** Update entity (optional - throws if not supported) */\n update?(id: string, data: Partial<T>): Promise<T>\n\n /** Delete entity (optional - throws if not supported) */\n delete?(id: string): Promise<void>\n\n /** Get entity definition */\n readonly definition: EntityDefinition\n}\n\n/**\n * Entity controller handler type\n */\nexport type EntityHandler = (req: Request, res: Response) => Promise<void>\n\n/**\n * Entity controller interface\n */\nexport interface EntityController {\n /** List entities */\n list: EntityHandler\n\n /** Get single entity */\n get: EntityHandler\n\n /** Create entity (optional) */\n create?: EntityHandler\n\n /** Update entity (optional) */\n update?: EntityHandler\n\n /** Delete entity (optional) */\n delete?: EntityHandler\n\n /** Execute action (for action entities) */\n execute?: EntityHandler\n}\n\n/**\n * Complete runtime for an entity\n */\nexport interface EntityRuntime<T = unknown> {\n service: EntityService<T>\n controller: EntityController\n router: Router\n}\n\n/**\n * External adapter interface for external entities\n */\nexport interface ExternalAdapter<T = unknown> {\n /** Adapter name */\n name: string\n\n /** Fetch all records */\n findAll(config: Record<string, unknown>, query?: EntityQuery): Promise<PaginatedResult<T>>\n\n /** Fetch single record */\n findById(config: Record<string, unknown>, id: string): Promise<T | null>\n\n /** Create record (optional) */\n create?(config: Record<string, unknown>, data: Partial<T>): Promise<T>\n\n /** Update record (optional) */\n update?(config: Record<string, unknown>, id: string, data: Partial<T>): Promise<T>\n\n /** Delete record (optional) */\n delete?(config: Record<string, unknown>, id: string): Promise<void>\n}\n\n/**\n * Registry of external adapters\n */\nexport const adapterRegistry = new Map<string, ExternalAdapter>()\n\n/**\n * Register an external adapter\n */\nexport function registerAdapter(adapter: ExternalAdapter): void {\n adapterRegistry.set(adapter.name, adapter)\n}\n\n/**\n * Get registered adapter\n */\nexport function getAdapter(name: string): ExternalAdapter | undefined {\n return adapterRegistry.get(name)\n}\n\n/**\n * Service creation context\n */\nexport interface ServiceContext {\n ctx: ModuleContext\n definition: EntityDefinition\n}\n","/**\n * LRU Cache - Least Recently Used cache with TTL support\n *\n * Features:\n * - LRU eviction when max entries reached\n * - TTL expiration per entry\n * - Hit/miss statistics\n * - Prefix-based deletion for invalidation\n */\n\ninterface CacheEntry<T> {\n data: T\n expires: number\n}\n\nexport interface LRUCacheOptions {\n /** Maximum number of entries (default: 100) */\n maxEntries?: number\n /** Default TTL in seconds (default: 60) */\n defaultTTL?: number\n}\n\nexport interface CacheStats {\n hits: number\n misses: number\n hitRate: number\n size: number\n maxEntries: number\n}\n\nexport class LRUCache<T = unknown> {\n private cache: Map<string, CacheEntry<T>>\n private readonly maxEntries: number\n private readonly defaultTTL: number\n\n private hits = 0\n private misses = 0\n\n constructor(options?: LRUCacheOptions) {\n this.cache = new Map()\n this.maxEntries = options?.maxEntries ?? 100\n this.defaultTTL = options?.defaultTTL ?? 60\n }\n\n /**\n * Get value from cache\n * Returns null if not found or expired\n * Moves entry to end (most recently used)\n */\n get(key: string): T | null {\n const entry = this.cache.get(key)\n\n if (!entry) {\n this.misses++\n return null\n }\n\n // Check expiration\n if (entry.expires > 0 && entry.expires < Date.now()) {\n this.cache.delete(key)\n this.misses++\n return null\n }\n\n // Move to end (most recently used)\n this.cache.delete(key)\n this.cache.set(key, entry)\n\n this.hits++\n return entry.data\n }\n\n /**\n * Set value in cache\n * Evicts oldest entry if max entries reached\n * @param ttl TTL in seconds (0 = no expiration, undefined = use default)\n */\n set(key: string, data: T, ttl?: number): void {\n // Delete existing to update position\n this.cache.delete(key)\n\n // Evict oldest if at capacity\n if (this.cache.size >= this.maxEntries) {\n const oldestKey = this.cache.keys().next().value\n if (oldestKey) {\n this.cache.delete(oldestKey)\n }\n }\n\n const actualTTL = ttl ?? this.defaultTTL\n const expires = actualTTL > 0 ? Date.now() + actualTTL * 1000 : 0\n\n this.cache.set(key, { data, expires })\n }\n\n /**\n * Delete specific key\n */\n delete(key: string): boolean {\n return this.cache.delete(key)\n }\n\n /**\n * Delete all keys matching prefix\n * @returns Number of deleted entries\n */\n deleteByPrefix(prefix: string): number {\n let deleted = 0\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key)\n deleted++\n }\n }\n return deleted\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.cache.clear()\n }\n\n /**\n * Check if key exists and is not expired\n */\n has(key: string): boolean {\n const entry = this.cache.get(key)\n if (!entry) return false\n if (entry.expires > 0 && entry.expires < Date.now()) {\n this.cache.delete(key)\n return false\n }\n return true\n }\n\n /**\n * Get current size\n */\n get size(): number {\n return this.cache.size\n }\n\n /**\n * Get cache statistics\n */\n getStats(): CacheStats {\n const total = this.hits + this.misses\n return {\n hits: this.hits,\n misses: this.misses,\n hitRate: total > 0 ? this.hits / total : 0,\n size: this.cache.size,\n maxEntries: this.maxEntries\n }\n }\n\n /**\n * Reset statistics\n */\n resetStats(): void {\n this.hits = 0\n this.misses = 0\n }\n\n /**\n * Prune expired entries\n * Call periodically to clean up memory\n */\n prune(): number {\n const now = Date.now()\n let pruned = 0\n\n for (const [key, entry] of this.cache.entries()) {\n if (entry.expires > 0 && entry.expires < now) {\n this.cache.delete(key)\n pruned++\n }\n }\n\n return pruned\n }\n}\n","import pkg from 'eventemitter2'\nconst { EventEmitter2 } = pkg\n\n// Payload genérico para eventos CRUD de DB\nexport interface DbEventPayload {\n table: string\n action: 'created' | 'updated' | 'deleted'\n data: unknown\n timestamp: Date\n}\n\n// Tipos de eventos\nexport interface NexusEvents {\n // Lifecycle\n 'server.starting': { port: number; host: string }\n 'server.started': { port: number; host: string }\n 'server.stopping': undefined\n 'server.stopped': undefined\n 'server.restarting': undefined\n\n // Database connection\n 'db.connected': { type: 'sqlite' | 'postgresql' | 'mysql' }\n 'db.disconnected': undefined\n\n // Database CRUD (automático via interceptor)\n // Uso: nexusEvents.on('db.users.created', ...) o nexusEvents.on('db.*.*', ...)\n [key: `db.${string}.created`]: DbEventPayload\n [key: `db.${string}.updated`]: DbEventPayload\n [key: `db.${string}.deleted`]: DbEventPayload\n\n // Auth (lógica de negocio, manual)\n 'auth.login': { userId: string; email: string }\n 'auth.logout': { userId: string }\n 'auth.refresh': { userId: string }\n 'auth.failed': { email: string; reason: string }\n\n // Socket.IO\n 'socket.initialized': undefined\n 'socket.user.connected': { userId: string; roleId: string; socketId: string }\n 'socket.user.disconnected': { userId: string; socketId: string }\n\n // Notifications\n 'notifications.sent': { id: string; target_type: string; target_value?: string; sent: number }\n}\n\n// Tipo helper para listeners tipados\nexport type NexusEventName = keyof NexusEvents\nexport type NexusEventPayload<T extends NexusEventName> = NexusEvents[T]\n\n// Emitter singleton\nclass TypedEventEmitter extends EventEmitter2 {\n emitEvent<T extends NexusEventName>(\n event: T,\n ...args: NexusEvents[T] extends undefined ? [] : [NexusEvents[T]]\n ): boolean {\n return this.emit(event, ...args)\n }\n\n onEvent<T extends NexusEventName>(\n event: T,\n listener: NexusEvents[T] extends undefined\n ? () => void\n : (payload: NexusEvents[T]) => void\n ): this {\n this.on(event, listener as (...args: unknown[]) => void)\n return this\n }\n\n onceEvent<T extends NexusEventName>(\n event: T,\n listener: NexusEvents[T] extends undefined\n ? () => void\n : (payload: NexusEvents[T]) => void\n ): this {\n this.once(event, listener as (...args: unknown[]) => void)\n return this\n }\n\n offEvent<T extends NexusEventName>(\n event: T,\n listener: NexusEvents[T] extends undefined\n ? () => void\n : (payload: NexusEvents[T]) => void\n ): this {\n this.off(event, listener as (...args: unknown[]) => void)\n return this\n }\n}\n\nexport const nexusEvents = new TypedEventEmitter({\n wildcard: true,\n delimiter: '.',\n maxListeners: 20,\n verboseMemoryLeak: true\n})\n\n// Re-export para uso directo\nexport { TypedEventEmitter }\n","/**\n * Cache Invalidator - Reactive cache invalidation via events\n *\n * Listens to db.* events and invalidates related cache entries\n */\n\nimport { nexusEvents, type DbEventPayload } from '../events/emitter.js'\nimport type { EventEmitter2 } from 'eventemitter2'\nimport type { LRUCache } from './lru-cache.js'\n\nexport interface InvalidationRule {\n /** Events that trigger invalidation (supports wildcards) */\n events: string[]\n /** Cache prefix to invalidate */\n cachePrefix: string\n}\n\ninterface RegisteredCache {\n name: string\n cache: LRUCache\n}\n\nclass CacheInvalidator {\n private rules: InvalidationRule[] = []\n private caches: RegisteredCache[] = []\n private listeners: Array<{ event: string; handler: (payload: DbEventPayload) => void }> = []\n private initialized = false\n\n /**\n * Register a cache instance\n */\n registerCache(name: string, cache: LRUCache): void {\n // Avoid duplicates\n const existing = this.caches.find(c => c.name === name)\n if (existing) {\n existing.cache = cache\n return\n }\n this.caches.push({ name, cache })\n }\n\n /**\n * Add invalidation rule\n */\n addRule(rule: InvalidationRule): void {\n // Avoid duplicate rules\n const exists = this.rules.some(\n r => r.cachePrefix === rule.cachePrefix &&\n JSON.stringify(r.events) === JSON.stringify(rule.events)\n )\n if (exists) return\n\n this.rules.push(rule)\n\n // If already initialized, add listener immediately\n if (this.initialized) {\n this.attachListenersForRule(rule)\n }\n }\n\n /**\n * Initialize event listeners\n */\n init(): void {\n if (this.initialized) return\n\n for (const rule of this.rules) {\n this.attachListenersForRule(rule)\n }\n\n this.initialized = true\n }\n\n /**\n * Attach listeners for a specific rule\n */\n private attachListenersForRule(rule: InvalidationRule): void {\n for (const eventPattern of rule.events) {\n const handler = (_payload: DbEventPayload) => {\n this.invalidate(rule.cachePrefix)\n }\n\n ;(nexusEvents as unknown as EventEmitter2).on(eventPattern, handler)\n this.listeners.push({ event: eventPattern, handler })\n }\n }\n\n /**\n * Invalidate cache entries by prefix\n */\n private invalidate(prefix: string): void {\n for (const { cache } of this.caches) {\n cache.deleteByPrefix(prefix)\n }\n }\n\n /**\n * Manually invalidate a prefix\n */\n invalidatePrefix(prefix: string): void {\n this.invalidate(prefix)\n }\n\n /**\n * Get all registered rules\n */\n getRules(): InvalidationRule[] {\n return [...this.rules]\n }\n\n /**\n * Get all registered caches\n */\n getCaches(): string[] {\n return this.caches.map(c => c.name)\n }\n\n /**\n * Clear all rules and listeners\n */\n destroy(): void {\n // Remove all listeners\n for (const { event, handler } of this.listeners) {\n ;(nexusEvents as unknown as EventEmitter2).off(event, handler)\n }\n\n this.listeners = []\n this.rules = []\n this.caches = []\n this.initialized = false\n }\n\n /**\n * Reset for testing\n */\n reset(): void {\n this.destroy()\n }\n}\n\n// Singleton instance\nexport const cacheInvalidator = new CacheInvalidator()\n","export { LRUCache, type LRUCacheOptions, type CacheStats } from './lru-cache.js'\nexport { cacheInvalidator, type InvalidationRule } from './cache-invalidator.js'\n","/**\n * External Service - Data from external APIs via adapters\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - LRU caching with TTL\n * - Reactive invalidation via events\n * - CRUD via adapter (if supported)\n */\n\nimport type {\n ExternalEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery, ExternalAdapter } from '../types.js'\nimport { getAdapter } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { LRUCache, cacheInvalidator } from '../../core/cache/index.js'\n\n// LRU cache for external results (shared across all external entities)\nconst externalCache = new LRUCache<unknown>({\n maxEntries: 100,\n defaultTTL: 60\n})\n\n// Register cache with invalidator\ncacheInvalidator.registerCache('external', externalCache)\n\nexport class ExternalService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ExternalEntityDefinition\n private adapter: ExternalAdapter<T> | undefined\n\n constructor(ctx: ModuleContext, definition: ExternalEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n this.adapter = getAdapter(definition.adapter) as ExternalAdapter<T> | undefined\n\n // Register invalidation rules if defined\n if (definition.cache?.invalidateOn?.length) {\n cacheInvalidator.addRule({\n events: definition.cache.invalidateOn,\n cachePrefix: `external:${definition.adapter}`\n })\n }\n }\n\n /**\n * Get table - external entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('External entities do not have a local table')\n }\n\n /**\n * Get the adapter config\n */\n private get adapterConfig(): Record<string, unknown> {\n return this.definition.source ?? {}\n }\n\n /**\n * Get cache key for a request\n */\n private getCacheKey(operation: string, id?: string): string {\n const keyField = this.definition.cache?.key ?? 'id'\n const base = `external:${this.definition.adapter}:${operation}`\n return id ? `${base}:${keyField}:${id}` : base\n }\n\n /**\n * Ensure adapter is available\n */\n private ensureAdapter(): ExternalAdapter<T> {\n if (!this.adapter) {\n throw new this.errors.AppError(\n `Adapter '${this.definition.adapter}' not registered. Register it with registerAdapter().`,\n 500\n )\n }\n return this.adapter\n }\n\n /**\n * Get all items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const adapter = this.ensureAdapter()\n\n // Check cache\n const cacheKey = this.getCacheKey('findAll')\n const cached = externalCache.get(cacheKey) as PaginatedResult<T> | null\n if (cached) {\n return cached\n }\n\n const result = await adapter.findAll(this.adapterConfig, query)\n\n // Cache result with entity-specific TTL\n const ttl = this.definition.cache?.ttl\n if (ttl && ttl > 0) {\n externalCache.set(cacheKey, result, ttl)\n }\n\n return result\n }\n\n /**\n * Get item by ID\n */\n async findById(id: string): Promise<T | null> {\n const adapter = this.ensureAdapter()\n\n // Check cache\n const cacheKey = this.getCacheKey('findById', id)\n const cached = externalCache.get(cacheKey) as T | null\n if (cached) {\n return cached\n }\n\n const result = await adapter.findById(this.adapterConfig, id)\n\n // Cache result with entity-specific TTL\n if (result) {\n const ttl = this.definition.cache?.ttl\n if (ttl && ttl > 0) {\n externalCache.set(cacheKey, result, ttl)\n }\n }\n\n return result\n }\n\n /**\n * Create via adapter (if supported)\n */\n async create(data: Partial<T>): Promise<T> {\n const adapter = this.ensureAdapter()\n\n if (!adapter.create) {\n throw new this.errors.ForbiddenError(\n `Adapter '${this.definition.adapter}' does not support create`\n )\n }\n\n const processedData = await this.beforeCreate(data)\n const result = await adapter.create(this.adapterConfig, processedData)\n await this.afterCreate(result)\n\n // Invalidate list cache\n externalCache.delete(this.getCacheKey('findAll'))\n\n return result\n }\n\n /**\n * Update via adapter (if supported)\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n const adapter = this.ensureAdapter()\n\n if (!adapter.update) {\n throw new this.errors.ForbiddenError(\n `Adapter '${this.definition.adapter}' does not support update`\n )\n }\n\n const processedData = await this.beforeUpdate(id, data)\n const result = await adapter.update(this.adapterConfig, id, processedData)\n await this.afterUpdate(result)\n\n // Invalidate caches\n externalCache.delete(this.getCacheKey('findAll'))\n externalCache.delete(this.getCacheKey('findById', id))\n\n return result\n }\n\n /**\n * Delete via adapter (if supported)\n */\n async delete(id: string): Promise<void> {\n const adapter = this.ensureAdapter()\n\n if (!adapter.delete) {\n throw new this.errors.ForbiddenError(\n `Adapter '${this.definition.adapter}' does not support delete`\n )\n }\n\n await this.beforeDelete(id)\n await adapter.delete(this.adapterConfig, id)\n await this.afterDelete(id)\n\n // Invalidate caches\n externalCache.delete(this.getCacheKey('findAll'))\n externalCache.delete(this.getCacheKey('findById', id))\n }\n\n /**\n * Clear all cache for this entity\n */\n clearCache(): void {\n const prefix = `external:${this.definition.adapter}:`\n externalCache.deleteByPrefix(prefix)\n }\n\n /**\n * Refresh data from external source (bypass cache)\n */\n async refresh(query?: EntityQuery): Promise<PaginatedResult<T>> {\n this.clearCache()\n return this.findAll(query)\n }\n\n /**\n * Get cache statistics\n */\n static getCacheStats() {\n return externalCache.getStats()\n }\n}\n","/**\n * Virtual Service - Orchestration of multiple data sources\n *\n * Supports:\n * - Read all (combines multiple sources)\n * - Read by ID\n * - Custom resolver function\n */\n\nimport type {\n VirtualEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery, EntityService } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\n\nexport class VirtualService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: VirtualEntityDefinition\n\n constructor(ctx: ModuleContext, definition: VirtualEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get table - virtual entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('Virtual entities do not have a local table')\n }\n\n /**\n * Get source services from context\n */\n private getSourceServices(): Record<string, EntityService> {\n const sources: Record<string, EntityService> = {}\n\n for (const sourceName of this.definition.sources) {\n const service = this.ctx.services[sourceName] as EntityService | undefined\n if (service) {\n sources[sourceName] = service\n } else {\n this.logger.warn({ source: sourceName }, 'Source service not found')\n }\n }\n\n return sources\n }\n\n /**\n * Fetch data from all sources\n */\n private async fetchSourceData(query?: EntityQuery): Promise<Record<string, unknown[]>> {\n const services = this.getSourceServices()\n const data: Record<string, unknown[]> = {}\n\n await Promise.all(\n Object.entries(services).map(async ([name, service]) => {\n try {\n const result = await service.findAll(query)\n data[name] = result.items\n } catch (err) {\n this.logger.error({ source: name, err }, 'Failed to fetch source data')\n data[name] = []\n }\n })\n )\n\n return data\n }\n\n /**\n * Get all items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit } = this.getPagination(query)\n\n // Fetch data from all sources\n const sourceData = await this.fetchSourceData(query)\n\n // Apply resolver if defined\n let items: unknown[]\n if (this.definition.resolver) {\n const resolved = this.definition.resolver(sourceData, this.ctx)\n items = resolved instanceof Promise ? await resolved : resolved\n } else {\n // Default: merge all sources\n items = Object.values(sourceData).flat()\n }\n\n // Apply search filter\n if (query?.search && this.definition.labelField) {\n const labelField = this.definition.labelField\n const searchLower = query.search.toLowerCase()\n items = items.filter(item => {\n const value = (item as Record<string, unknown>)[labelField]\n return value && String(value).toLowerCase().includes(searchLower)\n })\n }\n\n // Apply sorting\n if (query?.sort) {\n const sortField = query.sort\n const order = query.order ?? 'asc'\n items = items.sort((a, b) => {\n const aVal = (a as Record<string, unknown>)[sortField]\n const bVal = (b as Record<string, unknown>)[sortField]\n if (String(aVal) < String(bVal)) return order === 'asc' ? -1 : 1\n if (String(aVal) > String(bVal)) return order === 'asc' ? 1 : -1\n return 0\n })\n }\n\n // Apply pagination\n const total = items.length\n const offset = (page - 1) * limit\n const paginatedItems = items.slice(offset, offset + limit) as T[]\n\n return this.buildPaginatedResult(paginatedItems, total, page, limit)\n }\n\n /**\n * Get item by ID (search in all sources)\n */\n async findById(id: string): Promise<T | null> {\n const services = this.getSourceServices()\n\n // Search in all sources\n for (const service of Object.values(services)) {\n try {\n const item = await service.findById(id)\n if (item) {\n return item as T\n }\n } catch {\n // Continue to next source\n }\n }\n\n return null\n }\n\n /**\n * Virtual entities are read-only\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Virtual entities are read-only')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Virtual entities are read-only')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Virtual entities are read-only')\n }\n}\n","/**\n * Computed Service - On-demand calculations with optional caching\n *\n * Supports:\n * - Read all (computed on-demand)\n * - Read by ID\n * - LRU caching with TTL\n * - Reactive invalidation via events\n */\n\nimport type {\n ComputedEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { LRUCache, cacheInvalidator } from '../../core/cache/index.js'\n\n// LRU cache for computed results (shared across all computed entities)\nconst computeCache = new LRUCache<unknown[]>({\n maxEntries: 200,\n defaultTTL: 60\n})\n\n// Register cache with invalidator\ncacheInvalidator.registerCache('computed', computeCache)\n\nexport class ComputedService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ComputedEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ComputedEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n\n // Register invalidation rules if defined\n if (definition.cache?.invalidateOn?.length) {\n cacheInvalidator.addRule({\n events: definition.cache.invalidateOn,\n cachePrefix: `computed:${definition.label}`\n })\n }\n }\n\n /**\n * Get table - computed entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('Computed entities do not have a local table')\n }\n\n /**\n * Get cache key\n */\n private getCacheKey(params?: Record<string, unknown>): string {\n const base = `computed:${this.definition.label}`\n if (!params || Object.keys(params).length === 0) {\n return base\n }\n return `${base}:${JSON.stringify(params)}`\n }\n\n /**\n * Execute compute function\n */\n private async compute(params?: Record<string, unknown>): Promise<unknown[]> {\n if (!this.definition.compute) {\n throw new this.errors.AppError(\n `No compute function defined for ${this.definition.label}`,\n 500\n )\n }\n\n // Check cache\n const cacheKey = this.getCacheKey(params)\n const cached = computeCache.get(cacheKey)\n if (cached) {\n return cached\n }\n\n // Execute compute\n const result = await this.definition.compute(this.ctx, params)\n\n // Cache result with entity-specific TTL\n const ttl = this.definition.cache?.ttl\n if (ttl && ttl > 0) {\n computeCache.set(cacheKey, result, ttl)\n }\n\n return result\n }\n\n /**\n * Get all computed items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit } = this.getPagination(query)\n\n // Compute data\n let items = await this.compute(query?.filters)\n\n // Apply search filter\n if (query?.search && this.definition.labelField) {\n const labelField = this.definition.labelField\n const searchLower = query.search.toLowerCase()\n items = items.filter(item => {\n const value = (item as Record<string, unknown>)[labelField]\n return value && String(value).toLowerCase().includes(searchLower)\n })\n }\n\n // Apply sorting\n if (query?.sort) {\n const sortField = query.sort\n const order = query.order ?? 'asc'\n items = items.sort((a, b) => {\n const aVal = (a as Record<string, unknown>)[sortField]\n const bVal = (b as Record<string, unknown>)[sortField]\n if (String(aVal) < String(bVal)) return order === 'asc' ? -1 : 1\n if (String(aVal) > String(bVal)) return order === 'asc' ? 1 : -1\n return 0\n })\n }\n\n // Apply pagination\n const total = items.length\n const offset = (page - 1) * limit\n const paginatedItems = items.slice(offset, offset + limit) as T[]\n\n return this.buildPaginatedResult(paginatedItems, total, page, limit)\n }\n\n /**\n * Get computed item by ID\n */\n async findById(id: string): Promise<T | null> {\n const items = await this.compute()\n const item = items.find(i => (i as Record<string, unknown>)['id'] === id)\n return (item as T) ?? null\n }\n\n /**\n * Recompute with specific params\n */\n async recompute(params?: Record<string, unknown>): Promise<T[]> {\n // Clear cache for this computation\n const cacheKey = this.getCacheKey(params)\n computeCache.delete(cacheKey)\n\n return this.compute(params) as Promise<T[]>\n }\n\n /**\n * Clear all cache for this entity\n */\n clearCache(): void {\n const prefix = `computed:${this.definition.label}`\n computeCache.deleteByPrefix(prefix)\n }\n\n /**\n * Get cache statistics\n */\n static getCacheStats() {\n return computeCache.getStats()\n }\n\n /**\n * Computed entities are read-only\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Computed entities are read-only')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Computed entities are read-only')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Computed entities are read-only')\n }\n}\n","/**\n * Action Service - Execute operations/workflows\n *\n * Supports:\n * - Execute action handler\n * - Input validation\n * - Output schema (documentation)\n */\n\nimport type {\n ActionEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks,\n Request,\n Response\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\n\nexport class ActionService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ActionEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ActionEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get table - action entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('Action entities do not have a local table')\n }\n\n /**\n * Actions don't support findAll\n */\n async findAll(_query?: EntityQuery): Promise<PaginatedResult<T>> {\n return {\n items: [],\n total: 0,\n page: 1,\n limit: 0,\n totalPages: 0,\n hasNext: false\n }\n }\n\n /**\n * Actions don't support findById\n */\n async findById(_id: string): Promise<T | null> {\n return null\n }\n\n /**\n * Execute the action\n * @param input - Body data\n * @param req - Express request (optional, for accessing files, params, etc.)\n * @param res - Express response (optional, for streaming, custom headers, etc.)\n * @returns Result to be sent as JSON, or undefined if handler controlled response\n */\n async execute(input: unknown, req?: Request, res?: Response): Promise<unknown> {\n // Validate input if schema defined\n if (this.definition.inputSchema) {\n try {\n input = this.definition.inputSchema.parse(input)\n } catch (err) {\n throw new this.errors.AppError(\n `Invalid input for action ${this.definition.label}: ${err}`,\n 400\n )\n }\n }\n\n // Check handler exists\n if (!this.definition.handler) {\n throw new this.errors.AppError(\n `No handler defined for action ${this.definition.label}`,\n 500\n )\n }\n\n // Extend input with _authUserId\n let extendedInput = (input ?? {}) as Record<string, unknown>\n\n // Inject authUserId if user is authenticated\n const authReq = req as { user?: { id?: string } }\n if (authReq?.user?.id) {\n extendedInput = { ...extendedInput, _authUserId: authReq.user.id }\n }\n\n // Execute handler with extended input\n const result = await this.definition.handler(this.ctx, extendedInput, req, res)\n\n // Validate output if schema defined (for documentation/debugging)\n if (this.definition.outputSchema && result !== undefined) {\n try {\n this.definition.outputSchema.parse(result)\n } catch (err) {\n this.logger.warn(\n { action: this.definition.label, err },\n 'Action output does not match schema'\n )\n }\n }\n\n return result\n }\n\n /**\n * Get action metadata\n */\n getMetadata(): {\n label: string\n hasInputSchema: boolean\n hasOutputSchema: boolean\n fields: string[]\n } {\n return {\n label: this.definition.label,\n hasInputSchema: !!this.definition.inputSchema,\n hasOutputSchema: !!this.definition.outputSchema,\n fields: Object.keys(this.definition.fields)\n }\n }\n\n /**\n * Actions don't support CRUD\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Use execute() for actions')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Use execute() for actions')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Use execute() for actions')\n }\n}\n","/**\n * Schema Builder - Genera schemas Zod desde FieldDefinition en runtime\n *\n * Convierte FieldValidationConfig a validaciones Zod automáticamente\n */\n\nimport { z, type ZodSchema, type ZodObject, type ZodRawShape } from 'zod'\nimport type { FieldDefinition, EntityDefinition, InputType, DbType } from '@gzl10/nexus-sdk'\n\n/**\n * Infer db type from input type for fields without db config\n */\nfunction inferTypeFromInput(input: InputType): DbType {\n switch (input) {\n case 'number':\n case 'decimal':\n return 'decimal'\n case 'checkbox':\n case 'switch':\n return 'boolean'\n case 'date':\n return 'date'\n case 'datetime':\n return 'datetime'\n case 'json':\n return 'json'\n case 'textarea':\n case 'markdown':\n return 'text'\n default:\n return 'string'\n }\n}\n\n/**\n * Build Zod schema for a single field based on its definition\n */\nfunction buildFieldSchema(field: FieldDefinition): ZodSchema {\n const { db, validation } = field\n let schema: ZodSchema\n\n // For fields without db config (actions), infer type from input or use string\n const dbType = db?.type ?? inferTypeFromInput(field.input)\n\n // Determine base type from db.type\n switch (dbType) {\n case 'string':\n case 'text':\n schema = z.string()\n\n // Apply string validations\n if (validation?.min !== undefined) {\n schema = (schema as z.ZodString).min(validation.min)\n }\n if (validation?.max !== undefined) {\n schema = (schema as z.ZodString).max(validation.max)\n }\n if (db?.size && !validation?.max) {\n // Use db.size as max length if no explicit max\n schema = (schema as z.ZodString).max(db.size)\n }\n if (validation?.pattern) {\n schema = (schema as z.ZodString).regex(new RegExp(validation.pattern))\n }\n if (validation?.format) {\n switch (validation.format) {\n case 'email':\n schema = (schema as z.ZodString).email()\n break\n case 'url':\n schema = (schema as z.ZodString).url()\n break\n case 'uuid':\n schema = (schema as z.ZodString).uuid()\n break\n case 'slug':\n schema = (schema as z.ZodString).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)\n break\n }\n }\n if (validation?.enum) {\n schema = z.enum(validation.enum as [string, ...string[]])\n }\n break\n\n case 'integer':\n schema = z.number().int()\n if (validation?.min !== undefined) {\n schema = (schema as z.ZodNumber).min(validation.min)\n }\n if (validation?.max !== undefined) {\n schema = (schema as z.ZodNumber).max(validation.max)\n }\n break\n\n case 'decimal':\n schema = z.number()\n if (validation?.min !== undefined) {\n schema = (schema as z.ZodNumber).min(validation.min)\n }\n if (validation?.max !== undefined) {\n schema = (schema as z.ZodNumber).max(validation.max)\n }\n break\n\n case 'boolean':\n // Coerce numeric/string values to boolean (SQLite stores as 0/1)\n schema = z.preprocess((val) => {\n if (val === 0 || val === '0' || val === 'false') return false\n if (val === 1 || val === '1' || val === 'true') return true\n return val\n }, z.boolean())\n break\n\n case 'date':\n case 'datetime':\n // Accept string (ISO) or Date\n schema = z.union([z.string(), z.date()])\n break\n\n case 'json':\n schema = z.unknown()\n break\n\n case 'uuid':\n schema = z.string().uuid()\n break\n\n default:\n schema = z.unknown()\n }\n\n // Apply nullable if db allows (or no db config = treat as nullable for actions)\n if ((db?.nullable ?? true) && !validation?.required) {\n schema = schema.nullable().optional()\n } else if (!validation?.required) {\n schema = schema.optional()\n }\n\n return schema\n}\n\n/**\n * Fields to exclude from create/update schemas\n */\nconst AUTO_FIELDS = ['id', 'created_at', 'updated_at', 'created_by', 'updated_by']\n\n/**\n * Build Zod schema for entity create operation\n *\n * - Excludes auto-generated fields (id, timestamps, audit) from required validation\n * - Applies required validation\n * - Uses passthrough() to allow custom fields (like custom id)\n */\nexport function buildCreateSchema(definition: EntityDefinition): ZodObject<ZodRawShape> {\n const shape: ZodRawShape = {}\n\n if (!('fields' in definition)) {\n return z.object(shape).passthrough()\n }\n\n for (const [name, field] of Object.entries(definition.fields)) {\n // Skip auto fields - they're optional and handled by service\n if (AUTO_FIELDS.includes(name)) continue\n\n shape[name] = buildFieldSchema(field)\n }\n\n // passthrough allows custom fields like id to be passed to service\n return z.object(shape).passthrough()\n}\n\n/**\n * Build Zod schema for entity update operation\n *\n * - Excludes auto-generated fields\n * - All fields are optional (partial update)\n * - Uses passthrough() to allow custom fields\n */\nexport function buildUpdateSchema(definition: EntityDefinition): ZodObject<ZodRawShape> {\n const shape: ZodRawShape = {}\n\n if (!('fields' in definition)) {\n return z.object(shape).passthrough()\n }\n\n for (const [name, field] of Object.entries(definition.fields)) {\n // Skip auto fields\n if (AUTO_FIELDS.includes(name)) continue\n\n // Make all fields optional for update\n let schema = buildFieldSchema(field)\n if (!schema.isOptional()) {\n schema = schema.optional()\n }\n\n shape[name] = schema\n }\n\n return z.object(shape).passthrough()\n}\n\n/**\n * Cache for compiled schemas (per entity definition)\n */\nconst schemaCache = new WeakMap<EntityDefinition, {\n create: ZodObject<ZodRawShape>\n update: ZodObject<ZodRawShape>\n}>()\n\n/**\n * Get cached schemas for an entity definition\n */\nexport function getSchemas(definition: EntityDefinition): {\n create: ZodObject<ZodRawShape>\n update: ZodObject<ZodRawShape>\n} {\n let cached = schemaCache.get(definition)\n\n if (!cached) {\n cached = {\n create: buildCreateSchema(definition),\n update: buildUpdateSchema(definition)\n }\n schemaCache.set(definition, cached)\n }\n\n return cached\n}\n","export { buildCreateSchema, buildUpdateSchema, getSchemas } from './schema-builder.js'\n","/**\n * Entity Controller - Auto-generated controllers based on entity type\n *\n * Soporte automático:\n * - CASL: Si definition.casl está definido, verifica permisos\n * - Validación: Genera Zod schemas desde definition.fields.validation\n */\n\nimport type { Request, Response } from 'express'\nimport type {\n EntityDefinition,\n ModuleContext,\n AuthRequest,\n EntityAction,\n CollectionEntityDefinition,\n SingleEntityDefinition\n} from '@gzl10/nexus-sdk'\nimport { ZodError } from 'zod'\nimport type { EntityController, EntityService, EntityQuery, EntityHandler } from '../types.js'\nimport { ActionService } from '../services/action.service.js'\nimport { getSchemas } from '../validation/index.js'\n\n/**\n * Capitalize first letter (for inferring CASL subject from table name)\n */\nfunction capitalizeFirst(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\n/**\n * Create controller for an entity service with optional CASL authorization\n */\nexport function createEntityController(\n service: EntityService,\n definition: EntityDefinition,\n ctx: ModuleContext\n): EntityController {\n const type = definition.type ?? 'collection'\n\n // CASL subject (from definition or inferred from table/key name)\n const entityName = 'table' in definition ? definition.table : ('key' in definition ? definition.key : 'entity')\n const caslSubject = definition.casl?.subject ?? capitalizeFirst(entityName ?? 'Entity')\n const hasCasl = !!definition.casl\n\n // Get validation schemas (cached)\n const schemas = getSchemas(definition)\n\n /**\n * Verify CASL permission\n * @throws ForbiddenError if permission denied\n */\n function checkPermission(\n req: Request,\n action: 'read' | 'create' | 'update' | 'delete' | 'manage' | 'execute',\n instance?: unknown\n ): void {\n if (!hasCasl) return // No CASL config = no authorization check\n\n const authReq = req as AuthRequest\n if (!authReq.ability) return // No ability = anonymous access allowed (handled by auth middleware)\n\n const { subject, ForbiddenError: CASLForbiddenError } = ctx.abilities\n\n // If instance provided, check with subject() for conditions support\n const target = instance ? subject(caslSubject, instance as Record<string, unknown>) : caslSubject\n\n try {\n CASLForbiddenError.from(authReq.ability).throwUnlessCan(action, target)\n } catch {\n throw new ctx.errors.ForbiddenError(`No tienes permiso para ${action} ${definition.label}`)\n }\n }\n\n // Base handlers\n const controller: EntityController = {\n /**\n * List entities\n */\n async list(req: Request, res: Response): Promise<void> {\n checkPermission(req, 'read')\n\n // Parse and validate pagination params\n const page = Math.max(1, parseInt(req.query['page'] as string) || 1)\n const limit = Math.min(100, Math.max(1, parseInt(req.query['limit'] as string) || 20))\n\n // Parse filters with error handling\n let filters: Record<string, unknown> | undefined\n if (req.query['filters']) {\n try {\n filters = JSON.parse(req.query['filters'] as string)\n } catch {\n throw new ctx.errors.ValidationError('Invalid filters JSON')\n }\n }\n\n const query: EntityQuery = {\n page,\n limit,\n sort: req.query['sort'] as string | undefined,\n order: (req.query['order'] as 'asc' | 'desc' | undefined) ?? 'asc',\n search: req.query['search'] as string | undefined,\n filters\n }\n\n const result = await service.findAll(query)\n res.json(result)\n },\n\n /**\n * Get single entity\n */\n async get(req: Request, res: Response): Promise<void> {\n const id = req.params['id'] ?? ''\n\n const entity = await service.findById(id)\n\n if (!entity) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n\n // Check permission with instance (for conditions like { id: '${user.id}' })\n checkPermission(req, 'read', entity)\n\n res.json(entity)\n }\n }\n\n // Add create handler if supported\n if (supportsCreate(type)) {\n controller.create = async (req: Request, res: Response): Promise<void> => {\n checkPermission(req, 'create')\n\n if (!service.create) {\n throw new ctx.errors.ForbiddenError(`${definition.label} does not support create`)\n }\n\n // Validate input\n let validated: Record<string, unknown>\n try {\n validated = schemas.create.parse(req.body)\n } catch (error) {\n if (error instanceof ZodError) {\n throw new ctx.errors.ValidationError('Validation failed', error.errors)\n }\n throw error\n }\n\n const entity = await service.create(validated)\n res.status(201).json(entity)\n }\n }\n\n // Add update handler if supported\n if (supportsUpdate(type)) {\n controller.update = async (req: Request, res: Response): Promise<void> => {\n if (!service.update) {\n throw new ctx.errors.ForbiddenError(`${definition.label} does not support update`)\n }\n\n const id = req.params['id'] ?? ''\n\n // First fetch the entity to check permission with instance\n const existing = await service.findById(id)\n if (!existing) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n\n checkPermission(req, 'update', existing)\n\n // Validate input\n let validated: Record<string, unknown>\n try {\n validated = schemas.update.parse(req.body)\n } catch (error) {\n if (error instanceof ZodError) {\n throw new ctx.errors.ValidationError('Validation failed', error.errors)\n }\n throw error\n }\n\n const entity = await service.update(id, validated)\n res.json(entity)\n }\n }\n\n // Add delete handler if supported\n if (supportsDelete(type)) {\n controller.delete = async (req: Request, res: Response): Promise<void> => {\n if (!service.delete) {\n throw new ctx.errors.ForbiddenError(`${definition.label} does not support delete`)\n }\n\n const id = req.params['id'] ?? ''\n\n // First fetch the entity to check permission with instance\n const existing = await service.findById(id)\n if (!existing) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n\n checkPermission(req, 'delete', existing)\n\n await service.delete(id)\n res.status(204).send()\n }\n }\n\n // Add execute handler for actions\n if (type === 'action') {\n controller.execute = async (req: Request, res: Response): Promise<void> => {\n checkPermission(req, 'execute') // Actions require 'execute' permission\n\n const actionService = service as ActionService\n const result = await actionService.execute(req.body, req, res)\n\n // Only send JSON response if handler returned a result\n // (handler may have already sent response for streaming, etc.)\n if (result !== undefined && !res.headersSent) {\n const successStatus = (definition as { successStatus?: number }).successStatus ?? 200\n res.status(successStatus).json(result)\n }\n }\n }\n\n return controller\n}\n\n/**\n * Check if entity type supports create via API\n * Note: 'event' entities are append-only INTERNALLY, not via API\n */\nfunction supportsCreate(type: string): boolean {\n return ['collection', 'temp', 'reference', 'config'].includes(type)\n}\n\n/**\n * Check if entity type supports update\n */\nfunction supportsUpdate(type: string): boolean {\n return ['collection', 'single', 'temp', 'reference', 'config'].includes(type)\n}\n\n/**\n * Check if entity type supports delete\n */\nfunction supportsDelete(type: string): boolean {\n return ['collection', 'temp', 'reference'].includes(type)\n}\n\n/**\n * Create handler for an EntityAction defined in a collection/single entity\n * Injects _record and _authUserId automatically into the input\n */\nexport function createActionHandler(\n action: EntityAction,\n definition: CollectionEntityDefinition | SingleEntityDefinition,\n ctx: ModuleContext\n): EntityHandler {\n // Get table name for querying the record\n const tableName = 'table' in definition ? definition.table : undefined\n\n // CASL subject (from definition or inferred from table/key name)\n const entityName = 'table' in definition ? definition.table : ('key' in definition ? definition.key : 'entity')\n const caslSubject = definition.casl?.subject ?? capitalizeFirst(entityName ?? 'Entity')\n const hasCasl = !!definition.casl || !!action.casl\n\n return async (req: Request, res: Response): Promise<void> => {\n const recordId = req.params['id']\n\n // 1. Load record from database\n let record: Record<string, unknown> | undefined\n if (tableName && recordId) {\n let query = ctx.db(tableName).where('id', recordId)\n if (action.select?.length) {\n query = query.select(action.select)\n }\n record = await query.first()\n\n if (!record) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n }\n\n // 2. Check CASL permission\n if (hasCasl) {\n const authReq = req as AuthRequest\n if (authReq.ability) {\n const { subject, ForbiddenError: CASLForbiddenError } = ctx.abilities\n const caslAction = action.casl?.action ?? 'execute'\n\n // Use record as subject for conditions support\n const target = record ? subject(caslSubject, record) : caslSubject\n\n try {\n CASLForbiddenError.from(authReq.ability).throwUnlessCan(caslAction, target)\n } catch {\n throw new ctx.errors.ForbiddenError(`No tienes permiso para ${action.label}`)\n }\n }\n }\n\n // 3. Validate input\n let input: Record<string, unknown> = req.body ?? {}\n if (action.inputSchema) {\n try {\n input = action.inputSchema.parse(input) as Record<string, unknown>\n } catch (error) {\n if (error instanceof ZodError) {\n throw new ctx.errors.ValidationError('Validation failed', error.errors)\n }\n throw error\n }\n }\n\n // 4. Extend input with _record and _authUserId\n const extendedInput: Record<string, unknown> = { ...input }\n if (record) {\n extendedInput['_record'] = record\n }\n const userReq = req as { user?: { id?: string } }\n if (userReq.user?.id) {\n extendedInput['_authUserId'] = userReq.user.id\n }\n\n // 5. Execute handler\n const result = await action.handler(ctx, extendedInput, req, res)\n\n // 6. Send response if not already sent\n if (result !== undefined && !res.headersSent) {\n res.json(result)\n }\n }\n}\n","/**\n * Entity Routes - Auto-generated routes based on entity type\n *\n * Soporte CASL automático:\n * - Si definition.casl está definido, aplica auth middleware\n * - La verificación de permisos se hace en el controller\n */\n\nimport type { Router, Request, Response, NextFunction, RequestHandler } from 'express'\nimport type {\n EntityDefinition,\n ActionEntityDefinition,\n ModuleContext,\n CollectionEntityDefinition,\n SingleEntityDefinition\n} from '@gzl10/nexus-sdk'\nimport type { EntityController, EntityHandler } from '../types.js'\nimport { createActionHandler } from '../controllers/entity.controller.js'\n\n/**\n * Create router for an entity controller with optional auth middleware\n */\nexport function createEntityRouter(\n controller: EntityController,\n definition: EntityDefinition,\n ctx: ModuleContext\n): Router {\n const router = ctx.createRouter()\n const type = definition.type ?? 'collection'\n\n // Apply auth middleware if CASL is configured\n if (definition.casl && ctx.middleware['auth']) {\n router.use(ctx.middleware['auth'])\n }\n\n // Special handling for standalone actions (type: 'action')\n if (type === 'action' && controller.execute) {\n const actionDef = definition as ActionEntityDefinition\n const method = actionDef.method ?? 'POST'\n const handlers: RequestHandler[] = []\n\n // Apply custom middleware if defined\n if (actionDef.middleware) {\n const middleware = actionDef.middleware(ctx)\n if (Array.isArray(middleware)) {\n handlers.push(...middleware)\n } else {\n handlers.push(middleware)\n }\n }\n\n // Add the execute handler\n handlers.push(asyncHandler(controller.execute))\n\n // Register route at root path\n if (method === 'GET') {\n router.get('/', ...handlers)\n } else {\n router.post('/', ...handlers)\n }\n\n return router\n }\n\n // List - GET / (not for single entities - they only have one record)\n if (type !== 'single') {\n router.get('/', asyncHandler(controller.list))\n }\n\n // Get by ID - GET /:id (or GET / for single entities)\n if (type === 'single') {\n router.get('/', asyncHandler(controller.get))\n } else {\n router.get('/:id', asyncHandler(controller.get))\n }\n\n // Create - POST /\n if (controller.create) {\n router.post('/', asyncHandler(controller.create))\n }\n\n // Update - PUT /:id\n if (controller.update) {\n if (type === 'single') {\n // Single entities update without ID param\n router.put('/', asyncHandler(controller.update))\n } else {\n router.put('/:id', asyncHandler(controller.update))\n }\n }\n\n // Delete - DELETE /:id\n if (controller.delete) {\n router.delete('/:id', asyncHandler(controller.delete))\n }\n\n // Entity actions - /{key}/:id for collection/single entities\n const entityDef = definition as CollectionEntityDefinition | SingleEntityDefinition\n const entityActions = entityDef.actions\n if (entityActions?.length) {\n for (const action of entityActions) {\n const actionPath = `/${action.key}/:id`\n const handlers: RequestHandler[] = []\n\n // Apply custom middleware if defined\n if (action.middleware) {\n const middleware = action.middleware(ctx)\n if (Array.isArray(middleware)) {\n handlers.push(...middleware)\n } else {\n handlers.push(middleware)\n }\n }\n\n // Add the action handler\n const actionHandler = createActionHandler(action, entityDef, ctx)\n handlers.push(asyncHandler(actionHandler))\n\n // Register route with appropriate method\n const method = action.method ?? 'POST'\n if (method === 'GET') {\n router.get(actionPath, ...handlers)\n } else {\n router.post(actionPath, ...handlers)\n }\n }\n }\n\n return router\n}\n\n/**\n * Wrap async handler to catch errors\n * Express 5 handles this natively, but this is for compatibility\n */\nfunction asyncHandler(\n fn: EntityHandler\n): (req: Request, res: Response, next: NextFunction) => void {\n return (req, res, next) => {\n Promise.resolve(fn(req, res)).catch(next)\n }\n}\n","/**\n * Entity Factory - Creates service, controller, and router from EntityDefinition\n */\n\nimport type { Router } from 'express'\nimport type {\n EntityDefinition,\n CollectionEntityDefinition,\n SingleEntityDefinition,\n ReferenceEntityDefinition,\n EventEntityDefinition,\n ConfigEntityDefinition,\n TempEntityDefinition,\n ViewEntityDefinition,\n ExternalEntityDefinition,\n VirtualEntityDefinition,\n ComputedEntityDefinition,\n ActionEntityDefinition,\n ModuleContext\n} from '@gzl10/nexus-sdk'\nimport type { EntityRuntime, EntityService } from './types.js'\n\n// Import all services\nimport { CollectionService } from './services/collection.service.js'\nimport { SingleService } from './services/single.service.js'\nimport { ReferenceService } from './services/reference.service.js'\nimport { EventService } from './services/event.service.js'\nimport { ConfigService } from './services/config.service.js'\nimport { TempService } from './services/temp.service.js'\nimport { ViewService } from './services/view.service.js'\nimport { ExternalService } from './services/external.service.js'\nimport { VirtualService } from './services/virtual.service.js'\nimport { ComputedService } from './services/computed.service.js'\nimport { ActionService } from './services/action.service.js'\n\n// Import controller and route factory\nimport { createEntityController } from './controllers/entity.controller.js'\nimport { createEntityRouter } from './routes/entity.routes.js'\n\n/**\n * Get entity type with default 'collection'\n */\nfunction getEntityType(definition: EntityDefinition): string {\n return definition.type ?? 'collection'\n}\n\n/**\n * Create service based on entity type\n */\nexport function createEntityService<T = unknown>(\n ctx: ModuleContext,\n definition: EntityDefinition\n): EntityService<T> {\n const type = getEntityType(definition)\n\n switch (type) {\n case 'collection':\n return new CollectionService<Record<string, unknown>>(\n ctx,\n definition as CollectionEntityDefinition\n ) as EntityService<T>\n\n case 'single':\n return new SingleService<Record<string, unknown>>(\n ctx,\n definition as SingleEntityDefinition\n ) as EntityService<T>\n\n case 'reference':\n return new ReferenceService<Record<string, unknown>>(\n ctx,\n definition as ReferenceEntityDefinition\n ) as EntityService<T>\n\n case 'event':\n return new EventService<Record<string, unknown>>(\n ctx,\n definition as EventEntityDefinition\n ) as EntityService<T>\n\n case 'config':\n return new ConfigService<Record<string, unknown>>(\n ctx,\n definition as ConfigEntityDefinition\n ) as EntityService<T>\n\n case 'temp':\n return new TempService<Record<string, unknown>>(\n ctx,\n definition as TempEntityDefinition\n ) as EntityService<T>\n\n case 'view':\n return new ViewService<Record<string, unknown>>(\n ctx,\n definition as ViewEntityDefinition\n ) as EntityService<T>\n\n case 'external':\n return new ExternalService<Record<string, unknown>>(\n ctx,\n definition as ExternalEntityDefinition\n ) as EntityService<T>\n\n case 'virtual':\n return new VirtualService<Record<string, unknown>>(\n ctx,\n definition as VirtualEntityDefinition\n ) as EntityService<T>\n\n case 'computed':\n return new ComputedService<Record<string, unknown>>(\n ctx,\n definition as ComputedEntityDefinition\n ) as EntityService<T>\n\n case 'action':\n return new ActionService<Record<string, unknown>>(\n ctx,\n definition as ActionEntityDefinition\n ) as EntityService<T>\n\n default:\n throw new Error(`Unknown entity type: ${type}`)\n }\n}\n\n/**\n * Create complete runtime (service + controller + router) for an entity\n */\nexport function createEntityRuntime<T = unknown>(\n ctx: ModuleContext,\n definition: EntityDefinition\n): EntityRuntime<T> {\n // Create service\n const service = createEntityService<T>(ctx, definition)\n\n // Create controller\n const controller = createEntityController(service, definition, ctx)\n\n // Create router\n const router = createEntityRouter(controller, definition, ctx)\n\n return { service, controller, router }\n}\n\n/**\n * Create services for all definitions in a module\n */\nexport function createModuleServices(\n ctx: ModuleContext,\n definitions: EntityDefinition[]\n): Map<string, EntityService> {\n const services = new Map<string, EntityService>()\n\n for (const definition of definitions) {\n const key = getServiceKey(definition)\n const service = createEntityService(ctx, definition)\n services.set(key, service)\n }\n\n return services\n}\n\n/**\n * Get the key used to store service in ctx.services\n */\nexport function getServiceKey(definition: EntityDefinition): string {\n if ('table' in definition && definition.table) {\n return definition.table\n }\n if ('key' in definition && definition.key) {\n return definition.key\n }\n return definition.label.toLowerCase().replace(/\\s+/g, '_')\n}\n\n/**\n * Create routers for all definitions in a module\n */\nexport function createModuleRouters(\n ctx: ModuleContext,\n definitions: EntityDefinition[]\n): Router {\n const router = ctx.createRouter()\n\n for (const definition of definitions) {\n const runtime = createEntityRuntime(ctx, definition)\n\n // Mount at entity route\n const route = getEntityRoute(definition)\n router.use(route, runtime.router)\n\n // Register service in context (skip if already exists to avoid overwriting custom services)\n const key = getServiceKey(definition)\n if (ctx.services[key]) {\n ctx.logger.warn(\n { key, entity: definition.label },\n 'Service key already registered, skipping auto-registration to avoid overwriting custom service'\n )\n } else {\n ctx.services[key] = runtime.service\n }\n }\n\n return router\n}\n\n/**\n * Get route path for entity\n * Uses routePrefix if defined, otherwise infers from table/key/label\n */\nfunction getEntityRoute(definition: EntityDefinition): string {\n // Use explicit routePrefix if defined\n if (definition.routePrefix !== undefined) {\n return definition.routePrefix.startsWith('/') ? definition.routePrefix : `/${definition.routePrefix}`\n }\n\n // Infer from table name: cms_posts -> /posts\n if ('table' in definition && definition.table) {\n const tableName = definition.table\n const parts = tableName.split('_')\n // Remove prefix if present\n const name = parts.length > 1 ? parts.slice(1).join('_') : tableName\n return `/${name}`\n }\n\n // Infer from key: site_config -> /site_config\n if ('key' in definition && definition.key) {\n return `/${definition.key}`\n }\n\n // Fallback to label: \"My Entity\" -> /my-entity\n return `/${definition.label.toLowerCase().replace(/\\s+/g, '-')}`\n}\n","import type { SchemaObject } from 'openapi3-ts/oas31'\nimport type { CollectionEntityDefinition, FieldDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * Mapea db.type de EntityDefinition a OpenAPI type\n */\nfunction mapDbType(dbType: string): SchemaObject {\n switch (dbType) {\n case 'string':\n case 'text':\n return { type: 'string' }\n case 'integer':\n return { type: 'integer' }\n case 'float':\n case 'decimal':\n return { type: 'number' }\n case 'boolean':\n return { type: 'boolean' }\n case 'json':\n return { type: 'object' }\n case 'date':\n return { type: 'string', format: 'date' }\n case 'datetime':\n case 'timestamp':\n return { type: 'string', format: 'date-time' }\n default:\n return { type: 'string' }\n }\n}\n\n/**\n * Convierte un FieldDefinition a OpenAPI SchemaObject\n */\nfunction fieldToSchema(field: FieldDefinition): SchemaObject {\n // Default to string for fields without db config (actions, virtual, etc.)\n const dbType = field.db?.type ?? 'string'\n const schema: SchemaObject = {\n ...mapDbType(dbType),\n description: field.label\n }\n\n // Constraints desde validación\n if (field.validation) {\n if (field.validation.min !== undefined) {\n if (schema.type === 'string') {\n schema.minLength = field.validation.min\n } else if (schema.type === 'integer' || schema.type === 'number') {\n schema.minimum = field.validation.min\n }\n }\n if (field.validation.max !== undefined) {\n if (schema.type === 'string') {\n schema.maxLength = field.validation.max\n } else if (schema.type === 'integer' || schema.type === 'number') {\n schema.maximum = field.validation.max\n }\n }\n if (field.validation.enum) {\n schema.enum = field.validation.enum\n }\n if (field.validation.format === 'email') {\n schema.format = 'email'\n }\n if (field.validation.pattern) {\n schema.pattern = field.validation.pattern\n }\n }\n\n return schema\n}\n\n/**\n * Genera OpenAPI Schema desde CollectionEntityDefinition\n */\nexport function entityToSchema(entity: CollectionEntityDefinition): SchemaObject {\n const properties: Record<string, SchemaObject> = {}\n const required: string[] = []\n\n for (const [name, field] of Object.entries(entity.fields)) {\n // Skip password y campos sensibles en output\n if (entity.casl?.sensitiveFields?.includes(name)) {\n continue\n }\n\n properties[name] = fieldToSchema(field)\n\n if (field.validation?.required && field.db && !field.db.nullable) {\n required.push(name)\n }\n }\n\n // Timestamps si están habilitados\n if (entity.timestamps) {\n properties['created_at'] = { type: 'string', format: 'date-time' }\n properties['updated_at'] = { type: 'string', format: 'date-time' }\n }\n\n return {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined\n }\n}\n\n/**\n * Genera schema para input de creación (sin id, sin timestamps)\n */\nexport function entityToCreateSchema(entity: CollectionEntityDefinition): SchemaObject {\n const properties: Record<string, SchemaObject> = {}\n const required: string[] = []\n\n for (const [name, field] of Object.entries(entity.fields)) {\n // Skip id y campos autogenerados\n if (name === 'id') continue\n\n properties[name] = fieldToSchema(field)\n\n if (field.validation?.required) {\n required.push(name)\n }\n }\n\n return {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined\n }\n}\n\n/**\n * Genera schema para input de actualización (todos opcionales)\n */\nexport function entityToUpdateSchema(entity: CollectionEntityDefinition): SchemaObject {\n const properties: Record<string, SchemaObject> = {}\n\n for (const [name, field] of Object.entries(entity.fields)) {\n // Skip id\n if (name === 'id') continue\n\n properties[name] = fieldToSchema(field)\n }\n\n return {\n type: 'object',\n properties\n // Sin required - todo es opcional en update\n }\n}\n","import type { PathItemObject, OperationObject, ResponsesObject } from 'openapi3-ts/oas31'\nimport type { CollectionEntityDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * Respuesta paginada estándar\n */\nconst paginatedResponse = (schemaRef: string): ResponsesObject => ({\n '200': {\n description: 'Lista paginada',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: {\n type: 'array',\n items: { $ref: schemaRef }\n },\n meta: {\n type: 'object',\n properties: {\n total: { type: 'integer' },\n page: { type: 'integer' },\n limit: { type: 'integer' },\n totalPages: { type: 'integer' },\n hasNext: { type: 'boolean' },\n hasPrev: { type: 'boolean' }\n }\n }\n }\n }\n }\n }\n }\n})\n\n/**\n * Respuesta de item único\n */\nconst itemResponse = (schemaRef: string, description: string): ResponsesObject => ({\n '200': {\n description,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: { $ref: schemaRef }\n }\n }\n }\n }\n },\n '404': {\n description: 'No encontrado',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: { type: 'string' },\n code: { type: 'string' }\n }\n }\n }\n }\n }\n})\n\n/**\n * Genera paths CRUD para una CollectionEntityDefinition\n */\nexport function entityToPaths(\n entity: CollectionEntityDefinition,\n basePath: string\n): Record<string, PathItemObject> {\n const schemaRef = `#/components/schemas/${entity.table}`\n const createSchemaRef = `#/components/schemas/${entity.table}Create`\n const updateSchemaRef = `#/components/schemas/${entity.table}Update`\n const tag = entity.label\n\n const paths: Record<string, PathItemObject> = {}\n\n // GET /items (list) y POST /items (create)\n paths[basePath] = {\n get: {\n tags: [tag],\n summary: `Listar ${entity.label}`,\n operationId: `list${capitalize(entity.table)}`,\n parameters: [\n { name: 'page', in: 'query', schema: { type: 'integer', default: 1 } },\n { name: 'limit', in: 'query', schema: { type: 'integer', default: 20 } },\n { name: 'sort', in: 'query', schema: { type: 'string' } },\n { name: 'order', in: 'query', schema: { type: 'string', enum: ['asc', 'desc'] } }\n ],\n responses: paginatedResponse(schemaRef)\n } as OperationObject,\n post: {\n tags: [tag],\n summary: `Crear ${entity.label}`,\n operationId: `create${capitalize(entity.table)}`,\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: createSchemaRef }\n }\n }\n },\n responses: {\n '201': {\n description: 'Creado',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: { $ref: schemaRef }\n }\n }\n }\n }\n },\n '400': {\n description: 'Error de validación',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: { type: 'string' },\n code: { type: 'string' }\n }\n }\n }\n }\n }\n }\n } as OperationObject\n }\n\n // GET /items/:id, PATCH /items/:id, DELETE /items/:id\n paths[`${basePath}/{id}`] = {\n get: {\n tags: [tag],\n summary: `Obtener ${entity.label} por ID`,\n operationId: `get${capitalize(entity.table)}ById`,\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } }\n ],\n responses: itemResponse(schemaRef, `${entity.label} encontrado`)\n } as OperationObject,\n patch: {\n tags: [tag],\n summary: `Actualizar ${entity.label}`,\n operationId: `update${capitalize(entity.table)}`,\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } }\n ],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: updateSchemaRef }\n }\n }\n },\n responses: itemResponse(schemaRef, `${entity.label} actualizado`)\n } as OperationObject,\n delete: {\n tags: [tag],\n summary: `Eliminar ${entity.label}`,\n operationId: `delete${capitalize(entity.table)}`,\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } }\n ],\n responses: {\n '204': { description: 'Eliminado' },\n '404': {\n description: 'No encontrado',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: { type: 'string' },\n code: { type: 'string' }\n }\n }\n }\n }\n }\n }\n } as OperationObject\n }\n\n return paths\n}\n\nfunction capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n","import type { OpenAPIObject, SchemaObject, PathItemObject } from 'openapi3-ts/oas31'\nimport type { CollectionEntityDefinition, ModuleManifest } from '@gzl10/nexus-sdk'\nimport { entityToSchema, entityToCreateSchema, entityToUpdateSchema } from './schema-builder.js'\nimport { entityToPaths } from './path-builder.js'\nimport { getOrderedModules } from '../../engine/index.js'\n\nexport interface OpenAPIConfig {\n title: string\n version: string\n description?: string\n servers?: Array<{ url: string; description?: string }>\n}\n\n/**\n * Genera spec OpenAPI desde los módulos registrados\n */\nexport function generateOpenAPISpec(config: OpenAPIConfig): OpenAPIObject {\n const modules = getOrderedModules()\n\n const schemas: Record<string, SchemaObject> = {}\n const paths: Record<string, PathItemObject> = {}\n const tags: Array<{ name: string; description?: string }> = []\n\n for (const module of modules) {\n processModule(module, schemas, paths, tags)\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: config.title,\n version: config.version,\n description: config.description\n },\n servers: config.servers ?? [{ url: '/api/v1', description: 'API v1' }],\n tags,\n paths,\n components: {\n schemas,\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT'\n }\n }\n },\n security: [{ bearerAuth: [] }]\n }\n}\n\n/**\n * Procesa un módulo y extrae schemas/paths de sus definitions\n */\nfunction processModule(\n module: ModuleManifest,\n schemas: Record<string, SchemaObject>,\n paths: Record<string, PathItemObject>,\n tags: Array<{ name: string; description?: string }>\n): void {\n if (!module.definitions?.length) return\n\n for (const definition of module.definitions) {\n // Solo CollectionEntityDefinition genera CRUD paths\n if (definition.type !== 'collection') continue\n\n const entity = definition as CollectionEntityDefinition\n const basePath = buildBasePath(module, entity)\n\n // Schemas\n schemas[entity.table] = entityToSchema(entity)\n schemas[`${entity.table}Create`] = entityToCreateSchema(entity)\n schemas[`${entity.table}Update`] = entityToUpdateSchema(entity)\n\n // Paths\n const entityPaths = entityToPaths(entity, basePath)\n Object.assign(paths, entityPaths)\n\n // Tag\n if (!tags.find(t => t.name === entity.label)) {\n tags.push({\n name: entity.label,\n description: `Operaciones CRUD para ${entity.label}`\n })\n }\n }\n}\n\n/**\n * Construye el path base para una entidad\n */\nfunction buildBasePath(module: ModuleManifest, entity: CollectionEntityDefinition): string {\n const modulePrefix = module.routePrefix ?? `/${module.name}`\n const entityPrefix = entity.routePrefix ?? `/${entity.table}`\n\n // Si entityPrefix es '/', solo usar modulePrefix\n if (entityPrefix === '/') {\n return modulePrefix\n }\n\n return `${modulePrefix}${entityPrefix}`\n}\n","export { generateOpenAPISpec, type OpenAPIConfig } from './generator.js'\nexport { entityToSchema, entityToCreateSchema, entityToUpdateSchema } from './schema-builder.js'\nexport { entityToPaths } from './path-builder.js'\n","import { z } from 'zod'\nimport type { NexusConfig, ResolvedConfig } from './types.js'\n\nconst envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.coerce.number().default(3000),\n HOME_PATH: z.string().default('/ui'),\n CORS_ORIGIN: z.string().default('http://localhost:3001'),\n BACKEND_URL: z.string().optional(),\n DATABASE_URL: z.string().default('file:./dev.db'),\n ADMIN_EMAIL: z.string().email().optional(),\n ADMIN_PASSWORD: z.string().min(6).optional(),\n COOKIE_DOMAIN: z.string().optional(),\n TZ: z.string().default('UTC'),\n TRUST_PROXY: z.coerce.boolean().default(false)\n})\n\n// Configuración desde env vars (puede ser parcial)\nexport const env = envSchema.parse(process.env)\nexport type Env = z.infer<typeof envSchema>\n\n// Aplicar TZ inmediatamente al cargar el módulo\n// UTC por defecto para consistencia con bases de datos\nprocess.env.TZ = env.TZ\n\n// Configuración global resuelta\nlet resolvedConfig: ResolvedConfig | null = null\n\nexport function resolveConfig(config?: NexusConfig): ResolvedConfig {\n const timezone = config?.timezone ?? env.TZ\n\n // Aplicar timezone al proceso\n process.env.TZ = timezone\n\n resolvedConfig = {\n nodeEnv: env.NODE_ENV,\n port: config?.port ?? env.PORT,\n host: config?.host ?? '0.0.0.0',\n homePath: config?.homePath ?? env.HOME_PATH,\n corsOrigin: (Array.isArray(config?.cors?.origin)\n ? config.cors.origin[0]\n : config?.cors?.origin) ?? env.CORS_ORIGIN,\n databaseUrl: config?.database?.url ?? env.DATABASE_URL,\n adminEmail: config?.admin?.email ?? env.ADMIN_EMAIL,\n adminPassword: config?.admin?.password ?? env.ADMIN_PASSWORD,\n timezone\n }\n\n return resolvedConfig\n}\n\nexport function getConfig(): ResolvedConfig {\n if (!resolvedConfig) {\n return resolveConfig()\n }\n return resolvedConfig\n}\n\nexport function resetConfig(): void {\n resolvedConfig = null\n}\n","import type { Knex } from 'knex'\nimport { nexusEvents } from '../core/events/emitter.js'\n\n// Tablas a ignorar (internas del sistema)\nconst IGNORED_TABLES = new Set(['refresh_tokens', 'knex_migrations', 'knex_migrations_lock'])\n\nexport interface DbEventPayload {\n table: string\n action: 'created' | 'updated' | 'deleted'\n data: unknown\n timestamp: Date\n}\n\nexport function setupQueryInterceptor(knexInstance: Knex): Knex {\n // Interceptar eventos de query para emitir eventos CRUD\n knexInstance.on('query-response', (response, query) => {\n const sql = query.sql?.toLowerCase() ?? ''\n\n // Detectar tipo de operación desde SQL\n let action: string | undefined\n let table: string | undefined\n\n if (sql.startsWith('insert into')) {\n action = 'created'\n table = extractTableFromInsert(sql)\n } else if (sql.startsWith('update')) {\n action = 'updated'\n table = extractTableFromUpdate(sql)\n } else if (sql.startsWith('delete from')) {\n action = 'deleted'\n table = extractTableFromDelete(sql)\n }\n\n // Emitir evento si es operación CRUD válida\n if (action && table && !IGNORED_TABLES.has(table)) {\n nexusEvents.emit(`db.${table}.${action}`, {\n table,\n action,\n data: response,\n timestamp: new Date()\n } as DbEventPayload)\n }\n })\n\n return knexInstance\n}\n\n// Helpers para extraer nombre de tabla del SQL\nfunction extractTableFromInsert(sql: string): string | undefined {\n // INSERT INTO \"users\" ... o INSERT INTO users ...\n const match = sql.match(/insert into\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n\nfunction extractTableFromUpdate(sql: string): string | undefined {\n // UPDATE \"users\" SET ... o UPDATE users SET ...\n const match = sql.match(/update\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n\nfunction extractTableFromDelete(sql: string): string | undefined {\n // DELETE FROM \"users\" ... o DELETE FROM users ...\n const match = sql.match(/delete from\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n","import { dirname, join } from 'path'\nimport { fileURLToPath } from 'url'\nimport { existsSync, readFileSync } from 'fs'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\n/**\n * Busca hacia arriba el package.json de nexus-backend\n */\nfunction findLibRoot(startDir: string): string {\n let dir = startDir\n while (dir !== '/') {\n const pkgPath = join(dir, 'package.json')\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n if (pkg.name === '@gzl10/nexus-backend') {\n return dir\n }\n } catch {\n // Continuar buscando\n }\n }\n dir = dirname(dir)\n }\n // Fallback: subir 2 niveles desde shared/\n return join(startDir, '../..')\n}\n\n// Cache del resultado\nlet _libPath: string | null = null\n\n/**\n * Ruta raíz de la librería nexus-backend\n * - Dev: /proyecto/nexus-backend/\n * - Lib: /proyecto-usuario/node_modules/@gzl10/nexus-backend/\n */\nexport function getLibPath(): string {\n if (!_libPath) {\n _libPath = findLibRoot(__dirname)\n }\n return _libPath\n}\n\n/**\n * Ruta raíz del proyecto del usuario (process.cwd)\n * - Dev: coincide con getLibPath()\n * - Lib: /proyecto-usuario/\n */\nexport function getProjectPath(): string {\n return process.cwd();\n}\n\n/**\n * Busca .env subiendo desde cwd hasta encontrarlo (máx 5 niveles)\n * Útil para monorepos donde el .env está en la raíz\n */\nexport function findEnvFile(): string | null {\n let dir = process.cwd()\n console.log('[findEnvFile] Starting search from cwd:', dir)\n for (let i = 0; i < 5; i++) {\n const envPath = join(dir, '.env')\n console.log(`[findEnvFile] Checking: ${envPath}`, existsSync(envPath) ? '✓ FOUND' : '✗ not found')\n if (existsSync(envPath)) return envPath\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n console.log('[findEnvFile] .env NOT FOUND after 5 levels')\n return null\n}\n","/**\n * Registry de campos boolean por tabla\n *\n * SQLite almacena booleans como 0/1 (INTEGER).\n * Este registry permite convertirlos a true/false en postProcessResponse.\n */\n\n// Map: tabla → Set de columnas boolean\nconst booleanColumns = new Map<string, Set<string>>()\n\n/**\n * Registra una columna como boolean para una tabla\n */\nexport function registerBooleanColumn(table: string, column: string): void {\n if (!booleanColumns.has(table)) {\n booleanColumns.set(table, new Set())\n }\n booleanColumns.get(table)!.add(column)\n}\n\n/**\n * Registra múltiples columnas boolean para una tabla\n */\nexport function registerBooleanColumns(table: string, columns: string[]): void {\n for (const column of columns) {\n registerBooleanColumn(table, column)\n }\n}\n\n/**\n * Obtiene las columnas boolean registradas para una tabla\n */\nexport function getBooleanColumns(table: string): Set<string> | undefined {\n return booleanColumns.get(table)\n}\n\n/**\n * Verifica si una columna es boolean\n */\nexport function isBooleanColumn(table: string, column: string): boolean {\n return booleanColumns.get(table)?.has(column) ?? false\n}\n\n/**\n * Convierte valores 0/1 a boolean para las columnas registradas\n * Solo debe usarse con SQLite\n */\nexport function convertBooleans(\n table: string,\n row: Record<string, unknown>\n): Record<string, unknown> {\n const columns = booleanColumns.get(table)\n if (!columns || columns.size === 0) {\n return row\n }\n\n const result = { ...row }\n for (const column of columns) {\n if (column in result) {\n const value = result[column]\n if (value === 0 || value === 1) {\n result[column] = value === 1\n }\n }\n }\n return result\n}\n\n/**\n * Limpia el registry (útil para tests)\n */\nexport function clearBooleanRegistry(): void {\n booleanColumns.clear()\n}\n","import knex, { type Knex } from 'knex'\nimport { join, dirname, isAbsolute } from 'path'\nimport { mkdirSync } from 'fs'\nimport { getConfig } from './env.js'\nimport { setupQueryInterceptor } from '../db/query-interceptor.js'\nimport { getProjectPath } from '../core/paths.js'\nimport { convertBooleans } from '../db/boolean-registry.js'\n\n/**\n * Extrae el nombre de la tabla de una query SQL SELECT\n */\nfunction extractTableFromSelect(sql: string): string | undefined {\n const match = sql.match(/from\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n\n/**\n * postProcessResponse para SQLite: convierte 0/1 → true/false\n * Solo procesa queries SELECT y usa el registry de campos boolean\n */\nfunction sqlitePostProcess(result: unknown, queryContext: { sql?: string }): unknown {\n const sql = queryContext?.sql?.toLowerCase() ?? ''\n if (!sql.startsWith('select')) return result\n\n const table = extractTableFromSelect(sql)\n if (!table) return result\n\n if (Array.isArray(result)) {\n return result.map(row =>\n typeof row === 'object' && row !== null\n ? convertBooleans(table, row as Record<string, unknown>)\n : row\n )\n }\n\n if (typeof result === 'object' && result !== null) {\n return convertBooleans(table, result as Record<string, unknown>)\n }\n\n return result\n}\n\nfunction getDatabaseConfig(): Knex.Config {\n const url = getConfig().databaseUrl\n\n // SQLite in-memory\n if (url === ':memory:') {\n return {\n client: 'better-sqlite3',\n connection: { filename: ':memory:' },\n useNullAsDefault: true,\n postProcessResponse: sqlitePostProcess\n }\n }\n\n // SQLite (default)\n if (url.startsWith('file:') || url.startsWith('sqlite:')) {\n let filename = url.replace(/^(file:|sqlite:)/, '')\n // Rutas relativas se resuelven desde getProjectPath()/data/\n if (!isAbsolute(filename)) {\n filename = join(getProjectPath(), 'data', filename)\n }\n // Asegurar que el directorio existe\n mkdirSync(dirname(filename), { recursive: true })\n return {\n client: 'better-sqlite3',\n connection: { filename },\n useNullAsDefault: true,\n postProcessResponse: sqlitePostProcess\n }\n }\n\n // PostgreSQL\n if (url.startsWith('postgresql://') || url.startsWith('postgres://')) {\n return {\n client: 'pg',\n connection: url,\n pool: { min: 2, max: 10 }\n }\n }\n\n // MySQL\n if (url.startsWith('mysql://')) {\n // Calcular offset del timezone actual (process.env.TZ ya aplicado)\n const offsetMinutes = new Date().getTimezoneOffset()\n const offsetHours = Math.abs(Math.floor(offsetMinutes / 60))\n const offsetMins = Math.abs(offsetMinutes % 60)\n const sign = offsetMinutes <= 0 ? '+' : '-'\n const tzOffset = `${sign}${String(offsetHours).padStart(2, '0')}:${String(offsetMins).padStart(2, '0')}`\n\n return {\n client: 'mysql2',\n connection: {\n uri: url,\n timezone: tzOffset // mysql2 requiere formato \"+HH:MM\"\n },\n pool: { min: 2, max: 10 }\n }\n }\n\n throw new Error(`Unsupported database URL: ${url}`)\n}\n\nconst globalForKnex = globalThis as unknown as { db: Knex | undefined }\n\n/**\n * Inicializa o reinicializa la conexión a la BD\n */\nexport function initDb(): Knex {\n if (!globalForKnex.db) {\n const knexInstance = knex(getDatabaseConfig())\n globalForKnex.db = setupQueryInterceptor(knexInstance)\n }\n return globalForKnex.db\n}\n\n// Crear instancia inicial\ninitDb()\n\n/**\n * Obtiene la instancia actual de la BD\n * Usar en lugar de `db` para soportar restart\n */\nexport function getDb(): Knex {\n return initDb()\n}\n\n// @deprecated Use getDb() para soportar restart\nexport const db = initDb()\n\n// Helper para verificar el tipo de BD\nexport function getDatabaseType(): 'sqlite' | 'postgresql' | 'mysql' {\n const url = getConfig().databaseUrl\n if (url === ':memory:' || url.startsWith('file:') || url.startsWith('sqlite:')) return 'sqlite'\n if (url.startsWith('postgresql://') || url.startsWith('postgres://')) return 'postgresql'\n if (url.startsWith('mysql://')) return 'mysql'\n return 'sqlite'\n}\n\n// Helper para obtener la ruta/URL de la BD (sin credenciales)\nexport function getDatabasePath(): string {\n const url = getConfig().databaseUrl\n if (url === ':memory:') return ':memory:'\n if (url.startsWith('file:') || url.startsWith('sqlite:')) {\n let filename = url.replace(/^(file:|sqlite:)/, '')\n if (!isAbsolute(filename)) {\n filename = join(getProjectPath(), 'data', filename)\n }\n return filename\n }\n // Para PostgreSQL/MySQL, ocultar credenciales\n try {\n const parsed = new URL(url)\n parsed.password = '***'\n return parsed.toString()\n } catch {\n return url.replace(/:\\/\\/[^@]+@/, '://***@')\n }\n}\n\n// Cerrar conexión de BD (para stop/cleanup)\nexport async function destroyDb(): Promise<void> {\n if (globalForKnex.db) {\n await globalForKnex.db.destroy()\n globalForKnex.db = undefined\n }\n}\n","import crypto from 'crypto'\n\n// Genera un ID único similar a cuid\nexport function generateId(): string {\n const timestamp = Date.now().toString(36)\n const randomPart = crypto.randomBytes(8).toString('base64url')\n return `${timestamp}${randomPart}`.slice(0, 25)\n}\n","import type { Request, Response, NextFunction } from 'express'\nimport type { ValidateSchemas } from '@gzl10/nexus-sdk'\n\n// Extender Request para datos validados (Express 5: query/params son readonly)\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n validated?: {\n query?: unknown\n params?: unknown\n }\n }\n }\n}\n\nexport function validate(schemas: ValidateSchemas) {\n return (req: Request, _res: Response, next: NextFunction) => {\n req.validated = {}\n\n if (schemas.body) {\n req.body = schemas.body.parse(req.body)\n }\n if (schemas.query) {\n req.validated.query = schemas.query.parse(req.query)\n }\n if (schemas.params) {\n req.validated.params = schemas.params.parse(req.params)\n }\n next()\n }\n}\n","import { AbilityBuilder, createMongoAbility, type MongoAbility, type RawRuleOf } from '@casl/ability'\nimport type { User, Permission } from '../../modules/users/users.types.js'\nimport type { Actions, Subjects, SubjectStrings, AppAbility } from './ability.types.js'\n\n/**\n * Interpola variables en condiciones de permisos.\n * Soporta: ${user.id}, ${user.email}, etc.\n */\nfunction interpolateConditions(\n conditions: Record<string, unknown>,\n user: User\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const [key, value] of Object.entries(conditions)) {\n if (typeof value === 'string' && value.startsWith('${user.')) {\n const prop = value.slice(7, -1) as keyof User\n result[key] = user[prop]\n } else {\n result[key] = value\n }\n }\n\n return result\n}\n\n/**\n * Construye abilities CASL desde permisos de BD.\n * @param user - Usuario autenticado\n * @param permissions - Permisos del rol del usuario (cargados desde BD)\n */\nexport function defineAbilityFor(user: User, permissions: Permission[]): AppAbility {\n const { can, cannot, build } = new AbilityBuilder<MongoAbility<[Actions, Subjects]>>(createMongoAbility)\n\n for (const perm of permissions) {\n const action = perm.action as Actions\n const subject = perm.subject as SubjectStrings\n const conditions = perm.conditions\n ? interpolateConditions(perm.conditions as Record<string, unknown>, user)\n : undefined\n const fields = perm.fields as string[] | undefined\n\n if (perm.inverted) {\n // cannot(action, subject, fields, conditions) - CASL signature\n if (fields?.length) {\n cannot(action, subject, fields, conditions)\n } else {\n cannot(action, subject, conditions)\n }\n } else {\n // can(action, subject, fields, conditions) - CASL signature\n if (fields?.length) {\n can(action, subject, fields, conditions)\n } else {\n can(action, subject, conditions)\n }\n }\n }\n\n return build()\n}\n\n// Serializar abilities para enviar al frontend\nexport function packRules(ability: AppAbility): RawRuleOf<AppAbility>[] {\n return ability.rules as RawRuleOf<AppAbility>[]\n}\n\n// Reconstruir abilities desde reglas serializadas\nexport function unpackRules(rules: RawRuleOf<AppAbility>[]): AppAbility {\n return createMongoAbility<[Actions, Subjects]>(rules)\n}\n","import { Server as SocketServer, Socket } from 'socket.io'\nimport type { Server as HttpServer } from 'http'\nimport jwt from 'jsonwebtoken'\nimport { getAuthConfig } from '../../modules/auth/auth.config.js'\nimport { nexusEvents } from '../events/emitter.js'\nimport { logger } from '../logger.js'\n\nlet io: SocketServer | null = null\n\n// Mapa de conexiones: userId -> Set<socketId>\nconst userSockets = new Map<string, Set<string>>()\n// Mapa inverso: socketId -> userId\nconst socketUsers = new Map<string, string>()\n\ninterface JwtPayload {\n userId: string\n roleId: string\n}\n\n/**\n * Inicializa Socket.IO en el servidor HTTP\n */\nexport function initSocketIO(httpServer: HttpServer): SocketServer {\n io = new SocketServer(httpServer, {\n cors: { origin: '*', methods: ['GET', 'POST'] },\n path: '/socket.io'\n })\n\n // Middleware de autenticación (opcional - permite guests)\n io.use((socket, next) => {\n const token = socket.handshake.auth?.['token'] || socket.handshake.query?.['token']\n\n if (token && typeof token === 'string') {\n try {\n const payload = jwt.verify(token, getAuthConfig().secret) as JwtPayload\n socket.data.userId = payload.userId\n socket.data.roleId = payload.roleId\n socket.data.authenticated = true\n } catch {\n socket.data.authenticated = false\n }\n } else {\n socket.data.authenticated = false\n }\n next()\n })\n\n io.on('connection', handleConnection)\n\n logger.info('Socket.IO initialized')\n nexusEvents.emitEvent('socket.initialized')\n\n return io\n}\n\nfunction handleConnection(socket: Socket) {\n const { userId, roleId, authenticated } = socket.data\n\n // Registrar conexión\n if (authenticated && userId) {\n if (!userSockets.has(userId)) {\n userSockets.set(userId, new Set())\n }\n userSockets.get(userId)!.add(socket.id)\n socketUsers.set(socket.id, userId)\n\n // Unir a rooms del usuario y del role\n socket.join(`user:${userId}`)\n socket.join(`role:${roleId}`)\n socket.join('authenticated')\n\n logger.debug({ userId, roleId, socketId: socket.id }, 'User connected')\n nexusEvents.emitEvent('socket.user.connected', { userId, roleId, socketId: socket.id })\n }\n\n // Unir a room global (todos, incluyendo guests)\n socket.join('all')\n\n socket.on('disconnect', () => {\n if (userId) {\n userSockets.get(userId)?.delete(socket.id)\n if (userSockets.get(userId)?.size === 0) {\n userSockets.delete(userId)\n }\n socketUsers.delete(socket.id)\n\n logger.debug({ userId, socketId: socket.id }, 'User disconnected')\n nexusEvents.emitEvent('socket.user.disconnected', { userId, socketId: socket.id })\n }\n })\n}\n\n/**\n * Obtiene la instancia de Socket.IO\n * @throws Error si Socket.IO no ha sido inicializado\n */\nexport function getIO(): SocketServer {\n if (!io) throw new Error('Socket.IO not initialized. Call initSocketIO first.')\n return io\n}\n\n/**\n * Verifica si Socket.IO está inicializado\n */\nexport function isSocketIOInitialized(): boolean {\n return io !== null\n}\n\n/**\n * Obtiene los IDs de usuarios conectados\n */\nexport function getConnectedUsers(): string[] {\n return Array.from(userSockets.keys())\n}\n\n/**\n * Verifica si un usuario específico está conectado\n */\nexport function isUserConnected(userId: string): boolean {\n return userSockets.has(userId)\n}\n\n/**\n * Obtiene el número de sockets conectados para un usuario\n */\nexport function getUserSocketCount(userId: string): number {\n return userSockets.get(userId)?.size ?? 0\n}\n\n/**\n * Cierra Socket.IO (para cleanup en tests o shutdown)\n */\nexport function closeSocketIO(): void {\n if (io) {\n io.close()\n io = null\n userSockets.clear()\n socketUsers.clear()\n logger.debug('Socket.IO closed')\n }\n}\n","import { Router } from 'express'\nimport type {\n ModuleContext,\n ModuleMiddlewares,\n EntityDefinition,\n BaseEntityService,\n EntityController,\n CollectionEntityDefinition,\n TempEntityDefinition,\n EventEntityDefinition,\n SingleEntityDefinition,\n ReferenceEntityDefinition,\n ConfigEntityDefinition,\n ViewEntityDefinition,\n ComputedEntityDefinition,\n ExternalEntityDefinition,\n VirtualEntityDefinition,\n ActionEntityDefinition,\n CreateEntityServiceOptions\n} from '@gzl10/nexus-sdk'\nimport { getDb } from '../config/database.js'\nimport { getConfig } from '../config/env.js'\nimport { logger } from '../core/logger.js'\nimport { generateId } from '../core/utils/id.js'\nimport { addTimestamps, addAuditFieldsIfMissing, addConfigDefaultField, addColumnIfMissing, nowTimestamp, formatTimestamp } from '../db/helpers.js'\nimport { validate } from '../core/middleware/validate.middleware.js'\nimport { createRateLimit } from '../core/middleware/rate-limit.middleware.js'\nimport { AppError, NotFoundError, UnauthorizedError, ForbiddenError, ConflictError, ValidationError } from '../core/errors/app-error.js'\nimport { ForbiddenError as CASLForbiddenError, subject } from '@casl/ability'\nimport { defineAbilityFor, packRules } from '../core/abilities/ability.factory.js'\nimport { nexusEvents } from '../core/events/emitter.js'\nimport type { ModuleServices } from '../types/services.js'\nimport { getLibPath, getProjectPath } from '../core/paths.js'\n// Crypto utilities\nimport { hashPassword, verifyPassword, DUMMY_HASH } from '../core/crypto/index.js'\n// Socket.IO utilities\nimport { getIO, isSocketIOInitialized, isUserConnected, getUserSocketCount, getConnectedUsers } from '../core/socket/index.js'\n// Runtime services for createService factory\nimport { CollectionService } from '../runtime/services/collection.service.js'\nimport { TempService } from '../runtime/services/temp.service.js'\nimport { EventService } from '../runtime/services/event.service.js'\nimport { SingleService } from '../runtime/services/single.service.js'\nimport { ReferenceService } from '../runtime/services/reference.service.js'\nimport { ConfigService } from '../runtime/services/config.service.js'\nimport { ViewService } from '../runtime/services/view.service.js'\nimport { ComputedService } from '../runtime/services/computed.service.js'\nimport { ExternalService } from '../runtime/services/external.service.js'\nimport { VirtualService } from '../runtime/services/virtual.service.js'\nimport { ActionService } from '../runtime/services/action.service.js'\n// Runtime controller & router factories\nimport { createEntityController } from '../runtime/controllers/entity.controller.js'\nimport { createEntityRouter } from '../runtime/routes/entity.routes.js'\n// Engine utilities for module/plugin introspection\nimport { getModules, getPlugins, getModuleSubjects, getRegisteredSubjects } from '../engine/index.js'\n\n/**\n * Crea el contexto que se inyecta a los módulos\n * Centraliza las herramientas genéricas para migraciones y seeds\n *\n * Los servicios se registran en el init() de cada módulo:\n * - users: ctx.services.users = createUsersService(ctx)\n * - mail: ctx.services.mail = initMailService(ctx.logger, ctx.services.logger)\n */\nexport function createModuleContext(): ModuleContext {\n // Registry de middlewares con validate y rateLimit como base\n const middleware: ModuleMiddlewares = {\n validate,\n rateLimit: createRateLimit\n }\n\n // Services registry (typed, filled by modules in init())\n const services = {} as ModuleServices\n\n // Cast necesarios para compatibilidad con tipos genéricos del SDK\n // Los tipos concretos (ResolvedConfig, AppAbility, TypedEventEmitter) son compatibles en runtime\n return {\n db: getDb(),\n logger,\n helpers: {\n generateId,\n addTimestamps,\n addAuditFieldsIfMissing,\n addConfigDefaultField,\n addColumnIfMissing,\n getLibPath,\n getProjectPath,\n nowTimestamp,\n formatTimestamp\n },\n crypto: {\n hashPassword,\n verifyPassword,\n DUMMY_HASH\n },\n socket: {\n getIO,\n isInitialized: isSocketIOInitialized,\n isUserConnected,\n getUserSocketCount,\n getConnectedUsers\n },\n engine: {\n getModules,\n getPlugins,\n getModuleSubjects,\n getRegisteredSubjects\n },\n createRouter: () => Router(),\n middleware,\n config: getConfig() as unknown as Record<string, unknown>,\n errors: {\n AppError,\n NotFoundError,\n UnauthorizedError,\n ForbiddenError,\n ConflictError,\n ValidationError\n },\n abilities: {\n defineAbilityFor: defineAbilityFor as ModuleContext['abilities']['defineAbilityFor'],\n packRules: packRules as ModuleContext['abilities']['packRules'],\n subject,\n ForbiddenError: CASLForbiddenError\n },\n events: nexusEvents as unknown as ModuleContext['events'],\n services,\n // Factory para crear servicios de entidades (detecta tipo automáticamente)\n createEntityService: createEntityServiceFactory,\n // Factory para crear controller de entidad\n createEntityController: createEntityControllerFactory,\n // Factory para crear router de entidad\n createEntityRouter: createEntityRouterFactory\n } as ModuleContext\n}\n\n/**\n * Factory function para crear servicios de entidades\n * Se define fuera para evitar problemas de tipado con `this`\n *\n * @param definition - Definición de la entidad\n * @param options - Opciones opcionales, incluyendo hooks para personalizar comportamiento\n */\nfunction createEntityServiceFactory<T extends Record<string, unknown> = Record<string, unknown>>(\n this: ModuleContext,\n definition: EntityDefinition,\n options?: CreateEntityServiceOptions<T>\n): BaseEntityService<T> {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const ctx = this\n const hooks = options?.hooks\n switch (definition.type) {\n case 'collection':\n return new CollectionService<T>(ctx, definition as CollectionEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'temp':\n return new TempService<T>(ctx, definition as TempEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'event':\n return new EventService<T>(ctx, definition as EventEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'single':\n return new SingleService<T>(ctx, definition as SingleEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'reference':\n return new ReferenceService<T>(ctx, definition as ReferenceEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'config':\n return new ConfigService<T>(ctx, definition as ConfigEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'view':\n return new ViewService<T>(ctx, definition as ViewEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'computed':\n return new ComputedService<T>(ctx, definition as ComputedEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'external':\n return new ExternalService<T>(ctx, definition as ExternalEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'virtual':\n return new VirtualService<T>(ctx, definition as VirtualEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'action':\n return new ActionService<T>(ctx, definition as ActionEntityDefinition, hooks) as unknown as BaseEntityService<T>\n default:\n throw new Error(`Unknown entity type: ${(definition as EntityDefinition).type}`)\n }\n}\n\n/**\n * Factory function para crear controllers de entidades\n */\nfunction createEntityControllerFactory(\n this: ModuleContext,\n service: BaseEntityService,\n definition: EntityDefinition\n): EntityController {\n return createEntityController(service, definition, this)\n}\n\n/**\n * Factory function para crear routers de entidades\n */\nfunction createEntityRouterFactory(\n this: ModuleContext,\n controller: EntityController,\n definition: EntityDefinition\n): Router {\n return createEntityRouter(controller, definition, this)\n}\n","import type { Request, Response, NextFunction } from 'express'\nimport { ZodError } from 'zod'\nimport { ForbiddenError as CASLForbiddenError } from '@casl/ability'\nimport { AppError } from '../errors/app-error.js'\nimport { env } from '../../config/env.js'\nimport { logger } from '../logger.js'\nimport { captureExceptionSafe } from '../../modules/logger/logger.service.js'\n\nexport function errorMiddleware(\n err: Error,\n req: Request,\n res: Response,\n _next: NextFunction\n) {\n // Log todos los errores en desarrollo\n if (env.NODE_ENV !== 'production') {\n logger.error({ err, url: req.url, method: req.method }, 'Error en request')\n }\n\n // Zod validation errors\n if (err instanceof ZodError) {\n return res.status(400).json({\n error: 'Error de validación',\n details: err.errors.map((e) => ({\n path: e.path.join('.'),\n message: e.message\n }))\n })\n }\n\n // CASL forbidden\n if (err instanceof CASLForbiddenError) {\n return res.status(403).json({\n error: 'No tienes permiso para esta acción'\n })\n }\n\n // Custom app errors\n if (err instanceof AppError) {\n const response: { error: string; details?: unknown } = { error: err.message }\n if (err.details) {\n response.details = err.details\n }\n return res.status(err.statusCode).json(response)\n }\n\n // Unknown errors (siempre loguear)\n logger.error({ err, url: req.url, method: req.method, stack: err.stack }, 'Unhandled error')\n captureExceptionSafe(err, { url: req.url, method: req.method })\n res.status(500).json({\n error: env.NODE_ENV === 'production' ? 'Error interno del servidor' : err.message\n })\n}\n","import express from 'express'\nimport cors from 'cors'\nimport helmet from 'helmet'\nimport compression from 'compression'\nimport cookieParser from 'cookie-parser'\nimport path from 'path'\nimport { randomUUID } from 'crypto'\n\nimport { getOrderedModules } from '../engine/index.js'\nimport { createModuleRouters } from '../runtime/entity-factory.js'\nimport { generateOpenAPISpec } from './openapi/index.js'\nimport { createModuleContext } from '../modules/context.js'\nimport { errorMiddleware } from './middleware/error.middleware.js'\nimport { env, getConfig } from '../config/env.js'\nimport { logger } from './logger.js'\nimport { getProjectPath } from './paths.js'\n\nexport function createApp() {\n const app = express()\n\n // Trust proxy (required behind reverse proxy for rate-limit, secure cookies, etc.)\n if (env.TRUST_PROXY) {\n app.set('trust proxy', true)\n }\n\n // Security\n app.use(helmet({\n contentSecurityPolicy: env.NODE_ENV === 'production' ? undefined : false\n }))\n\n // CORS\n app.use(cors({\n origin: env.CORS_ORIGIN,\n credentials: true,\n allowedHeaders: ['Content-Type', 'Authorization', 'X-Correlation-ID', 'X-Request-ID'],\n exposedHeaders: ['X-Correlation-ID', 'X-Request-ID']\n }))\n\n // Request ID y Correlation ID (siempre activo)\n app.use((req, res, next) => {\n const requestId = randomUUID()\n const correlationId = req.get('X-Correlation-ID') || req.get('X-Request-ID') || requestId\n\n res.setHeader('X-Request-ID', requestId)\n res.setHeader('X-Correlation-ID', correlationId)\n\n req.requestId = requestId\n req.correlationId = correlationId\n\n next()\n })\n\n // HTTP logging (API=debug, rest=trace)\n const logLevel = process.env['LOG_LEVEL']\n if (logLevel === 'debug' || logLevel === 'trace') {\n app.use((req, res, next) => {\n const start = Date.now()\n res.on('finish', () => {\n const ms = Date.now() - start\n const msg = `[${req.correlationId.slice(0, 8)}] ${req.method} ${req.originalUrl} ${res.statusCode} ${ms}ms`\n if (req.originalUrl.startsWith('/api/')) {\n logger.debug(msg)\n } else {\n logger.trace(msg)\n }\n })\n next()\n })\n }\n\n // Compression\n app.use(compression())\n\n // Body parsing\n app.use(express.json())\n app.use(cookieParser())\n\n // API routes (auto-discovery from modules)\n const ctx = createModuleContext()\n const modules = getOrderedModules()\n\n // 1. Inicializar módulos (registrar middlewares, etc.)\n for (const mod of modules) {\n if (mod.init) {\n mod.init(ctx)\n }\n }\n\n // 2. Registrar rutas (ya tienen middlewares disponibles)\n for (const mod of modules) {\n const prefix = mod.routePrefix ?? `/${mod.name}`\n\n // 2a. Rutas custom primero (tienen prioridad, manejan lógica especial)\n if (mod.routes) {\n app.use(`/api/v1${prefix}`, mod.routes(ctx))\n }\n\n // 2b. Rutas automáticas para entities que no necesitan lógica custom\n // Tipos: action, view, computed, virtual, external, reference, event\n if (mod.definitions && mod.definitions.length > 0) {\n const AUTO_MOUNT_TYPES = ['action', 'view', 'computed', 'virtual', 'external', 'reference', 'event']\n const autoMountable = mod.definitions.filter(d => AUTO_MOUNT_TYPES.includes(d.type ?? 'collection'))\n if (autoMountable.length > 0) {\n const autoRouter = createModuleRouters(ctx, autoMountable)\n app.use(`/api/v1${prefix}`, autoRouter)\n }\n }\n }\n\n // Health check\n app.get('/health', (_req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() })\n })\n\n // OpenAPI spec\n app.get('/api/openapi.json', (_req, res) => {\n const spec = generateOpenAPISpec({\n title: 'Nexus API',\n version: '1.0.0',\n description: 'API generada automáticamente desde EntityDefinitions'\n })\n res.json(spec)\n })\n\n // Redirect root to homePath\n app.get('/', (_req, res) => {\n res.redirect(getConfig().homePath)\n })\n\n // Serve static files from public/\n const publicPath = path.join(getProjectPath(), 'public')\n app.use('/public', express.static(publicPath))\n\n // Serve Vue UI\n const uiPath = path.join(getProjectPath(), '../ui/dist')\n\n app.use('/ui', express.static(uiPath))\n app.get('/ui/{*splat}', (_req, res) => {\n res.sendFile(path.join(uiPath, 'index.html'))\n })\n\n // Global error handler (Express 5 async support)\n app.use(errorMiddleware)\n\n return app\n}\n","import net from 'node:net'\nimport { execSync } from 'child_process'\nimport { logger } from '../logger.js'\n\n/**\n * Busca el PID del proceso usando un puerto\n */\nfunction findProcessOnPort(port: number): number | null {\n try {\n // macOS/Linux: lsof\n const output = execSync(`lsof -ti :${port} 2>/dev/null`, { encoding: 'utf-8' })\n const pid = parseInt(output.trim().split('\\n')[0] ?? '', 10)\n return isNaN(pid) ? null : pid\n } catch {\n return null\n }\n}\n\n/**\n * Mata el proceso que está usando un puerto (solo en desarrollo)\n */\nexport function killProcessOnPort(port: number): boolean {\n const pid = findProcessOnPort(port)\n if (!pid) return false\n\n try {\n process.kill(pid, 'SIGTERM')\n logger.warn({ port, pid }, `Killed process ${pid} on port ${port}`)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Verifica si un puerto está disponible\n * En desarrollo, intenta liberar el puerto automáticamente\n */\nexport async function checkPortAvailable(port: number, host = '0.0.0.0'): Promise<void> {\n return new Promise((resolve, reject) => {\n const server = net.createServer()\n\n server.once('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n // En desarrollo, intentar liberar el puerto\n if (process.env['NODE_ENV'] !== 'production') {\n if (killProcessOnPort(port)) {\n // Esperar un poco y reintentar\n setTimeout(() => {\n checkPortAvailable(port, host).then(resolve).catch(reject)\n }, 500)\n return\n }\n }\n logger.error({ port }, `Port ${port} is already in use`)\n reject(new Error(`Port ${port} is already in use`))\n } else {\n reject(err)\n }\n })\n\n server.once('listening', () => {\n server.close(() => resolve())\n })\n\n server.listen(port, host)\n })\n}\n","/**\n * Ejecuta migraciones inteligentes desde EntityDefinitions\n *\n * Características:\n * - Crea tablas nuevas automáticamente\n * - Detecta y añade columnas nuevas (ALTER TABLE ADD)\n * - Detecta cambios de tipo y loguea advertencia (no modifica)\n * - Detecta columnas obsoletas y loguea advertencia (no elimina)\n */\n\nimport type { Knex } from 'knex'\nimport type { ModuleContext, ModuleManifest, FieldDefinition, FieldDbConfig } from '@gzl10/nexus-sdk'\nimport { isPersistentEntity, getEntityName } from '@gzl10/nexus-sdk'\nimport { registerBooleanColumns } from './boolean-registry.js'\n\n/** Campos de sistema que no deben marcarse como obsoletos */\nconst SYSTEM_FIELDS = new Set([\n 'id',\n 'created_at',\n 'updated_at',\n 'created_by',\n 'updated_by',\n 'is_default'\n])\n\n/** Información de columna desde introspección */\ninterface ColumnInfo {\n type: string\n maxLength: number | null\n nullable: boolean\n defaultValue: unknown\n}\n\n/**\n * Ejecuta migración inteligente desde las definitions del módulo\n * Detecta diferencias entre EntityDefinition y estado actual de BD\n */\nexport async function runGeneratedMigration(\n ctx: ModuleContext,\n mod: ModuleManifest\n): Promise<void> {\n const { db, logger, helpers } = ctx\n const { addTimestamps, addAuditFieldsIfMissing, addConfigDefaultField } = helpers\n\n const definitions = mod.definitions ?? []\n const persistentEntities = definitions.filter(isPersistentEntity)\n\n if (persistentEntities.length === 0) {\n return\n }\n\n for (const entity of persistentEntities) {\n const { table, fields } = entity\n const timestamps = 'timestamps' in entity ? entity.timestamps : false\n const audit = 'audit' in entity ? entity.audit : false\n const indexes = 'indexes' in entity ? entity.indexes : undefined\n const name = getEntityName(entity)\n\n // Registrar campos boolean para conversión SQLite 0/1 → true/false\n const booleanFields = Object.entries(fields)\n .filter(([, field]) => field.db?.type === 'boolean')\n .map(([fieldName]) => fieldName)\n if (booleanFields.length > 0) {\n registerBooleanColumns(table, booleanFields)\n }\n\n const tableExists = await db.schema.hasTable(table)\n\n if (!tableExists) {\n // ========================================\n // CREAR TABLA NUEVA\n // ========================================\n await db.schema.createTable(table, (tableBuilder) => {\n for (const [fieldName, field] of Object.entries(fields)) {\n createColumn(tableBuilder, fieldName, field)\n }\n\n if (timestamps) {\n addTimestamps(tableBuilder, db)\n }\n\n if (indexes?.length) {\n for (const idx of indexes) {\n if (idx.unique) {\n tableBuilder.unique(idx.columns)\n } else {\n tableBuilder.index(idx.columns)\n }\n }\n }\n })\n logger.info(`Created table: ${table} (from ${name} definition)`)\n } else {\n // ========================================\n // MIGRACIÓN INTELIGENTE - DIFF DE COLUMNAS\n // ========================================\n const currentColumns = await db(table).columnInfo() as Record<string, ColumnInfo>\n const definedFields = new Set(Object.keys(fields))\n\n // 1. Detectar columnas nuevas → ADD COLUMN\n for (const [fieldName, field] of Object.entries(fields)) {\n // Skip fields without db config (actions, virtual entities, etc.)\n if (!field.db) continue\n\n if (!currentColumns[fieldName]) {\n await addColumn(db, table, fieldName, field, logger)\n } else {\n // 2. Detectar cambios de tipo → WARNING\n const typeChange = detectTypeChange(currentColumns[fieldName]!, field.db)\n if (typeChange) {\n logger.warn(\n `[${table}.${fieldName}] Type mismatch: BD has \"${typeChange.current}\", definition expects \"${typeChange.expected}\". ` +\n `Manual migration required.`\n )\n }\n }\n }\n\n // 3. Detectar columnas obsoletas → WARNING (no eliminar)\n for (const colName of Object.keys(currentColumns)) {\n if (!definedFields.has(colName) && !SYSTEM_FIELDS.has(colName)) {\n logger.warn(\n `[${table}.${colName}] Column exists in DB but not in EntityDefinition. ` +\n `Consider removing manually if no longer needed.`\n )\n }\n }\n }\n\n // Audit fields (siempre intentar añadir si audit: true)\n if (audit) {\n await addAuditFieldsIfMissing(db, table)\n }\n\n // Config entities: añadir campo is_default automáticamente\n if (entity.type === 'config') {\n await addConfigDefaultField(db, table)\n }\n }\n}\n\n/**\n * Añade una columna nueva a tabla existente\n */\nasync function addColumn(\n db: Knex,\n table: string,\n name: string,\n field: FieldDefinition,\n logger: ModuleContext['logger']\n): Promise<void> {\n await db.schema.alterTable(table, (tableBuilder) => {\n createColumn(tableBuilder, name, field, true) // isAlter = true\n })\n logger.info(`Added column: ${table}.${name}`)\n}\n\n/**\n * Detecta si hay cambio de tipo entre BD y definition\n * Retorna null si son compatibles, o un objeto con los tipos si difieren\n */\nfunction detectTypeChange(\n current: ColumnInfo,\n expected: FieldDbConfig\n): { current: string; expected: string } | null {\n const currentType = normalizeDbType(current.type)\n const expectedType = expected.type\n\n // Mapeo de tipos equivalentes\n const equivalentTypes: Record<string, string[]> = {\n string: ['varchar', 'character varying', 'char', 'nvarchar'],\n text: ['text', 'longtext', 'mediumtext', 'clob'],\n integer: ['integer', 'int', 'int4', 'bigint', 'smallint', 'tinyint'],\n decimal: ['decimal', 'numeric', 'real', 'double', 'float'],\n boolean: ['boolean', 'bool', 'tinyint'],\n date: ['date'],\n datetime: ['datetime', 'timestamp', 'timestamptz'],\n json: ['json', 'jsonb', 'text'], // SQLite usa text para JSON\n uuid: ['uuid', 'char', 'varchar'] // SQLite/MySQL usa varchar para UUID\n }\n\n const expectedEquivalents = equivalentTypes[expectedType] ?? [expectedType]\n\n if (expectedEquivalents.includes(currentType)) {\n return null // Tipos compatibles\n }\n\n return { current: currentType, expected: expectedType }\n}\n\n/**\n * Normaliza el tipo de BD a formato consistente\n */\nfunction normalizeDbType(type: string): string {\n return type.toLowerCase().replace(/\\(\\d+\\)/, '').trim()\n}\n\n/**\n * Crea una columna en la tabla según la definición del campo\n * @param isAlter - Si es ALTER TABLE (no aplicar primary key)\n */\nfunction createColumn(\n table: any, // Knex.CreateTableBuilder | Knex.AlterTableBuilder\n name: string,\n field: FieldDefinition,\n isAlter = false\n): void {\n const { db } = field\n if (!db) {\n throw new Error(`Field ${name} has no db config, cannot create column`)\n }\n let column: any\n\n // Tipo base\n switch (db.type) {\n case 'string':\n column = db.size ? table.string(name, db.size) : table.string(name)\n break\n case 'text':\n column = table.text(name)\n break\n case 'integer':\n column = table.integer(name)\n break\n case 'decimal':\n if (db.precision) {\n column = table.decimal(name, db.precision[0], db.precision[1])\n } else {\n column = table.decimal(name)\n }\n break\n case 'boolean':\n column = table.boolean(name)\n break\n case 'date':\n column = table.date(name)\n break\n case 'datetime':\n column = table.datetime(name)\n break\n case 'json':\n column = table.json(name)\n break\n case 'uuid':\n column = table.uuid(name)\n break\n default:\n column = table.string(name)\n }\n\n // Primary key (solo en CREATE, no en ALTER)\n if (name === 'id' && !isAlter) {\n column.primary()\n }\n\n // Nullable - En ALTER TABLE, nuevas columnas deben ser nullable o tener default\n if (isAlter) {\n // Nuevas columnas siempre nullable para evitar errores con datos existentes\n column.nullable()\n } else if (!db.nullable) {\n column.notNullable()\n } else {\n column.nullable()\n }\n\n // Unique (solo en CREATE para evitar errores con datos duplicados)\n if (db.unique && !isAlter) {\n column.unique()\n }\n\n // Default\n if (db.default !== undefined) {\n column.defaultTo(db.default)\n } else if (db.defaultFn === 'now') {\n // Usar fn.now() del cliente Knex para compatibilidad con PostgreSQL\n const knexClient = (table as unknown as { client: { fn: { now: () => unknown } } }).client\n if (knexClient?.fn?.now) {\n column.defaultTo(knexClient.fn.now())\n }\n // Si no hay cliente disponible, no poner default (se manejará en la aplicación)\n }\n\n // Index\n if (db.index && !isAlter) {\n column.index()\n }\n\n // Foreign key (solo en CREATE para evitar errores de integridad)\n if (field.relation && !isAlter) {\n column.references(field.relation.column ?? 'id').inTable(field.relation.table)\n if (field.relation.onDelete) {\n column.onDelete(field.relation.onDelete)\n }\n }\n}\n","import type { Knex } from 'knex'\n\n/**\n * Asegura que existan las tablas de infraestructura del sistema.\n * Se ejecuta ANTES de las migraciones de módulos.\n */\nexport async function ensureSystemTables(db: Knex): Promise<void> {\n // single_records: almacena entities tipo \"single\" (singletons)\n if (!await db.schema.hasTable('single_records')) {\n await db.schema.createTable('single_records', (table) => {\n table.string('id').primary()\n table.string('key').notNullable().unique()\n table.text('value')\n table.timestamp('created_at').defaultTo(db.fn.now())\n table.timestamp('updated_at').defaultTo(db.fn.now())\n table.string('created_by').nullable()\n table.string('updated_by').nullable()\n })\n }\n}\n","import http from 'node:http'\nimport { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { pathToFileURL } from 'node:url'\nimport { createApp } from './app.js'\nimport { destroyDb, getDb, getDatabaseType, getDatabasePath } from '../config/database.js'\nimport { resolveConfig, resetConfig, env } from '../config/env.js'\nimport { nexusEvents } from './events/emitter.js'\nimport { logger, setLoggerInstance } from './logger.js'\nimport { getLoggerConfig } from '../modules/logger/logger.config.js'\nimport { initLoggerService, getPinoLogger } from '../modules/logger/logger.service.js'\nimport { checkPortAvailable } from './utils/net.js'\nimport { loadCoreModules, getOrderedModules, resetStore } from '../engine/index.js'\nimport { initSocketIO, closeSocketIO } from './socket/index.js'\nimport { createModuleContext } from '../modules/context.js'\nimport { getLibPath, getProjectPath } from './paths.js'\nimport { runGeneratedMigration } from '../db/generated-migrate.js'\nimport { ensureSystemTables } from '../db/ensure-system-tables.js'\nimport { cacheInvalidator } from './cache/index.js'\nimport type { NexusConfig } from '../config/types.js'\nimport type { ModuleContext, ModuleManifest } from '@gzl10/nexus-sdk'\n\nlet server: http.Server | null = null\n\nexport type { NexusConfig }\n\n/**\n * Intenta ejecutar el seed de un módulo.\n * 1. Si mod.seed está definido, lo usa directamente\n * 2. Si no, intenta auto-detectar {name}.seed.js en el directorio del módulo\n */\nasync function runModuleSeed(mod: ModuleManifest, ctx: ModuleContext): Promise<boolean> {\n // Seed explícito en manifest\n if (mod.seed) {\n await mod.seed(ctx)\n return true\n }\n\n // Auto-detección: buscar {name}.seed.js en dist/modules/{name}/\n const seedPath = join(getLibPath(), 'dist', 'modules', mod.name, `${mod.name}.seed.js`)\n if (!existsSync(seedPath)) {\n return false\n }\n\n try {\n const seedModule = await import(pathToFileURL(seedPath).href)\n if (typeof seedModule.seed === 'function') {\n await seedModule.seed(ctx)\n return true\n }\n } catch (err) {\n logger.warn({ module: mod.name, err }, 'Failed to load auto-detected seed')\n }\n\n return false\n}\n\nasync function runMigrationsAndSeeds(): Promise<void> {\n // Inicializar logger antes de cualquier log para evitar múltiples instancias de pino-pretty\n initLoggerService(getLoggerConfig())\n setLoggerInstance(getPinoLogger())\n\n // Cargar módulos core antes de usarlos\n loadCoreModules()\n\n const ctx = createModuleContext()\n const modules = getOrderedModules()\n\n logger.info({ type: getDatabaseType(), path: getDatabasePath() }, 'Database ready')\n\n // Asegurar tablas de sistema antes de migraciones de módulos\n await ensureSystemTables(getDb())\n\n logger.info('Running migrations...')\n for (const mod of modules) {\n if (mod.migrate) {\n // Usar migración manual si existe\n await mod.migrate(ctx)\n } else if (mod.definitions?.length) {\n // Fallback: generar y ejecutar migración desde definitions\n await runGeneratedMigration(ctx, mod)\n }\n }\n\n logger.info('Running seeds...')\n for (const mod of modules) {\n await runModuleSeed(mod, ctx)\n }\n}\n\nexport async function start(config?: NexusConfig): Promise<http.Server> {\n if (server) {\n throw new Error('Server already running. Call stop() first.')\n }\n\n const resolved = resolveConfig(config)\n\n // Verificar puerto disponible antes de iniciar\n await checkPortAvailable(resolved.port, resolved.host)\n\n nexusEvents.emitEvent('server.starting', { port: resolved.port, host: resolved.host })\n\n // Ejecutar migraciones y seeds antes de iniciar\n await runMigrationsAndSeeds()\n\n // Inicializar cache invalidator (escucha eventos db.*)\n cacheInvalidator.init()\n\n const app = createApp()\n\n return new Promise((resolve) => {\n server = app.listen(resolved.port, resolved.host, () => {\n // Inicializar Socket.IO después de que el servidor esté escuchando\n initSocketIO(server!)\n\n const baseUrl = env.BACKEND_URL || `http://localhost:${resolved.port}`\n logger.info({ libPath: getLibPath(), projectPath: getProjectPath() }, 'Paths')\n logger.info(`API: ${baseUrl}/api/v1`)\n logger.info(`UI: ${baseUrl}/ui`)\n logger.info({ port: resolved.port, mode: resolved.nodeEnv }, 'Server started')\n nexusEvents.emitEvent('server.started', { port: resolved.port, host: resolved.host })\n resolve(server!)\n })\n })\n}\n\nexport async function stop(): Promise<void> {\n if (!server) return\n\n nexusEvents.emitEvent('server.stopping')\n\n // Limpiar cache invalidator\n cacheInvalidator.destroy()\n\n // Cerrar Socket.IO antes del servidor HTTP\n closeSocketIO()\n\n await new Promise<void>((resolve, reject) => {\n server!.close((err) => {\n if (err) reject(err)\n else resolve()\n })\n })\n\n await destroyDb()\n nexusEvents.emitEvent('db.disconnected')\n\n resetConfig()\n resetStore()\n server = null\n nexusEvents.emitEvent('server.stopped')\n logger.info('Server stopped')\n}\n\nexport async function restart(config?: NexusConfig): Promise<http.Server> {\n nexusEvents.emitEvent('server.restarting')\n await stop()\n return start(config)\n}\n\nexport function isRunning(): boolean {\n return server !== null\n}\n\n// Graceful shutdown handlers\nfunction setupGracefulShutdown() {\n let shuttingDown = false\n\n const shutdown = async (signal: string) => {\n if (shuttingDown) return\n shuttingDown = true\n\n logger.info({ signal }, 'Graceful shutdown initiated')\n\n try {\n await stop()\n process.exit(0)\n } catch (err) {\n logger.fatal({ err }, 'Error during shutdown')\n process.exit(1)\n }\n }\n\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n process.on('SIGINT', () => shutdown('SIGINT'))\n}\n\nsetupGracefulShutdown()\n","/**\n * Carga .env antes de cualquier otro import del proyecto\n * Este archivo SOLO importa de node/npm, nunca de archivos locales\n */\nimport { existsSync } from 'fs'\nimport { join, dirname } from 'path'\nimport { config } from 'dotenv'\n\nlet dir = process.cwd()\nconsole.log('[env-loader] Starting search from cwd:', dir)\n\nfor (let i = 0; i < 5; i++) {\n const envPath = join(dir, '.env')\n const exists = existsSync(envPath)\n console.log(`[env-loader] Checking: ${envPath}`, exists ? '✓ FOUND' : '✗ not found')\n if (exists) {\n config({ path: envPath })\n console.log('[env-loader] Loaded:', envPath)\n break\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n}\n","// Cargar .env PRIMERO - este import no tiene deps locales\nimport './env-loader.js'\n\n// Server lifecycle\nexport { start, stop, restart, isRunning } from './core/server.js'\nexport type { NexusConfig } from './core/server.js'\n\n// Core exports\nexport { createApp } from './core/app.js'\nexport { db, getDb, destroyDb, getDatabaseType } from './config/database.js'\nexport { getConfig } from './config/env.js'\nexport type { ResolvedConfig } from './config/types.js'\n\n// Module system (engine)\nexport { registerModule, registerPlugin, getModules, getModule, getOrderedModules } from './engine/index.js'\nexport { getRegisteredSubjects, isValidSubject, getPlugin, getPlugins, loadCoreModules } from './engine/index.js'\n\n// Runtime - Auto-generated services, controllers, routes\nexport {\n createEntityRuntime,\n createEntityService,\n createModuleServices,\n createModuleRouters,\n getServiceKey,\n registerAdapter,\n getAdapter\n} from './runtime/index.js'\nexport type {\n EntityService,\n EntityController,\n EntityRuntime,\n EntityQuery,\n ExternalAdapter,\n EntityHandler\n} from './runtime/index.js'\n// Service classes (for extension)\nexport { BaseEntityService } from './runtime/index.js'\nexport { CollectionService } from './runtime/index.js'\nexport { SingleService } from './runtime/index.js'\nexport { ReferenceService } from './runtime/index.js'\nexport { EventService } from './runtime/index.js'\nexport { ConfigService } from './runtime/index.js'\nexport { TempService } from './runtime/index.js'\nexport { ViewService } from './runtime/index.js'\nexport { ExternalService } from './runtime/index.js'\nexport { VirtualService } from './runtime/index.js'\nexport { ComputedService } from './runtime/index.js'\nexport { ActionService } from './runtime/index.js'\nexport type {\n ModuleManifest,\n ModuleContext,\n EntityDefinition,\n ModuleRequirements,\n ModuleMiddlewares,\n ModuleAbilities,\n ContextHelpers,\n ValidateSchemas,\n PluginManifest,\n Category,\n Request,\n Response,\n NextFunction,\n RequestHandler,\n Router,\n CookieOptions\n} from '@gzl10/nexus-sdk'\n\n// Pagination & Auth types\nexport type { PaginatedResult, PaginationParams, AuthRequest } from './types/index.js'\n\n// Entity models\nexport type { User, Role, Permission } from './modules/users/users.types.js'\nexport type { UserWithoutPassword, UserWithRole, UserPresence, RoleWithPermissions, RoleWithCounts } from './modules/users/users.service.js'\nexport type { RefreshToken, AuthAudit } from './modules/auth/auth.types.js'\nexport type { JwtPayload, TokenPair } from './modules/auth/jwt.utils.js'\n\n// CASL abilities\nexport { defineAbilityFor, packRules, unpackRules } from './core/abilities/ability.factory.js'\nexport type { AppAbility, Actions, Subjects, SubjectStrings, SubjectRegistry } from './core/abilities/ability.types.js'\n\n// Events\nexport { nexusEvents } from './core/events/emitter.js'\nexport type { NexusEvents, NexusEventName, NexusEventPayload, DbEventPayload } from './core/events/emitter.js'\n\n// Socket.IO\nexport {\n getIO,\n initSocketIO,\n isSocketIOInitialized,\n getConnectedUsers,\n isUserConnected,\n getUserSocketCount,\n closeSocketIO\n} from './core/socket/index.js'\n\n// Notifications\nexport {\n NotificationService,\n getNotificationService,\n initNotificationService\n} from './modules/notifications/index.js'\nexport type {\n NotificationType,\n NotificationPriority,\n NotificationTarget,\n SendNotificationInput,\n Notification,\n NotificationPayload\n} from './modules/notifications/index.js'\n\n// Paths (rutas de librería y proyecto)\nexport { getLibPath, getProjectPath, findEnvFile } from './core/paths.js'\n\n// Auto-start si se ejecuta directamente (CLI mode)\nif (import.meta.url === `file://${process.argv[1]}`) {\n const { start } = await import('./core/server.js')\n start()\n}\n","/**\n * Runtime - Auto-generated services, controllers, and routes for entities\n *\n * Usage:\n * ```typescript\n * import { createEntityRuntime, createModuleRouters } from './runtime/index.js'\n *\n * // Create runtime for a single entity\n * const runtime = createEntityRuntime(ctx, postEntity)\n * app.use('/posts', runtime.router)\n *\n * // Create routers for all entities in a module\n * const router = createModuleRouters(ctx, module.definitions)\n * app.use('/api/cms', router)\n * ```\n */\n\n// Types\nexport * from './types.js'\n\n// Entity Factory\nexport {\n createEntityService,\n createEntityRuntime,\n createModuleServices,\n createModuleRouters,\n getServiceKey\n} from './entity-factory.js'\n\n// Services\nexport { BaseEntityService } from './services/base.service.js'\nexport { CollectionService } from './services/collection.service.js'\nexport { SingleService } from './services/single.service.js'\nexport { ReferenceService } from './services/reference.service.js'\nexport { EventService } from './services/event.service.js'\nexport { ConfigService } from './services/config.service.js'\nexport { TempService } from './services/temp.service.js'\nexport { ViewService } from './services/view.service.js'\nexport { ExternalService } from './services/external.service.js'\nexport { VirtualService } from './services/virtual.service.js'\nexport { ComputedService } from './services/computed.service.js'\nexport { ActionService } from './services/action.service.js'\n\n// Controllers\nexport { createEntityController } from './controllers/entity.controller.js'\n\n// Routes\nexport { createEntityRouter } from './routes/entity.routes.js'\n\n// Validation\nexport { buildCreateSchema, buildUpdateSchema, getSchemas } from './validation/index.js'\n"],"mappings":"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","names":["subject","subject","config","config","config","logger","pino","loggerInstance","init_logger","config","join","existsSync","db","cpus","existsSync","join","dirname","config","dir","path","createHash","extname","config","path","join","existsSync","mkdirSync","path","db","config","db","db","logger","generateId","projectPath","config","TABLE","type","DEFAULT_MAX_SIZE","rateLimit","config","multer","config","db","logger","generateId","TABLE","DEFAULT_MAX_SIZE","seed","z","verifyPassword","hashPassword","z","validate","CASLForbiddenError","db","generateId","nowTimestamp","hashPassword","isUserConnected","getUserSocketCount","seed","db","logger","generateId","config","hashPassword","seed","pino","z","path","config","db","generateId","nowTimestamp","crypto","verifyPassword","DUMMY_HASH","defineAbilityFor","packRules","USERS","ROLES","config","z","validate","jwt","defineAbilityFor","USERS","seed","db","logger","generateId","seed","getModuleSubjects","z","existsSync","join","logger","config","nodemailer","getConfigByScope","config","subject","seed","db","logger","generateId","seed","type","io","z","io","config","path","z","init_logger","getTableAndSubject","subject","z","db","type","subject","CASLForbiddenError","type","type","init_schema_builder","config","init_schema_builder","init_schema_builder","z","config","dirname","join","existsSync","readFileSync","dir","pkg","join","dirname","isAbsolute","mkdirSync","crypto","subject","jwt","ZodError","CASLForbiddenError","start","server","db","logger","addTimestamps","addAuditFieldsIfMissing","addConfigDefaultField","type","db","join","existsSync","config","start"]}
|
|
1
|
+
{"version":3,"sources":["../src/engine/store.ts","../src/engine/registry.ts","../src/engine/queries.ts","../src/modules/logger/logger.config.ts","../src/core/logger.ts","../src/modules/logger/logger.service.ts","../src/modules/logger/logger.entity.ts","../src/modules/logger/logger.routes.ts","../src/modules/logger/index.ts","../src/modules/system/system.controller.ts","../src/modules/system/system.routes.ts","../src/modules/system/system.entity.ts","../src/modules/system/index.ts","../src/modules/storage/drivers/filesystem.driver.ts","../src/modules/storage/drivers/s3.driver.ts","../src/modules/storage/storage.config.ts","../src/db/helpers.ts","../src/core/errors/app-error.ts","../src/modules/storage/storage.service.ts","../src/core/middleware/rate-limit.middleware.ts","../src/modules/storage/storage.entity.ts","../src/modules/storage/storage.routes.ts","../src/modules/storage/storage.seed.ts","../src/modules/storage/index.ts","../src/core/crypto/hash.ts","../src/core/crypto/index.ts","../src/modules/users/users.entity.ts","../src/modules/users/users.routes.ts","../src/modules/users/users.service.ts","../src/modules/users/users.seed.ts","../src/modules/users/index.ts","../src/core/startup-logger.ts","../src/modules/auth/auth.config.ts","../src/modules/auth/jwt.utils.ts","../src/modules/auth/auth.entity.ts","../src/modules/auth/auth.service.ts","../src/modules/auth/auth.controller.ts","../src/modules/auth/auth.routes.ts","../src/modules/auth/auth.middleware.ts","../src/modules/auth/auth.seed.ts","../src/modules/auth/index.ts","../src/modules/ui/ui.entity.ts","../src/modules/ui/index.ts","../src/modules/mail/mail.config.ts","../src/modules/mail/mail.service.ts","../src/modules/mail/mail.entity.ts","../src/modules/mail/mail.routes.ts","../src/modules/mail/mail.seed.ts","../src/modules/mail/index.ts","../src/modules/notifications/notifications.service.ts","../src/modules/notifications/notifications.entity.ts","../src/modules/notifications/notifications.routes.ts","../src/modules/notifications/notifications.socket.ts","../src/modules/notifications/index.ts","../src/modules/schedules/schedules.executor.ts","../src/modules/schedules/schedules.service.ts","../src/modules/schedules/schedules.entity.ts","../src/modules/schedules/schedules.routes.ts","../src/modules/schedules/index.ts","../src/engine/loader.ts","../src/engine/utils.ts","../src/engine/index.ts","../src/runtime/services/base.service.ts","../src/runtime/services/collection.service.ts","../src/runtime/services/single.service.ts","../src/runtime/services/reference.service.ts","../src/runtime/services/event.service.ts","../src/runtime/services/config.service.ts","../src/runtime/services/temp.service.ts","../src/runtime/services/view.service.ts","../src/runtime/types.ts","../src/core/cache/lru-cache.ts","../src/core/events/emitter.ts","../src/core/cache/cache-invalidator.ts","../src/core/cache/index.ts","../src/runtime/services/external.service.ts","../src/runtime/services/virtual.service.ts","../src/runtime/services/computed.service.ts","../src/runtime/services/action.service.ts","../src/runtime/validation/schema-builder.ts","../src/runtime/validation/index.ts","../src/runtime/controllers/entity.controller.ts","../src/runtime/routes/entity.routes.ts","../src/runtime/entity-factory.ts","../src/core/openapi/schema-builder.ts","../src/core/openapi/path-builder.ts","../src/core/openapi/generator.ts","../src/core/openapi/index.ts","../src/config/env.ts","../src/db/query-interceptor.ts","../src/core/paths.ts","../src/db/boolean-registry.ts","../src/config/database.ts","../src/core/utils/id.ts","../src/core/middleware/validate.middleware.ts","../src/core/abilities/ability.factory.ts","../src/core/socket/index.ts","../src/modules/context.ts","../src/core/middleware/error.middleware.ts","../src/core/app.ts","../src/core/utils/net.ts","../src/db/generated-migrate.ts","../src/db/ensure-system-tables.ts","../src/core/server.ts","../src/env-loader.ts","../src/index.ts","../src/runtime/index.ts"],"sourcesContent":["import type { ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\n\n/**\n * Estado en memoria del engine\n * IMPORTANTE: Este archivo NO importa módulos para evitar dependencias circulares\n */\nexport const moduleStore = {\n /** Módulos registrados */\n modules: [] as ModuleManifest[],\n\n /** Plugins registrados (por name) */\n plugins: new Map<string, PluginManifest>(),\n\n /** Tablas registradas (para validar unicidad) */\n tables: new Set<string>(),\n\n /** Subjects registrados (para validar unicidad) */\n subjects: new Set<string>(['all'])\n}\n\n/**\n * Resetea el store a su estado inicial\n * Usado por stop() para permitir restart limpio\n */\nexport function resetStore(): void {\n moduleStore.modules.length = 0\n moduleStore.plugins.clear()\n moduleStore.tables.clear()\n moduleStore.subjects.clear()\n moduleStore.subjects.add('all')\n}\n","import type { ModuleManifest, PluginManifest, EntityDefinition } from '@gzl10/nexus-sdk'\nimport { moduleStore } from './store.js'\n\n/**\n * Obtiene tabla y subject de una definition.\n * Subject solo se retorna si está explícitamente definido en casl.subject.\n */\nfunction getTableAndSubject(def: EntityDefinition): { table?: string; subject?: string } {\n const typesWithTable = ['collection', 'reference', 'event', 'config', 'temp', 'view', undefined]\n const caslSubject = (def as { casl?: { subject?: string } }).casl?.subject\n\n if (!typesWithTable.includes(def.type)) {\n // computed, action, external, virtual no tienen tabla\n return { subject: caslSubject }\n }\n\n const table = (def as { table: string }).table\n return { table, subject: caslSubject }\n}\n\n/**\n * Valida unicidad de tablas y subjects al registrar un módulo\n */\nfunction validateUniqueness(mod: ModuleManifest): void {\n const errors: string[] = []\n\n // Validar label requerido\n if (!mod.label) {\n throw new Error(`Módulo '${mod.name}': label es requerido`)\n }\n\n for (const def of mod.definitions ?? []) {\n const { table, subject } = getTableAndSubject(def)\n\n if (table && moduleStore.tables.has(table)) {\n errors.push(`tabla '${table}' ya está registrada`)\n }\n if (subject && moduleStore.subjects.has(subject)) {\n errors.push(`subject '${subject}' ya está registrado`)\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Módulo '${mod.name}' tiene conflictos:\\n - ${errors.join('\\n - ')}`)\n }\n}\n\n/**\n * Registra tablas y subjects de un módulo\n */\nfunction registerTablesAndSubjects(mod: ModuleManifest): void {\n for (const def of mod.definitions ?? []) {\n const { table, subject } = getTableAndSubject(def)\n if (table) moduleStore.tables.add(table)\n if (subject) moduleStore.subjects.add(subject)\n }\n}\n\n/**\n * Registrar módulo dinámicamente\n */\nexport function registerModule(mod: ModuleManifest): void {\n validateUniqueness(mod)\n registerTablesAndSubjects(mod)\n moduleStore.modules.push(mod)\n}\n\n/**\n * Registrar un plugin completo (todos sus módulos)\n * Hereda del plugin: label e icon (si el módulo no los define)\n */\nexport function registerPlugin(plugin: PluginManifest): void {\n // Registrar plugin para lookup\n moduleStore.plugins.set(plugin.name, plugin)\n\n for (const mod of plugin.modules) {\n // Inyectar propiedades del plugin al módulo (solo si no están definidas)\n const moduleWithPluginProps = {\n ...mod,\n label: mod.label ?? plugin.label,\n icon: mod.icon ?? plugin.icon,\n category: plugin.category,\n }\n registerModule(moduleWithPluginProps)\n }\n}\n","import type { ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\nimport { moduleStore } from './store.js'\n\n/**\n * Obtener todos los módulos registrados\n */\nexport function getModules(): ModuleManifest[] {\n return [...moduleStore.modules]\n}\n\n/**\n * Ordenar módulos por dependencias (topological sort)\n * Garantiza que un módulo se procese después de sus dependencias\n */\nexport function getOrderedModules(): ModuleManifest[] {\n const sorted: ModuleManifest[] = []\n const visited = new Set<string>()\n const moduleMap = new Map(moduleStore.modules.map(m => [m.name, m]))\n\n function visit(mod: ModuleManifest) {\n if (visited.has(mod.name)) return\n visited.add(mod.name)\n\n for (const dep of mod.dependencies ?? []) {\n const depMod = moduleMap.get(dep)\n if (depMod) visit(depMod)\n }\n sorted.push(mod)\n }\n\n moduleStore.modules.forEach(visit)\n return sorted\n}\n\n/**\n * Obtener módulo por nombre\n */\nexport function getModule(name: string): ModuleManifest | undefined {\n return moduleStore.modules.find(m => m.name === name)\n}\n\n/**\n * Obtener plugin por nombre\n */\nexport function getPlugin(name: string): PluginManifest | undefined {\n return moduleStore.plugins.get(name)\n}\n\n/**\n * Obtener todos los plugins registrados\n */\nexport function getPlugins(): PluginManifest[] {\n return [...moduleStore.plugins.values()]\n}\n\n/**\n * Obtener todos los subjects registrados en módulos\n * Incluye 'all' que siempre está disponible\n */\nexport function getRegisteredSubjects(): string[] {\n return [...moduleStore.subjects]\n}\n\n/**\n * Validar que un subject existe en algún módulo registrado\n */\nexport function isValidSubject(subject: string): boolean {\n return moduleStore.subjects.has(subject)\n}\n","import { z } from 'zod'\nimport type { LoggerConfig } from './logger.types.js'\n\n/**\n * Schema de variables de entorno para logger\n * Completamente independiente de la configuración global\n */\nconst loggerEnvSchema = z.object({\n LOG_LEVEL: z.enum(['silent', 'fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n LOG_FORMAT: z.enum(['json', 'pretty']).default('pretty'),\n // Sentry opcional - solo se activa si DSN está definido\n SENTRY_DSN: z.string().url().optional(),\n SENTRY_ENVIRONMENT: z.string().default('development'),\n SENTRY_SAMPLE_RATE: z.coerce.number().min(0).max(1).default(1.0)\n})\n\nexport const loggerEnv = loggerEnvSchema.parse(process.env)\n\n/**\n * Obtiene la configuración de logger desde las variables de entorno\n */\nexport function getLoggerConfig(): LoggerConfig {\n return {\n level: loggerEnv.LOG_LEVEL,\n format: loggerEnv.LOG_FORMAT,\n // Sentry solo si DSN está definido\n sentry: loggerEnv.SENTRY_DSN\n ? {\n dsn: loggerEnv.SENTRY_DSN,\n environment: loggerEnv.SENTRY_ENVIRONMENT,\n sampleRate: loggerEnv.SENTRY_SAMPLE_RATE\n }\n : undefined\n }\n}\n","import pino from 'pino'\nimport { createRequire } from 'module'\n\n/**\n * Logger global con fallback durante bootstrap\n *\n * Inicialmente crea un pino logger básico.\n * Cuando el módulo logger se inicializa, reemplaza la instancia.\n */\n\nconst isDev = process.env['NODE_ENV'] !== 'production'\n\n/**\n * Detecta si pino-pretty está disponible\n * En producción o cuando no está instalado, retorna false\n */\nexport function hasPinoPretty(): boolean {\n if (!isDev) return false\n try {\n const require = createRequire(import.meta.url)\n require.resolve('pino-pretty')\n return true\n } catch {\n return false\n }\n}\n\n// Logger inicial (fallback durante bootstrap, antes de que el módulo se inicialice)\nlet loggerInstance: pino.Logger = pino({\n level: process.env['LOG_LEVEL'] || 'info',\n transport: hasPinoPretty()\n ? { target: 'pino-pretty', options: { colorize: true, sync: true } }\n : undefined\n})\n\n/**\n * Reemplaza la instancia del logger\n * Llamado desde el init() del módulo logger\n */\nexport function setLoggerInstance(instance: pino.Logger): void {\n loggerInstance = instance\n}\n\n/**\n * Proxy que delega al logger actual\n * Permite hot-swap del logger cuando el módulo se inicializa\n */\nexport const logger = new Proxy({} as pino.Logger, {\n get(_, prop) {\n const target = loggerInstance as unknown as Record<string | symbol, unknown>\n const value = target[prop]\n // Bind methods para preservar `this`\n return typeof value === 'function' ? value.bind(loggerInstance) : value\n }\n})\n\nexport const createChildLogger = (context: string) => logger.child({ context })\n","import pino from 'pino'\nimport * as Sentry from '@sentry/node'\nimport type { LoggerConfig, LoggerService } from './logger.types.js'\nimport { hasPinoPretty } from '../../core/logger.js'\n\nlet loggerInstance: LoggerService | null = null\nlet pinoInstance: pino.Logger | null = null\nlet sentryEnabled = false\n\n/**\n * Inicializa el servicio de logger con Pino y opcionalmente Sentry\n */\nexport function initLoggerService(config: LoggerConfig): LoggerService {\n // Si ya está inicializado, retornar instancia existente (idempotente)\n if (loggerInstance) {\n return loggerInstance\n }\n\n // Inicializar Pino\n const usePretty = config.format === 'pretty' && hasPinoPretty()\n const pinoLogger = pino({\n level: config.level,\n transport: usePretty\n ? { target: 'pino-pretty', options: { colorize: true, sync: true } }\n : undefined\n })\n\n // Inicializar Sentry solo si DSN está configurado\n sentryEnabled = !!config.sentry\n if (sentryEnabled && config.sentry) {\n Sentry.init({\n dsn: config.sentry.dsn,\n environment: config.sentry.environment,\n sampleRate: config.sentry.sampleRate\n })\n pinoLogger.info({ sentry: config.sentry.environment }, 'Sentry initialized')\n }\n\n // Guardar instancia de pino para shared/logger.ts\n pinoInstance = pinoLogger\n\n loggerInstance = {\n fatal: pinoLogger.fatal.bind(pinoLogger),\n error: pinoLogger.error.bind(pinoLogger),\n warn: pinoLogger.warn.bind(pinoLogger),\n info: pinoLogger.info.bind(pinoLogger),\n debug: pinoLogger.debug.bind(pinoLogger),\n trace: pinoLogger.trace.bind(pinoLogger),\n child: pinoLogger.child.bind(pinoLogger),\n\n // Sentry helpers (no-op si no está habilitado)\n captureException: (error: Error, context?: Record<string, unknown>) => {\n if (sentryEnabled) {\n Sentry.captureException(error, { extra: context })\n }\n },\n captureMessage: (msg: string, level: 'info' | 'warning' | 'error' = 'info') => {\n if (sentryEnabled) {\n Sentry.captureMessage(msg, level)\n }\n },\n setUser: (user: { id: string; email?: string }) => {\n if (sentryEnabled) {\n Sentry.setUser(user)\n }\n },\n isSentryEnabled: () => sentryEnabled\n }\n\n return loggerInstance\n}\n\n/**\n * Obtiene la instancia del LoggerService (singleton)\n */\nexport function getLoggerService(): LoggerService {\n if (!loggerInstance) {\n throw new Error('Logger not initialized. Call initLoggerService() first.')\n }\n return loggerInstance\n}\n\n/**\n * Resetea el logger service (solo para tests)\n */\nexport function resetLoggerService(): void {\n loggerInstance = null\n pinoInstance = null\n sentryEnabled = false\n}\n\n/**\n * Obtiene la instancia de pino.Logger (para ctx.logger)\n */\nexport function getPinoLogger(): pino.Logger {\n if (!pinoInstance) {\n throw new Error('Logger not initialized. Call initLoggerService() first.')\n }\n return pinoInstance\n}\n\nexport function captureExceptionSafe(error: Error, context?: Record<string, unknown>): void {\n if (loggerInstance?.isSentryEnabled()) {\n loggerInstance.captureException(error, context)\n }\n}\n\nexport function captureMessageSafe(msg: string, level?: 'info' | 'warning' | 'error'): void {\n if (loggerInstance?.isSentryEnabled()) {\n loggerInstance.captureMessage(msg, level)\n }\n}\n\nexport function setUserSafe(user: { id: string; email?: string }): void {\n if (loggerInstance?.isSentryEnabled()) {\n loggerInstance.setUser(user)\n }\n}\n","import type { ComputedEntityDefinition } from '@gzl10/nexus-sdk'\nimport { getLoggerConfig } from './logger.config.js'\n\n/**\n * Computed Entity: config\n * Muestra la configuración del logger actual (read-only)\n */\nexport const loggerConfigEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Logger Config',\n routePrefix: '/config',\n\n fields: {\n level: {\n name: 'level',\n label: 'Log Level',\n input: 'select',\n hint: 'Env: LOG_LEVEL (default: info)',\n db: { type: 'string', size: 10, nullable: false },\n options: {\n static: [\n { value: 'silent', label: 'Silent (sin logs)' },\n { value: 'fatal', label: 'Fatal' },\n { value: 'error', label: 'Error' },\n { value: 'warn', label: 'Warn' },\n { value: 'info', label: 'Info' },\n { value: 'debug', label: 'Debug' },\n { value: 'trace', label: 'Trace' }\n ]\n }\n },\n format: {\n name: 'format',\n label: 'Formato',\n input: 'select',\n hint: 'Env: LOG_FORMAT (default: pretty)',\n db: { type: 'string', size: 10, nullable: false },\n options: {\n static: [\n { value: 'pretty', label: 'Pretty (desarrollo)' },\n { value: 'json', label: 'JSON (producción)' }\n ]\n }\n },\n sentry_enabled: {\n name: 'sentry_enabled',\n label: 'Sentry Habilitado',\n input: 'switch',\n hint: 'Env: SENTRY_DSN (opcional)',\n db: { type: 'boolean', nullable: false }\n },\n sentry_environment: {\n name: 'sentry_environment',\n label: 'Sentry Environment',\n input: 'text',\n hint: 'Env: SENTRY_ENVIRONMENT (default: development)',\n db: { type: 'string', size: 50, nullable: true }\n },\n sentry_sample_rate: {\n name: 'sentry_sample_rate',\n label: 'Sentry Sample Rate',\n input: 'number',\n hint: 'Env: SENTRY_SAMPLE_RATE (default: 1.0)',\n db: { type: 'decimal', nullable: true }\n }\n },\n\n compute: async () => {\n const config = getLoggerConfig()\n return [{\n level: config.level,\n format: config.format,\n sentry_enabled: !!config.sentry,\n sentry_environment: config.sentry?.environment ?? null,\n sentry_sample_rate: config.sentry?.sampleRate ?? null\n }]\n },\n\n cache: { ttl: 0 },\n\n casl: {\n subject: 'LoggerConfig',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { getLoggerConfig } from './logger.config.js'\nimport { getLoggerService } from './logger.service.js'\n\n/**\n * Crea las rutas del módulo logger\n */\nexport function createLoggerRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { optionalAuth } = ctx.middleware\n\n /**\n * GET /logger/health\n * Estado del servicio de logging\n *\n * - Sin auth: solo status básico (para healthchecks externos)\n * - Con auth ADMIN: información completa de configuración\n */\n router.get('/health', optionalAuth!, (_req, res) => {\n const config = getLoggerConfig()\n const logger = getLoggerService()\n\n // Info básica para todos (healthchecks)\n const basicInfo = {\n status: 'ok',\n level: config.level\n }\n\n // Info completa solo para admins autenticados\n if (_req.user && _req.ability?.can('manage', 'all')) {\n res.json({\n ...basicInfo,\n format: config.format,\n sentry: {\n enabled: logger.isSentryEnabled(),\n environment: config.sentry?.environment ?? null\n }\n })\n return\n }\n\n res.json(basicInfo)\n })\n\n return router\n}\n","import type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { getLoggerConfig } from './logger.config.js'\nimport { initLoggerService, getPinoLogger } from './logger.service.js'\nimport { loggerConfigEntity } from './logger.entity.js'\nimport { createLoggerRoutes } from './logger.routes.js'\nimport { setLoggerInstance } from '../../core/logger.js'\n\n// Re-export types del módulo\nexport type { LoggerConfig, LoggerService } from './logger.types.js'\n\nexport const loggerModule: ModuleManifest = {\n name: 'logger',\n label: 'Logger',\n icon: 'mdi:text-box-outline',\n description: 'Centralized logging with Pino and optional Sentry integration',\n type: 'core',\n category: 'analytics',\n dependencies: [], // Sin dependencias - debe cargar primero\n definitions: [loggerConfigEntity],\n init: (ctx: ModuleContext) => {\n const config = getLoggerConfig()\n const service = initLoggerService(config)\n // Registrar servicio en ctx.services\n ctx.services['logger'] = service\n // Actualizar el logger global de shared/logger.ts\n setLoggerInstance(getPinoLogger())\n service.debug('Logger module initialized')\n },\n routes: createLoggerRoutes,\n routePrefix: '/logger'\n}\n\nexport default loggerModule\n","import { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Request, Response, ModuleContext, ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\nimport type { FieldDefinitionDTO, ModuleDTO, PluginDTO } from './system.types.js'\n\nfunction moduleHasSeedWithPath(mod: ModuleManifest, libPath: string): boolean {\n if (mod.seed) return true\n const seedPath = join(libPath, 'dist', 'modules', mod.name, `${mod.name}.seed.js`)\n return existsSync(seedPath)\n}\n\n/**\n * Convierte FieldDefinition a DTO serializable (sin funciones)\n */\nfunction toFieldDTO(name: string, field: Record<string, unknown>): FieldDefinitionDTO {\n const db = field['db'] as Record<string, unknown> | undefined\n const relation = field['relation'] as Record<string, unknown> | undefined\n const validation = field['validation'] as Record<string, unknown> | undefined\n const options = field['options'] as Record<string, unknown> | undefined\n const storage = field['storage'] as Record<string, unknown> | undefined\n const meta = field['meta'] as Record<string, unknown> | undefined\n\n return {\n name,\n label: field['label'] as string,\n input: field['input'] as string,\n placeholder: field['placeholder'] as string | undefined,\n hint: field['hint'] as string | undefined,\n hidden: field['hidden'] as boolean | undefined,\n disabled: field['disabled'] as boolean | undefined,\n db: {\n type: String(db?.['type'] ?? 'text'),\n nullable: db?.['nullable'] as boolean | undefined,\n default: db?.['default'],\n unique: db?.['unique'] as boolean | undefined,\n index: db?.['index'] as boolean | undefined\n },\n relation: relation ? {\n table: String(relation['table']),\n column: relation['column'] as string | undefined,\n labelField: relation['labelField'] as string | undefined,\n onDelete: relation['onDelete'] as string | undefined\n } : undefined,\n validation: validation ? {\n required: validation['required'] as boolean | undefined,\n min: validation['min'] as number | undefined,\n max: validation['max'] as number | undefined,\n pattern: validation['pattern'] as string | undefined,\n format: validation['format'] as string | undefined,\n enum: validation['enum'] as string[] | undefined\n } : undefined,\n options: options ? {\n endpoint: options['endpoint'] as string | undefined,\n valueField: options['valueField'] as string | undefined,\n labelField: options['labelField'] as string | undefined,\n static: options['static'] as Array<{ value: string; label: string }> | undefined\n } : undefined,\n storage: storage ? {\n accept: storage['accept'] as string | undefined,\n maxSize: storage['maxSize'] as number | undefined,\n maxFiles: storage['maxFiles'] as number | undefined,\n folder: storage['folder'] as string | undefined\n } : undefined,\n meta: meta ? {\n sortable: meta['sortable'] as boolean | undefined,\n searchable: meta['searchable'] as boolean | undefined\n } : undefined\n }\n}\n\nexport function createSystemController(ctx: ModuleContext) {\n const { errors, engine } = ctx\n\n function toModuleDTO(mod: ModuleManifest, libPath: string): ModuleDTO {\n return {\n name: mod.name,\n label: mod.label!,\n icon: mod.icon,\n description: mod.description,\n type: mod.type ?? 'core',\n dependencies: mod.dependencies ?? [],\n routePrefix: mod.routePrefix ?? `/${mod.name}`,\n subjects: engine.getModuleSubjects(mod),\n definitions: (mod.definitions ?? []).map(def => {\n const typesWithoutTable = ['action', 'external', 'virtual', 'computed', 'single']\n const hasTable = !typesWithoutTable.includes(def.type ?? 'collection')\n\n const fields: Record<string, FieldDefinitionDTO> = {}\n for (const [name, field] of Object.entries(def.fields)) {\n fields[name] = toFieldDTO(name, field as unknown as Record<string, unknown>)\n }\n\n return {\n table: hasTable ? (def as { table: string }).table : '',\n key: def.type === 'single' ? (def as { key: string }).key : undefined,\n type: def.type ?? 'collection',\n label: def.label,\n labelField: 'labelField' in def ? def.labelField : undefined,\n icon: 'icon' in def ? (def.icon as string) : undefined,\n routePrefix: 'routePrefix' in def ? (def.routePrefix as string) : undefined,\n order: 'order' in def ? (def.order as number) : undefined,\n fields,\n fieldsCount: Object.keys(fields).length,\n hasTimestamps: 'timestamps' in def ? !!def.timestamps : false,\n hasAudit: 'audit' in def ? !!def.audit : false,\n caslSubject: 'casl' in def ? def.casl?.subject : undefined\n }\n }),\n hasRoutes: !!mod.routes,\n hasMigrate: !!mod.migrate,\n hasSeed: moduleHasSeedWithPath(mod, libPath),\n hasInit: !!mod.init\n }\n }\n\n function toPluginDTO(plugin: PluginManifest): PluginDTO {\n return {\n name: plugin.name,\n code: plugin.code,\n label: plugin.label,\n icon: plugin.icon,\n category: plugin.category,\n version: plugin.version,\n description: plugin.description\n }\n }\n\n return {\n /**\n * GET /system/modules\n * Lista todos los módulos registrados\n */\n listModules(_req: Request, res: Response) {\n const libPath = ctx.helpers.getLibPath()\n const modules = engine.getModules().map(mod => toModuleDTO(mod, libPath))\n res.json({\n items: modules,\n total: modules.length,\n page: 1,\n limit: modules.length,\n totalPages: 1,\n hasNext: false\n })\n },\n\n /**\n * GET /system/modules/:name\n * Obtiene un módulo por nombre\n */\n getModule(req: Request<{ name: string }>, res: Response) {\n const { name } = req.params\n const mod = engine.getModules().find((m) => m.name === name)\n\n if (!mod) {\n throw new errors.NotFoundError('Módulo no encontrado')\n }\n\n res.json(toModuleDTO(mod, ctx.helpers.getLibPath()))\n },\n\n /**\n * GET /system/plugins\n * Lista todos los plugins registrados\n */\n listPlugins(_req: Request, res: Response) {\n const plugins = engine.getPlugins().map(toPluginDTO)\n res.json({\n items: plugins,\n total: plugins.length,\n page: 1,\n limit: plugins.length,\n totalPages: 1,\n hasNext: false\n })\n },\n\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { createSystemController } from './system.controller.js'\n\n/**\n * System Routes\n *\n * Auto-montaje desde definitions:\n * - moduleEntity, pluginEntity, osEntity (computed)\n */\nexport function createSystemRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const controller = createSystemController(ctx)\n\n // Rutas públicas - Información del sistema (sin auth)\n router.get('/modules', controller.listModules)\n router.get('/modules/:name', controller.getModule)\n router.get('/plugins', controller.listPlugins)\n\n // osEntity se auto-monta desde definitions (computed con routePrefix)\n\n return router\n}\n","import * as os from 'node:os'\nimport type { ComputedEntityDefinition, ModuleContext } from '@gzl10/nexus-sdk'\nimport type { ModuleComputedDTO, PluginComputedDTO, OsComputedDTO } from './system.types.js'\n\n/**\n * EntityDefinition para Módulos del sistema (computed)\n * Datos calculados en runtime desde el engine\n */\nexport const moduleEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Modules',\n labelField: 'name',\n routePrefix: '/modules',\n\n fields: {\n name: {\n name: 'name',\n label: 'Nombre',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false },\n meta: { sortable: true, searchable: true }\n },\n label: {\n name: 'label',\n label: 'Etiqueta',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false },\n meta: { sortable: true }\n },\n icon: {\n name: 'icon',\n label: 'Icono',\n input: 'text',\n db: { type: 'string', size: 50, nullable: true }\n },\n type: {\n name: 'type',\n label: 'Tipo',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n validation: { enum: ['core', 'plugin', 'auth-plugin', 'custom'] },\n options: {\n static: [\n { value: 'core', label: 'Core' },\n { value: 'plugin', label: 'Plugin' },\n { value: 'auth-plugin', label: 'Auth Plugin' },\n { value: 'custom', label: 'Custom' }\n ]\n },\n meta: { sortable: true }\n }\n },\n\n // Sin CASL - módulos son públicos\n casl: {\n subject: 'Module',\n permissions: {\n // Vacío = acceso público a lectura\n }\n },\n\n // Función que calcula los módulos desde el engine\n compute: async (ctx: ModuleContext): Promise<ModuleComputedDTO[]> => {\n return ctx.engine.getModules().map(mod => ({\n name: mod.name,\n label: mod.label!,\n icon: mod.icon,\n description: mod.description,\n type: mod.type ?? 'core',\n dependencies: mod.dependencies ?? [],\n routePrefix: mod.routePrefix ?? `/${mod.name}`,\n subjects: ctx.engine.getModuleSubjects(mod),\n definitionsCount: mod.definitions?.length ?? 0,\n hasRoutes: !!mod.routes,\n hasMigrate: !!mod.migrate,\n hasInit: !!mod.init\n }))\n },\n\n cache: {\n ttl: 60 // Cache de 60 segundos (módulos no cambian en runtime)\n }\n}\n\n/**\n * EntityDefinition para Plugins del sistema (computed)\n * Datos calculados en runtime desde el engine\n */\nexport const pluginEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Plugins',\n labelField: 'name',\n routePrefix: '/plugins',\n\n fields: {\n name: {\n name: 'name',\n label: 'Nombre',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false },\n meta: { sortable: true, searchable: true }\n },\n code: {\n name: 'code',\n label: 'Código',\n input: 'text',\n db: { type: 'string', size: 10, nullable: false },\n meta: { sortable: true }\n },\n label: {\n name: 'label',\n label: 'Etiqueta',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false },\n meta: { sortable: true }\n },\n version: {\n name: 'version',\n label: 'Versión',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false }\n },\n category: {\n name: 'category',\n label: 'Categoría',\n input: 'select',\n db: { type: 'string', size: 20, nullable: true },\n options: {\n static: [\n { value: 'content', label: 'Content' },\n { value: 'data', label: 'Data' },\n { value: 'storage', label: 'Storage' },\n { value: 'messaging', label: 'Messaging' },\n { value: 'jobs', label: 'Jobs' },\n { value: 'ai', label: 'AI' },\n { value: 'analytics', label: 'Analytics' },\n { value: 'integrations', label: 'Integrations' },\n { value: 'commerce', label: 'Commerce' },\n { value: 'security', label: 'Security' }\n ]\n },\n meta: { sortable: true }\n }\n },\n\n // Sin CASL - plugins son públicos\n casl: {\n subject: 'Plugin',\n permissions: {\n // Vacío = acceso público a lectura\n }\n },\n\n // Función que calcula los plugins desde el engine\n compute: async (ctx: ModuleContext): Promise<PluginComputedDTO[]> => {\n return ctx.engine.getPlugins().map(plugin => ({\n name: plugin.name,\n code: plugin.code,\n label: plugin.label,\n icon: plugin.icon,\n category: plugin.category,\n version: plugin.version,\n description: plugin.description\n }))\n },\n\n cache: {\n ttl: 60 // Cache de 60 segundos\n }\n}\n\n/**\n * EntityDefinition para información del Sistema Operativo (computed)\n * Datos calculados en runtime desde node:os\n */\nexport const osEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'OS Info',\n labelField: 'hostname',\n routePrefix: '/os',\n\n fields: {\n hostname: {\n name: 'hostname',\n label: 'Hostname',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false }\n },\n platform: {\n name: 'platform',\n label: 'Platform',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false },\n meta: { sortable: true }\n },\n arch: {\n name: 'arch',\n label: 'Architecture',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false }\n },\n release: {\n name: 'release',\n label: 'Release',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false }\n },\n type: {\n name: 'type',\n label: 'Type',\n input: 'text',\n db: { type: 'string', size: 30, nullable: false }\n },\n uptime: {\n name: 'uptime',\n label: 'Uptime (s)',\n input: 'number',\n db: { type: 'integer', nullable: false },\n meta: { sortable: true }\n },\n totalMemory: {\n name: 'totalMemory',\n label: 'Total Memory',\n input: 'number',\n db: { type: 'integer', nullable: false }\n },\n freeMemory: {\n name: 'freeMemory',\n label: 'Free Memory',\n input: 'number',\n db: { type: 'integer', nullable: false }\n },\n cpuCount: {\n name: 'cpuCount',\n label: 'CPU Count',\n input: 'number',\n db: { type: 'integer', nullable: false }\n },\n cpuModel: {\n name: 'cpuModel',\n label: 'CPU Model',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false }\n },\n loadAverage: {\n name: 'loadAverage',\n label: 'Load Average',\n input: 'hidden',\n db: { type: 'json', nullable: false }\n }\n },\n\n // Solo ADMIN - info del sistema es sensible\n casl: {\n subject: 'OsInfo',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n },\n\n compute: async (_ctx: ModuleContext): Promise<OsComputedDTO[]> => {\n const cpus = os.cpus()\n return [{\n hostname: os.hostname(),\n platform: os.platform(),\n arch: os.arch(),\n release: os.release(),\n type: os.type(),\n uptime: os.uptime(),\n totalMemory: os.totalmem(),\n freeMemory: os.freemem(),\n cpuCount: cpus.length,\n cpuModel: cpus[0]?.model ?? 'Unknown',\n loadAverage: os.loadavg()\n }]\n },\n\n cache: {\n ttl: 5 // Cache corto (5s) porque uptime/memory cambian\n }\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { createSystemRoutes } from './system.routes.js'\nimport { moduleEntity, pluginEntity, osEntity } from './system.entity.js'\n\n// Re-exports\nexport { createSystemController } from './system.controller.js'\nexport { moduleEntity, pluginEntity, osEntity } from './system.entity.js'\nexport type {\n Module,\n Plugin,\n OSInfo,\n Setting,\n FieldDefinitionDTO,\n EntityDefinitionDTO,\n ModuleDTO,\n PluginDTO,\n ModuleComputedDTO,\n PluginComputedDTO,\n OsComputedDTO\n} from './system.types.js'\n\nexport const systemModule: ModuleManifest = {\n name: 'system',\n label: 'System',\n icon: 'mdi:cog-outline',\n description: 'System configuration, module registry, and platform metadata',\n type: 'core',\n category: 'data',\n dependencies: ['logger'],\n definitions: [moduleEntity, pluginEntity, osEntity],\n // migrate: usa migración generada desde definitions\n routes: createSystemRoutes,\n routePrefix: '/system'\n}\n\nexport default systemModule\n","/**\n * Filesystem Storage Driver\n *\n * Almacena archivos en el sistema de archivos local.\n */\n\nimport { createReadStream, createWriteStream, existsSync, unlinkSync, mkdirSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { join, dirname, extname } from 'node:path'\nimport { createHash } from 'node:crypto'\nimport type { StorageDriver, StorageFile, PutOptions } from './driver.interface.js'\nimport type { StorageConfig } from '../storage.config.js'\n\nexport class FilesystemDriver implements StorageDriver {\n private basePath: string\n private baseUrl: string | undefined\n private generateId: () => string\n\n constructor(config: StorageConfig) {\n this.basePath = config.basePath\n this.baseUrl = config.baseUrl\n this.generateId = config.generateId\n\n // Crear directorio base si no existe\n if (!existsSync(this.basePath)) {\n mkdirSync(this.basePath, { recursive: true })\n }\n }\n\n async put(buffer: Buffer, filename: string, options?: PutOptions): Promise<StorageFile> {\n const id = this.generateId()\n const ext = extname(filename) || ''\n const diskFilename = `${id}${ext}`\n const folder = options?.folder || ''\n const relativePath = folder ? `${folder}/${diskFilename}` : diskFilename\n const fullPath = join(this.basePath, relativePath)\n\n // Crear subdirectorio si es necesario\n const dir = dirname(fullPath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n\n // Calcular hash SHA256\n const hash = createHash('sha256').update(buffer).digest('hex')\n\n // Escribir archivo\n await new Promise<void>((resolve, reject) => {\n const stream = createWriteStream(fullPath)\n stream.on('finish', resolve)\n stream.on('error', reject)\n stream.write(buffer)\n stream.end()\n })\n\n return {\n id,\n filename,\n diskFilename,\n mimetype: options?.mimetype || 'application/octet-stream',\n size: buffer.length,\n folder: folder || undefined,\n path: relativePath,\n url: this.getUrl(relativePath) || undefined,\n hash\n }\n }\n\n async get(path: string): Promise<NodeJS.ReadableStream> {\n const fullPath = join(this.basePath, path)\n if (!existsSync(fullPath)) {\n throw new Error(`File not found: ${path}`)\n }\n return createReadStream(fullPath)\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const fullPath = join(this.basePath, path)\n return readFile(fullPath)\n }\n\n async delete(path: string): Promise<void> {\n const fullPath = join(this.basePath, path)\n if (existsSync(fullPath)) {\n unlinkSync(fullPath)\n }\n }\n\n async exists(path: string): Promise<boolean> {\n const fullPath = join(this.basePath, path)\n return existsSync(fullPath)\n }\n\n getUrl(path: string): string | null {\n if (!this.baseUrl) return null\n return `${this.baseUrl}/files/${path}`\n }\n}\n","/**\n * S3 Storage Driver\n *\n * Almacena archivos en AWS S3 o compatible (MinIO, DigitalOcean Spaces, etc.)\n */\n\nimport { Readable } from 'node:stream'\nimport { createHash } from 'node:crypto'\nimport { extname } from 'node:path'\nimport {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n HeadObjectCommand\n} from '@aws-sdk/client-s3'\nimport type { StorageDriver, StorageFile, PutOptions } from './driver.interface.js'\nimport type { StorageConfig } from '../storage.config.js'\n\nexport class S3Driver implements StorageDriver {\n private client: S3Client\n private bucket: string\n private baseUrl: string | undefined\n private generateId: () => string\n\n constructor(config: StorageConfig) {\n if (!config.s3) {\n throw new Error('S3 configuration is required for S3Driver')\n }\n\n const { bucket, region, accessKeyId, secretAccessKey, endpoint } = config.s3\n\n this.bucket = bucket\n this.baseUrl = config.baseUrl\n this.generateId = config.generateId\n\n this.client = new S3Client({\n region,\n credentials: {\n accessKeyId,\n secretAccessKey\n },\n ...(endpoint && {\n endpoint,\n forcePathStyle: true // Necesario para MinIO\n })\n })\n }\n\n async put(buffer: Buffer, filename: string, options?: PutOptions): Promise<StorageFile> {\n const id = this.generateId()\n const ext = extname(filename) || ''\n const diskFilename = `${id}${ext}`\n const folder = options?.folder || ''\n const key = folder ? `${folder}/${diskFilename}` : diskFilename\n\n // Calcular hash SHA256\n const hash = createHash('sha256').update(buffer).digest('hex')\n\n // Subir a S3\n await this.client.send(new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: buffer,\n ContentType: options?.mimetype || 'application/octet-stream',\n ContentLength: buffer.length,\n Metadata: {\n 'original-filename': filename,\n 'sha256': hash\n }\n }))\n\n return {\n id,\n filename,\n diskFilename,\n mimetype: options?.mimetype || 'application/octet-stream',\n size: buffer.length,\n folder: folder || undefined,\n path: key,\n url: this.getUrl(key) || undefined,\n hash\n }\n }\n\n async get(path: string): Promise<NodeJS.ReadableStream> {\n const response = await this.client.send(new GetObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n\n if (!response.Body) {\n throw new Error(`File not found: ${path}`)\n }\n\n // El Body de S3 es un Readable stream\n return response.Body as Readable\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const response = await this.client.send(new GetObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n\n if (!response.Body) {\n throw new Error(`File not found: ${path}`)\n }\n\n // Convertir stream a buffer\n const stream = response.Body as Readable\n const chunks: Buffer[] = []\n\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk))\n }\n\n return Buffer.concat(chunks)\n }\n\n async delete(path: string): Promise<void> {\n await this.client.send(new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await this.client.send(new HeadObjectCommand({\n Bucket: this.bucket,\n Key: path\n }))\n return true\n } catch {\n return false\n }\n }\n\n getUrl(path: string): string | null {\n if (this.baseUrl) {\n return `${this.baseUrl}/files/${path}`\n }\n // URL pública de S3 (si el bucket tiene permisos públicos)\n return `https://${this.bucket}.s3.amazonaws.com/${path}`\n }\n}\n","/**\n * Storage Module Configuration\n *\n * Configuración para el sistema de almacenamiento de archivos.\n * Soporta filesystem local y S3 (AWS/MinIO).\n * Lee configuración desde BD (storage_config) con fallback a env vars.\n */\n\nimport { join, isAbsolute } from 'node:path'\nimport { existsSync, mkdirSync } from 'node:fs'\nimport type { Knex } from 'knex'\nimport type { FilesystemMetadata, S3Metadata } from './storage.types.js'\n\nconst TABLE = 'storage_config'\n\nexport interface StorageConfig {\n /** Scope de configuración (identificador único) */\n scope: string\n\n /** Driver de almacenamiento */\n driver: 'filesystem' | 's3'\n\n /** Ruta base para filesystem (default: ./storage) */\n basePath: string\n\n /** URL pública base para generar URLs de archivos */\n baseUrl?: string\n\n /** Tamaño máximo de archivo en bytes (default: 10MB) */\n maxFileSize: number\n\n /** Tipos MIME permitidos globalmente (opcional) */\n allowedMimeTypes?: string[]\n\n /** Generador de IDs (inyectado desde ctx.helpers) */\n generateId: () => string\n\n /** Configuración S3 */\n s3?: {\n bucket: string\n region: string\n accessKeyId: string\n secretAccessKey: string\n /** Endpoint personalizado para MinIO/otros proveedores */\n endpoint?: string\n }\n}\n\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\n\n/** Scope por defecto para filesystem */\nexport const DEFAULT_FILESYSTEM_SCOPE = 'default_filesystem'\n\n/** Scope por defecto para S3 */\nexport const DEFAULT_S3_SCOPE = 'default_s3'\n\n/** Scope por defecto según driver */\nfunction getDefaultScope(driver: 'filesystem' | 's3'): string {\n return driver === 's3' ? DEFAULT_S3_SCOPE : DEFAULT_FILESYSTEM_SCOPE\n}\n\n/** Config singleton para compatibilidad con código existente */\nlet defaultConfig: StorageConfig | null = null\n\n/** Project path para resolver rutas relativas */\nlet projectPath: string = process.cwd()\n\n/** GenerateId function */\nlet generateIdFn: (() => string) | null = null\n\n/**\n * Obtiene la configuración de storage por defecto (singleton)\n */\nexport function getStorageConfig(): StorageConfig {\n if (!defaultConfig) {\n throw new Error('StorageConfig not initialized. Call initStorageConfig() first.')\n }\n return defaultConfig\n}\n\n/**\n * Resuelve una ruta de storage:\n * - Rutas absolutas: se usan directamente\n * - Rutas relativas (./storage): se resuelven a projectPath/data/{path}\n */\nfunction resolveStoragePath(path: string, projPath: string): string {\n if (isAbsolute(path)) {\n return path\n }\n // Rutas relativas van dentro de data/\n const cleanPath = path.startsWith('./') ? path.slice(2) : path\n return join(projPath, 'data', cleanPath)\n}\n\n/**\n * Registro de BD para storage_config\n */\ninterface StorageConfigRow {\n scope: string\n driver: 'filesystem' | 's3'\n base_url: string | null\n max_file_size: number\n allowed_mime_types: string | null\n metadata: string | null\n}\n\n/**\n * Obtiene configuración de storage por scope desde BD\n * Fallback a variables de entorno si no existe en BD\n */\nexport async function getConfigByScope(\n db: Knex,\n scope: string\n): Promise<StorageConfig> {\n if (!generateIdFn) {\n throw new Error('StorageConfig not initialized. Call initStorageConfig() first.')\n }\n\n const row = await db(TABLE).where({ scope }).first<StorageConfigRow>()\n\n if (row) {\n return buildConfigFromRow(row)\n }\n\n // Fallback a env vars (usa config por defecto según driver esperado)\n const isS3Scope = scope.includes('s3')\n return buildConfigFromEnv(isS3Scope ? 's3' : 'filesystem')\n}\n\n/**\n * Construye StorageConfig desde un registro de BD\n */\nfunction buildConfigFromRow(row: StorageConfigRow): StorageConfig {\n const metadata = row.metadata ? JSON.parse(row.metadata) : {}\n\n const config: StorageConfig = {\n scope: row.scope,\n driver: row.driver,\n basePath: '',\n baseUrl: row.base_url || undefined,\n maxFileSize: row.max_file_size,\n allowedMimeTypes: row.allowed_mime_types?.split(',').map(t => t.trim()),\n generateId: generateIdFn!\n }\n\n if (row.driver === 'filesystem') {\n const fsMeta = metadata as FilesystemMetadata\n config.basePath = resolveStoragePath(fsMeta.basePath || './storage', projectPath)\n\n // Crear directorio si no existe\n if (!existsSync(config.basePath)) {\n mkdirSync(config.basePath, { recursive: true })\n }\n } else if (row.driver === 's3') {\n const s3Meta = metadata as S3Metadata\n config.basePath = '' // No aplica para S3\n config.s3 = {\n bucket: s3Meta.bucket,\n region: s3Meta.region,\n accessKeyId: s3Meta.accessKeyId,\n secretAccessKey: s3Meta.secretAccessKey,\n endpoint: s3Meta.endpoint\n }\n }\n\n return config\n}\n\n/**\n * Construye StorageConfig desde variables de entorno\n */\nfunction buildConfigFromEnv(driver: 'filesystem' | 's3'): StorageConfig {\n const config: StorageConfig = {\n scope: getDefaultScope(driver),\n driver,\n basePath: '',\n baseUrl: process.env['STORAGE_URL'],\n maxFileSize: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowedMimeTypes: process.env['STORAGE_ALLOWED_TYPES']?.split(',').map(t => t.trim()),\n generateId: generateIdFn!\n }\n\n if (driver === 'filesystem') {\n const rawPath = process.env['STORAGE_PATH'] || './storage'\n config.basePath = resolveStoragePath(rawPath, projectPath)\n\n if (!existsSync(config.basePath)) {\n mkdirSync(config.basePath, { recursive: true })\n }\n } else if (driver === 's3') {\n const bucket = process.env['S3_BUCKET']\n const region = process.env['S3_REGION']\n const accessKeyId = process.env['S3_ACCESS_KEY']\n const secretAccessKey = process.env['S3_SECRET_KEY']\n\n if (!bucket || !region || !accessKeyId || !secretAccessKey) {\n throw new Error('S3 configuration incomplete. Required: S3_BUCKET, S3_REGION, S3_ACCESS_KEY, S3_SECRET_KEY')\n }\n\n config.s3 = {\n bucket,\n region,\n accessKeyId,\n secretAccessKey,\n endpoint: process.env['S3_ENDPOINT']\n }\n }\n\n return config\n}\n\nexport interface InitStorageConfigOptions {\n projectPath?: string\n generateId: () => string\n}\n\n/**\n * Inicializa la configuración de storage (singleton por defecto)\n * Usa scope 'default_filesystem' desde BD si existe, sino env vars\n */\nexport function initStorageConfig(options: InitStorageConfigOptions): StorageConfig {\n projectPath = options.projectPath ?? process.cwd()\n generateIdFn = options.generateId\n\n // Config por defecto desde env vars (sync, para init rápido)\n const driver = (process.env['STORAGE_DRIVER'] as 'filesystem' | 's3') || 'filesystem'\n defaultConfig = buildConfigFromEnv(driver)\n\n return defaultConfig\n}\n","import type { Knex } from 'knex'\nimport { logger } from '../core/logger.js'\n\n/**\n * Get the database client type\n * Returns 'sqlite' as default when client type cannot be determined (e.g., in mocks)\n */\nexport function getDbClient(db: Knex): 'postgres' | 'mysql' | 'sqlite' {\n const client = (db.client?.config?.client ?? 'sqlite') as string\n if (client === 'pg' || client === 'postgresql') return 'postgres'\n if (client === 'mysql' || client === 'mysql2') return 'mysql'\n return 'sqlite'\n}\n\n/**\n * Format timestamp for database insert/update\n * - PostgreSQL: accepts ISO strings directly\n * - MySQL: requires 'YYYY-MM-DD HH:MM:SS' format\n * - SQLite: accepts ISO strings (stored as TEXT)\n *\n * @param db Knex instance to detect driver\n * @param date Date object (defaults to now)\n * @returns Formatted timestamp string\n */\nexport function formatTimestamp(db: Knex, date: Date = new Date()): string {\n const client = getDbClient(db)\n\n if (client === 'mysql') {\n // MySQL requires YYYY-MM-DD HH:MM:SS format\n return date.toISOString().slice(0, 19).replace('T', ' ')\n }\n\n // PostgreSQL and SQLite accept ISO strings\n return date.toISOString()\n}\n\n/**\n * Get current timestamp formatted for the database\n */\nexport function nowTimestamp(db: Knex): string {\n return formatTimestamp(db, new Date())\n}\n\n/**\n * Añade campos de timestamp a una tabla durante su creación\n * - PostgreSQL: usa timestamptz (timestamp with time zone)\n * - MySQL: usa timestamp estándar\n * - SQLite: usa TEXT con datetime('now') para consistencia con ISO strings\n */\nexport function addTimestamps(table: Knex.CreateTableBuilder, db: Knex) {\n const client = (db.client?.config?.client ?? 'sqlite3') as string\n const isPostgres = client === 'pg' || client === 'postgresql'\n const isSqlite = client === 'better-sqlite3' || client === 'sqlite3' || client === 'sqlite'\n\n if (isPostgres) {\n // PostgreSQL: usar timestamp with time zone\n table.timestamp('created_at', { useTz: true }).defaultTo(db.fn.now())\n table.timestamp('updated_at', { useTz: true }).defaultTo(db.fn.now())\n } else if (isSqlite) {\n // SQLite: usar datetime('now') que genera strings ISO directamente\n // Nota: SQLite requiere paréntesis extra para funciones en DEFAULT\n table.text('created_at').defaultTo(db.raw(\"(datetime('now'))\"))\n table.text('updated_at').defaultTo(db.raw(\"(datetime('now'))\"))\n } else {\n // MySQL: timestamp estándar\n table.timestamp('created_at').defaultTo(db.fn.now())\n table.timestamp('updated_at').defaultTo(db.fn.now())\n }\n}\n\n/**\n * Añade campos de auditoría (created_by, updated_by) a una tabla existente si no existen\n * Nota: SQLite no soporta ALTER TABLE ADD COLUMN con default no constante\n */\nexport async function addAuditFieldsIfMissing(db: Knex, tableName: string): Promise<void> {\n if (!(await db.schema.hasColumn(tableName, 'created_by'))) {\n await db.schema.alterTable(tableName, (table) => {\n // Sin FK para evitar dependencias circulares entre módulos\n table.string('created_by').nullable()\n table.string('updated_by').nullable()\n })\n logger.info(`Added audit fields to: ${tableName}`)\n }\n}\n\n/**\n * Añade campo is_default a tablas de tipo config\n * Permite marcar cuál configuración es la default en runtime\n */\nexport async function addConfigDefaultField(db: Knex, tableName: string): Promise<void> {\n if (!(await db.schema.hasColumn(tableName, 'is_default'))) {\n await db.schema.alterTable(tableName, (table) => {\n table.boolean('is_default').defaultTo(false).nullable()\n })\n logger.info(`Added is_default field to config table: ${tableName}`)\n }\n}\n\n/**\n * Añade una columna si no existe\n */\nexport async function addColumnIfMissing(\n db: Knex,\n tableName: string,\n columnName: string,\n columnBuilder: (table: Knex.AlterTableBuilder) => void\n): Promise<boolean> {\n if (!(await db.schema.hasColumn(tableName, columnName))) {\n await db.schema.alterTable(tableName, columnBuilder)\n logger.info(`Added column: ${tableName}.${columnName}`)\n return true\n }\n return false\n}\n","export class AppError extends Error {\n public readonly statusCode: number\n public readonly details?: unknown\n\n constructor(message: string, statusCode: number = 400, details?: unknown) {\n super(message)\n this.statusCode = statusCode\n this.details = details\n this.name = 'AppError'\n Error.captureStackTrace(this, this.constructor)\n }\n}\n\nexport class NotFoundError extends AppError {\n constructor(resource: string = 'Recurso') {\n super(`${resource} no encontrado`, 404)\n this.name = 'NotFoundError'\n }\n}\n\nexport class UnauthorizedError extends AppError {\n constructor(message: string = 'No autorizado') {\n super(message, 401)\n this.name = 'UnauthorizedError'\n }\n}\n\nexport class ForbiddenError extends AppError {\n constructor(message: string = 'Acceso denegado') {\n super(message, 403)\n this.name = 'ForbiddenError'\n }\n}\n\nexport class ConflictError extends AppError {\n constructor(message: string = 'Conflicto') {\n super(message, 409)\n this.name = 'ConflictError'\n }\n}\n\nexport class ValidationError extends AppError {\n public readonly errors: unknown[]\n\n constructor(message: string = 'Error de validación', errors: unknown[] = []) {\n super(message, 400)\n this.name = 'ValidationError'\n this.errors = errors\n }\n}\n","/**\n * Storage Service\n *\n * Servicio para gestión de archivos con soporte para thumbnails.\n * Soporta múltiples configuraciones de storage (scopes) desde BD.\n */\n\nimport type { Logger } from 'pino'\nimport type { Knex } from 'knex'\nimport sharp from 'sharp'\nimport type { StorageDriver, StorageFile } from './drivers/driver.interface.js'\nimport { FilesystemDriver } from './drivers/filesystem.driver.js'\nimport { S3Driver } from './drivers/s3.driver.js'\nimport { initStorageConfig, getConfigByScope, type StorageConfig } from './storage.config.js'\nimport type { UploadedFile, UploadOptions, StorageFileRecord } from './storage.types.js'\nimport type { LoggerReporter } from '@gzl10/nexus-sdk'\nimport { nowTimestamp } from '../../db/helpers.js'\nimport { ValidationError, NotFoundError } from '../../core/errors/app-error.js'\n\n// Re-export types for backwards compatibility\nexport type { UploadedFile, UploadOptions, StorageFileRecord } from './storage.types.js'\n\nconst TABLE = 'storage_files'\n\nlet storageServiceInstance: StorageService | null = null\n\n/**\n * Obtiene la instancia del servicio de storage\n */\nexport function getStorageService(): StorageService {\n if (!storageServiceInstance) {\n throw new Error('StorageService not initialized. Call initStorageService() first.')\n }\n return storageServiceInstance\n}\n\nexport interface InitStorageServiceOptions {\n db: Knex\n logger: Logger\n generateId: () => string\n loggerService?: LoggerReporter\n projectPath?: string\n}\n\n/**\n * Inicializa el servicio de storage\n */\nexport function initStorageService(options: InitStorageServiceOptions): StorageService {\n const { db, logger, generateId, loggerService, projectPath } = options\n const config = initStorageConfig({ projectPath, generateId })\n storageServiceInstance = new StorageService(db, config, logger, loggerService)\n return storageServiceInstance\n}\n\nexport class StorageService {\n private driver: StorageDriver\n private config: StorageConfig\n private db: Knex\n private logger: Logger\n private loggerService?: LoggerReporter\n /** Cache de drivers por scope */\n private driverCache: Map<string, StorageDriver> = new Map()\n\n constructor(db: Knex, config: StorageConfig, logger: Logger, loggerService?: LoggerReporter) {\n this.db = db\n this.config = config\n this.logger = logger.child({ service: 'storage' })\n this.loggerService = loggerService\n\n // Inicializar driver por defecto según configuración\n this.driver = this.createDriver(config)\n this.logger.debug({ driver: config.driver }, 'Storage driver initialized')\n }\n\n /**\n * Crea un driver según la configuración\n */\n private createDriver(config: StorageConfig): StorageDriver {\n switch (config.driver) {\n case 's3':\n return new S3Driver(config)\n case 'filesystem':\n default:\n return new FilesystemDriver(config)\n }\n }\n\n /**\n * Obtiene un driver por scope (con cache)\n */\n private async getDriverByScope(scope: string): Promise<{ driver: StorageDriver; config: StorageConfig }> {\n // Revisar cache primero\n const cached = this.driverCache.get(scope)\n if (cached) {\n // Obtener config para validaciones\n const config = await getConfigByScope(this.db, scope)\n return { driver: cached, config }\n }\n\n // Obtener config desde BD\n const config = await getConfigByScope(this.db, scope)\n const driver = this.createDriver(config)\n\n // Guardar en cache\n this.driverCache.set(scope, driver)\n this.logger.debug({ scope, driver: config.driver }, 'Driver created for scope')\n\n return { driver, config }\n }\n\n /**\n * Subir un archivo\n */\n async upload(file: UploadedFile, options?: UploadOptions): Promise<StorageFileRecord> {\n // Obtener driver y config según scope (o usar defaults)\n let driver = this.driver\n let config = this.config\n\n if (options?.scope) {\n const scoped = await this.getDriverByScope(options.scope)\n driver = scoped.driver\n config = scoped.config\n }\n\n // Validar tamaño\n if (file.size > config.maxFileSize) {\n throw new ValidationError(`File size ${file.size} exceeds limit ${config.maxFileSize}`)\n }\n\n // Validar tipo MIME\n if (config.allowedMimeTypes?.length) {\n const allowed = config.allowedMimeTypes.some(type => {\n if (type.endsWith('/*')) {\n return file.mimetype.startsWith(type.slice(0, -1))\n }\n return type === file.mimetype\n })\n if (!allowed) {\n throw new ValidationError(`File type ${file.mimetype} not allowed`)\n }\n }\n\n // Guardar archivo principal\n const storageFile = await driver.put(file.buffer, file.originalname, {\n folder: options?.folder,\n mimetype: file.mimetype\n })\n\n // Generar thumbnails si es imagen y se solicitan\n let thumbnailUrl: string | undefined\n if (options?.thumbnails?.length && this.isImage(file.mimetype)) {\n thumbnailUrl = await this.generateThumbnails(\n file.buffer,\n storageFile,\n options.thumbnails,\n options.folder,\n driver\n )\n }\n\n // Guardar metadatos en BD\n const now = nowTimestamp(this.db)\n const record: StorageFileRecord = {\n ...storageFile,\n url: storageFile.url || driver.getUrl(storageFile.path) || undefined,\n created_at: now,\n updated_at: now,\n created_by: options?.userId || null,\n updated_by: options?.userId || null\n }\n\n await this.db(TABLE).insert({\n id: record.id,\n filename: record.filename,\n disk_filename: record.diskFilename,\n mimetype: record.mimetype,\n size: record.size,\n folder: record.folder || null,\n scope: config.scope,\n path: record.path,\n url: record.url || null,\n thumbnail_url: thumbnailUrl || null,\n hash: record.hash || null,\n metadata: null,\n created_at: now,\n updated_at: now,\n created_by: record.created_by,\n updated_by: record.updated_by\n })\n\n this.logger.info({ id: record.id, filename: record.filename, size: record.size }, 'File uploaded')\n\n return {\n ...record,\n url: record.url,\n thumbnail_url: thumbnailUrl\n } as StorageFileRecord & { thumbnail_url?: string }\n }\n\n /**\n * Genera thumbnails para una imagen\n */\n private async generateThumbnails(\n buffer: Buffer,\n originalFile: StorageFile,\n sizes: Array<{ width: number; height: number }>,\n folder: string | undefined,\n driver: StorageDriver\n ): Promise<string | undefined> {\n // Generar el primer thumbnail como principal\n const firstSize = sizes[0]\n if (!firstSize) return undefined\n\n try {\n const thumbnailBuffer = await sharp(buffer)\n .resize(firstSize.width, firstSize.height, {\n fit: 'cover',\n position: 'center'\n })\n .jpeg({ quality: 80 })\n .toBuffer()\n\n const thumbnailFolder = folder\n ? `${folder}/thumbnails/${firstSize.width}x${firstSize.height}`\n : `thumbnails/${firstSize.width}x${firstSize.height}`\n\n const thumbnail = await driver.put(\n thumbnailBuffer,\n originalFile.filename.replace(/\\.[^.]+$/, '.jpg'),\n { folder: thumbnailFolder, mimetype: 'image/jpeg' }\n )\n\n this.logger.debug(\n { originalId: originalFile.id, size: `${firstSize.width}x${firstSize.height}` },\n 'Thumbnail generated'\n )\n\n // Generar thumbnails adicionales en background (no bloqueante)\n if (sizes.length > 1) {\n this.generateAdditionalThumbnails(buffer, originalFile, sizes.slice(1), folder, driver)\n .catch(err => {\n const error = err instanceof Error ? err : new Error('Error generating additional thumbnails')\n this.logger.error({ err }, 'Error generating additional thumbnails')\n this.loggerService?.captureException(error, { service: 'storage', action: 'thumbnail', originalId: originalFile.id })\n })\n }\n\n return thumbnail.url || driver.getUrl(thumbnail.path) || undefined\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Error generating thumbnail')\n this.logger.error({ err, originalId: originalFile.id }, 'Error generating thumbnail')\n this.loggerService?.captureException(error, { service: 'storage', action: 'thumbnail', originalId: originalFile.id })\n return undefined\n }\n }\n\n /**\n * Genera thumbnails adicionales en background\n */\n private async generateAdditionalThumbnails(\n buffer: Buffer,\n originalFile: StorageFile,\n sizes: Array<{ width: number; height: number }>,\n folder: string | undefined,\n driver: StorageDriver\n ): Promise<void> {\n for (const size of sizes) {\n try {\n const thumbnailBuffer = await sharp(buffer)\n .resize(size.width, size.height, {\n fit: 'cover',\n position: 'center'\n })\n .jpeg({ quality: 80 })\n .toBuffer()\n\n const thumbnailFolder = folder\n ? `${folder}/thumbnails/${size.width}x${size.height}`\n : `thumbnails/${size.width}x${size.height}`\n\n await driver.put(\n thumbnailBuffer,\n originalFile.filename.replace(/\\.[^.]+$/, '.jpg'),\n { folder: thumbnailFolder, mimetype: 'image/jpeg' }\n )\n\n this.logger.debug(\n { originalId: originalFile.id, size: `${size.width}x${size.height}` },\n 'Additional thumbnail generated'\n )\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Error generating additional thumbnail')\n this.logger.error({ err, size }, 'Error generating additional thumbnail')\n this.loggerService?.captureException(error, { service: 'storage', action: 'thumbnail', size })\n }\n }\n }\n\n /**\n * Verifica si un mimetype es de imagen\n */\n private isImage(mimetype: string): boolean {\n return mimetype.startsWith('image/')\n }\n\n /**\n * Obtener archivo por ID\n */\n async getById(id: string): Promise<StorageFileRecord | null> {\n const record = await this.db(TABLE).where('id', id).first()\n if (!record) return null\n\n return this.mapRecord(record)\n }\n\n /**\n * Obtener múltiples archivos por IDs\n */\n async getByIds(ids: string[]): Promise<StorageFileRecord[]> {\n if (ids.length === 0) return []\n\n const records = await this.db(TABLE).whereIn('id', ids)\n return records.map((r: unknown) => this.mapRecord(r))\n }\n\n /**\n * Obtener el driver apropiado para un scope\n * Si el scope coincide con el default, usa this.driver\n */\n private async getDriverForScope(scope: string | undefined): Promise<StorageDriver> {\n // Si no hay scope o es el scope por defecto, usar driver default\n if (!scope || scope === this.config.scope) {\n return this.driver\n }\n return (await this.getDriverByScope(scope)).driver\n }\n\n /**\n * Obtener stream de archivo\n */\n async getStream(id: string): Promise<NodeJS.ReadableStream> {\n const record = await this.getById(id)\n if (!record) {\n throw new NotFoundError(`File not found: ${id}`)\n }\n\n const driver = await this.getDriverForScope(record.scope)\n return driver.get(record.path)\n }\n\n /**\n * Obtener buffer de archivo\n */\n async getBuffer(id: string): Promise<Buffer> {\n const record = await this.getById(id)\n if (!record) {\n throw new NotFoundError(`File not found: ${id}`)\n }\n\n const driver = await this.getDriverForScope(record.scope)\n return driver.getBuffer(record.path)\n }\n\n /**\n * Eliminar archivo\n */\n async delete(id: string): Promise<void> {\n const record = await this.getById(id)\n if (!record) return\n\n const driver = await this.getDriverForScope(record.scope)\n\n // Eliminar de storage\n await driver.delete(record.path)\n\n // Eliminar de BD\n await this.db(TABLE).where('id', id).delete()\n\n this.logger.info({ id, filename: record.filename }, 'File deleted')\n }\n\n /**\n * Listar archivos con paginación\n */\n async findAll(params: {\n page: number\n limit: number\n folder?: string\n mimetype?: string\n }): Promise<{\n items: StorageFileRecord[]\n total: number\n page: number\n limit: number\n totalPages: number\n hasNext: boolean\n }> {\n const { page, limit, folder, mimetype } = params\n const offset = (page - 1) * limit\n\n let query = this.db(TABLE)\n\n if (folder) {\n query = query.where('folder', folder)\n }\n if (mimetype) {\n query = query.where('mimetype', 'like', `${mimetype}%`)\n }\n\n const [countResult, items] = await Promise.all([\n query.clone().count('* as count').first<{ count: string | number }>(),\n query.clone().orderBy('created_at', 'desc').limit(limit).offset(offset)\n ])\n\n const total = Number(countResult?.count ?? 0)\n const totalPages = Math.ceil(total / limit)\n\n return {\n items: items.map((r: unknown) => this.mapRecord(r)),\n total,\n page,\n limit,\n totalPages,\n hasNext: page < totalPages\n }\n }\n\n /**\n * Mapea un registro de BD a StorageFileRecord\n */\n private mapRecord(record: unknown): StorageFileRecord {\n const r = record as Record<string, unknown>\n return {\n id: r['id'] as string,\n filename: r['filename'] as string,\n diskFilename: r['disk_filename'] as string,\n mimetype: r['mimetype'] as string,\n size: r['size'] as number,\n folder: r['folder'] as string | undefined,\n scope: r['scope'] as string | undefined,\n path: r['path'] as string,\n url: r['url'] as string | undefined,\n hash: r['hash'] as string | undefined,\n created_at: r['created_at'] as string,\n updated_at: r['updated_at'] as string,\n created_by: r['created_by'] as string | null,\n updated_by: r['updated_by'] as string | null\n }\n }\n}\n","import rateLimit, { type Options } from 'express-rate-limit'\n\nexport interface RateLimitOptions {\n /** Time window in milliseconds (default: 60000 = 1 minute) */\n windowMs?: number\n /** Max requests per window (default: 100) */\n max?: number\n /** Message when limit is reached */\n message?: string\n}\n\n/**\n * Creates a rate limit middleware\n *\n * @example\n * // 100 requests per minute (default)\n * router.use(createRateLimit())\n *\n * @example\n * // 5 requests per 15 minutes for login\n * router.post('/login', createRateLimit({ windowMs: 15 * 60 * 1000, max: 5 }), handler)\n */\nexport function createRateLimit(options: RateLimitOptions = {}) {\n const {\n windowMs = 60 * 1000,\n max = 100,\n message = 'Too many requests, please try again later'\n } = options\n\n return rateLimit({\n windowMs,\n max,\n message: { error: message },\n standardHeaders: 'draft-7',\n legacyHeaders: false,\n // Skip trust proxy validation - we handle this at app level\n validate: { trustProxy: false }\n } satisfies Partial<Options>)\n}\n","import type { CollectionEntityDefinition, ConfigEntityDefinition, ActionEntityDefinition, ModuleContext, Request, Response } from '@gzl10/nexus-sdk'\nimport multer from 'multer'\nimport { getStorageService } from './storage.service.js'\nimport { getStorageConfig } from './storage.config.js'\nimport type { UploadedFile } from './storage.types.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\n// Re-export types for backwards compatibility\nexport type { FilesystemMetadata, S3Metadata, StorageDriverMetadata } from './storage.types.js'\n\n// ============================================================================\n// CONFIG ENTITY\n// ============================================================================\n\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\n\n/**\n * Config Entity: storage_config\n *\n * Campos comunes + metadata JSON para especialización por driver.\n */\nexport const storageConfigEntity: ConfigEntityDefinition = {\n type: 'config',\n table: 'storage_config',\n label: 'Storage Config',\n routePrefix: '/config',\n scopeField: 'scope',\n timestamps: true,\n\n // Defaults desde variables de entorno\n get defaults() {\n return {\n driver: process.env['STORAGE_DRIVER'] || 'filesystem',\n base_url: process.env['STORAGE_URL'] || '',\n max_file_size: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowed_mime_types: process.env['STORAGE_ALLOWED_TYPES'] || '',\n metadata: {}\n }\n },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n scope: {\n name: 'scope',\n label: 'Scope',\n disabled: true,\n input: 'text',\n hint: 'Identificador único (ej: default_filesystem, default_s3)',\n db: { type: 'string', size: 100, nullable: false, unique: true }\n },\n driver: {\n name: 'driver',\n label: 'Driver',\n input: 'select',\n hint: 'Backend de almacenamiento',\n db: { type: 'string', size: 20, nullable: false },\n validation: { required: true, enum: ['filesystem', 's3'] },\n options: {\n static: [\n { value: 'filesystem', label: 'Filesystem (local)' },\n { value: 's3', label: 'S3 (AWS/MinIO)' }\n ]\n }\n },\n base_url: {\n name: 'base_url',\n label: 'Base URL',\n input: 'url',\n hint: 'URL pública para generar enlaces a archivos',\n db: { type: 'string', size: 500, nullable: true }\n },\n max_file_size: {\n name: 'max_file_size',\n label: 'Max File Size (bytes)',\n input: 'number',\n hint: 'Tamaño máximo en bytes (default: 10MB = 10485760)',\n db: { type: 'integer', nullable: false }\n },\n allowed_mime_types: {\n name: 'allowed_mime_types',\n label: 'Allowed MIME Types',\n input: 'text',\n hint: 'Tipos permitidos separados por coma (ej: image/*,application/pdf)',\n db: { type: 'string', size: 1000, nullable: true }\n },\n metadata: {\n name: 'metadata',\n label: 'Driver Config',\n input: 'json',\n hint: 'Configuración específica del driver (filesystem: basePath, s3: bucket/region/keys)',\n db: { type: 'json', nullable: true }\n }\n },\n\n casl: {\n subject: 'StorageConfig',\n permissions: {\n ADMIN: { actions: ['read', 'update'] }\n }\n }\n}\n\n// ============================================================================\n// COLLECTION ENTITY\n// ============================================================================\n\n/**\n * EntityDefinition para Storage Files\n *\n * Almacena metadatos de archivos subidos al sistema.\n * Los archivos físicos se guardan en el driver configurado (filesystem/S3).\n */\nexport const storageFilesEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'storage_files',\n label: 'Storage Files',\n labelField: 'filename',\n timestamps: true,\n audit: true,\n routePrefix: '/files',\n\n actions: [\n {\n key: 'download',\n label: 'Download File',\n icon: 'mdi:download',\n method: 'GET',\n select: ['id', 'filename', 'mimetype', 'size'],\n handler: async (ctx: ModuleContext, input: unknown, _req?: Request, res?: Response) => {\n if (!res) {\n throw new ctx.errors.AppError('Response required for download', 500)\n }\n\n const { _record: file } = input as {\n _record: { id: string; filename: string; mimetype: string; size: number }\n }\n\n const storageService = getStorageService()\n const stream = await storageService.getStream(file.id)\n\n res.setHeader('Content-Type', file.mimetype)\n res.setHeader('Content-Disposition', `attachment; filename=\"${encodeURIComponent(file.filename)}\"`)\n res.setHeader('Content-Length', file.size.toString())\n\n stream.pipe(res)\n },\n casl: { action: 'read' }\n },\n {\n key: 'inline',\n label: 'View File',\n icon: 'mdi:eye',\n method: 'GET',\n select: ['id', 'filename', 'mimetype', 'size'],\n handler: async (ctx: ModuleContext, input: unknown, _req?: Request, res?: Response) => {\n if (!res) {\n throw new ctx.errors.AppError('Response required for inline view', 500)\n }\n\n const { _record: file } = input as {\n _record: { id: string; filename: string; mimetype: string; size: number }\n }\n\n const storageService = getStorageService()\n const stream = await storageService.getStream(file.id)\n\n res.setHeader('Content-Type', file.mimetype)\n res.setHeader('Content-Disposition', `inline; filename=\"${encodeURIComponent(file.filename)}\"`)\n res.setHeader('Content-Length', file.size.toString())\n\n stream.pipe(res)\n },\n casl: { action: 'read' }\n }\n ],\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n filename: {\n name: 'filename',\n label: 'Nombre original',\n input: 'text',\n db: { type: 'string', size: 255, nullable: false },\n validation: { required: true },\n meta: { sortable: true, searchable: true }\n },\n disk_filename: {\n name: 'disk_filename',\n label: 'Nombre en disco',\n input: 'hidden',\n db: { type: 'string', size: 255, nullable: false },\n validation: { required: true }\n },\n mimetype: {\n name: 'mimetype',\n label: 'Tipo MIME',\n input: 'text',\n db: { type: 'string', size: 100, nullable: false, index: true },\n validation: { required: true },\n meta: { sortable: true, searchable: true }\n },\n size: {\n name: 'size',\n label: 'Tamaño (bytes)',\n input: 'number',\n db: { type: 'integer', nullable: false },\n validation: { required: true, min: 0 },\n meta: { sortable: true }\n },\n folder: {\n name: 'folder',\n label: 'Carpeta',\n input: 'text',\n db: { type: 'string', size: 100, nullable: true, index: true },\n meta: { searchable: true }\n },\n scope: {\n name: 'scope',\n label: 'Storage Scope',\n input: 'hidden',\n db: { type: 'string', size: 50, nullable: true, index: true },\n hint: 'Storage configuration scope used for this file'\n },\n path: {\n name: 'path',\n label: 'Ruta completa',\n input: 'hidden',\n db: { type: 'string', size: 500, nullable: false },\n validation: { required: true }\n },\n url: {\n name: 'url',\n label: 'URL pública',\n input: 'url',\n db: { type: 'string', size: 500, nullable: true },\n meta: { exportable: true }\n },\n thumbnail_url: {\n name: 'thumbnail_url',\n label: 'URL thumbnail',\n input: 'url',\n db: { type: 'string', size: 500, nullable: true }\n },\n hash: {\n name: 'hash',\n label: 'Hash SHA256',\n input: 'hidden',\n db: { type: 'string', size: 64, nullable: true, index: true }\n },\n metadata: {\n name: 'metadata',\n label: 'Metadata',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n }\n },\n\n indexes: [\n { columns: ['folder', 'filename'] }\n ],\n\n casl: {\n subject: 'StorageFile',\n permissions: {\n ADMIN: {\n actions: ['manage']\n },\n EDITOR: {\n actions: ['create', 'read', 'delete'],\n conditions: { created_by: '${user.id}' }\n },\n VIEWER: {\n actions: ['read']\n }\n }\n }\n}\n\n// ============================================================================\n// ACTION ENTITIES\n// ============================================================================\n\n/**\n * Action: Upload File\n *\n * POST /storage/upload\n * Content-Type: multipart/form-data\n */\nexport const storageUploadAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Upload File',\n icon: 'mdi:upload',\n routePrefix: '/upload',\n successStatus: 201,\n\n fields: {\n file: {\n name: 'file',\n label: 'File',\n input: 'file',\n validation: { required: true }\n },\n folder: {\n name: 'folder',\n label: 'Folder',\n input: 'text',\n hint: 'Optional folder path'\n },\n scope: {\n name: 'scope',\n label: 'Storage Scope',\n input: 'text',\n hint: 'Storage config scope (default: uses default config)'\n }\n },\n\n middleware: (_ctx) => {\n const rateLimit = createRateLimit({ windowMs: 60 * 1000, max: 20, message: 'Demasiados uploads, intenta en 1 minuto' })\n const config = getStorageConfig()\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: config.maxFileSize }\n })\n return [rateLimit, upload.single('file')]\n },\n\n handler: async (ctx, _input, req, res) => {\n if (!req || !res) {\n throw new ctx.errors.AppError('Request and response required for upload', 500)\n }\n\n const authReq = req as AuthRequest\n const file = authReq.file as UploadedFile | undefined\n\n if (!file) {\n res.status(400).json({ error: 'No file provided' })\n return\n }\n\n const folder = req.body?.folder as string | undefined\n const scope = req.body?.scope as string | undefined\n\n const storageService = getStorageService()\n const result = await storageService.upload(\n {\n fieldname: file.fieldname,\n originalname: file.originalname,\n mimetype: file.mimetype,\n buffer: file.buffer,\n size: file.size\n },\n {\n folder,\n scope,\n userId: authReq.user?.id\n }\n )\n\n return result\n },\n\n casl: {\n subject: 'StorageFile',\n permissions: {\n ADMIN: { actions: ['execute'] },\n EDITOR: { actions: ['execute'] }\n }\n }\n}\n\n// NOTE: storageDownloadAction ha sido migrado a storageFilesEntity.actions[]\n// Ruta: GET /storage/files/download/:id\n","/**\n * Storage Routes\n *\n * Rutas adicionales para storage (upload multiple).\n * Las rutas principales (upload, download, inline) se manejan via EntityActions.\n */\n\nimport type { ModuleContext, Request, Response } from '@gzl10/nexus-sdk'\nimport multer from 'multer'\nimport { getStorageConfig } from './storage.config.js'\nimport { getStorageService, type UploadedFile } from './storage.service.js'\nimport { storageFilesEntity, storageConfigEntity } from './storage.entity.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\nexport function createStorageRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { auth } = ctx.middleware\n const config = getStorageConfig()\n\n // Configurar multer para almacenamiento en memoria\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: { fileSize: config.maxFileSize }\n })\n\n // ============================================================================\n // UPLOAD MULTIPLE (no hay action para esto aún)\n // ============================================================================\n\n const uploadMultiple = async (req: Request, res: Response): Promise<void> => {\n const authReq = req as AuthRequest\n const files = (req as { files?: Express.Multer.File[] }).files\n\n if (!files?.length) {\n res.status(400).json({ error: 'No files uploaded' })\n return\n }\n\n const folder = req.body?.['folder'] as string | undefined\n const storageService = getStorageService()\n const results = []\n\n for (const f of files) {\n const file: UploadedFile = {\n fieldname: f.fieldname,\n originalname: f.originalname,\n mimetype: f.mimetype,\n buffer: f.buffer,\n size: f.size\n }\n const result = await storageService.upload(file, {\n folder,\n userId: authReq.user?.id\n })\n results.push(result)\n }\n\n res.status(201).json(results)\n }\n\n // Rate limit para prevenir abuso de uploads\n const uploadRateLimit = createRateLimit({ windowMs: 60 * 1000, max: 20, message: 'Demasiados uploads, intenta en 1 minuto' })\n\n if (auth) {\n router.post('/upload/multiple', uploadRateLimit, auth, upload.array('files', 10), uploadMultiple)\n } else {\n router.post('/upload/multiple', uploadRateLimit, upload.array('files', 10), uploadMultiple)\n }\n\n // ============================================================================\n // CRUD para storage_files (runtime)\n // Las EntityActions 'download' e 'inline' se montan automáticamente\n // ============================================================================\n\n const filesService = ctx.createEntityService(storageFilesEntity)\n const filesController = ctx.createEntityController(filesService, storageFilesEntity)\n\n // Deshabilitar create y update via API REST estándar\n // Los archivos solo se crean via upload action\n delete filesController.create\n delete filesController.update\n\n // Sobrescribir delete para eliminar también el archivo físico\n filesController.delete = async (req: Request, res: Response): Promise<void> => {\n const id = req.params['id']\n if (!id) {\n res.status(400).json({ error: 'File ID required' })\n return\n }\n\n const storageService = getStorageService()\n const file = await storageService.getById(id)\n if (!file) {\n res.status(404).json({ error: 'File not found' })\n return\n }\n\n await storageService.delete(id)\n res.status(204).send()\n }\n\n const filesRouter = ctx.createEntityRouter(filesController, storageFilesEntity)\n router.use(storageFilesEntity.routePrefix ?? '/files', filesRouter)\n\n // ============================================================================\n // CONFIG (runtime)\n // ============================================================================\n\n const configService = ctx.createEntityService(storageConfigEntity)\n const configController = ctx.createEntityController(configService, storageConfigEntity)\n const configRouter = ctx.createEntityRouter(configController, storageConfigEntity)\n router.use(storageConfigEntity.routePrefix ?? '/config', configRouter)\n\n return router\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport type { FilesystemMetadata, S3Metadata } from './storage.entity.js'\nimport { DEFAULT_FILESYSTEM_SCOPE, DEFAULT_S3_SCOPE } from './storage.config.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nconst TABLE = 'storage_config'\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\n\n/**\n * Seed para storage: crea configuraciones iniciales desde variables de entorno\n *\n * Scopes creados:\n * - default_filesystem: siempre se crea con config filesystem\n * - default_s3: solo si S3_BUCKET está configurado\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n const now = nowTimestamp(db)\n\n // ============================================================================\n // FILESYSTEM CONFIG (siempre)\n // ============================================================================\n\n const existingFs = await db(TABLE).where({ scope: DEFAULT_FILESYSTEM_SCOPE }).first()\n if (!existingFs) {\n const fsMetadata: FilesystemMetadata = {\n basePath: process.env['STORAGE_PATH'] || './storage'\n }\n\n await db(TABLE).insert({\n id: generateId(),\n scope: DEFAULT_FILESYSTEM_SCOPE,\n driver: 'filesystem',\n base_url: process.env['STORAGE_URL'] || null,\n max_file_size: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowed_mime_types: process.env['STORAGE_ALLOWED_TYPES'] || null,\n metadata: JSON.stringify(fsMetadata),\n is_default: true,\n created_at: now,\n updated_at: now\n })\n logger.info(`Storage config seeded: ${DEFAULT_FILESYSTEM_SCOPE}`)\n } else {\n logger.debug(`Storage config ${DEFAULT_FILESYSTEM_SCOPE} already exists`)\n }\n\n // ============================================================================\n // S3 CONFIG (solo si hay bucket configurado)\n // ============================================================================\n\n const s3Bucket = process.env['S3_BUCKET']\n if (s3Bucket) {\n const existingS3 = await db(TABLE).where({ scope: DEFAULT_S3_SCOPE }).first()\n if (!existingS3) {\n const s3Region = process.env['S3_REGION']\n const s3AccessKey = process.env['S3_ACCESS_KEY']\n const s3SecretKey = process.env['S3_SECRET_KEY']\n\n if (!s3Region || !s3AccessKey || !s3SecretKey) {\n logger.warn('S3_BUCKET defined but missing S3_REGION, S3_ACCESS_KEY or S3_SECRET_KEY - skipping S3 seed')\n return\n }\n\n const s3Metadata: S3Metadata = {\n bucket: s3Bucket,\n region: s3Region,\n accessKeyId: s3AccessKey,\n secretAccessKey: s3SecretKey,\n endpoint: process.env['S3_ENDPOINT'] || undefined\n }\n\n await db(TABLE).insert({\n id: generateId(),\n scope: DEFAULT_S3_SCOPE,\n driver: 's3',\n base_url: process.env['STORAGE_URL'] || null,\n max_file_size: parseInt(process.env['STORAGE_MAX_SIZE'] || '') || DEFAULT_MAX_SIZE,\n allowed_mime_types: process.env['STORAGE_ALLOWED_TYPES'] || null,\n metadata: JSON.stringify(s3Metadata),\n is_default: false,\n created_at: now,\n updated_at: now\n })\n logger.info(`Storage config seeded: ${DEFAULT_S3_SCOPE}`)\n } else {\n logger.debug(`Storage config ${DEFAULT_S3_SCOPE} already exists`)\n }\n }\n}\n","/**\n * Storage Module\n *\n * Gestión de archivos con soporte para filesystem y S3.\n */\n\nimport type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { storageConfigEntity, storageFilesEntity, storageUploadAction } from './storage.entity.js'\nimport { initStorageService } from './storage.service.js'\nimport { createStorageRoutes } from './storage.routes.js'\n\n// Re-exports\nexport { StorageService, getStorageService } from './storage.service.js'\nexport { getStorageConfig, type StorageConfig } from './storage.config.js'\nexport type { StorageDriver, StorageFile, PutOptions } from './drivers/driver.interface.js'\nexport { FilesystemDriver } from './drivers/filesystem.driver.js'\nexport { S3Driver } from './drivers/s3.driver.js'\nexport { storageConfigEntity, storageFilesEntity, storageUploadAction } from './storage.entity.js'\n\n// Types from storage.types.ts\nexport type {\n FilesystemMetadata,\n S3Metadata,\n StorageDriverMetadata,\n UploadedFile,\n UploadOptions,\n StorageFileRecord\n} from './storage.types.js'\n\nexport const storageModule: ModuleManifest = {\n name: 'storage',\n label: 'Storage',\n icon: 'mdi:cloud-upload-outline',\n description: 'File storage and management',\n type: 'core',\n category: 'storage',\n dependencies: ['logger'],\n\n definitions: [storageConfigEntity, storageFilesEntity, storageUploadAction],\n\n routePrefix: '/storage',\n\n init: (ctx: ModuleContext) => {\n // Inicializar y registrar el servicio de storage\n const storageService = initStorageService({\n db: ctx.db,\n logger: ctx.logger,\n generateId: ctx.helpers.generateId,\n loggerService: ctx.services['logger'],\n projectPath: ctx.helpers.getProjectPath()\n })\n ctx.services['storage'] = storageService\n ctx.logger.debug('Storage service registered')\n },\n\n routes: (ctx: ModuleContext) => createStorageRoutes(ctx),\n\n // Import dinámico para evitar ciclos\n seed: async (ctx) => {\n const { seed } = await import('./storage.seed.js')\n await seed(ctx)\n }\n}\n\nexport default storageModule\n","import bcrypt from 'bcryptjs'\n\nconst SALT_ROUNDS = 10\n\n/**\n * Hash dummy para timing-safe login.\n * Se usa cuando el usuario no existe para evitar timing attacks.\n */\nexport const DUMMY_HASH = '$2a$10$N9qo8uLOickgx2ZMRZoMyeUv9rT7dRVqTMtKYzOYQVxZi1qU2cFaW'\n\n/**\n * Hashea un password con bcrypt\n */\nexport function hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, SALT_ROUNDS)\n}\n\n/**\n * Verifica un password contra su hash\n */\nexport function verifyPassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash)\n}\n","/**\n * Crypto utilities - shared across modules\n */\nexport { hashPassword, verifyPassword, DUMMY_HASH } from './hash.js'\n","import type { CollectionEntityDefinition, ModuleContext } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { nowTimestamp } from '../../db/helpers.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\n/**\n * EntityDefinition para Users\n *\n * Single source of truth para:\n * - Migraciones Knex (generateMigration)\n * - Schemas Zod (generateZodSchema)\n * - Tipos TypeScript (generateModel)\n * - Permisos CASL (generateCaslPermissions)\n */\nexport const userEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: \"users\",\n label: \"Users\",\n labelField: \"name\",\n timestamps: true,\n audit: true,\n order: 1,\n routePrefix: '/', // Monta en raíz del módulo: /users/*\n\n fields: {\n id: {\n name: \"id\",\n label: \"ID\",\n input: \"hidden\",\n db: { type: \"string\", size: 26, nullable: false },\n meta: { sortable: false },\n },\n email: {\n name: \"email\",\n label: \"Email\",\n input: \"email\",\n placeholder: \"usuario@ejemplo.com\",\n db: { type: \"string\", size: 255, nullable: false, unique: true },\n validation: { required: true, format: \"email\" },\n meta: { sortable: true, searchable: true },\n },\n password: {\n name: \"password\",\n label: \"Contraseña\",\n input: \"password\",\n placeholder: \"••••••••\",\n db: { type: \"string\", size: 255, nullable: false },\n validation: { required: true, min: 6 },\n meta: { exportable: false },\n },\n name: {\n name: \"name\",\n label: \"Nombre\",\n input: \"text\",\n placeholder: \"Nombre completo\",\n db: { type: \"string\", size: 255, nullable: false },\n validation: { required: true, min: 1 },\n meta: { sortable: true, searchable: true },\n },\n role_id: {\n name: \"role_id\",\n label: \"Rol\",\n input: \"select\",\n db: { type: \"string\", size: 26, nullable: false },\n relation: { table: \"roles\", column: \"id\" },\n validation: { required: true },\n options: {\n endpoint: \"/users/roles\",\n valueField: \"id\",\n labelField: \"name\",\n },\n meta: {\n searchable: true,\n // Solo ADMIN puede modificar el rol\n casl: { writeRoles: [\"ADMIN\"] },\n },\n },\n metadata: {\n name: \"metadata\",\n label: \"Metadata\",\n input: \"hidden\",\n db: { type: \"json\", nullable: true },\n meta: {\n exportable: false,\n // Solo ADMIN puede ver/modificar metadata\n casl: { readRoles: [\"ADMIN\"], writeRoles: [\"ADMIN\"] },\n },\n },\n avatar: {\n name: \"avatar\",\n label: \"Avatar\",\n input: \"image\",\n db: { type: \"string\", size: 26, nullable: true },\n relation: { table: \"storage_files\", column: \"id\", onDelete: \"SET NULL\" },\n storage: {\n accept: \"image/*\",\n maxSize: 2 * 1024 * 1024, // 2MB\n folder: \"avatars\",\n thumbnails: [{ width: 128, height: 128 }],\n },\n meta: { exportable: false },\n },\n },\n\n // Entity Actions\n actions: [\n {\n key: 'change-password',\n label: 'Change Password',\n icon: 'mdi:lock-reset',\n method: 'POST',\n select: ['id', 'password'],\n inputSchema: z.object({\n currentPassword: z.string().min(1, 'Current password is required'),\n newPassword: z.string().min(6, 'Password must be at least 6 characters')\n }),\n middleware: () => createRateLimit({ windowMs: 15 * 60 * 1000, max: 5, message: 'Demasiados intentos, intenta en 15 minutos' }),\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { _record: user, currentPassword, newPassword } = input as {\n _record: { id: string; password: string }\n currentPassword: string\n newPassword: string\n }\n const { verifyPassword, hashPassword } = await import('../../core/crypto/index.js')\n\n // Verificar password actual\n const isValid = await verifyPassword(currentPassword, user.password)\n if (!isValid) {\n throw new ctx.errors.UnauthorizedError('Current password is incorrect')\n }\n\n // Hash y actualizar\n const hashedPassword = await hashPassword(newPassword)\n await ctx.db('users').where('id', user.id).update({\n password: hashedPassword,\n updated_at: nowTimestamp(ctx.db)\n })\n\n return { updated: true }\n },\n casl: { action: 'update' }\n }\n ],\n\n // Autorización CASL\n casl: {\n subject: \"User\",\n sensitiveFields: [\"password\"],\n permissions: {\n ADMIN: {\n actions: [\"manage\"],\n },\n EDITOR: {\n actions: [\"read\"],\n },\n VIEWER: {\n // Solo puede ver su propio perfil\n actions: [\"read\", \"update\"],\n conditions: { id: \"${user.id}\" },\n },\n },\n },\n};\n\n/**\n * EntityDefinition para Roles\n */\nexport const roleEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'roles',\n label: 'Roles',\n labelField: 'name',\n timestamps: true,\n audit: true,\n order: 10,\n routePrefix: '/roles', // Monta en /users/roles/*\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n name: {\n name: 'name',\n label: 'Nombre',\n input: 'text',\n placeholder: 'ROLE_NAME',\n db: { type: 'string', size: 50, nullable: false, unique: true },\n validation: { required: true, min: 2, max: 50, pattern: '^[A-Z_]+$' },\n meta: { sortable: true, searchable: true }\n },\n description: {\n name: 'description',\n label: 'Descripción',\n input: 'text',\n db: { type: 'string', size: 255, nullable: true },\n meta: { sortable: false }\n },\n is_system: {\n name: 'is_system',\n label: 'Sistema',\n input: 'checkbox',\n disabled: true,\n db: { type: 'boolean', nullable: false, default: false },\n meta: { sortable: true }\n }\n },\n\n casl: {\n subject: 'Role',\n permissions: {\n ADMIN: {\n actions: ['manage']\n }\n }\n }\n}\n\n/**\n * EntityDefinition para Role Permissions\n */\nexport const rolePermissionEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'role_permissions',\n label: 'Permissions',\n labelField: 'action',\n timestamps: true,\n order: 20,\n audit: true,\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n role_id: {\n name: 'role_id',\n label: 'Rol',\n input: 'select',\n db: { type: 'string', size: 26, nullable: false },\n relation: { table: 'roles', column: 'id', onDelete: 'CASCADE' },\n validation: { required: true },\n options: { endpoint: '/users/roles', valueField: 'id', labelField: 'name' },\n meta: { searchable: true }\n },\n action: {\n name: 'action',\n label: 'Acción',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n validation: { required: true, enum: ['manage', 'create', 'read', 'update', 'delete'] },\n options: {\n static: [\n { value: 'manage', label: 'Manage (all)' },\n { value: 'create', label: 'Create' },\n { value: 'read', label: 'Read' },\n { value: 'update', label: 'Update' },\n { value: 'delete', label: 'Delete' }\n ]\n },\n meta: { sortable: true }\n },\n subject: {\n name: 'subject',\n label: 'Subject',\n input: 'text',\n db: { type: 'string', size: 50, nullable: false },\n validation: { required: true },\n meta: { sortable: true, searchable: true }\n },\n conditions: {\n name: 'conditions',\n label: 'Condiciones',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n },\n fields: {\n name: 'fields',\n label: 'Campos',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n },\n inverted: {\n name: 'inverted',\n label: 'Invertido',\n input: 'checkbox',\n db: { type: 'boolean', nullable: false, default: false }\n }\n },\n\n indexes: [\n { columns: ['role_id', 'action', 'subject'], unique: true }\n ],\n\n casl: {\n subject: 'RolePermission',\n permissions: {\n ADMIN: {\n actions: ['manage']\n }\n }\n }\n}\n\n","/**\n * Users Routes - Uses runtime with custom services\n *\n * Estructura:\n * - /users/* → CRUD Users (runtime auto-generado)\n * - /users/roles/* → CRUD Roles (runtime auto-generado)\n * - /users/roles/permissions → List all permissions\n * - /users/roles/permissions/:id → Update role permissions\n * - /users/change-password/:id → Change user password (entity action)\n */\n\nimport type { Request, Response, ModuleContext, Router } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { userEntity, roleEntity } from './users.entity.js'\nimport type { createUsersService } from './users.service.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\n\n// ============================================================================\n// Schemas para endpoints especiales\n// ============================================================================\n\nexport const permissionSchema = z.object({\n action: z.enum(['manage', 'create', 'read', 'update', 'delete']),\n subject: z.string().min(1),\n conditions: z.record(z.unknown()).optional(),\n fields: z.array(z.string()).optional(),\n inverted: z.boolean().default(false)\n})\n\nexport const updatePermissionsSchema = z.object({\n permissions: z.array(permissionSchema)\n})\n\nconst roleParamsSchema = z.object({\n id: z.string().min(1)\n})\n\nexport type PermissionInput = z.infer<typeof permissionSchema>\nexport type UpdatePermissionsInput = z.infer<typeof updatePermissionsSchema>\n\n// ============================================================================\n// Routes Factory\n// ============================================================================\n\nexport function createUsersRoutes(ctx: ModuleContext): Router {\n const router = ctx.createRouter()\n const { auth, validate } = ctx.middleware\n const { ForbiddenError: CASLForbiddenError } = ctx.abilities\n\n // Obtener servicio registrado en init() via createUsersService()\n const users = ctx.services['users'] as ReturnType<typeof createUsersService>\n const usersService = users\n const rolesService = users.roles\n\n // ============================================================================\n // USERS ROUTES (runtime auto-generado con CASL)\n // ============================================================================\n\n const usersController = ctx.createEntityController(usersService, userEntity)\n\n // Interceptar delete para añadir validación \"no puedes eliminarte a ti mismo\"\n const originalUsersDelete = usersController.delete\n if (originalUsersDelete) {\n usersController.delete = async (req: Request, res: Response) => {\n const authReq = req as AuthRequest\n const id = req.params['id'] ?? ''\n\n if (authReq.user?.id === id) {\n throw new ctx.errors.ForbiddenError('No puedes eliminarte a ti mismo')\n }\n\n return originalUsersDelete(req, res)\n }\n }\n\n // ============================================================================\n // ROLES ROUTES (montar ANTES de users para evitar que /:id capture /roles)\n // ============================================================================\n\n const rolesController = ctx.createEntityController(rolesService, roleEntity)\n const rolesRouter = ctx.createEntityRouter(rolesController, roleEntity)\n const rolesPrefix = roleEntity.routePrefix ?? '/roles'\n\n // Endpoints especiales (montar ANTES de las rutas CRUD para evitar conflictos con :id)\n\n // --- GET /roles/permissions (listar todos los permisos) ---\n router.get(`${rolesPrefix}/permissions`,\n auth!,\n async (req: Request, res: Response) => {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('read', 'Permission')\n\n const result = await rolesService.findAllPermissions(req.query as Record<string, unknown>)\n // result ya es PaginatedResult { data, total, page, limit }\n res.json(result)\n }\n )\n\n // --- PUT /roles/permissions/:id ---\n router.put(`${rolesPrefix}/permissions/:id`,\n auth!,\n validate({ params: roleParamsSchema, body: updatePermissionsSchema }),\n async (req: Request, res: Response) => {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('update', 'Role')\n\n const { id } = req.validated?.params as { id: string }\n const { permissions } = req.body as UpdatePermissionsInput\n\n const role = await rolesService.updatePermissions(id, permissions, authReq.user?.id)\n res.json(role)\n }\n )\n\n // Montar rutas CRUD de roles\n router.use(rolesPrefix, rolesRouter)\n\n // ============================================================================\n // USERS ROUTES (montar DESPUÉS de roles para que /roles no sea capturado por /:id)\n // ============================================================================\n\n const usersRouter = ctx.createEntityRouter(usersController, userEntity)\n router.use(userEntity.routePrefix ?? '/', usersRouter)\n\n return router\n}\n","/**\n * Users Service - Composición con createEntityService + hooks\n *\n * Usa ctx.createEntityService en lugar de herencia para:\n * - Password hashing en beforeCreate/beforeUpdate\n * - Email uniqueness validation\n * - System roles protection\n * - User-role joins en findAll/findById\n */\n\nimport type { ModuleContext, PaginatedResult, CollectionEntityService, EntityQuery } from '@gzl10/nexus-sdk'\nimport type {\n User,\n Role,\n Permission,\n UserWithoutPassword,\n UserPresence,\n UserWithRole,\n RoleWithPermissions,\n RoleWithCounts,\n PermissionInput,\n PermissionWithRole\n} from './users.types.js'\nimport { userEntity, roleEntity } from './users.entity.js'\n\n// Re-export types for backwards compatibility\nexport type {\n UserWithoutPassword,\n UserPresence,\n UserWithRole,\n RoleWithPermissions,\n RoleWithCounts,\n PermissionInput,\n PermissionWithRole\n} from './users.types.js'\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\n/** Parse JSON fields from permission rows */\nfunction parsePermission(p: Record<string, unknown>): Permission {\n return {\n ...p,\n conditions: typeof p['conditions'] === 'string' ? JSON.parse(p['conditions']) : p['conditions'],\n fields: typeof p['fields'] === 'string' ? JSON.parse(p['fields']) : p['fields']\n } as Permission\n}\n\n// ============================================================================\n// FACTORY FUNCTION\n// ============================================================================\n\n/**\n * Factory function para crear servicio de usuarios\n * Usa composición con createEntityService + hooks\n */\nexport function createUsersService(ctx: ModuleContext) {\n const { db, errors, helpers: { generateId, nowTimestamp }, crypto: { hashPassword }, socket } = ctx\n const { isUserConnected, getUserSocketCount } = socket\n const USERS_TABLE = 'users'\n const ROLES_TABLE = 'roles'\n const PERMISSIONS_TABLE = 'role_permissions'\n\n // ============================================================================\n // USERS SERVICE (composición)\n // ============================================================================\n\n const baseUsersService = ctx.createEntityService<User>(userEntity, {\n hooks: {\n beforeCreate: async (data) => {\n const processed = { ...data }\n\n // 1. Hash password\n if (processed.password) {\n processed.password = await hashPassword(processed.password)\n }\n\n // 2. Validar email único\n if (processed.email) {\n const existing = await db(USERS_TABLE).where({ email: processed.email }).first()\n if (existing) {\n throw new errors.ConflictError('El email ya está en uso')\n }\n }\n\n // 3. Validar rol existe\n if (processed.role_id) {\n const role = await db(ROLES_TABLE).where({ id: processed.role_id }).first()\n if (!role) {\n throw new errors.NotFoundError('Rol')\n }\n }\n\n return processed\n },\n\n beforeUpdate: async (id, data) => {\n const processed = { ...data }\n\n // 1. Hash password si cambia\n if (processed.password) {\n processed.password = await hashPassword(processed.password)\n }\n\n // 2. Validar email único (excluyendo actual)\n if (processed.email) {\n const existing = await db(USERS_TABLE)\n .where({ email: processed.email })\n .whereNot({ id })\n .first()\n if (existing) {\n throw new errors.ConflictError('El email ya está en uso')\n }\n }\n\n // 3. Validar rol existe\n if (processed.role_id) {\n const role = await db(ROLES_TABLE).where({ id: processed.role_id }).first()\n if (!role) {\n throw new errors.NotFoundError('Rol')\n }\n }\n\n return processed\n }\n }\n }) as CollectionEntityService<User>\n\n // Helpers para mapear rows\n function excludePassword(user: User): UserWithoutPassword {\n const { password: _, ...rest } = user\n return rest\n }\n\n function mapRowToUserWithRole(row: Record<string, unknown>): UserWithRole {\n const {\n password: _,\n role_name,\n role_description,\n role_is_system,\n role_created_at,\n role_updated_at,\n ...user\n } = row\n\n const userId = user['id'] as string\n\n return {\n ...user,\n role: user['role_id']\n ? {\n id: user['role_id'] as string,\n name: role_name as string,\n description: role_description as string | null,\n is_system: role_is_system as boolean,\n created_at: role_created_at as Date,\n updated_at: role_updated_at as Date\n }\n : null,\n presence: {\n isOnline: isUserConnected(userId),\n socketCount: getUserSocketCount(userId)\n }\n } as UserWithRole\n }\n\n // Métodos de usuarios con lógica personalizada\n const usersService = {\n /**\n * findAll con JOIN de roles\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<UserWithRole>> {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n\n const selectColumns = [\n `${USERS_TABLE}.*`,\n `${ROLES_TABLE}.name as role_name`,\n `${ROLES_TABLE}.description as role_description`,\n `${ROLES_TABLE}.is_system as role_is_system`,\n `${ROLES_TABLE}.created_at as role_created_at`,\n `${ROLES_TABLE}.updated_at as role_updated_at`\n ]\n\n let qb = db(USERS_TABLE)\n .select(...selectColumns)\n .leftJoin(ROLES_TABLE, `${USERS_TABLE}.role_id`, `${ROLES_TABLE}.id`)\n\n // Apply role_id filter\n let countQb = db(USERS_TABLE).count('* as count')\n const roleIdFilter = (query as Record<string, unknown>)?.['role_id'] ?? query?.filters?.['role_id']\n if (roleIdFilter) {\n qb = qb.where(`${USERS_TABLE}.role_id`, roleIdFilter)\n countQb = countQb.where('role_id', roleIdFilter)\n }\n\n const countResult = await countQb.first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n qb = qb.orderBy(`${USERS_TABLE}.created_at`, 'desc')\n qb = qb.limit(limit).offset(offset)\n\n const rows = await qb as Record<string, unknown>[]\n const items = rows.map(mapRowToUserWithRole)\n\n const totalPages = Math.ceil(total / limit)\n return { items, total, page, limit, totalPages, hasNext: page < totalPages }\n },\n\n /**\n * findById sin password\n */\n async findById(id: string): Promise<UserWithoutPassword> {\n const user = await baseUsersService.findById(id)\n if (!user) throw new errors.NotFoundError('Usuario')\n return excludePassword(user)\n },\n\n /**\n * findByIdWithRole - usuario con rol incluido\n */\n async findByIdWithRole(id: string): Promise<UserWithRole | null> {\n const selectColumns = [\n `${USERS_TABLE}.*`,\n `${ROLES_TABLE}.name as role_name`,\n `${ROLES_TABLE}.description as role_description`,\n `${ROLES_TABLE}.is_system as role_is_system`,\n `${ROLES_TABLE}.created_at as role_created_at`,\n `${ROLES_TABLE}.updated_at as role_updated_at`\n ]\n\n const row = await db(USERS_TABLE)\n .select(...selectColumns)\n .leftJoin(ROLES_TABLE, `${USERS_TABLE}.role_id`, `${ROLES_TABLE}.id`)\n .where(`${USERS_TABLE}.id`, id)\n .first() as Record<string, unknown> | undefined\n\n if (!row) return null\n return mapRowToUserWithRole(row)\n },\n\n /**\n * findByIdWithPassword - para autenticación\n */\n async findByIdWithPassword(id: string): Promise<User | null> {\n return baseUsersService.findById(id)\n },\n\n /**\n * create con userId para audit (retorna sin password)\n */\n async create(data: Record<string, unknown>, userId?: string): Promise<UserWithoutPassword> {\n const user = await baseUsersService.create({ ...data, created_by: userId ?? null })\n return excludePassword(user)\n },\n\n /**\n * update con userId para audit (retorna sin password)\n */\n async update(id: string, data: Record<string, unknown>, userId?: string): Promise<UserWithoutPassword> {\n const user = await baseUsersService.update(id, { ...data, updated_by: userId ?? null })\n return excludePassword(user)\n },\n\n /**\n * delete\n */\n async delete(id: string) {\n return baseUsersService.delete(id)\n }\n }\n\n // ============================================================================\n // ROLES SERVICE (composición)\n // ============================================================================\n\n const baseRolesService = ctx.createEntityService<Role>(roleEntity, {\n hooks: {\n beforeCreate: async (data) => {\n if (data.name) {\n const existing = await db(ROLES_TABLE).where({ name: data.name }).first()\n if (existing) {\n throw new errors.ConflictError('Ya existe un rol con ese nombre')\n }\n }\n return data\n },\n\n beforeUpdate: async (id, data) => {\n const role = await db(ROLES_TABLE).where({ id }).first() as Role | undefined\n\n if (role?.is_system) {\n throw new errors.ForbiddenError('No se pueden modificar roles del sistema')\n }\n\n if (data.name && data.name !== role?.name) {\n const existing = await db(ROLES_TABLE).where({ name: data.name }).first()\n if (existing) {\n throw new errors.ConflictError('Ya existe un rol con ese nombre')\n }\n }\n\n return data\n },\n\n beforeDelete: async (id) => {\n const role = await db(ROLES_TABLE).where({ id }).first() as Role | undefined\n\n if (role?.is_system) {\n throw new errors.ForbiddenError('No se pueden eliminar roles del sistema')\n }\n\n const usersCount = await db(USERS_TABLE)\n .where({ role_id: id })\n .count('* as count')\n .first<{ count: string | number }>()\n\n if (Number(usersCount?.count ?? 0) > 0) {\n throw new errors.ConflictError('No se puede eliminar un rol con usuarios asignados')\n }\n }\n }\n }) as CollectionEntityService<Role>\n\n const rolesService = {\n /**\n * findAll con conteos\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<RoleWithCounts>> {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n\n const permissionsCountSubquery = db(PERMISSIONS_TABLE)\n .count('*')\n .whereRaw(`${PERMISSIONS_TABLE}.role_id = ${ROLES_TABLE}.id`)\n .as('permissions_count')\n\n const usersCountSubquery = db(USERS_TABLE)\n .count('*')\n .whereRaw(`${USERS_TABLE}.role_id = ${ROLES_TABLE}.id`)\n .as('users_count')\n\n const baseQuery = db(ROLES_TABLE)\n .select(`${ROLES_TABLE}.*`, permissionsCountSubquery, usersCountSubquery)\n\n const [roles, countResult] = await Promise.all([\n baseQuery.clone().orderBy('name', 'asc').limit(limit).offset(offset),\n db(ROLES_TABLE).count('* as count').first<{ count: string | number }>()\n ])\n\n const total = Number(countResult?.count ?? 0)\n const items = (roles as Record<string, unknown>[]).map((role) => ({\n ...role,\n permissions_count: Number(role['permissions_count'] ?? 0),\n users_count: Number(role['users_count'] ?? 0)\n })) as RoleWithCounts[]\n\n const totalPages = Math.ceil(total / limit)\n return { items, total, page, limit, totalPages, hasNext: page < totalPages }\n },\n\n /**\n * findById con permisos\n */\n async findById(id: string): Promise<RoleWithPermissions> {\n const role = await baseRolesService.findById(id)\n if (!role) throw new errors.NotFoundError('Rol')\n\n const permissions = await db(PERMISSIONS_TABLE)\n .where({ role_id: id })\n .orderBy('subject', 'asc')\n .orderBy('action', 'asc') as Record<string, unknown>[]\n\n return { ...role, permissions: permissions.map(parsePermission) }\n },\n\n /**\n * findByName\n */\n async findByName(name: string): Promise<Role | undefined> {\n return db(ROLES_TABLE).where({ name }).first() as Promise<Role | undefined>\n },\n\n /**\n * getPermissionsByRoleId\n */\n async getPermissionsByRoleId(roleId: string): Promise<Permission[]> {\n const permissions = await db(PERMISSIONS_TABLE).where({ role_id: roleId }) as Record<string, unknown>[]\n return permissions.map(parsePermission)\n },\n\n /**\n * findAllPermissions\n */\n async findAllPermissions(query?: EntityQuery): Promise<PaginatedResult<PermissionWithRole>> {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n\n const baseQuery = db(PERMISSIONS_TABLE)\n .select(`${PERMISSIONS_TABLE}.*`, `${ROLES_TABLE}.name as role_name`)\n .leftJoin(ROLES_TABLE, `${PERMISSIONS_TABLE}.role_id`, `${ROLES_TABLE}.id`)\n\n const [permissions, countResult] = await Promise.all([\n baseQuery.clone().orderBy(`${ROLES_TABLE}.name`, 'asc').orderBy('subject', 'asc').limit(limit).offset(offset),\n db(PERMISSIONS_TABLE).count('* as count').first<{ count: string | number }>()\n ])\n\n const total = Number(countResult?.count ?? 0)\n const items = (permissions as Record<string, unknown>[]).map((p) => ({\n ...parsePermission(p),\n role: { name: p['role_name'] as string }\n }))\n\n const totalPages = Math.ceil(total / limit)\n return { items, total, page, limit, totalPages, hasNext: page < totalPages }\n },\n\n /**\n * create con userId para audit\n */\n async create(data: Record<string, unknown>, userId?: string) {\n return baseRolesService.create({ ...data, created_by: userId ?? null })\n },\n\n /**\n * update con userId para audit\n */\n async update(id: string, data: Record<string, unknown>, userId?: string) {\n return baseRolesService.update(id, { ...data, updated_by: userId ?? null })\n },\n\n /**\n * delete\n */\n async delete(id: string) {\n return baseRolesService.delete(id)\n },\n\n /**\n * updatePermissions - actualizar permisos de un rol (transacción)\n */\n async updatePermissions(id: string, permissions: PermissionInput[], userId?: string): Promise<RoleWithPermissions> {\n return db.transaction(async (trx) => {\n const role = await trx(ROLES_TABLE).where({ id }).first() as Role | undefined\n if (!role) throw new errors.NotFoundError('Rol')\n\n if (role.is_system && role.name === 'ADMIN') {\n throw new errors.ForbiddenError('No se pueden modificar los permisos del rol ADMIN')\n }\n\n // Eliminar permisos existentes\n await trx(PERMISSIONS_TABLE).where({ role_id: id }).delete()\n\n // Insertar nuevos permisos\n if (permissions.length > 0) {\n const permissionsData = permissions.map((p) => ({\n id: generateId(),\n role_id: id,\n action: p.action,\n subject: p.subject,\n conditions: p.conditions ? JSON.stringify(p.conditions) : null,\n fields: p.fields ? JSON.stringify(p.fields) : null,\n inverted: p.inverted ?? false,\n created_by: userId ?? null\n }))\n await trx(PERMISSIONS_TABLE).insert(permissionsData)\n }\n\n // Actualizar timestamp del rol\n await trx(ROLES_TABLE).where({ id }).update({\n updated_at: nowTimestamp(db),\n updated_by: userId ?? null\n })\n\n // Retornar rol con permisos\n const updatedRole = await trx(ROLES_TABLE).where({ id }).first() as Role\n const updatedPermissions = await trx(PERMISSIONS_TABLE)\n .where({ role_id: id })\n .orderBy('subject', 'asc')\n .orderBy('action', 'asc') as Record<string, unknown>[]\n\n return { ...updatedRole, permissions: updatedPermissions.map(parsePermission) }\n })\n }\n }\n\n // ============================================================================\n // RETURN\n // ============================================================================\n\n return {\n // Definition para compatibilidad con BaseEntityService (requerido por createEntityController)\n definition: userEntity,\n\n // Users methods\n findAll: usersService.findAll,\n findById: usersService.findById,\n findByIdWithRole: usersService.findByIdWithRole,\n findByIdWithPassword: usersService.findByIdWithPassword,\n create: usersService.create,\n update: usersService.update,\n delete: usersService.delete,\n\n // Roles nested service (con definition para createEntityController)\n roles: {\n definition: roleEntity,\n ...rolesService\n }\n }\n}\n","import type { ModuleContext, CollectionEntityDefinition } from '@gzl10/nexus-sdk'\nimport { userEntity, roleEntity, rolePermissionEntity } from './users.entity.js'\n\n// Table names from EntityDefinition\nconst USERS = (userEntity as CollectionEntityDefinition).table\nconst ROLES = (roleEntity as CollectionEntityDefinition).table\nconst PERMISSIONS = (rolePermissionEntity as CollectionEntityDefinition).table\n\n/**\n * Seed para users: crea roles de sistema y usuario admin\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n await seedRoles(ctx)\n await seedAdminUser(ctx)\n}\n\n/**\n * Crea los roles de sistema y sus permisos si no existen\n */\nasync function seedRoles(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n\n // Solo crear roles si la tabla está vacía\n const existingRoles = await db(ROLES).count('* as count').first<{ count: string | number }>()\n if (Number(existingRoles?.count ?? 0) > 0) return\n\n // Insertar roles de sistema\n const systemRoles = [\n { id: generateId(), name: 'ADMIN', description: 'Administrador con control total', is_system: true },\n { id: generateId(), name: 'EDITOR', description: 'Puede crear y editar contenido propio', is_system: true },\n { id: generateId(), name: 'VIEWER', description: 'Solo lectura', is_system: true }\n ]\n await db(ROLES).insert(systemRoles)\n logger.info('Inserted system roles: ADMIN, EDITOR, VIEWER')\n\n // Insertar permisos para roles de sistema\n const roles = await db(ROLES).select('id', 'name')\n const roleMap = Object.fromEntries(roles.map((r: { id: string; name: string }) => [r.name, r.id]))\n\n const permissions = [\n // ADMIN: manage all\n { id: generateId(), role_id: roleMap['ADMIN'], action: 'manage', subject: 'all', conditions: null, inverted: false },\n // EDITOR: read users, CRUD posts (own for update/delete)\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'read', subject: 'User', conditions: null, inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'create', subject: 'PstPost', conditions: null, inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'read', subject: 'PstPost', conditions: null, inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'update', subject: 'PstPost', conditions: JSON.stringify({ author_id: '${user.id}' }), inverted: false },\n { id: generateId(), role_id: roleMap['EDITOR'], action: 'delete', subject: 'PstPost', conditions: JSON.stringify({ author_id: '${user.id}' }), inverted: false },\n // VIEWER: read published posts, read own profile\n { id: generateId(), role_id: roleMap['VIEWER'], action: 'read', subject: 'PstPost', conditions: JSON.stringify({ status: 'PUBLISHED' }), inverted: false },\n { id: generateId(), role_id: roleMap['VIEWER'], action: 'read', subject: 'User', conditions: JSON.stringify({ id: '${user.id}' }), inverted: false }\n ]\n await db(PERMISSIONS).insert(permissions)\n logger.info('Inserted permissions for system roles')\n}\n\n/**\n * Crea el usuario administrador inicial si no existe\n */\nasync function seedAdminUser(ctx: ModuleContext): Promise<void> {\n const { db, logger, config, helpers: { generateId }, crypto: { hashPassword } } = ctx\n\n const email = (config['adminEmail'] as string) || 'admin@example.com'\n const password = (config['adminPassword'] as string) || 'admin123'\n\n const existing = await db(USERS).where({ email }).first()\n if (existing) {\n logger.info({ email }, 'Admin user already exists')\n return\n }\n\n // Get ADMIN role ID\n const adminRole = await db(ROLES).where({ name: 'ADMIN' }).first()\n if (!adminRole) {\n logger.error('ADMIN role not found. Run migrations first.')\n throw new Error('ADMIN role not found')\n }\n\n const hashedPassword = await hashPassword(password)\n\n await db(USERS).insert({\n id: generateId(),\n email,\n password: hashedPassword,\n name: 'Administrador',\n role_id: adminRole.id\n })\n\n logger.info({ email }, 'Admin user created')\n}\n","import type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { createUsersRoutes } from './users.routes.js'\nimport { createUsersService } from './users.service.js'\nimport { userEntity, roleEntity, rolePermissionEntity } from './users.entity.js'\n\n// Re-exports\nexport { createUsersService } from './users.service.js'\nexport { userEntity, roleEntity, rolePermissionEntity } from './users.entity.js'\n\n// Types from users.types.ts\nexport type {\n User,\n Role,\n Permission,\n UserWithoutPassword,\n UserPresence,\n UserWithRole,\n RoleWithPermissions,\n RoleWithCounts,\n PermissionInput,\n PermissionWithRole\n} from './users.types.js'\n\nexport const usersModule: ModuleManifest = {\n name: 'users',\n label: 'Users & Roles',\n icon: 'mdi:account-group-outline',\n description: 'User accounts, authentication profiles, roles and permissions',\n type: 'core',\n category: 'data',\n dependencies: ['logger'],\n // Import dinámico para evitar posibles ciclos\n seed: async (ctx) => {\n const { seed } = await import('./users.seed.js')\n await seed(ctx)\n },\n\n init: (ctx: ModuleContext) => {\n // Registrar servicio de usuarios en ctx.services\n ctx.services['users'] = createUsersService(ctx)\n ctx.logger.debug('Users service registered')\n },\n\n routes: createUsersRoutes,\n routePrefix: '/users',\n // Orden importante: roles primero (FK de users.role_id → roles.id)\n // changePassword es entity action dentro de userEntity\n definitions: [roleEntity, rolePermissionEntity, userEntity]\n}\n\nexport default usersModule\n","/**\n * Startup Logger\n *\n * Logger simple para errores de configuración que ocurren\n * antes de que el logger principal esté inicializado.\n *\n * Usa pino directamente con pino-pretty si está disponible.\n */\nimport pino from 'pino'\nimport { createRequire } from 'module'\n\nfunction hasPinoPretty(): boolean {\n try {\n const require = createRequire(import.meta.url)\n require.resolve('pino-pretty')\n return true\n } catch {\n return false\n }\n}\n\nconst startupLogger = pino({\n level: 'error',\n transport: hasPinoPretty()\n ? {\n target: 'pino-pretty',\n options: {\n colorize: true,\n sync: true,\n messageFormat: '{msg}'\n }\n }\n : undefined\n})\n\n/**\n * Muestra un error de configuración formateado y termina el proceso\n */\nexport function configError(module: string, errors: string[]): never {\n startupLogger.error(`\\n${'═'.repeat(60)}`)\n startupLogger.error(`NEXUS BACKEND - Configuration Error [${module}]`)\n startupLogger.error('═'.repeat(60))\n errors.forEach((err) => startupLogger.error(` ${err}`))\n startupLogger.error('═'.repeat(60) + '\\n')\n\n process.exit(1)\n}\n\nexport { startupLogger }\n","import { z } from 'zod'\nimport { configError } from '../../core/startup-logger.js'\n\n/**\n * Schema de variables de entorno para auth\n * Completamente independiente de la configuración global\n */\nconst authEnvSchema = z.object({\n AUTH_SECRET: z.string().min(32, 'AUTH_SECRET must be at least 32 characters'),\n AUTH_ACCESS_EXPIRES: z.string().default('15m'),\n AUTH_REFRESH_EXPIRES: z.string().default('7d'),\n // Rate limiting (default: 5 requests per 15 minutes)\n AUTH_RATE_LIMIT_MAX: z.coerce.number().default(5),\n AUTH_RATE_LIMIT_WINDOW: z.coerce.number().default(900), // seconds\n // Cookie domain for SSO across subdomains (e.g., '.example.com')\n AUTH_COOKIE_DOMAIN: z.string().optional()\n})\n\nfunction parseAuthEnv() {\n const result = authEnvSchema.safeParse(process.env)\n\n if (!result.success) {\n const errors = result.error.issues.map((issue) => {\n const path = issue.path.join('.')\n if (path === 'AUTH_SECRET' && issue.code === 'invalid_type') {\n return 'AUTH_SECRET is required. Set it in your .env file or environment.'\n }\n if (path === 'AUTH_SECRET' && issue.code === 'too_small') {\n return `AUTH_SECRET must be at least 32 characters (current: ${String(process.env['AUTH_SECRET']).length})`\n }\n return `${path}: ${issue.message}`\n })\n configError('auth', errors)\n }\n\n return result.data\n}\n\nexport const authEnv = parseAuthEnv()\n\n/**\n * Configuración Auth tipada\n */\nexport interface AuthConfig {\n secret: string\n accessExpires: string\n refreshExpires: string\n rateLimitMax: number\n rateLimitWindowMs: number\n /** Cookie domain for SSO across subdomains (e.g., '.example.com') */\n cookieDomain?: string\n}\n\n/**\n * Obtiene la configuración de auth desde las variables de entorno\n */\nexport function getAuthConfig(): AuthConfig {\n return {\n secret: authEnv.AUTH_SECRET,\n accessExpires: authEnv.AUTH_ACCESS_EXPIRES,\n refreshExpires: authEnv.AUTH_REFRESH_EXPIRES,\n rateLimitMax: authEnv.AUTH_RATE_LIMIT_MAX,\n rateLimitWindowMs: authEnv.AUTH_RATE_LIMIT_WINDOW * 1000, // convert to ms\n cookieDomain: authEnv.AUTH_COOKIE_DOMAIN\n }\n}\n","import jwt from 'jsonwebtoken'\nimport crypto from 'crypto'\nimport { getAuthConfig } from './auth.config.js'\n\nexport interface JwtPayload {\n userId: string\n email: string\n roleId: string\n}\n\nexport interface TokenPair {\n accessToken: string\n refreshToken: string\n}\n\nfunction parseExpiration(exp: string): number {\n const match = exp.match(/^(\\d+)([smhd])$/)\n if (!match) return 900 // 15 min default\n\n const value = parseInt(match[1]!, 10)\n const unit = match[2]\n\n switch (unit) {\n case 's': return value\n case 'm': return value * 60\n case 'h': return value * 60 * 60\n case 'd': return value * 60 * 60 * 24\n default: return 900\n }\n}\n\nexport function generateAccessToken(payload: JwtPayload): string {\n const config = getAuthConfig()\n return jwt.sign(payload, config.secret, {\n expiresIn: config.accessExpires as jwt.SignOptions['expiresIn']\n })\n}\n\nexport function generateRefreshToken(): string {\n return crypto.randomBytes(64).toString('hex')\n}\n\nexport function getRefreshTokenExpiration(): Date {\n const seconds = parseExpiration(getAuthConfig().refreshExpires)\n return new Date(Date.now() + seconds * 1000)\n}\n\nexport function generateTokenPair(payload: JwtPayload): TokenPair {\n return {\n accessToken: generateAccessToken(payload),\n refreshToken: generateRefreshToken()\n }\n}\n\nexport function verifyAccessToken(token: string): JwtPayload {\n return jwt.verify(token, getAuthConfig().secret) as JwtPayload\n}\n","import type { TempEntityDefinition, EventEntityDefinition, SingleEntityDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * EntityDefinition para Refresh Tokens\n *\n * Usa tipo 'temp' para limpieza automática de tokens expirados.\n * TTL: 7 días (604800 segundos) - mismo que jwtRefreshExpires default\n */\nexport const refreshTokenEntity: TempEntityDefinition = {\n type: 'temp',\n table: 'auth_refresh_tokens',\n label: 'Refresh Tokens',\n labelField: 'id',\n routePrefix: '/tokens',\n ttl: 604800, // 7 días en segundos\n ttlField: 'expires_at',\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n token: {\n name: 'token',\n label: 'Token',\n input: 'hidden',\n db: { type: 'string', size: 255, nullable: false, unique: true },\n meta: { exportable: false }\n },\n user_id: {\n name: 'user_id',\n label: 'Usuario',\n input: 'select',\n db: { type: 'string', size: 26, nullable: false, index: true },\n relation: { table: 'users', column: 'id', onDelete: 'CASCADE' },\n validation: { required: true },\n options: { endpoint: '/users', valueField: 'id', labelField: 'name' },\n meta: { searchable: true }\n },\n expires_at: {\n name: 'expires_at',\n label: 'Expira',\n input: 'datetime',\n db: { type: 'datetime', nullable: false, index: true },\n validation: { required: true },\n meta: { sortable: true }\n },\n device_id: {\n name: 'device_id',\n label: 'Device ID',\n input: 'text',\n db: { type: 'string', size: 64, nullable: true, index: true },\n meta: { searchable: true }\n },\n device_name: {\n name: 'device_name',\n label: 'Dispositivo',\n input: 'text',\n db: { type: 'string', size: 100, nullable: true },\n hint: 'Nombre legible del dispositivo (ej: iPhone de Juan)'\n },\n created_at: {\n name: 'created_at',\n label: 'Creado',\n input: 'datetime',\n disabled: true,\n db: { type: 'datetime', nullable: true, defaultFn: 'now' },\n meta: { sortable: true }\n }\n },\n\n casl: {\n subject: 'AuthRefreshToken',\n permissions: {\n ADMIN: { actions: ['manage'] }\n }\n }\n}\n\n/**\n * EntityDefinition para Auth Audit\n *\n * Eventos de autenticación persistidos (append-only).\n * Retención: 90 días por defecto.\n */\nexport const authAuditEntity: EventEntityDefinition = {\n type: 'event',\n table: 'auth_audit',\n label: 'Auth Audit',\n labelField: 'event_type',\n routePrefix: '/audit',\n // timestamps: false - created_at está definido explícitamente en fields para metadata extra\n retention: {\n days: 90\n },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false },\n meta: { sortable: false }\n },\n event_type: {\n name: 'event_type',\n label: 'Tipo',\n input: 'select',\n db: { type: 'string', size: 50, nullable: false, index: true },\n validation: {\n required: true,\n enum: ['login', 'logout', 'failed', 'refresh', 'password_reset']\n },\n options: {\n static: [\n { value: 'login', label: 'Login' },\n { value: 'logout', label: 'Logout' },\n { value: 'failed', label: 'Failed' },\n { value: 'refresh', label: 'Refresh' },\n { value: 'password_reset', label: 'Password Reset' }\n ]\n },\n meta: { sortable: true, searchable: true }\n },\n user_id: {\n name: 'user_id',\n label: 'Usuario',\n input: 'select',\n db: { type: 'string', size: 26, nullable: true, index: true },\n relation: { table: 'users', column: 'id', onDelete: 'SET NULL' },\n options: { endpoint: '/users', valueField: 'id', labelField: 'name' },\n meta: { searchable: true }\n },\n email: {\n name: 'email',\n label: 'Email',\n input: 'email',\n db: { type: 'string', size: 255, nullable: true },\n validation: { format: 'email' },\n meta: { searchable: true }\n },\n ip_address: {\n name: 'ip_address',\n label: 'IP',\n input: 'text',\n db: { type: 'string', size: 45, nullable: true },\n meta: { searchable: true }\n },\n user_agent: {\n name: 'user_agent',\n label: 'User Agent',\n input: 'textarea',\n db: { type: 'text', nullable: true },\n meta: { exportable: false }\n },\n details: {\n name: 'details',\n label: 'Detalles',\n input: 'hidden',\n db: { type: 'json', nullable: true },\n meta: { exportable: false }\n },\n created_at: {\n name: 'created_at',\n label: 'Fecha',\n input: 'datetime',\n disabled: true,\n db: { type: 'datetime', nullable: false, defaultFn: 'now', index: true },\n meta: { sortable: true }\n }\n },\n\n casl: {\n subject: 'AuthAudit',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n\n/**\n * Single Entity: Auth Config\n *\n * Configuración de autenticación persistida en DB.\n * AUTH_SECRET siempre viene de env por seguridad.\n */\nexport const authConfigEntity: SingleEntityDefinition = {\n type: 'single',\n key: 'auth_config',\n label: 'Auth Config',\n routePrefix: '/config',\n\n // Defaults desde variables de entorno\n get defaults() {\n return {\n access_expires: process.env['AUTH_ACCESS_EXPIRES'] || '15m',\n refresh_expires: process.env['AUTH_REFRESH_EXPIRES'] || '7d',\n rate_limit_max: parseInt(process.env['AUTH_RATE_LIMIT_MAX'] || '') || 5,\n rate_limit_window: parseInt(process.env['AUTH_RATE_LIMIT_WINDOW'] || '') || 900,\n cookie_domain: process.env['AUTH_COOKIE_DOMAIN'] || null\n }\n },\n\n fields: {\n access_expires: {\n name: 'access_expires',\n label: 'Access Token Expira',\n input: 'text',\n hint: 'Duración del access token (ej: 15m, 1h, 1d)',\n db: { type: 'string', size: 20, nullable: false, default: '15m' }\n },\n refresh_expires: {\n name: 'refresh_expires',\n label: 'Refresh Token Expira',\n input: 'text',\n hint: 'Duración del refresh token (ej: 7d, 30d)',\n db: { type: 'string', size: 20, nullable: false, default: '7d' }\n },\n rate_limit_max: {\n name: 'rate_limit_max',\n label: 'Rate Limit (intentos)',\n input: 'number',\n hint: 'Máximo de intentos de login por ventana',\n db: { type: 'integer', nullable: false, default: 5 }\n },\n rate_limit_window: {\n name: 'rate_limit_window',\n label: 'Rate Limit (segundos)',\n input: 'number',\n hint: 'Ventana de tiempo para rate limit en segundos',\n db: { type: 'integer', nullable: false, default: 900 }\n },\n cookie_domain: {\n name: 'cookie_domain',\n label: 'Cookie Domain',\n input: 'text',\n hint: 'Dominio para SSO entre subdominios (ej: .example.com)',\n db: { type: 'string', size: 100, nullable: true }\n }\n },\n\n casl: {\n subject: 'AuthConfig',\n permissions: {\n ADMIN: { actions: ['read', 'update'] }\n }\n }\n}\n","import type { ModuleContext, TempEntityDefinition, EventEntityDefinition } from '@gzl10/nexus-sdk'\nimport { generateTokenPair, getRefreshTokenExpiration } from './jwt.utils.js'\nimport type { LoginInput, RegisterInput } from './auth.routes.js'\nimport { refreshTokenEntity, authAuditEntity } from './auth.entity.js'\nimport type { UsersService } from '../../types/services.js'\nimport type { TypedEventEmitter } from '../../core/events/emitter.js'\nimport type { RequestInfo, UserSession } from './auth.types.js'\n\n// Table names (hardcoded for module isolation - auth depends on users via ctx.services)\nconst USERS = 'users'\nconst ROLES = 'roles'\nconst REFRESH_TOKENS = (refreshTokenEntity as TempEntityDefinition).table\nconst AUTH_AUDIT = (authAuditEntity as EventEntityDefinition).table\n\n/**\n * Tipo local para datos de usuario - auth no importa de users module\n * Define los campos que auth necesita para autenticación y CASL\n */\nexport interface AuthUserRecord {\n id: string\n email: string\n password: string\n name: string\n role_id: string\n created_at: Date\n updated_at: Date\n created_by: string | null\n updated_by: string | null\n [key: string]: unknown\n}\n\nexport function createAuthService(ctx: ModuleContext) {\n const { db, errors, helpers: { generateId, nowTimestamp }, abilities, crypto } = ctx\n const { verifyPassword, DUMMY_HASH } = crypto\n const events = ctx.events as TypedEventEmitter\n const { defineAbilityFor, packRules } = abilities\n\n // Obtener servicio de usuarios desde ctx.services (registrado en users.init())\n const usersService = ctx.services['users'] as UsersService\n if (!usersService) {\n throw new Error('UsersService not initialized. Ensure users module loads before auth.')\n }\n const { roles: rolesService } = usersService\n\n /** Persiste evento de audit en base de datos */\n async function persistAuditEvent(\n eventType: 'login' | 'logout' | 'failed' | 'refresh' | 'password_reset',\n data: {\n userId?: string\n email?: string\n requestInfo?: RequestInfo\n details?: Record<string, unknown>\n }\n ): Promise<void> {\n try {\n await db(AUTH_AUDIT).insert({\n id: generateId(),\n event_type: eventType,\n user_id: data.userId ?? null,\n email: data.email ?? null,\n ip_address: data.requestInfo?.ip ?? null,\n user_agent: data.requestInfo?.userAgent ?? null,\n details: data.details ? JSON.stringify(data.details) : null,\n created_at: nowTimestamp(db)\n })\n } catch {\n // No fallar el flujo principal si audit falla\n ctx.logger.warn(`Failed to persist audit event: ${eventType}`)\n }\n }\n\n async function getUserWithRole(userId: string) {\n const user = await db<AuthUserRecord & { role_name: string; role_description: string | null; role_is_system: boolean }>(USERS)\n .leftJoin(ROLES, `${USERS}.role_id`, `${ROLES}.id`)\n .where(`${USERS}.id`, userId)\n .select(\n `${USERS}.*`,\n `${ROLES}.name as role_name`,\n `${ROLES}.description as role_description`,\n `${ROLES}.is_system as role_is_system`\n )\n .first()\n\n if (!user) return null\n\n const { role_name, role_description, role_is_system, password: _, ...userWithoutPassword } = user\n\n return {\n ...userWithoutPassword,\n role: {\n id: user.role_id,\n name: role_name,\n description: role_description,\n is_system: role_is_system\n }\n }\n }\n\n return {\n async login(input: LoginInput, requestInfo?: RequestInfo) {\n const user = await db<AuthUserRecord>(USERS).where({ email: input.email }).first()\n\n // Timing-safe: siempre ejecutar bcrypt aunque usuario no exista\n const hashToCheck = user?.password ?? DUMMY_HASH\n const validPassword = await verifyPassword(input.password, hashToCheck)\n\n if (!user || !validPassword) {\n const reason = user ? 'invalid_password' : 'user_not_found'\n events.emitEvent('auth.failed', { email: input.email, reason })\n\n // Persistir evento de fallo\n await persistAuditEvent('failed', {\n email: input.email,\n requestInfo,\n details: { reason }\n })\n\n throw new errors.UnauthorizedError('Credenciales inválidas')\n }\n\n const tokens = generateTokenPair({\n userId: user.id,\n email: user.email,\n roleId: user.role_id\n })\n\n // Guardar refresh token en DB\n await db(REFRESH_TOKENS).insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration(),\n device_id: requestInfo?.deviceId ?? null,\n device_name: requestInfo?.deviceName ?? null\n })\n\n // Cargar permisos del rol\n const permissions = await rolesService.getPermissionsByRoleId(user.role_id)\n const ability = defineAbilityFor(user, permissions)\n\n // Obtener usuario con rol\n const userWithRole = await getUserWithRole(user.id)\n\n events.emitEvent('auth.login', { userId: user.id, email: user.email })\n\n // Persistir evento de login exitoso\n await persistAuditEvent('login', {\n userId: user.id,\n email: user.email,\n requestInfo\n })\n\n return {\n user: userWithRole,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n abilities: packRules(ability)\n }\n },\n\n async register(input: RegisterInput, requestInfo?: RequestInfo) {\n // Buscar rol por defecto (VIEWER)\n const defaultRole = await rolesService.findByName('VIEWER')\n if (!defaultRole) {\n throw new errors.AppError('Rol VIEWER no encontrado. Ejecuta las migraciones.', 500)\n }\n\n // Crear usuario (usersService hace hash de password y valida email único)\n const user = await usersService.create({\n email: input.email,\n password: input.password,\n name: input.name,\n role_id: defaultRole.id\n })\n\n // Generar tokens\n const tokens = generateTokenPair({\n userId: user.id,\n email: user.email,\n roleId: defaultRole.id\n })\n\n // Guardar refresh token en DB\n await db(REFRESH_TOKENS).insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration(),\n device_id: requestInfo?.deviceId ?? null,\n device_name: requestInfo?.deviceName ?? null\n })\n\n // Cargar permisos del rol\n const permissions = await rolesService.getPermissionsByRoleId(defaultRole.id)\n // User siempre tiene role_id en registro (acabamos de asignarlo)\n const ability = defineAbilityFor({ ...user, role_id: defaultRole.id }, permissions)\n\n // Obtener usuario con rol\n const userWithRole = await getUserWithRole(user.id)\n\n events.emitEvent('auth.login', { userId: user.id, email: user.email })\n\n // Persistir evento de registro\n await persistAuditEvent('login', {\n userId: user.id,\n email: user.email,\n requestInfo,\n details: { isRegistration: true }\n })\n\n return {\n user: userWithRole,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n abilities: packRules(ability)\n }\n },\n\n async refresh(refreshToken: string, requestInfo?: RequestInfo) {\n // Toda la lógica de refresh dentro de transacción para evitar race conditions\n const result = await db.transaction(async (trx) => {\n // Buscar token con bloqueo (forUpdate solo en PostgreSQL/MySQL)\n let query = trx(REFRESH_TOKENS).where({ token: refreshToken })\n const client = db.client.config.client as string\n if (!client.includes('sqlite')) {\n query = query.forUpdate()\n }\n const storedToken = await query.first()\n\n if (!storedToken) {\n throw new errors.UnauthorizedError('Refresh token inválido')\n }\n\n if (new Date(storedToken.expires_at) < new Date()) {\n await trx(REFRESH_TOKENS).where({ id: storedToken.id }).delete()\n throw new errors.UnauthorizedError('Refresh token expirado')\n }\n\n const user = await trx<AuthUserRecord>(USERS).where({ id: storedToken.user_id }).first()\n if (!user) {\n throw new errors.UnauthorizedError('Usuario no encontrado')\n }\n\n const tokens = generateTokenPair({\n userId: user.id,\n email: user.email,\n roleId: user.role_id\n })\n\n // Rotar refresh token atómicamente (preservando device info)\n await trx(REFRESH_TOKENS).where({ id: storedToken.id }).delete()\n await trx(REFRESH_TOKENS).insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration(),\n device_id: storedToken.device_id ?? null,\n device_name: storedToken.device_name ?? null\n })\n\n return { user, tokens }\n })\n\n // Cargar permisos del rol (fuera de transacción, solo lectura)\n const permissions = await rolesService.getPermissionsByRoleId(result.user.role_id)\n const ability = defineAbilityFor(result.user, permissions)\n\n events.emitEvent('auth.refresh', { userId: result.user.id })\n\n // Persistir evento de refresh\n await persistAuditEvent('refresh', {\n userId: result.user.id,\n requestInfo\n })\n\n return {\n accessToken: result.tokens.accessToken,\n refreshToken: result.tokens.refreshToken,\n abilities: packRules(ability)\n }\n },\n\n async logout(refreshToken: string, userId?: string, requestInfo?: RequestInfo) {\n const deleted = await db(REFRESH_TOKENS).where({ token: refreshToken }).delete()\n if (deleted > 0 && userId) {\n events.emitEvent('auth.logout', { userId })\n\n // Persistir evento de logout\n await persistAuditEvent('logout', {\n userId,\n requestInfo\n })\n }\n return deleted > 0\n },\n\n async logoutAll(userId: string, requestInfo?: RequestInfo) {\n const deleted = await db(REFRESH_TOKENS).where({ user_id: userId }).delete()\n\n events.emitEvent('auth.logout', { userId })\n\n // Persistir evento de logout-all con detalles\n await persistAuditEvent('logout', {\n userId,\n requestInfo,\n details: { allDevices: true, sessionsRevoked: deleted }\n })\n\n return deleted\n },\n\n async me(userId: string) {\n const userWithRole = await getUserWithRole(userId)\n\n if (!userWithRole) {\n throw new errors.NotFoundError('Usuario')\n }\n\n // Cargar permisos del rol\n const permissions = await rolesService.getPermissionsByRoleId(userWithRole.role_id)\n const ability = defineAbilityFor(userWithRole, permissions)\n\n return {\n user: userWithRole,\n abilities: packRules(ability)\n }\n },\n\n async cleanupExpiredTokens() {\n const deleted = await db(REFRESH_TOKENS)\n .where('expires_at', '<', nowTimestamp(db))\n .delete()\n return deleted\n },\n\n async getSessions(userId: string, currentToken?: string): Promise<UserSession[]> {\n const tokens = await db(REFRESH_TOKENS)\n .where({ user_id: userId })\n .where('expires_at', '>', new Date())\n .select('id', 'device_id', 'device_name', 'token', 'created_at', 'expires_at')\n .orderBy('created_at', 'desc')\n\n return tokens.map(t => ({\n id: t.id,\n device_id: t.device_id ?? null,\n device_name: t.device_name ?? null,\n created_at: t.created_at,\n expires_at: t.expires_at,\n is_current: currentToken ? t.token === currentToken : false\n }))\n },\n\n async revokeSession(userId: string, sessionId: string, requestInfo?: RequestInfo): Promise<boolean> {\n // Solo permite revocar sesiones del propio usuario\n const deleted = await db(REFRESH_TOKENS)\n .where({ id: sessionId, user_id: userId })\n .delete()\n\n if (deleted > 0) {\n await persistAuditEvent('logout', {\n userId,\n requestInfo,\n details: { sessionId, revokedByUser: true }\n })\n }\n\n return deleted > 0\n }\n }\n}\n","import type { Request, Response, CookieOptions, ModuleContext } from '@gzl10/nexus-sdk'\nimport { createAuthService } from './auth.service.js'\nimport { getAuthConfig } from './auth.config.js'\nimport type { LoginInput, RegisterInput } from './auth.routes.js'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport type { RequestInfo } from './auth.types.js'\n\nexport function createAuthController(ctx: ModuleContext) {\n const { errors } = ctx\n const authService = createAuthService(ctx)\n\n function getCookieOptions(req: Request): CookieOptions {\n const config = getAuthConfig()\n const isSecure = req.secure || req.get('x-forwarded-proto') === 'https'\n return {\n httpOnly: true,\n secure: isSecure,\n sameSite: isSecure ? 'strict' : 'lax',\n path: '/api/v1',\n maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days\n ...(config.cookieDomain && { domain: config.cookieDomain })\n }\n }\n\n /** Extrae información del request para audit */\n function getRequestInfo(req: Request, deviceInfo?: { deviceId?: string, deviceName?: string }): RequestInfo {\n return {\n ip: req.ip ?? req.socket?.remoteAddress,\n userAgent: req.get('user-agent'),\n deviceId: deviceInfo?.deviceId,\n deviceName: deviceInfo?.deviceName\n }\n }\n\n return {\n async login(req: Request, res: Response) {\n const body = req.body as LoginInput\n const result = await authService.login(body, getRequestInfo(req, { deviceId: body.deviceId, deviceName: body.deviceName }))\n\n // Refresh token in HttpOnly cookie\n res.cookie('refreshToken', result.refreshToken, getCookieOptions(req))\n\n // Access token in body (client stores in localStorage)\n res.json({\n user: result.user,\n accessToken: result.accessToken,\n abilities: result.abilities\n })\n },\n\n async register(req: Request, res: Response) {\n const body = req.body as RegisterInput\n const result = await authService.register(body, getRequestInfo(req, { deviceId: body.deviceId, deviceName: body.deviceName }))\n\n // Refresh token in HttpOnly cookie (auto-login after register)\n res.cookie('refreshToken', result.refreshToken, getCookieOptions(req))\n\n res.status(201).json({\n user: result.user,\n accessToken: result.accessToken,\n abilities: result.abilities\n })\n },\n\n async refresh(req: Request, res: Response) {\n const refreshToken = req.cookies?.['refreshToken'] as string | undefined\n if (!refreshToken) {\n throw new errors.UnauthorizedError('Refresh token required')\n }\n\n const result = await authService.refresh(refreshToken, getRequestInfo(req))\n\n res.cookie('refreshToken', result.refreshToken, getCookieOptions(req))\n res.json({\n accessToken: result.accessToken,\n abilities: result.abilities\n })\n },\n\n async logout(req: Request, res: Response) {\n const refreshToken = req.cookies?.['refreshToken'] as string | undefined\n const authReq = req as AuthRequest\n\n if (refreshToken) {\n await authService.logout(refreshToken, authReq.user?.id, getRequestInfo(req))\n }\n\n res.clearCookie('refreshToken', { path: '/api/v1' })\n res.status(204).send()\n },\n\n async me(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const result = await authService.me(authReq.user.id)\n res.json(result)\n },\n\n async logoutAll(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const sessionsRevoked = await authService.logoutAll(authReq.user.id, getRequestInfo(req))\n\n res.clearCookie('refreshToken', { path: '/api/v1' })\n res.json({ sessionsRevoked })\n },\n\n async getSessions(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const currentToken = req.cookies?.['refreshToken'] as string | undefined\n const sessions = await authService.getSessions(authReq.user.id, currentToken)\n res.json(sessions)\n },\n\n async revokeSession(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const sessionId = req.params['id']\n if (!sessionId) {\n throw new errors.AppError('ID de sesión requerido', 400)\n }\n\n const currentToken = req.cookies?.['refreshToken'] as string | undefined\n\n // No permitir revocar la sesión actual (usar logout para eso)\n const sessions = await authService.getSessions(authReq.user.id, currentToken)\n const targetSession = sessions.find(s => s.id === sessionId)\n\n if (targetSession?.is_current) {\n throw new errors.AppError('No puedes revocar tu sesión actual. Usa logout.', 400)\n }\n\n const revoked = await authService.revokeSession(authReq.user.id, sessionId, getRequestInfo(req))\n\n if (!revoked) {\n throw new errors.NotFoundError('Sesión')\n }\n\n res.status(204).send()\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { createAuthController } from './auth.controller.js'\nimport { refreshTokenEntity, authConfigEntity } from './auth.entity.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\nimport { getAuthConfig } from './auth.config.js'\n\n// Schemas para rutas manuales\nexport const loginSchema = z.object({\n email: z.string().email('Email inválido'),\n password: z.string().min(1, 'Password requerido'),\n deviceId: z.string().max(64).optional(),\n deviceName: z.string().max(100).optional()\n})\n\nexport type LoginInput = z.infer<typeof loginSchema>\n\nexport const registerSchema = z.object({\n email: z.string().email('Email inválido'),\n password: z.string().min(8, 'Password debe tener al menos 8 caracteres'),\n name: z.string().min(2, 'Nombre debe tener al menos 2 caracteres'),\n deviceId: z.string().max(64).optional(),\n deviceName: z.string().max(100).optional()\n})\n\nexport type RegisterInput = z.infer<typeof registerSchema>\n\n/**\n * Auth Routes\n *\n * Auto-montaje desde definitions:\n * - authAuditEntity (event) - read-only por diseño\n *\n * Aquí montamos:\n * - Rutas de autenticación (login, refresh, logout, me)\n * - refreshTokenEntity (temp con personalización: sin create/update vía API)\n * - authConfigEntity (single - configuración de auth)\n */\nexport function createAuthRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { validate, auth } = ctx.middleware\n const controller = createAuthController(ctx)\n\n if (!auth) {\n throw new Error('Auth middleware not initialized. Ensure auth.init() runs before routes.')\n }\n\n // ============================================================================\n // RUTAS DE AUTENTICACIÓN (manuales - lógica específica)\n // ============================================================================\n\n // Rate limits desde configuración (AUTH_RATE_LIMIT_MAX, AUTH_RATE_LIMIT_WINDOW)\n const authConfig = getAuthConfig()\n const loginRateLimit = createRateLimit({\n windowMs: authConfig.rateLimitWindowMs,\n max: authConfig.rateLimitMax,\n message: 'Demasiados intentos de login, intenta más tarde'\n })\n const refreshRateLimit = createRateLimit({\n windowMs: 60 * 1000,\n max: authConfig.rateLimitMax * 2,\n message: 'Demasiadas solicitudes de refresh'\n })\n const logoutRateLimit = createRateLimit({\n windowMs: 60 * 1000,\n max: authConfig.rateLimitMax,\n message: 'Demasiadas solicitudes de logout'\n })\n\n router.post('/login', loginRateLimit, validate({ body: loginSchema }), controller.login)\n router.post('/register', loginRateLimit, validate({ body: registerSchema as z.ZodSchema }), controller.register)\n router.post('/refresh', refreshRateLimit, controller.refresh)\n router.post('/logout', auth, logoutRateLimit, controller.logout)\n router.post('/logout-all', auth, logoutRateLimit, controller.logoutAll)\n router.get('/me', auth, controller.me)\n\n // Gestión de sesiones/dispositivos\n router.get('/sessions', auth, controller.getSessions)\n router.delete('/sessions/:id', auth, controller.revokeSession)\n\n // ============================================================================\n // TOKENS (temp - personalización: sin create/update vía API)\n // ============================================================================\n\n const tokensService = ctx.createEntityService(refreshTokenEntity)\n const tokensController = ctx.createEntityController(tokensService, refreshTokenEntity)\n\n // Tokens solo se crean/rotan internamente\n delete tokensController.create\n delete tokensController.update\n\n const tokensRouter = ctx.createEntityRouter(tokensController, refreshTokenEntity)\n router.use(refreshTokenEntity.routePrefix ?? '/tokens', tokensRouter)\n\n ctx.services['refreshTokens'] = tokensService\n\n // ============================================================================\n // CONFIG (single - configuración de auth)\n // ============================================================================\n\n const configService = ctx.createEntityService(authConfigEntity)\n const configController = ctx.createEntityController(configService, authConfigEntity)\n const configRouter = ctx.createEntityRouter(configController, authConfigEntity)\n router.use(authConfigEntity.routePrefix ?? '/config', configRouter)\n\n return router\n}\n","import jwt from 'jsonwebtoken'\nimport type { Request, Response, NextFunction, RequestHandler, ModuleContext } from '@gzl10/nexus-sdk'\nimport type { JwtPayload } from './jwt.utils.js'\nimport type { AuthUserRecord } from './auth.service.js'\nimport type { UsersService } from '../../types/services.js'\nimport { getAuthConfig } from './auth.config.js'\n\n// Table name (hardcoded for module isolation)\nconst USERS = 'users'\n\n/**\n * Crea el middleware de autenticación requerida\n * Falla si no hay token válido\n */\nexport function createAuthMiddleware(ctx: ModuleContext): RequestHandler {\n const { errors, abilities } = ctx\n const { defineAbilityFor } = abilities\n const { secret } = getAuthConfig()\n\n // Obtener servicio de usuarios desde ctx.services\n const usersService = ctx.services['users'] as UsersService\n if (!usersService) {\n throw new Error('UsersService not initialized. Ensure users module loads before auth.')\n }\n const { roles: rolesService } = usersService\n\n return async (req: Request, _res: Response, next: NextFunction) => {\n const authHeader = req.headers.authorization\n\n if (!authHeader?.startsWith('Bearer ')) {\n throw new errors.UnauthorizedError('Token no proporcionado')\n }\n\n const token = authHeader.slice(7)\n\n try {\n const decoded = jwt.verify(token, secret) as unknown as JwtPayload\n\n const user = await ctx.db<AuthUserRecord>(USERS).where({ id: decoded.userId }).first()\n\n if (!user) {\n throw new errors.UnauthorizedError('Usuario no encontrado')\n }\n\n // Cargar permisos del rol desde BD\n const permissions = await rolesService.getPermissionsByRoleId(user.role_id)\n\n req.user = user\n req.ability = defineAbilityFor(user, permissions) as Request['ability']\n next()\n } catch (error) {\n if (error instanceof jwt.JsonWebTokenError) {\n throw new errors.UnauthorizedError('Token inválido')\n }\n if (error instanceof jwt.TokenExpiredError) {\n throw new errors.UnauthorizedError('Token expirado')\n }\n throw error\n }\n }\n}\n\n/**\n * Crea el middleware de autenticación opcional\n * No falla si no hay token, simplemente continúa sin user\n */\nexport function createOptionalAuthMiddleware(ctx: ModuleContext): RequestHandler {\n const { abilities } = ctx\n const { defineAbilityFor } = abilities\n const { secret } = getAuthConfig()\n\n // Obtener servicio de usuarios desde ctx.services\n const usersService = ctx.services['users'] as UsersService\n if (!usersService) {\n throw new Error('UsersService not initialized. Ensure users module loads before auth.')\n }\n const { roles: rolesService } = usersService\n\n return async (req: Request, _res: Response, next: NextFunction) => {\n const authHeader = req.headers.authorization\n\n if (!authHeader?.startsWith('Bearer ')) {\n return next()\n }\n\n const token = authHeader.slice(7)\n\n try {\n const decoded = jwt.verify(token, secret) as unknown as JwtPayload\n\n const user = await ctx.db<AuthUserRecord>(USERS).where({ id: decoded.userId }).first()\n\n if (user) {\n const permissions = await rolesService.getPermissionsByRoleId(user.role_id)\n req.user = user\n req.ability = defineAbilityFor(user, permissions) as Request['ability']\n }\n } catch {\n // Token inválido, continuar sin autenticación\n }\n\n next()\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { authConfigEntity } from './auth.entity.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nconst SINGLE_RECORDS = 'single_records'\n\n/**\n * Seed para auth: crea configuración inicial desde variables de entorno\n *\n * AUTH_SECRET nunca se persiste en DB (siempre desde env por seguridad)\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n\n const key = authConfigEntity.key\n\n // Verificar si ya existe\n const existing = await db(SINGLE_RECORDS).where({ key }).first()\n if (existing) {\n logger.debug('Auth config already seeded')\n return\n }\n\n const now = nowTimestamp(db)\n const defaults = authConfigEntity.defaults\n\n // Crear config inicial desde variables de entorno\n await db(SINGLE_RECORDS).insert({\n id: generateId(),\n key,\n value: JSON.stringify(defaults),\n created_at: now,\n updated_at: now\n })\n\n logger.info('Auth config seeded from environment variables')\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { createAuthRoutes } from './auth.routes.js'\nimport { createAuthMiddleware, createOptionalAuthMiddleware } from './auth.middleware.js'\nimport { refreshTokenEntity, authAuditEntity, authConfigEntity } from './auth.entity.js'\n\n// Re-export types del módulo\nexport type { RefreshToken, AuthAudit } from './auth.types.js'\n\nexport const authModule: ModuleManifest = {\n name: 'auth',\n label: 'Authentication',\n icon: 'mdi:lock-outline',\n description: 'JWT authentication with refresh tokens, session management, and password security',\n type: 'core',\n category: 'security',\n dependencies: ['logger', 'users'],\n definitions: [refreshTokenEntity, authAuditEntity, authConfigEntity],\n // migrate: usa migración generada desde definitions\n init: (ctx) => {\n // Registrar middlewares para uso de otros módulos\n ctx.middleware['auth'] = createAuthMiddleware(ctx)\n ctx.middleware['optionalAuth'] = createOptionalAuthMiddleware(ctx)\n },\n routes: createAuthRoutes,\n routePrefix: '/auth',\n\n // Import dinámico para evitar ciclos\n seed: async (ctx) => {\n const { seed } = await import('./auth.seed.js')\n await seed(ctx)\n }\n}\n\nexport default authModule\n","import type { ComputedEntityDefinition, ModuleContext, ModuleManifest, PluginManifest, Category } from '@gzl10/nexus-sdk'\nimport { CATEGORIES, CATEGORY_ORDER } from '@gzl10/nexus-sdk'\n\n/**\n * Tipos de items del sidebar\n */\nexport type SidebarItemType = 'item' | 'divider' | 'group'\n\n/**\n * Item del sidebar para la UI\n */\nexport interface SidebarItem {\n type: SidebarItemType\n key: string\n label?: string\n icon?: string\n to?: string\n children?: SidebarItem[]\n}\n\n/**\n * Respuesta del sidebar con metadata\n */\nexport interface SidebarDTO {\n items: SidebarItem[]\n version: string\n}\n\n/**\n * Agrupa módulos por categoría (del módulo o heredada del plugin)\n */\ninterface ModuleWithCategory {\n module: ModuleManifest\n category: string\n pluginIcon?: string\n}\n\nfunction groupModulesByCategory(\n plugins: PluginManifest[],\n coreModules: ModuleManifest[]\n): Map<string, ModuleWithCategory[]> {\n const groups = new Map<string, ModuleWithCategory[]>()\n\n // Core modules usan su propia category\n for (const mod of coreModules) {\n if (!mod.routes) continue\n const category = mod.category || 'other'\n if (!groups.has(category)) {\n groups.set(category, [])\n }\n groups.get(category)!.push({ module: mod, category })\n }\n\n // Plugin modules: usar category del módulo, o heredar del plugin\n for (const plugin of plugins) {\n for (const mod of plugin.modules) {\n if (!mod.routes) continue\n const category = mod.category || plugin.category || 'other'\n if (!groups.has(category)) {\n groups.set(category, [])\n }\n groups.get(category)!.push({\n module: mod,\n category,\n pluginIcon: plugin.icon\n })\n }\n }\n\n return groups\n}\n\n/**\n * Convierte un módulo a item del sidebar\n */\nfunction moduleToSidebarItem(\n mod: ModuleManifest,\n getModuleSubjects: (mod: ModuleManifest) => string[],\n userSubjects?: string[]\n): SidebarItem | null {\n // Solo módulos con rutas\n if (!mod.routes) return null\n\n // Verificar permisos si se proporcionan subjects del usuario\n if (userSubjects) {\n const moduleSubjects = getModuleSubjects(mod)\n // Si el módulo tiene subjects y el usuario no tiene acceso a ninguno, ocultar\n if (moduleSubjects.length > 0) {\n const hasAccess = moduleSubjects.some((s: string) => userSubjects.includes(s))\n if (!hasAccess) return null\n }\n }\n\n return {\n type: 'item',\n key: `module-${mod.name}`,\n label: mod.label || mod.name,\n icon: mod.icon || 'mdi:cube-outline',\n to: `/admin/module/${mod.name}`\n }\n}\n\n/**\n * Fallback para categoría 'other' (no definida en CATEGORIES)\n */\nconst OTHER_CATEGORY = { label: 'Other', icon: 'mdi:package-variant', order: 99 }\n\n/**\n * EntityDefinition para Sidebar (computed)\n * Calcula el contenido del sidebar desde módulos y plugins\n */\nexport const sidebarEntity: ComputedEntityDefinition = {\n type: 'computed',\n label: 'Sidebar',\n labelField: 'version',\n routePrefix: '/sidebar',\n\n fields: {\n items: {\n name: 'items',\n label: 'Items',\n input: 'hidden',\n db: { type: 'json', nullable: false }\n },\n version: {\n name: 'version',\n label: 'Version',\n input: 'text',\n db: { type: 'string', size: 20, nullable: false }\n }\n },\n\n // Sin restricciones CASL - sidebar es público\n // El filtrado de items se hace según abilities del usuario\n casl: {\n subject: 'Sidebar',\n permissions: {}\n },\n\n compute: async (ctx: ModuleContext): Promise<SidebarDTO[]> => {\n const items: SidebarItem[] = []\n const modules = ctx.engine.getModules()\n const plugins = ctx.engine.getPlugins()\n\n // 1. Dashboard (siempre visible)\n items.push({\n type: 'item',\n key: 'dashboard',\n label: 'Dashboard',\n icon: 'mdi:view-dashboard-outline',\n to: '/admin'\n })\n\n // Separador entre Dashboard y categorías\n items.push({\n type: 'divider',\n key: 'divider-main'\n })\n\n // 2. Agrupar todos los módulos por category\n const coreModules = modules.filter(m => m.type === 'core')\n const modulesByCategory = groupModulesByCategory(plugins, coreModules)\n\n // Orden de categorías en sidebar (CATEGORY_ORDER + 'other' como fallback)\n const categoryOrder = [...CATEGORY_ORDER, 'other' as Category]\n\n for (const category of categoryOrder) {\n const categoryModules = modulesByCategory.get(category)\n if (!categoryModules || categoryModules.length === 0) continue\n\n const categoryItems = categoryModules\n .map(({ module, pluginIcon }) => {\n const item = moduleToSidebarItem(module, ctx.engine.getModuleSubjects)\n if (item && pluginIcon) {\n item.icon = pluginIcon\n }\n return item\n })\n .filter((item): item is SidebarItem => item !== null)\n\n if (categoryItems.length > 0) {\n const meta = CATEGORIES[category] || OTHER_CATEGORY\n\n items.push({\n type: 'group',\n key: `category-${category}`,\n label: meta.label,\n icon: meta.icon,\n children: categoryItems\n })\n }\n }\n\n return [{\n items,\n version: new Date().toISOString()\n }]\n },\n\n cache: {\n ttl: 60 // Cache 60s - estructura no cambia frecuentemente\n }\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { sidebarEntity } from './ui.entity.js'\n\n/**\n * UI Module\n *\n * sidebarEntity (computed) se auto-monta desde definitions.\n * No necesita routes custom.\n */\nexport const uiModule: ModuleManifest = {\n name: 'ui',\n label: 'UI',\n icon: 'mdi:view-dashboard',\n description: 'UI configuration and sidebar structure',\n type: 'core',\n category: 'content',\n dependencies: ['logger'],\n definitions: [sidebarEntity],\n routePrefix: '/ui'\n}\n\nexport default uiModule\n","import { z } from 'zod'\nimport type { MailConfig } from './mail.types.js'\n\n// Re-export type for backwards compatibility\nexport type { MailConfig } from './mail.types.js'\n\n/**\n * Schema de variables de entorno para mail\n * Completamente independiente de la configuración global\n */\nconst mailEnvSchema = z.object({\n SMTP_HOST: z.string().default('localhost'),\n SMTP_PORT: z.coerce.number().default(1025),\n SMTP_SECURE: z.string().default('false').transform(v => v === 'true' || v === '1'),\n SMTP_USER: z.string().optional(),\n SMTP_PASS: z.string().optional(),\n SMTP_FROM: z.string().default('noreply@nexus.local')\n})\n\nexport const mailEnv = mailEnvSchema.parse(process.env)\n\n/**\n * Obtiene la configuración de mail desde las variables de entorno\n */\nexport function getMailConfig(): MailConfig {\n return {\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n auth: mailEnv.SMTP_USER\n ? { user: mailEnv.SMTP_USER, pass: mailEnv.SMTP_PASS! }\n : undefined,\n from: mailEnv.SMTP_FROM\n }\n}\n","import nodemailer, { type Transporter } from 'nodemailer'\nimport { readFileSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport type { Logger } from 'pino'\nimport { getMailConfig } from './mail.config.js'\nimport type { LoggerReporter } from '@gzl10/nexus-sdk'\nimport type { MailConfig, MailAction, SendMailOptions, SendMailResult } from './mail.types.js'\n\n// Re-export types for backwards compatibility\nexport type { MailAction, SendMailOptions, SendMailResult } from './mail.types.js'\n\n// Assets en public/ para que se publiquen con el paquete npm\nconst TEMPLATE_REL_PATH = join('public', 'mail', 'base.html')\n// Logo blanco para header azul (fondo #3B82F6)\nconst LOGO_REL_PATH = join('public', 'nexus', 'nexus-light-512.png')\n\n/**\n * Servicio de mail singleton\n */\nlet mailServiceInstance: MailService | null = null\n\nexport function getMailService(): MailService {\n if (!mailServiceInstance) {\n throw new Error('MailService not initialized. Call initMailService() first.')\n }\n return mailServiceInstance\n}\n\nexport function initMailService(\n logger: Logger,\n loggerService?: LoggerReporter,\n options?: { libPath?: string }\n): MailService {\n const config = getMailConfig()\n mailServiceInstance = new MailService(config, logger, loggerService, options)\n return mailServiceInstance\n}\n\nexport class MailService {\n private transporter: Transporter\n private defaultFrom: string\n private defaultLogoUrl: string\n private logger: Logger\n private template: string\n private loggerService?: LoggerReporter\n\n constructor(\n config: MailConfig,\n logger: Logger,\n loggerService?: LoggerReporter,\n options?: { libPath?: string }\n ) {\n this.defaultFrom = config.from\n this.logger = logger.child({ service: 'mail' })\n this.loggerService = loggerService\n\n const libPath = options?.libPath ?? process.cwd()\n this.template = readFileSync(join(libPath, TEMPLATE_REL_PATH), 'utf-8')\n\n // Cargar logo como base64 data URI\n const logoPath = join(libPath, LOGO_REL_PATH)\n if (existsSync(logoPath)) {\n const logoBase64 = readFileSync(logoPath).toString('base64')\n this.defaultLogoUrl = `data:image/png;base64,${logoBase64}`\n } else {\n this.defaultLogoUrl = ''\n }\n\n this.transporter = nodemailer.createTransport({\n host: config.host,\n port: config.port,\n secure: config.secure,\n auth: config.auth,\n // MailHog y servidores dev no necesitan TLS\n ...(config.auth ? {} : { ignoreTLS: true })\n })\n }\n\n async send(options: SendMailOptions): Promise<SendMailResult | null> {\n const from = options.from ?? this.defaultFrom\n const to = Array.isArray(options.to) ? options.to.join(', ') : options.to\n\n // Si hay title o message, usar template; si no, usar html raw\n const html = (options.title || options.message)\n ? this.renderTemplate(options)\n : options.html\n\n this.logger.info({ to, subject: options.subject }, 'Sending email')\n\n try {\n const result = await this.transporter.sendMail({\n from,\n to,\n subject: options.subject,\n text: options.text,\n html,\n replyTo: options.replyTo,\n attachments: options.attachments\n })\n\n this.logger.info(\n { messageId: result.messageId, accepted: result.accepted },\n 'Email sent'\n )\n\n return {\n messageId: result.messageId,\n accepted: result.accepted as string[],\n rejected: result.rejected as string[]\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Failed to send email')\n this.logger.warn({ error, to, subject: options.subject }, 'Failed to send email (continuing)')\n this.loggerService?.captureException(err, { service: 'mail', action: 'send', toCount: options.to?.length ?? 0 })\n return null\n }\n }\n\n private renderTemplate(options: SendMailOptions): string {\n let html = this.template\n\n // Reemplazar variables simples\n html = html.replace(/\\{\\{subject\\}\\}/g, options.subject)\n html = html.replace(/\\{\\{logoUrl\\}\\}/g, options.logoUrl ?? this.defaultLogoUrl)\n html = html.replace(/\\{\\{year\\}\\}/g, new Date().getFullYear().toString())\n\n // Procesar bloques condicionales con patrón específico\n html = this.processConditionalBlock(html, 'title', options.title)\n html = this.processConditionalBlock(html, 'message', options.message)\n\n // Actions (botones) - Nexus Blue (#3B82F6)\n if (options.actions?.length) {\n const actionsHtml = options.actions.map(a =>\n `<a href=\"${a.url}\" style=\"display:inline-block; background-color:#3B82F6; color:#ffffff; padding:12px 24px; text-decoration:none; border-radius:6px; margin:4px; font-weight:500;\">${a.label}</a>`\n ).join('')\n html = html.replace(/\\{\\{#if actions\\}\\}([\\s\\S]*?)\\{\\{\\/if\\}\\}/g, (_, content) =>\n content.replace(/\\{\\{actions\\}\\}/g, actionsHtml)\n )\n } else {\n html = html.replace(/\\{\\{#if actions\\}\\}[\\s\\S]*?\\{\\{\\/if\\}\\}/g, '')\n }\n\n return html\n }\n\n private processConditionalBlock(html: string, name: string, value?: string): string {\n const pattern = new RegExp(`\\\\{\\\\{#if ${name}\\\\}\\\\}([\\\\s\\\\S]*?)\\\\{\\\\{\\\\/if\\\\}\\\\}`, 'g')\n if (value) {\n return html.replace(pattern, (_, content) =>\n content.replace(new RegExp(`\\\\{\\\\{${name}\\\\}\\\\}`, 'g'), value)\n )\n }\n return html.replace(pattern, '')\n }\n\n async verify(): Promise<boolean> {\n try {\n await this.transporter.verify()\n this.logger.info('SMTP connection verified')\n return true\n } catch (error) {\n const err = error instanceof Error ? error : new Error('SMTP connection failed')\n this.logger.warn({ error }, 'SMTP connection failed (emails may not work)')\n this.loggerService?.captureException(err, { service: 'mail', action: 'verify' })\n return false\n }\n }\n}\n","import type {\n ConfigEntityDefinition,\n ActionEntityDefinition,\n EventEntityDefinition,\n ModuleContext\n} from '@gzl10/nexus-sdk'\nimport nodemailer from 'nodemailer'\nimport { mailEnv } from './mail.config.js'\nimport { getMailService } from './mail.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\nimport type { SendMailInput, SendMailOptions, MailConfigRow } from './mail.types.js'\n\n/**\n * Get mail config from DB by scope, fallback to env vars\n */\nasync function getConfigByScope(ctx: ModuleContext, scope: string): Promise<MailConfigRow> {\n const row = await ctx.db('mail_config').where({ scope }).first<MailConfigRow>()\n\n if (row) {\n return {\n ...row,\n // Coerce SQLite 0/1 to boolean\n secure: row.secure === true || row.secure === 1\n }\n }\n\n // Fallback to env vars\n return {\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n from: mailEnv.SMTP_FROM,\n auth_user: mailEnv.SMTP_USER ?? null,\n auth_pass: mailEnv.SMTP_PASS ?? null\n }\n}\n\n/**\n * Create nodemailer transporter from config\n */\nfunction createTransporter(config: MailConfigRow) {\n const auth = config.auth_user\n ? { user: config.auth_user, pass: config.auth_pass! }\n : undefined\n\n return nodemailer.createTransport({\n host: config.host,\n port: config.port,\n secure: config.secure as boolean,\n auth,\n ...(auth ? {} : { ignoreTLS: true })\n })\n}\n\n/** Normalize to to array */\nfunction normalizeRecipients(to: string | string[]): string[] {\n if (Array.isArray(to)) return to\n return to.split(',').map(s => s.trim()).filter(Boolean)\n}\n\n/**\n * Config Entity: config\n * Configuración SMTP persistida en BD con scope\n */\nexport const mailConfigEntity: ConfigEntityDefinition = {\n type: 'config',\n table: 'mail_config',\n label: 'Mail Config',\n routePrefix: '/config',\n scopeField: 'scope',\n timestamps: true,\n\n // Defaults desde variables de entorno\n defaults: {\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n from: mailEnv.SMTP_FROM,\n auth_user: mailEnv.SMTP_USER ?? '',\n auth_pass: ''\n },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n scope: {\n name: 'scope',\n label: 'Scope',\n disabled: true,\n input: 'text',\n hint: 'Identificador de scope (ej: default, tenant-123)',\n db: { type: 'string', size: 100, nullable: false, unique: true }\n },\n host: {\n name: 'host',\n label: 'SMTP Host',\n input: 'text',\n hint: 'Default: SMTP_HOST env var',\n db: { type: 'string', size: 255, nullable: false }\n },\n port: {\n name: 'port',\n label: 'Port',\n input: 'number',\n hint: 'Default: SMTP_PORT env var',\n db: { type: 'integer', nullable: false }\n },\n secure: {\n name: 'secure',\n label: 'TLS/SSL',\n input: 'switch',\n hint: 'Default: SMTP_SECURE env var',\n db: { type: 'boolean', nullable: false }\n },\n from: {\n name: 'from',\n label: 'Sender',\n input: 'email',\n hint: 'Default: SMTP_FROM env var',\n db: { type: 'string', size: 255, nullable: false }\n },\n auth_user: {\n name: 'auth_user',\n label: 'Auth User',\n input: 'text',\n hint: 'SMTP username (optional)',\n db: { type: 'string', size: 255, nullable: true }\n },\n auth_pass: {\n name: 'auth_pass',\n label: 'Auth Password',\n input: 'password',\n hint: 'SMTP password (optional)',\n db: { type: 'string', size: 255, nullable: true }\n }\n },\n\n casl: {\n subject: 'MailConfig',\n permissions: {\n ADMIN: { actions: ['read', 'update'] }\n }\n }\n}\n\n/**\n * Action Entity: send\n * Endpoint para enviar emails\n */\nexport const mailSendAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Send Email',\n routePrefix: '/send',\n\n fields: {\n scope: {\n name: 'scope',\n label: 'Config Scope',\n input: 'select',\n hint: 'Which mail config to use',\n options: { endpoint: '/mail/config', valueField: 'scope', labelField: 'scope' }\n },\n to: {\n name: 'to',\n label: 'Recipient(s)',\n input: 'tags',\n placeholder: 'Add email address',\n validation: { required: true, format: 'email' }\n },\n subject: {\n name: 'subject',\n label: 'Subject',\n input: 'text',\n validation: { required: true, min: 1, max: 255 }\n },\n title: {\n name: 'title',\n label: 'Title',\n input: 'text',\n hint: 'Large title in email header'\n },\n message: {\n name: 'message',\n label: 'Message',\n input: 'markdown',\n hint: 'Email body (supports markdown)'\n },\n html: {\n name: 'html',\n label: 'HTML',\n input: 'hidden',\n hint: 'Alternative HTML (ignores title/message if provided)'\n }\n },\n\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { to: rawTo, subject, title, message, html, scope = 'default' } = input as SendMailInput\n const recipients = normalizeRecipients(rawTo)\n\n // Get config from DB by scope\n const config = await getConfigByScope(ctx, scope)\n const transporter = createTransporter(config)\n\n // Use MailService for template rendering if available\n const mailService = getMailService()\n\n // Build email options\n const mailOptions: SendMailOptions = {\n to: recipients,\n subject,\n title,\n message,\n html,\n from: config.from\n }\n\n // Send using dynamic transporter but delegate to service for template\n let result: { messageId: string; accepted: string[]; rejected: string[] } | null = null\n try {\n // If using title/message, let service render template\n if (title || message) {\n result = await mailService.send(mailOptions)\n } else {\n // Direct send with raw html\n const sendResult = await transporter.sendMail({\n from: config.from,\n to: recipients.join(', '),\n subject,\n html\n })\n result = {\n messageId: sendResult.messageId,\n accepted: sendResult.accepted as string[],\n rejected: sendResult.rejected as string[]\n }\n }\n } catch (error) {\n ctx.logger.warn({ error, scope }, 'Failed to send email')\n\n // Log del fallo\n await ctx.db('mail_log').insert({\n id: ctx.helpers.generateId(),\n to: recipients.join(', '),\n subject,\n status: 'failed',\n message_id: null,\n error: error instanceof Error ? error.message : 'Failed to send email',\n created_at: nowTimestamp(ctx.db)\n })\n\n throw new ctx.errors.AppError('Failed to send email', 500)\n }\n\n // Guard: result siempre definido si llegamos aquí\n if (!result) {\n throw new ctx.errors.AppError('Failed to send email', 500)\n }\n\n // Log del éxito\n await ctx.db('mail_log').insert({\n id: ctx.helpers.generateId(),\n to: recipients.join(', '),\n subject,\n status: 'sent',\n message_id: result.messageId,\n error: null,\n created_at: nowTimestamp(ctx.db)\n })\n\n const acceptedCount = result.accepted.length\n const rejectedCount = result.rejected.length\n let resultMessage = `Email sent to ${acceptedCount} recipient${acceptedCount !== 1 ? 's' : ''}`\n if (rejectedCount > 0) {\n resultMessage += ` (${rejectedCount} rejected)`\n }\n\n return {\n message: resultMessage,\n messageId: result.messageId,\n accepted: result.accepted,\n rejected: result.rejected\n }\n },\n\n casl: {\n subject: 'MailSend',\n permissions: {\n ADMIN: { actions: ['execute'] }\n }\n }\n}\n\n/**\n * Action Entity: test\n * Probar conexión SMTP\n */\nexport const mailTestAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Test Connection',\n order: 1, \n routePrefix: '/test',\n\n fields: {\n scope: {\n name: 'scope',\n label: 'Config Scope',\n input: 'select',\n hint: 'Which mail config to test',\n options: { endpoint: '/mail/config', valueField: 'scope', labelField: 'scope' }\n }\n },\n\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { scope = 'default' } = input as { scope?: string }\n\n // Get config from DB by scope\n const config = await getConfigByScope(ctx, scope)\n const transporter = createTransporter(config)\n\n try {\n await transporter.verify()\n ctx.logger.info({ scope, host: config.host, port: config.port }, 'SMTP connection verified')\n } catch (error) {\n ctx.logger.warn({ error, scope }, 'SMTP connection failed')\n throw new ctx.errors.AppError(\n `Failed to connect to SMTP server ${config.host}:${config.port}`,\n 500\n )\n }\n\n return {\n scope,\n host: config.host,\n port: config.port,\n message: `SMTP connection to ${config.host}:${config.port} verified successfully`\n }\n },\n\n casl: {\n subject: 'MailTest',\n permissions: {\n ADMIN: { actions: ['execute'] }\n }\n }\n}\n\n/**\n * Event Entity: log\n * Log append-only de emails enviados\n */\nexport const mailLogEntity: EventEntityDefinition = {\n type: 'event',\n table: 'mail_log',\n label: 'Mail Log',\n labelField: 'subject',\n routePrefix: '/log',\n // timestamps: false - created_at está definido explícitamente en fields\n retention: { days: 90 },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n created_at: {\n name: 'created_at',\n label: 'Date',\n input: 'datetime',\n disabled: true,\n db: { type: 'datetime', nullable: false, defaultFn: 'now', index: true },\n meta: { sortable: true }\n },\n to: {\n name: 'to',\n label: 'Recipient(s)',\n input: 'text',\n db: { type: 'string', size: 1000, nullable: false },\n meta: { searchable: true }\n },\n subject: {\n name: 'subject',\n label: 'Subject',\n input: 'text',\n db: { type: 'string', size: 255, nullable: false },\n meta: { searchable: true, sortable: true }\n },\n status: {\n name: 'status',\n label: 'Status',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false, index: true },\n validation: { enum: ['pending', 'sent', 'failed', 'bounced'] },\n options: {\n static: [\n { value: 'pending', label: 'Pending' },\n { value: 'sent', label: 'Sent' },\n { value: 'failed', label: 'Failed' },\n { value: 'bounced', label: 'Bounced' }\n ]\n },\n meta: { sortable: true }\n },\n message_id: {\n name: 'message_id',\n label: 'Message ID',\n input: 'hidden',\n db: { type: 'string', size: 255, nullable: true }\n },\n error: {\n name: 'error',\n label: 'Error',\n input: 'text',\n db: { type: 'text', nullable: true }\n },\n sent_by: {\n name: 'sent_by',\n label: 'Sent by',\n input: 'select',\n db: { type: 'string', size: 26, nullable: true, index: true },\n relation: { table: 'users', column: 'id', onDelete: 'SET NULL' },\n options: { endpoint: '/users', valueField: 'id', labelField: 'name' }\n }\n },\n\n casl: {\n subject: 'MailLog',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { mailConfigEntity } from './mail.entity.js'\n\n/**\n * Mail Routes\n *\n * Auto-montaje desde definitions:\n * - mailSendAction, mailTestAction (action)\n * - mailLogEntity (event)\n *\n * Aquí solo montamos mailConfigEntity (config - no auto-monta).\n */\nexport function createMailRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n\n // ============================================================================\n // CONFIG (config entity - no auto-monta)\n // ============================================================================\n\n const configService = ctx.createEntityService(mailConfigEntity)\n const configController = ctx.createEntityController(configService, mailConfigEntity)\n const configRouter = ctx.createEntityRouter(configController, mailConfigEntity)\n\n router.use(mailConfigEntity.routePrefix ?? '/config', configRouter)\n\n ctx.services['mail-config'] = configService\n\n return router\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { mailEnv } from './mail.config.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\n/**\n * Seed para mail: crea configuración inicial desde variables de entorno\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers: { generateId } } = ctx\n\n // Verificar si ya existe config 'default'\n const existing = await db('mail_config').where({ scope: 'default' }).first()\n if (existing) {\n logger.debug('Mail config already seeded')\n return\n }\n\n const now = nowTimestamp(db)\n\n // Crear config inicial desde variables de entorno\n const configData = {\n id: generateId(),\n scope: 'default',\n host: mailEnv.SMTP_HOST,\n port: mailEnv.SMTP_PORT,\n secure: mailEnv.SMTP_SECURE,\n from: mailEnv.SMTP_FROM,\n auth_user: mailEnv.SMTP_USER ?? null,\n auth_pass: mailEnv.SMTP_PASS ?? null,\n is_default: true,\n created_at: now,\n updated_at: now\n }\n\n await db('mail_config').insert(configData)\n logger.info('Mail config seeded from environment variables')\n}\n","import type { ModuleManifest, ModuleContext } from '@gzl10/nexus-sdk'\nimport { mailConfigEntity, mailSendAction, mailTestAction, mailLogEntity } from './mail.entity.js'\nimport { initMailService } from './mail.service.js'\nimport { createMailRoutes } from './mail.routes.js'\n\nexport { MailService, getMailService } from './mail.service.js'\nexport { getMailConfig } from './mail.config.js'\nexport type {\n MailConfig,\n MailConfigRow,\n MailAction,\n SendMailInput,\n SendMailOptions,\n SendMailResult\n} from './mail.types.js'\n\nexport const mailModule: ModuleManifest = {\n name: 'mail',\n label: 'Mail',\n icon: 'mdi:email-outline',\n description: 'Email sending and logging',\n type: 'core',\n category: 'messaging',\n dependencies: ['logger'],\n\n definitions: [\n mailConfigEntity,\n mailSendAction,\n mailTestAction,\n mailLogEntity\n ],\n\n routePrefix: '/mail',\n routes: createMailRoutes,\n\n init: (ctx: ModuleContext) => {\n // Inicializar y registrar el servicio de mail\n const mailService = initMailService(ctx.logger, ctx.services['logger'], { libPath: ctx.helpers.getLibPath() })\n ctx.services['mail'] = mailService\n ctx.logger.debug('Mail service registered')\n },\n\n // Import dinámico para evitar ciclos\n seed: async (ctx) => {\n const { seed } = await import('./mail.seed.js')\n await seed(ctx)\n }\n}\n\nexport default mailModule\n","import type { Knex } from 'knex'\nimport type { Logger } from 'pino'\nimport type { ModuleContext } from '@gzl10/nexus-sdk'\nimport type {\n NotificationType,\n NotificationPriority,\n NotificationTarget,\n SendNotificationInput\n} from './notifications.entity.js'\n\n/**\n * Notificación en BD\n */\nexport interface Notification {\n id: string\n title: string\n message: string\n type: NotificationType\n priority: NotificationPriority\n target_type: NotificationTarget\n target_value: string | null\n link: string | null\n read_by: string[] | null\n expires_at: Date | null\n created_at: Date\n}\n\n/**\n * Payload enviado por Socket.IO\n */\nexport interface NotificationPayload {\n id: string\n title: string\n message: string\n type: NotificationType\n priority: NotificationPriority\n link?: string\n timestamp: string\n}\n\n/**\n * Servicio de notificaciones\n */\nexport class NotificationService {\n private db: Knex\n private logger: Logger\n private generateId: () => string\n private nowTimestamp: (db: Knex) => string\n private formatTimestamp: (db: Knex, date?: Date) => string\n private socket: ModuleContext['socket']\n private events: ModuleContext['events']\n\n constructor(ctx: ModuleContext) {\n this.db = ctx.db\n this.logger = ctx.logger.child({ service: 'notifications' })\n this.generateId = ctx.helpers.generateId\n this.nowTimestamp = ctx.helpers.nowTimestamp\n this.formatTimestamp = ctx.helpers.formatTimestamp\n this.socket = ctx.socket\n this.events = ctx.events\n }\n\n /**\n * Envía una notificación\n */\n async send(options: SendNotificationInput): Promise<{ id: string; sent: number }> {\n const { target_type, target_value } = options\n let sent = 0\n\n const type = options.type || 'info'\n const priority = options.priority || 'normal'\n\n // 1. Persistir notificación\n const id = this.generateId()\n const now = this.nowTimestamp(this.db)\n\n await this.db('notifications').insert({\n id,\n title: options.title,\n message: options.message,\n type,\n priority,\n target_type,\n target_value: target_value || null,\n link: options.link || null,\n read_by: JSON.stringify([]),\n expires_at: options.expires_at ? this.formatTimestamp(this.db, new Date(options.expires_at)) : null,\n created_at: now\n })\n\n // 2. Emitir por Socket.IO si está inicializado\n if (this.socket.isInitialized()) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const io = this.socket.getIO() as any\n\n const payload: NotificationPayload = {\n id,\n title: options.title,\n message: options.message,\n type,\n priority,\n link: options.link || undefined,\n timestamp: now\n }\n\n switch (target_type) {\n case 'all':\n io.to('all').emit('notification', payload)\n sent = io.sockets.sockets.size\n break\n\n case 'authenticated':\n io.to('authenticated').emit('notification', payload)\n sent = (await io.in('authenticated').fetchSockets()).length\n break\n\n case 'role':\n if (target_value) {\n io.to(`role:${target_value}`).emit('notification', payload)\n sent = (await io.in(`role:${target_value}`).fetchSockets()).length\n }\n break\n\n case 'users':\n if (target_value) {\n try {\n const userIds = JSON.parse(target_value) as string[]\n for (const userId of userIds) {\n io.to(`user:${userId}`).emit('notification', payload)\n }\n sent = userIds.length\n } catch {\n this.logger.warn({ target_value }, 'Invalid user IDs JSON')\n }\n }\n break\n\n case 'user':\n if (target_value) {\n io.to(`user:${target_value}`).emit('notification', payload)\n sent = this.socket.isUserConnected(target_value) ? 1 : 0\n }\n break\n }\n\n this.logger.debug({ id, target_type, sent }, 'Notification sent')\n }\n\n // 3. Emitir evento interno\n this.events.emit('notifications.sent', { id, target_type, target_value, sent })\n\n return { id, sent }\n }\n\n /**\n * Marca una notificación como leída por un usuario\n */\n async markAsRead(notificationId: string, userId: string): Promise<boolean> {\n const notification = await this.db('notifications')\n .where('id', notificationId)\n .first()\n\n if (!notification) {\n return false\n }\n\n // Actualizar read_by (append userId si no existe)\n const readBy: string[] = JSON.parse(notification.read_by || '[]')\n if (!readBy.includes(userId)) {\n readBy.push(userId)\n await this.db('notifications')\n .where('id', notificationId)\n .update({ read_by: JSON.stringify(readBy) })\n\n // Insertar en notification_reads (event log)\n await this.db('notification_reads').insert({\n id: this.generateId(),\n notification_id: notificationId,\n user_id: userId,\n read_at: this.nowTimestamp(this.db)\n })\n\n // Emitir por Socket.IO para sync entre tabs\n if (this.socket.isInitialized()) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const io = this.socket.getIO() as any\n io.to(`user:${userId}`).emit('notification:read', { notificationId })\n }\n\n this.logger.debug({ notificationId, userId }, 'Notification marked as read')\n }\n\n return true\n }\n\n /**\n * Marca todas las notificaciones como leídas por un usuario\n */\n async markAllAsRead(userId: string, roleId?: string): Promise<number> {\n const unread = await this.getUnread(userId, roleId)\n let count = 0\n\n for (const notification of unread) {\n await this.markAsRead(notification.id, userId)\n count++\n }\n\n return count\n }\n\n /**\n * Obtiene notificaciones no leídas para un usuario\n */\n async getUnread(userId: string, roleId?: string): Promise<Notification[]> {\n const now = this.nowTimestamp(this.db)\n\n const query = this.db('notifications')\n .where(function () {\n // No expiradas\n this.whereNull('expires_at').orWhere('expires_at', '>', now)\n })\n .orderBy('created_at', 'desc')\n\n const notifications = await query\n\n // Filtrar por target y read_by en memoria (más flexible)\n return notifications.filter((n: Notification) => {\n // Verificar si ya fue leída\n const readBy: string[] = JSON.parse(n.read_by as unknown as string || '[]')\n if (readBy.includes(userId)) {\n return false\n }\n\n // Verificar target\n switch (n.target_type) {\n case 'all':\n case 'authenticated':\n return true\n\n case 'role':\n return n.target_value === roleId\n\n case 'users':\n try {\n const userIds = JSON.parse(n.target_value || '[]') as string[]\n return userIds.includes(userId)\n } catch {\n return false\n }\n\n case 'user':\n return n.target_value === userId\n\n default:\n return false\n }\n })\n }\n\n /**\n * Obtiene una notificación por ID\n */\n async findById(id: string): Promise<Notification | null> {\n const notification = await this.db('notifications').where('id', id).first()\n return notification || null\n }\n\n /**\n * Elimina una notificación\n */\n async delete(id: string): Promise<boolean> {\n const deleted = await this.db('notifications').where('id', id).delete()\n return deleted > 0\n }\n\n /**\n * Limpia notificaciones expiradas\n */\n async cleanupExpired(): Promise<number> {\n const deleted = await this.db('notifications')\n .where('expires_at', '<', this.nowTimestamp(this.db))\n .whereNotNull('expires_at')\n .delete()\n\n if (deleted > 0) {\n this.logger.info({ deleted }, 'Cleaned up expired notifications')\n }\n\n return deleted\n }\n}\n\nlet serviceInstance: NotificationService | null = null\n\n/**\n * Inicializa el servicio de notificaciones\n */\nexport function initNotificationService(ctx: ModuleContext): NotificationService {\n serviceInstance = new NotificationService(ctx)\n return serviceInstance\n}\n\n/**\n * Obtiene la instancia del servicio\n */\nexport function getNotificationService(): NotificationService {\n if (!serviceInstance) {\n throw new Error('NotificationService not initialized')\n }\n return serviceInstance\n}\n","import type { EventEntityDefinition, ActionEntityDefinition } from '@gzl10/nexus-sdk'\nimport { z } from 'zod'\nimport { getNotificationService } from './notifications.service.js'\n\n/**\n * Tipos de notificación\n */\nexport type NotificationType = 'info' | 'warning' | 'error' | 'success'\n\n/**\n * Prioridad de notificación\n */\nexport type NotificationPriority = 'low' | 'normal' | 'high' | 'urgent'\n\n/**\n * Tipos de target para notificaciones\n */\nexport type NotificationTarget = 'all' | 'authenticated' | 'role' | 'users' | 'user'\n\n/**\n * Notification (event) - Notificaciones efímeras con TTL\n */\nexport const notificationEntity: EventEntityDefinition = {\n type: 'event',\n table: 'notifications',\n label: 'Notifications',\n labelField: 'title',\n timestamps: true,\n retention: { days: 30 },\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n title: {\n name: 'title',\n label: 'Title',\n input: 'text',\n db: { type: 'string', size: 255, nullable: false }\n },\n message: {\n name: 'message',\n label: 'Message',\n input: 'textarea',\n db: { type: 'text', nullable: false }\n },\n type: {\n name: 'type',\n label: 'Type',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false, default: 'info' },\n options: {\n static: [\n { value: 'info', label: 'Info' },\n { value: 'success', label: 'Success' },\n { value: 'warning', label: 'Warning' },\n { value: 'error', label: 'Error' }\n ]\n }\n },\n priority: {\n name: 'priority',\n label: 'Priority',\n input: 'select',\n db: { type: 'string', size: 10, nullable: false, default: 'normal' },\n options: {\n static: [\n { value: 'low', label: 'Low' },\n { value: 'normal', label: 'Normal' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' }\n ]\n }\n },\n target_type: {\n name: 'target_type',\n label: 'Target Type',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n options: {\n static: [\n { value: 'user', label: 'User' },\n { value: 'role', label: 'Role' },\n { value: 'all', label: 'All users' }\n ]\n }\n },\n target_value: {\n name: 'target_value',\n label: 'Target Value',\n input: 'text',\n db: { type: 'string', size: 255, nullable: true }\n },\n link: {\n name: 'link',\n label: 'Link',\n input: 'url',\n db: { type: 'string', size: 500, nullable: true }\n },\n read_by: {\n name: 'read_by',\n label: 'Read By',\n input: 'hidden',\n db: { type: 'json', nullable: true }\n },\n expires_at: {\n name: 'expires_at',\n label: 'Expires At',\n input: 'datetime',\n db: { type: 'datetime', nullable: true }\n }\n },\n casl: {\n subject: 'Notification',\n permissions: {\n ADMIN: { actions: ['manage'] },\n EDITOR: { actions: ['read'] },\n VIEWER: { actions: ['read'] }\n }\n }\n}\n\n/**\n * NotificationRead (event) - Log de lecturas\n */\nexport const notificationReadEntity: EventEntityDefinition = {\n type: 'event',\n table: 'notification_reads',\n label: 'Notification Reads',\n labelField: 'notification_id',\n retention: { days: 90 },\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n notification_id: {\n name: 'notification_id',\n label: 'Notification ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n user_id: {\n name: 'user_id',\n label: 'User ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n read_at: {\n name: 'read_at',\n label: 'Read At',\n input: 'datetime',\n db: { type: 'datetime', nullable: false }\n }\n },\n casl: {\n subject: 'NotificationRead',\n permissions: {\n ADMIN: { actions: ['manage'] }\n }\n }\n}\n\n/**\n * Schema de input para enviar notificación\n */\nexport const sendNotificationInputSchema = z.object({\n title: z.string().min(1, 'Title is required'),\n message: z.string().min(1, 'Message is required'),\n type: z.enum(['info', 'warning', 'error', 'success']).optional().default('info'),\n priority: z.enum(['low', 'normal', 'high', 'urgent']).optional().default('normal'),\n target_type: z.enum(['all', 'authenticated', 'role', 'users', 'user']),\n target_value: z.string().optional(),\n link: z.string().url().optional().or(z.literal('')),\n expires_at: z.string().datetime().optional()\n})\n\nexport type SendNotificationInput = z.input<typeof sendNotificationInputSchema>\n\n/**\n * Schema de output\n */\nexport const sendNotificationOutputSchema = z.object({\n id: z.string(),\n sent: z.number()\n})\n\n/**\n * SendNotification (action) - Enviar notificación\n */\nexport const sendNotificationAction: ActionEntityDefinition = {\n type: 'action',\n label: 'Send Notification',\n routePrefix: '/send',\n inputSchema: sendNotificationInputSchema,\n outputSchema: sendNotificationOutputSchema,\n handler: async (_ctx, input: unknown) => {\n // Usar getNotificationService() directamente, no ctx.services\n // porque createModuleRouters() sobrescribe ctx.services['notifications']\n // con el EventEntityService de notificationEntity\n const service = getNotificationService()\n return service.send(input as SendNotificationInput)\n },\n fields: {\n title: {\n name: 'title',\n label: 'Title',\n input: 'text',\n validation: { required: true }\n },\n message: {\n name: 'message',\n label: 'Message',\n input: 'textarea',\n validation: { required: true }\n },\n type: {\n name: 'type',\n label: 'Type',\n input: 'select',\n options: {\n static: [\n { value: 'info', label: 'Info' },\n { value: 'success', label: 'Success' },\n { value: 'warning', label: 'Warning' },\n { value: 'error', label: 'Error' }\n ]\n }\n },\n priority: {\n name: 'priority',\n label: 'Priority',\n input: 'select',\n options: {\n static: [\n { value: 'low', label: 'Low' },\n { value: 'normal', label: 'Normal' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' }\n ]\n }\n },\n target_type: {\n name: 'target_type',\n label: 'Target Type',\n input: 'select',\n options: {\n static: [\n { value: 'user', label: 'User' },\n { value: 'role', label: 'Role' },\n { value: 'all', label: 'All users' }\n ]\n },\n validation: { required: true }\n },\n target_value: {\n name: 'target_value',\n label: 'Target Value',\n input: 'text'\n },\n link: {\n name: 'link',\n label: 'Link',\n input: 'url'\n },\n expires_at: {\n name: 'expires_at',\n label: 'Expires At',\n input: 'datetime'\n }\n },\n casl: {\n subject: 'Notification',\n permissions: {\n ADMIN: { actions: ['execute'] }\n }\n }\n}\n","import type { Request, Response, ModuleContext, Router } from '@gzl10/nexus-sdk'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { getNotificationService } from './notifications.service.js'\nimport { createRateLimit } from '../../core/middleware/rate-limit.middleware.js'\n\n/**\n * Notifications Routes\n *\n * La action sendNotificationAction se monta automáticamente desde definitions.\n * Aquí solo definimos rutas especiales que no son actions (unread, read, etc).\n */\nexport function createNotificationsRoutes(ctx: ModuleContext): Router {\n const router = ctx.createRouter()\n const { auth } = ctx.middleware\n\n if (!auth) {\n throw new Error('Auth middleware not found. Ensure auth module loads before notifications.')\n }\n\n // Crear middleware requireAdmin inline\n const requireAdmin = (req: Request, res: Response, next: () => void) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n // Verificar si es ADMIN por roleId o por abilities\n const ability = (req as AuthRequest).ability\n if (!ability?.can('manage', 'all')) {\n res.status(403).json({ error: 'Forbidden: Admin role required' })\n return\n }\n next()\n }\n\n /**\n * GET /notifications/unread\n * Obtiene notificaciones no leídas del usuario autenticado\n */\n router.get('/unread', auth, async (req: Request, res: Response) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const service = getNotificationService()\n const notifications = await service.getUnread(user.id, user.role_id)\n\n res.json({\n items: notifications,\n total: notifications.length,\n page: 1,\n limit: notifications.length,\n totalPages: 1,\n hasNext: false\n })\n })\n\n /**\n * POST /notifications/:id/read\n * Marca una notificación como leída\n */\n router.post('/:id/read', auth, async (req: Request, res: Response) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const id = req.params['id']\n if (!id) {\n res.status(400).json({ error: 'Missing notification ID' })\n return\n }\n\n const service = getNotificationService()\n const success = await service.markAsRead(id, user.id)\n\n if (!success) {\n res.status(404).json({ error: 'Notification not found' })\n return\n }\n\n res.status(204).send()\n })\n\n /**\n * POST /notifications/read-all\n * Marca todas las notificaciones como leídas\n */\n router.post('/read-all', auth, async (req: Request, res: Response) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const service = getNotificationService()\n const count = await service.markAllAsRead(user.id, user.role_id)\n\n res.json({ count })\n })\n\n /**\n * DELETE /notifications/:id\n * Elimina una notificación (solo admin)\n */\n router.delete('/:id', auth, requireAdmin, async (req: Request, res: Response) => {\n const id = req.params['id']\n if (!id) {\n res.status(400).json({ error: 'Missing notification ID' })\n return\n }\n\n const service = getNotificationService()\n const success = await service.delete(id)\n\n if (!success) {\n res.status(404).json({ error: 'Notification not found' })\n return\n }\n\n res.status(204).send()\n })\n\n /**\n * GET /notifications\n * Lista notificaciones (solo admin)\n */\n router.get('/', auth, requireAdmin, async (req: Request, res: Response) => {\n const limit = parseInt(req.query['limit'] as string) || 50\n const page = parseInt(req.query['page'] as string) || 1\n const offset = (page - 1) * limit\n\n const notifications = await ctx.db('notifications')\n .orderBy('created_at', 'desc')\n .limit(limit)\n .offset(offset)\n\n const countResult = await ctx.db('notifications').count('* as count').first<{ count: string | number }>()\n const total = parseInt(String(countResult?.count || 0))\n const totalPages = Math.ceil(total / limit)\n\n res.json({\n items: notifications,\n total,\n page,\n limit,\n totalPages,\n hasNext: page < totalPages\n })\n })\n\n /**\n * POST /notifications/cleanup\n * Limpia notificaciones expiradas (solo admin)\n */\n const cleanupRateLimit = createRateLimit({ windowMs: 60 * 1000, max: 1, message: 'Cleanup solo puede ejecutarse 1 vez por minuto' })\n router.post('/cleanup', cleanupRateLimit, auth, requireAdmin, async (_req: Request, res: Response) => {\n const service = getNotificationService()\n const deleted = await service.cleanupExpired()\n\n res.json({ deleted })\n })\n\n return router\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport { getNotificationService } from './notifications.service.js'\n\n/**\n * Registra handlers de Socket.IO para notificaciones\n */\nexport function registerNotificationSocketHandlers(ctx: ModuleContext): void {\n if (!ctx.socket.isInitialized()) {\n ctx.logger.debug('Socket.IO not initialized, skipping notification handlers')\n return\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const io = ctx.socket.getIO() as any\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n io.on('connection', (socket: any) => {\n const { userId, roleId, authenticated } = socket.data\n\n if (!authenticated || !userId) {\n return\n }\n\n /**\n * notification:read - Marcar notificación como leída\n */\n socket.on('notification:read', async (data: { notificationId: string }) => {\n try {\n const service = getNotificationService()\n await service.markAsRead(data.notificationId, userId)\n } catch (err) {\n ctx.logger.error({ err, userId, notificationId: data.notificationId }, 'Error marking notification as read')\n }\n })\n\n /**\n * notifications:read-all - Marcar todas como leídas\n */\n socket.on('notifications:read-all', async () => {\n try {\n const service = getNotificationService()\n await service.markAllAsRead(userId, roleId)\n } catch (err) {\n ctx.logger.error({ err, userId }, 'Error marking all notifications as read')\n }\n })\n })\n\n ctx.logger.debug('Notification socket handlers registered')\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport {\n notificationEntity,\n notificationReadEntity,\n sendNotificationAction\n} from './notifications.entity.js'\nimport { createNotificationsRoutes } from './notifications.routes.js'\nimport { initNotificationService, getNotificationService, NotificationService } from './notifications.service.js'\nimport { registerNotificationSocketHandlers } from './notifications.socket.js'\n\nexport {\n NotificationService,\n getNotificationService,\n initNotificationService\n}\n\nexport type {\n NotificationType,\n NotificationPriority,\n NotificationTarget,\n SendNotificationInput\n} from './notifications.entity.js'\n\nexport type {\n Notification,\n NotificationPayload\n} from './notifications.service.js'\n\n/**\n * Módulo de notificaciones en tiempo real\n */\nexport const notificationsModule: ModuleManifest = {\n name: 'notifications',\n label: 'Notifications',\n icon: 'mdi:bell-outline',\n description: 'Real-time notifications via Socket.IO',\n type: 'core',\n category: 'messaging',\n dependencies: ['logger', 'users'],\n\n definitions: [\n notificationEntity,\n notificationReadEntity,\n sendNotificationAction\n ],\n\n routePrefix: '/notifications',\n routes: createNotificationsRoutes,\n\n init: (ctx) => {\n const service = initNotificationService(ctx)\n ctx.services['notifications'] = service\n\n // Registrar handlers Socket.IO (después de que el servidor inicie)\n // Se ejecuta de forma diferida porque Socket.IO puede no estar listo\n setTimeout(() => {\n registerNotificationSocketHandlers(ctx)\n }, 0)\n\n ctx.logger.debug('Notifications module initialized')\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport type {\n Schedule,\n ServiceActionConfig,\n HttpInternalConfig,\n HttpExternalConfig,\n FunctionRegistryConfig,\n RegisteredFunction,\n ExecutionResult\n} from './schedules.types.js'\n\n/**\n * Registry de funciones para function_registry target\n */\nconst functionRegistry = new Map<string, RegisteredFunction>()\n\n/**\n * Registra una función para usar con function_registry\n */\nexport function registerFunction(key: string, fn: RegisteredFunction): void {\n functionRegistry.set(key, fn)\n}\n\n/**\n * Desregistra una función\n */\nexport function unregisterFunction(key: string): void {\n functionRegistry.delete(key)\n}\n\n/**\n * Obtiene una función registrada\n */\nexport function getRegisteredFunction(key: string): RegisteredFunction | undefined {\n return functionRegistry.get(key)\n}\n\n/**\n * Lista todas las funciones registradas\n */\nexport function listRegisteredFunctions(): string[] {\n return Array.from(functionRegistry.keys())\n}\n\n/**\n * Ejecuta un service_action target\n */\nasync function executeServiceAction(\n ctx: ModuleContext,\n config: ServiceActionConfig\n): Promise<unknown> {\n const { service, action, input, recordId } = config\n\n // Obtener el servicio del registro\n const targetService = ctx.services[service]\n if (!targetService) {\n throw new Error(`Service '${service}' not found in ctx.services`)\n }\n\n // Verificar que el servicio tiene executeAction\n if (typeof (targetService as { executeAction?: unknown }).executeAction !== 'function') {\n throw new Error(`Service '${service}' does not support executeAction()`)\n }\n\n // Ejecutar la action\n const result = await (targetService as {\n executeAction: (action: string, input?: Record<string, unknown>, recordId?: string) => Promise<unknown>\n }).executeAction(action, input ?? {}, recordId)\n\n return result\n}\n\n/**\n * Ejecuta un http_internal target (endpoint del propio backend)\n */\nasync function executeHttpInternal(\n _ctx: ModuleContext,\n config: HttpInternalConfig\n): Promise<unknown> {\n const { method, path, body, headers } = config\n\n // Usar fetch contra el propio servidor\n const port = process.env['PORT'] ?? 3000\n const baseUrl = `http://127.0.0.1:${port}`\n const url = `${baseUrl}${path}`\n\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...headers\n },\n body: body ? JSON.stringify(body) : undefined\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`HTTP ${response.status}: ${errorText}`)\n }\n\n // Intentar parsear como JSON, si falla devolver texto\n const contentType = response.headers.get('content-type')\n if (contentType?.includes('application/json')) {\n return response.json()\n }\n\n return response.text()\n}\n\n/**\n * Ejecuta un http_external target (webhook externo)\n */\nasync function executeHttpExternal(config: HttpExternalConfig): Promise<unknown> {\n const { method, url, body, headers, timeout = 30000 } = config\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n ...headers\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`HTTP ${response.status}: ${errorText}`)\n }\n\n const contentType = response.headers.get('content-type')\n if (contentType?.includes('application/json')) {\n return response.json()\n }\n\n return response.text()\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Ejecuta un function_registry target\n */\nasync function executeFunctionRegistry(config: FunctionRegistryConfig): Promise<unknown> {\n const { functionKey, args } = config\n\n const fn = functionRegistry.get(functionKey)\n if (!fn) {\n throw new Error(`Function '${functionKey}' not found in registry. Available: ${listRegisteredFunctions().join(', ') || 'none'}`)\n }\n\n return fn(args)\n}\n\n/**\n * Ejecuta el target de un schedule\n */\nexport async function executeTarget(\n ctx: ModuleContext,\n schedule: Schedule\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n\n try {\n let data: unknown\n\n switch (schedule.target_type) {\n case 'service_action':\n data = await executeServiceAction(ctx, schedule.target_config as ServiceActionConfig)\n break\n\n case 'http_internal':\n data = await executeHttpInternal(ctx, schedule.target_config as HttpInternalConfig)\n break\n\n case 'http_external':\n data = await executeHttpExternal(schedule.target_config as HttpExternalConfig)\n break\n\n case 'function_registry':\n data = await executeFunctionRegistry(schedule.target_config as FunctionRegistryConfig)\n break\n\n default:\n throw new Error(`Unknown target_type: ${schedule.target_type}`)\n }\n\n return {\n success: true,\n data,\n duration_ms: Date.now() - startTime\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n duration_ms: Date.now() - startTime\n }\n }\n}\n","import type { ModuleContext } from '@gzl10/nexus-sdk'\nimport cron from 'node-cron'\nimport type { ScheduledTask } from 'node-cron'\nimport { CronExpressionParser } from 'cron-parser'\nimport type {\n Schedule,\n ScheduleJob,\n ScheduleStatus,\n CreateScheduleInput,\n UpdateScheduleInput,\n RegisteredFunction,\n ExecutionResult,\n NextRunInfo\n} from './schedules.types.js'\nimport {\n executeTarget,\n registerFunction as registerFn,\n unregisterFunction as unregisterFn,\n listRegisteredFunctions\n} from './schedules.executor.js'\n\nlet schedulesService: SchedulesService | null = null\n\n/**\n * Servicio de schedules con node-cron\n */\nexport class SchedulesService {\n private ctx: ModuleContext\n private jobs: Map<string, ScheduleJob> = new Map()\n private initialized = false\n private generateId: () => string\n\n constructor(ctx: ModuleContext) {\n this.ctx = ctx\n this.generateId = ctx.helpers.generateId\n }\n\n /**\n * Inicializa el servicio cargando schedules activos de BD\n */\n async init(): Promise<void> {\n if (this.initialized) return\n\n this.ctx.logger.debug('Initializing schedules service...')\n\n // Cargar schedules activos de la BD\n const schedules = await this.ctx.db<Schedule>('schedules')\n .where('enabled', true)\n .whereNot('status', 'paused')\n .select('*')\n\n for (const schedule of schedules) {\n this.scheduleJob(schedule)\n }\n\n this.initialized = true\n this.ctx.logger.info(`Schedules service initialized with ${schedules.length} active jobs`)\n }\n\n /**\n * Detiene todos los jobs\n */\n shutdown(): void {\n this.ctx.logger.debug('Shutting down schedules service...')\n\n for (const [id, job] of this.jobs) {\n job.task.stop()\n this.ctx.logger.debug(`Stopped job: ${id}`)\n }\n\n this.jobs.clear()\n this.initialized = false\n this.ctx.logger.info('Schedules service shut down')\n }\n\n /**\n * Crea un nuevo schedule\n */\n async create(data: CreateScheduleInput, userId?: string): Promise<Schedule> {\n // Validar expresión cron\n if (!cron.validate(data.cron_expression)) {\n throw new this.ctx.errors.ValidationError(`Invalid cron expression: ${data.cron_expression}`)\n }\n\n // Validar timezone\n if (data.timezone && data.timezone !== 'UTC') {\n try {\n Intl.DateTimeFormat(undefined, { timeZone: data.timezone })\n } catch {\n throw new this.ctx.errors.ValidationError(`Invalid timezone: ${data.timezone}`)\n }\n }\n\n const now = new Date().toISOString()\n const schedule: Schedule = {\n id: this.generateId(),\n name: data.name,\n description: data.description ?? null,\n cron_expression: data.cron_expression,\n timezone: data.timezone ?? 'UTC',\n target_type: data.target_type,\n target_config: data.target_config,\n enabled: data.enabled ?? true,\n status: 'idle',\n last_run_at: null,\n last_error: null,\n run_count: 0,\n created_at: now,\n updated_at: now,\n created_by: userId ?? null,\n updated_by: userId ?? null\n }\n\n // Insertar en BD\n await this.ctx.db('schedules').insert({\n ...schedule,\n target_config: JSON.stringify(schedule.target_config)\n })\n\n // Programar job si está habilitado\n if (schedule.enabled) {\n this.scheduleJob(schedule)\n }\n\n this.ctx.logger.info(`Schedule created: ${schedule.name} (${schedule.id})`)\n return schedule\n }\n\n /**\n * Actualiza un schedule existente\n */\n async update(id: string, data: UpdateScheduleInput, userId?: string): Promise<Schedule> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n // Validar expresión cron si se actualiza\n if (data.cron_expression && !cron.validate(data.cron_expression)) {\n throw new this.ctx.errors.ValidationError(`Invalid cron expression: ${data.cron_expression}`)\n }\n\n // Validar timezone si se actualiza\n if (data.timezone && data.timezone !== 'UTC') {\n try {\n Intl.DateTimeFormat(undefined, { timeZone: data.timezone })\n } catch {\n throw new this.ctx.errors.ValidationError(`Invalid timezone: ${data.timezone}`)\n }\n }\n\n const updated: Partial<Schedule> = {\n ...data,\n updated_at: new Date().toISOString(),\n updated_by: userId ?? null\n }\n\n // Actualizar en BD\n await this.ctx.db('schedules')\n .where('id', id)\n .update({\n ...updated,\n target_config: data.target_config ? JSON.stringify(data.target_config) : undefined\n })\n\n // Obtener schedule actualizado\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found after update: ${id}`)\n }\n\n // Reprogramar job\n this.cancelJob(id)\n if (schedule.enabled && schedule.status !== 'paused') {\n this.scheduleJob(schedule)\n }\n\n this.ctx.logger.info(`Schedule updated: ${schedule.name} (${id})`)\n return schedule\n }\n\n /**\n * Elimina un schedule\n */\n async delete(id: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n // Cancelar job\n this.cancelJob(id)\n\n // Eliminar de BD\n await this.ctx.db('schedules').where('id', id).delete()\n\n this.ctx.logger.info(`Schedule deleted: ${existing.name} (${id})`)\n }\n\n /**\n * Busca un schedule por ID\n */\n async findById(id: string): Promise<Schedule | null> {\n const row = await this.ctx.db<Schedule>('schedules')\n .where('id', id)\n .first()\n\n if (!row) return null\n\n return {\n ...row,\n target_config: typeof row.target_config === 'string'\n ? JSON.parse(row.target_config)\n : row.target_config\n }\n }\n\n /**\n * Lista todos los schedules\n */\n async findAll(): Promise<Schedule[]> {\n const rows = await this.ctx.db<Schedule>('schedules')\n .orderBy('created_at', 'desc')\n .select('*')\n\n return rows.map(row => ({\n ...row,\n target_config: typeof row.target_config === 'string'\n ? JSON.parse(row.target_config)\n : row.target_config\n }))\n }\n\n /**\n * Pausa un schedule\n */\n async pause(id: string): Promise<void> {\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n // Cancelar job\n this.cancelJob(id)\n\n // Actualizar status en BD\n await this.ctx.db('schedules')\n .where('id', id)\n .update({ status: 'paused', updated_at: new Date().toISOString() })\n\n this.ctx.logger.info(`Schedule paused: ${schedule.name} (${id})`)\n }\n\n /**\n * Reanuda un schedule pausado\n */\n async resume(id: string): Promise<void> {\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n if (!schedule.enabled) {\n throw new this.ctx.errors.ValidationError(`Cannot resume disabled schedule: ${id}`)\n }\n\n // Actualizar status en BD\n await this.ctx.db('schedules')\n .where('id', id)\n .update({ status: 'idle', updated_at: new Date().toISOString() })\n\n // Reprogramar job\n const updated = await this.findById(id)\n if (updated) {\n this.scheduleJob(updated)\n }\n\n this.ctx.logger.info(`Schedule resumed: ${schedule.name} (${id})`)\n }\n\n /**\n * Ejecuta un schedule inmediatamente (trigger manual)\n */\n async trigger(id: string): Promise<ExecutionResult> {\n const schedule = await this.findById(id)\n if (!schedule) {\n throw new this.ctx.errors.NotFoundError(`Schedule not found: ${id}`)\n }\n\n this.ctx.logger.info(`Manual trigger: ${schedule.name} (${id})`)\n return this.executeSchedule(schedule)\n }\n\n /**\n * Obtiene las próximas ejecuciones\n */\n async getNextRuns(limit = 10): Promise<NextRunInfo[]> {\n const schedules = await this.ctx.db<Schedule>('schedules')\n .where('enabled', true)\n .whereNot('status', 'paused')\n .select('id', 'name', 'cron_expression', 'timezone')\n .limit(limit)\n\n const result: NextRunInfo[] = []\n\n for (const schedule of schedules) {\n const nextDate = this.getNextRunDate(schedule.cron_expression, schedule.timezone)\n if (nextDate) {\n result.push({\n id: schedule.id,\n name: schedule.name,\n cron_expression: schedule.cron_expression,\n next_run: nextDate.toISOString()\n })\n }\n }\n\n // Ordenar por próxima ejecución\n return result.sort((a, b) => new Date(a.next_run).getTime() - new Date(b.next_run).getTime())\n }\n\n /**\n * Sincroniza un job con la BD (para usar con eventos de CRUD auto-montado)\n */\n async syncJob(id: string): Promise<void> {\n const schedule = await this.findById(id)\n if (!schedule) {\n // Schedule fue eliminado, cancelar job si existe\n this.cancelJob(id)\n return\n }\n\n // Cancelar job existente\n this.cancelJob(id)\n\n // Reprogramar si está habilitado y no pausado\n if (schedule.enabled && schedule.status !== 'paused') {\n this.scheduleJob(schedule)\n }\n }\n\n /**\n * Cancela un job por ID (público para uso desde eventos)\n */\n cancelJobById(id: string): void {\n this.cancelJob(id)\n }\n\n /**\n * Registra una función para function_registry\n */\n registerFunction(key: string, fn: RegisteredFunction): void {\n registerFn(key, fn)\n this.ctx.logger.debug(`Function registered: ${key}`)\n }\n\n /**\n * Desregistra una función\n */\n unregisterFunction(key: string): void {\n unregisterFn(key)\n this.ctx.logger.debug(`Function unregistered: ${key}`)\n }\n\n /**\n * Lista funciones registradas\n */\n getRegisteredFunctions(): string[] {\n return listRegisteredFunctions()\n }\n\n // --- Private methods ---\n\n /**\n * Programa un job con node-cron\n */\n private scheduleJob(schedule: Schedule): void {\n if (this.jobs.has(schedule.id)) {\n this.ctx.logger.warn(`Job already scheduled: ${schedule.id}`)\n return\n }\n\n const task: ScheduledTask = cron.schedule(\n schedule.cron_expression,\n async () => {\n await this.executeSchedule(schedule)\n },\n {\n timezone: schedule.timezone\n }\n )\n\n this.jobs.set(schedule.id, { id: schedule.id, task, schedule })\n this.ctx.logger.debug(`Job scheduled: ${schedule.name} (${schedule.cron_expression})`)\n }\n\n /**\n * Cancela un job\n */\n private cancelJob(id: string): void {\n const job = this.jobs.get(id)\n if (job) {\n job.task.stop()\n this.jobs.delete(id)\n this.ctx.logger.debug(`Job cancelled: ${id}`)\n }\n }\n\n /**\n * Ejecuta un schedule\n */\n private async executeSchedule(schedule: Schedule): Promise<ExecutionResult> {\n // Verificar si ya está corriendo (skip concurrencia)\n const current = await this.findById(schedule.id)\n if (current?.status === 'running') {\n this.ctx.logger.warn(`Skipping execution, already running: ${schedule.name}`)\n await this.logExecution(schedule.id, {\n success: false,\n error: 'Skipped: previous execution still running',\n duration_ms: 0\n }, 'skipped')\n return { success: false, error: 'Skipped: already running', duration_ms: 0 }\n }\n\n // Marcar como running\n await this.ctx.db('schedules')\n .where('id', schedule.id)\n .update({ status: 'running' })\n\n // Ejecutar\n const result = await executeTarget(this.ctx, schedule)\n\n // Actualizar estado\n const newStatus: ScheduleStatus = result.success ? 'idle' : 'error'\n await this.ctx.db('schedules')\n .where('id', schedule.id)\n .update({\n status: newStatus,\n last_run_at: new Date().toISOString(),\n last_error: result.error ?? null,\n run_count: this.ctx.db.raw('run_count + 1')\n })\n\n // Log de ejecución\n await this.logExecution(schedule.id, result, result.success ? 'success' : 'error')\n\n if (result.success) {\n this.ctx.logger.info(`Schedule executed: ${schedule.name} (${result.duration_ms}ms)`)\n } else {\n this.ctx.logger.error(`Schedule failed: ${schedule.name} - ${result.error}`)\n }\n\n return result\n }\n\n /**\n * Registra log de ejecución\n */\n private async logExecution(\n scheduleId: string,\n result: ExecutionResult,\n status: 'success' | 'error' | 'skipped'\n ): Promise<void> {\n const now = new Date()\n const startedAt = new Date(now.getTime() - result.duration_ms)\n\n await this.ctx.db('schedule_logs').insert({\n id: this.generateId(),\n schedule_id: scheduleId,\n started_at: startedAt.toISOString(),\n finished_at: now.toISOString(),\n duration_ms: result.duration_ms,\n status,\n result: result.data ? JSON.stringify(result.data) : null,\n error: result.error ?? null,\n created_at: now.toISOString()\n })\n }\n\n /**\n * Calcula la próxima fecha de ejecución usando cron-parser\n */\n private getNextRunDate(cronExpression: string, timezone: string): Date | null {\n try {\n const interval = CronExpressionParser.parse(cronExpression, {\n tz: timezone\n })\n return interval.next().toDate()\n } catch {\n return null\n }\n }\n}\n\n/**\n * Inicializa el servicio de schedules\n */\nexport function initSchedulesService(ctx: ModuleContext): SchedulesService {\n schedulesService = new SchedulesService(ctx)\n return schedulesService\n}\n\n/**\n * Obtiene el servicio de schedules\n */\nexport function getSchedulesService(): SchedulesService {\n if (!schedulesService) {\n throw new Error('Schedules service not initialized. Call initSchedulesService() first.')\n }\n return schedulesService\n}\n","import type {\n CollectionEntityDefinition,\n EventEntityDefinition,\n ModuleContext\n} from '@gzl10/nexus-sdk'\nimport type { Request, Response } from 'express'\nimport { z } from 'zod'\nimport type { Schedule } from './schedules.types.js'\nimport { getSchedulesService } from './schedules.service.js'\n\n/**\n * Schema de validación para target_config según tipo\n */\nconst serviceActionConfigSchema = z.object({\n service: z.string().min(1),\n action: z.string().min(1),\n input: z.record(z.unknown()).optional(),\n recordId: z.string().optional()\n})\n\nconst httpInternalConfigSchema = z.object({\n method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']),\n path: z.string().startsWith('/'),\n body: z.record(z.unknown()).optional(),\n headers: z.record(z.string()).optional()\n})\n\nconst httpExternalConfigSchema = z.object({\n method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']),\n url: z.string().url(),\n body: z.record(z.unknown()).optional(),\n headers: z.record(z.string()).optional(),\n timeout: z.number().positive().optional()\n})\n\nconst functionRegistryConfigSchema = z.object({\n functionKey: z.string().min(1),\n args: z.record(z.unknown()).optional()\n})\n\n/**\n * Schema base para crear/actualizar schedule\n */\nexport const scheduleInputSchema = z.object({\n name: z.string().min(1).max(100),\n description: z.string().max(500).optional(),\n cron_expression: z.string().min(1).max(50),\n timezone: z.string().max(50).default('UTC'),\n target_type: z.enum(['service_action', 'http_internal', 'http_external', 'function_registry']),\n target_config: z.union([\n serviceActionConfigSchema,\n httpInternalConfigSchema,\n httpExternalConfigSchema,\n functionRegistryConfigSchema\n ]),\n enabled: z.boolean().default(true)\n})\n\nexport type ScheduleInput = z.infer<typeof scheduleInputSchema>\n\n/**\n * Schedule Entity (collection)\n */\nexport const scheduleEntity: CollectionEntityDefinition = {\n type: 'collection',\n table: 'schedules',\n label: 'Schedules',\n labelField: 'name',\n timestamps: true,\n audit: true,\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n name: {\n name: 'name',\n label: 'Name',\n input: 'text',\n validation: { required: true },\n db: { type: 'string', size: 100, nullable: false }\n },\n description: {\n name: 'description',\n label: 'Description',\n input: 'textarea',\n db: { type: 'text', nullable: true }\n },\n cron_expression: {\n name: 'cron_expression',\n label: 'Cron Expression',\n input: 'text',\n validation: { required: true },\n db: { type: 'string', size: 50, nullable: false }\n },\n timezone: {\n name: 'timezone',\n label: 'Timezone',\n input: 'select',\n db: { type: 'string', size: 50, nullable: false, default: 'UTC' },\n options: {\n static: [\n { value: 'UTC', label: 'UTC' },\n { value: 'Europe/Madrid', label: 'Europe/Madrid (CET/CEST)' },\n { value: 'Europe/London', label: 'Europe/London (GMT/BST)' },\n { value: 'Europe/Paris', label: 'Europe/Paris (CET/CEST)' },\n { value: 'Europe/Berlin', label: 'Europe/Berlin (CET/CEST)' },\n { value: 'America/New_York', label: 'America/New_York (EST/EDT)' },\n { value: 'America/Chicago', label: 'America/Chicago (CST/CDT)' },\n { value: 'America/Denver', label: 'America/Denver (MST/MDT)' },\n { value: 'America/Los_Angeles', label: 'America/Los_Angeles (PST/PDT)' },\n { value: 'America/Sao_Paulo', label: 'America/Sao_Paulo (BRT)' },\n { value: 'Asia/Tokyo', label: 'Asia/Tokyo (JST)' },\n { value: 'Asia/Shanghai', label: 'Asia/Shanghai (CST)' },\n { value: 'Asia/Singapore', label: 'Asia/Singapore (SGT)' },\n { value: 'Australia/Sydney', label: 'Australia/Sydney (AEST/AEDT)' }\n ],\n allowCreate: true\n }\n },\n target_type: {\n name: 'target_type',\n label: 'Target Type',\n input: 'select',\n validation: { required: true },\n db: { type: 'string', size: 20, nullable: false },\n options: {\n static: [\n { value: 'webhook', label: 'Webhook (HTTP)' },\n { value: 'event', label: 'Event (internal)' }\n ]\n }\n },\n target_config: {\n name: 'target_config',\n label: 'Target Configuration',\n input: 'json',\n validation: { required: true },\n db: { type: 'json', nullable: false }\n },\n enabled: {\n name: 'enabled',\n label: 'Enabled',\n input: 'switch',\n db: { type: 'boolean', nullable: false, default: true }\n },\n status: {\n name: 'status',\n label: 'Status',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false, default: 'idle' },\n options: {\n static: [\n { value: 'idle', label: 'Idle' },\n { value: 'running', label: 'Running' },\n { value: 'error', label: 'Error' }\n ]\n }\n },\n last_run_at: {\n name: 'last_run_at',\n label: 'Last Run',\n input: 'datetime',\n db: { type: 'datetime', nullable: true }\n },\n last_error: {\n name: 'last_error',\n label: 'Last Error',\n input: 'textarea',\n db: { type: 'text', nullable: true }\n },\n run_count: {\n name: 'run_count',\n label: 'Run Count',\n input: 'number',\n db: { type: 'integer', nullable: false, default: 0 }\n }\n },\n\n actions: [\n {\n key: 'pause',\n label: 'Pause Schedule',\n icon: 'mdi:pause',\n method: 'POST',\n select: ['id', 'name', 'status', 'enabled'],\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { _record } = input as { _record: Schedule }\n const service = getSchedulesService()\n await service.pause(_record.id)\n return { success: true, status: 'paused' }\n },\n casl: { action: 'update' }\n },\n {\n key: 'resume',\n label: 'Resume Schedule',\n icon: 'mdi:play',\n method: 'POST',\n select: ['id', 'name', 'status', 'enabled', 'cron_expression', 'timezone'],\n handler: async (ctx: ModuleContext, input: unknown) => {\n const { _record } = input as { _record: Schedule }\n const service = getSchedulesService()\n await service.resume(_record.id)\n return { success: true, status: 'idle' }\n },\n casl: { action: 'update' }\n },\n {\n key: 'trigger',\n label: 'Run Now',\n icon: 'mdi:play-circle',\n method: 'POST',\n select: ['id', 'name', 'status', 'target_type', 'target_config'],\n handler: async (ctx: ModuleContext, input: unknown, _req?: Request, res?: Response) => {\n const { _record } = input as { _record: Schedule }\n const service = getSchedulesService()\n const result = await service.trigger(_record.id)\n return result\n },\n casl: { action: 'execute' }\n }\n ],\n\n casl: {\n subject: 'Schedule',\n permissions: {\n ADMIN: { actions: ['manage'] }\n }\n }\n}\n\n/**\n * Schedule Log Entity (event - append-only)\n */\nexport const scheduleLogEntity: EventEntityDefinition = {\n type: 'event',\n table: 'schedule_logs',\n label: 'Schedule Logs',\n labelField: 'schedule_id',\n timestamps: true,\n retention: { days: 30 },\n\n fields: {\n id: {\n name: 'id',\n label: 'ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n schedule_id: {\n name: 'schedule_id',\n label: 'Schedule ID',\n input: 'hidden',\n db: { type: 'string', size: 26, nullable: false }\n },\n started_at: {\n name: 'started_at',\n label: 'Started At',\n input: 'datetime',\n db: { type: 'datetime', nullable: false }\n },\n finished_at: {\n name: 'finished_at',\n label: 'Finished At',\n input: 'datetime',\n db: { type: 'datetime', nullable: true }\n },\n duration_ms: {\n name: 'duration_ms',\n label: 'Duration (ms)',\n input: 'number',\n db: { type: 'integer', nullable: true }\n },\n status: {\n name: 'status',\n label: 'Status',\n input: 'select',\n db: { type: 'string', size: 20, nullable: false },\n options: {\n static: [\n { value: 'pending', label: 'Pending' },\n { value: 'running', label: 'Running' },\n { value: 'success', label: 'Success' },\n { value: 'failed', label: 'Failed' }\n ]\n }\n },\n result: {\n name: 'result',\n label: 'Result',\n input: 'json',\n db: { type: 'json', nullable: true }\n },\n error: {\n name: 'error',\n label: 'Error',\n input: 'textarea',\n db: { type: 'text', nullable: true }\n }\n },\n\n casl: {\n subject: 'ScheduleLog',\n permissions: {\n ADMIN: { actions: ['read'] }\n }\n }\n}\n","import type { Request, Response, ModuleContext, Router } from '@gzl10/nexus-sdk'\nimport type { AuthRequest } from '../../types/auth.types.js'\nimport { getSchedulesService } from './schedules.service.js'\n\n/**\n * Schedules Routes\n *\n * Las Entity Actions (pause, resume, trigger) se montan automáticamente.\n * Aquí solo definimos rutas adicionales.\n */\nexport function createSchedulesRoutes(ctx: ModuleContext): Router {\n const router = ctx.createRouter()\n const { auth } = ctx.middleware\n\n if (!auth) {\n throw new Error('Auth middleware not found. Ensure auth module loads before schedules.')\n }\n\n // Middleware para verificar ADMIN\n const requireAdmin = (req: Request, res: Response, next: () => void) => {\n const user = (req as AuthRequest).user\n if (!user) {\n res.status(401).json({ error: 'Unauthorized' })\n return\n }\n\n const ability = (req as AuthRequest).ability\n if (!ability?.can('manage', 'all')) {\n res.status(403).json({ error: 'Forbidden: Admin role required' })\n return\n }\n next()\n }\n\n /**\n * GET /schedules/next-runs\n * Obtiene las próximas ejecuciones programadas\n */\n router.get('/next-runs', auth, requireAdmin, async (req: Request, res: Response) => {\n const limit = Math.min(parseInt(req.query['limit'] as string) || 10, 100)\n\n const service = getSchedulesService()\n const nextRuns = await service.getNextRuns(limit)\n\n res.json({\n items: nextRuns,\n total: nextRuns.length\n })\n })\n\n /**\n * GET /schedules/functions\n * Lista las funciones registradas para function_registry\n */\n router.get('/functions', auth, requireAdmin, async (_req: Request, res: Response) => {\n const service = getSchedulesService()\n const functions = service.getRegisteredFunctions()\n\n res.json({\n items: functions,\n total: functions.length\n })\n })\n\n return router\n}\n","import type { ModuleManifest } from '@gzl10/nexus-sdk'\nimport { scheduleEntity, scheduleLogEntity } from './schedules.entity.js'\nimport { createSchedulesRoutes } from './schedules.routes.js'\nimport { initSchedulesService, getSchedulesService, SchedulesService } from './schedules.service.js'\nimport { registerFunction, unregisterFunction } from './schedules.executor.js'\n\n// Re-exports\nexport {\n SchedulesService,\n getSchedulesService,\n initSchedulesService,\n registerFunction,\n unregisterFunction\n}\n\nexport type {\n Schedule,\n ScheduleLog,\n ScheduleTargetType,\n ScheduleStatus,\n ScheduleLogStatus,\n CreateScheduleInput,\n UpdateScheduleInput,\n ServiceActionConfig,\n HttpInternalConfig,\n HttpExternalConfig,\n FunctionRegistryConfig,\n TargetConfig,\n RegisteredFunction,\n ExecutionResult,\n NextRunInfo\n} from './schedules.types.js'\n\n/**\n * Módulo de schedules (tareas programadas con cron)\n */\nexport const schedulesModule: ModuleManifest = {\n name: 'schedules',\n label: 'Schedules',\n icon: 'mdi:clock-outline',\n description: 'Scheduled tasks with cron expressions',\n type: 'core',\n category: 'jobs',\n dependencies: ['logger'],\n\n definitions: [\n scheduleEntity,\n scheduleLogEntity\n ],\n\n routePrefix: '/schedules',\n routes: createSchedulesRoutes,\n\n init: async (ctx) => {\n const service = initSchedulesService(ctx)\n ctx.services['schedules'] = service\n\n // Handler para sincronizar jobs cuando el CRUD auto-montado modifica schedules\n const handleScheduleChange = async (...args: unknown[]) => {\n try {\n const payload = args[0] as { data?: unknown; id?: string } | undefined\n if (payload?.id) {\n await service.syncJob(payload.id)\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n ctx.logger.error(`Failed to sync schedule job: ${message}`)\n }\n }\n\n const handleScheduleDelete = (...args: unknown[]) => {\n const payload = args[0] as { id?: string } | undefined\n if (payload?.id) {\n service.cancelJobById(payload.id)\n }\n }\n\n // Escuchar eventos de BD para sincronizar jobs\n ctx.events.on('db.schedules.created', handleScheduleChange)\n ctx.events.on('db.schedules.updated', handleScheduleChange)\n ctx.events.on('db.schedules.deleted', handleScheduleDelete)\n\n // Handler de shutdown\n const shutdownHandler = () => {\n // Remover listeners de eventos\n ctx.events.off('db.schedules.created', handleScheduleChange)\n ctx.events.off('db.schedules.updated', handleScheduleChange)\n ctx.events.off('db.schedules.deleted', handleScheduleDelete)\n // Detener jobs\n service.shutdown()\n }\n\n // Registrar shutdown handlers\n process.on('SIGTERM', shutdownHandler)\n process.on('SIGINT', shutdownHandler)\n\n // Inicializar jobs activos (diferido para que BD esté lista)\n setTimeout(async () => {\n try {\n await service.init()\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n ctx.logger.error(`Failed to initialize schedules: ${message}`)\n }\n }, 100)\n\n ctx.logger.debug('Schedules module initialized')\n }\n}\n\nexport default schedulesModule\n","import { registerModule } from './registry.js'\n\n// Imports de módulos core\nimport { loggerModule } from '../modules/logger/index.js'\nimport { systemModule } from '../modules/system/index.js'\nimport { storageModule } from '../modules/storage/index.js'\nimport { usersModule } from '../modules/users/index.js'\nimport { authModule } from '../modules/auth/index.js'\nimport { uiModule } from '../modules/ui/index.js'\nimport { mailModule } from '../modules/mail/index.js'\nimport { notificationsModule } from '../modules/notifications/index.js'\nimport { schedulesModule } from '../modules/schedules/index.js'\n\n/**\n * Carga los módulos core del backend\n * Esta es la única función que importa módulos directamente\n */\nexport function loadCoreModules(): void {\n // Logger primero - sin dependencias, otros módulos lo necesitan\n registerModule(loggerModule)\n registerModule(systemModule)\n registerModule(storageModule) // Antes de users para FK de avatar\n registerModule(usersModule)\n registerModule(authModule)\n registerModule(uiModule)\n registerModule(mailModule)\n registerModule(notificationsModule)\n registerModule(schedulesModule)\n}\n","import type { ModuleManifest, EntityDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * Obtiene tabla y subject de una definition.\n * Subject solo se retorna si está explícitamente definido en casl.subject.\n */\nfunction getTableAndSubject(def: EntityDefinition): { table?: string; subject?: string } {\n const typesWithTable = ['collection', 'reference', 'event', 'config', 'temp', 'view', undefined]\n const caslSubject = (def as { casl?: { subject?: string } }).casl?.subject\n\n if (!typesWithTable.includes(def.type)) {\n // computed, action, external, virtual no tienen tabla\n return { subject: caslSubject }\n }\n\n const table = (def as { table: string }).table\n return { table, subject: caslSubject }\n}\n\n/**\n * Obtener todos los subjects de un módulo (desde definitions)\n */\nexport function getModuleSubjects(mod: ModuleManifest): string[] {\n const subjects = new Set<string>()\n for (const def of mod.definitions ?? []) {\n const { subject } = getTableAndSubject(def)\n if (subject) subjects.add(subject)\n }\n return [...subjects]\n}\n","// Escritura\nexport { registerModule, registerPlugin } from './registry.js'\n\n// Lectura\nexport {\n getModules,\n getOrderedModules,\n getModule,\n getPlugins,\n getPlugin,\n getRegisteredSubjects,\n isValidSubject\n} from './queries.js'\n\n// Loader\nexport { loadCoreModules } from './loader.js'\n\n// Store reset\nexport { resetStore } from './store.js'\n\n// Utilidades\nexport { getModuleSubjects } from './utils.js'\n\n// Re-export types\nexport type { ModuleManifest, PluginManifest } from '@gzl10/nexus-sdk'\n","/**\n * Base Entity Service - Abstract class for all entity services\n */\n\nimport type { Knex } from 'knex'\nimport type {\n EntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks,\n EntityAction\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery, EntityService } from '../types.js'\nimport type { LoggerServiceInterface, ModuleServices } from '../../types/services.js'\n\n/**\n * Abstract base class for entity services\n *\n * Provides common functionality:\n * - Access to ModuleContext (db, logger, etc.)\n * - Entity definition\n * - Default pagination\n * - Hook system for lifecycle events (internos + externos via createEntityService)\n */\nexport abstract class BaseEntityService<T = unknown> implements EntityService<T> {\n protected readonly db: Knex\n protected readonly logger: ModuleContext['logger']\n protected readonly generateId: () => string\n protected readonly errors: ModuleContext['errors']\n /** Hooks externos inyectados via createEntityService */\n protected readonly externalHooks?: EntityServiceHooks<T>\n\n constructor(\n protected readonly ctx: ModuleContext,\n public readonly definition: EntityDefinition,\n hooks?: EntityServiceHooks<T>\n ) {\n this.db = ctx.db\n this.logger = ctx.logger\n this.generateId = ctx.helpers.generateId\n this.errors = ctx.errors\n this.externalHooks = hooks\n }\n\n /**\n * Get table name for persistent entities\n */\n protected get table(): string {\n if ('table' in this.definition && this.definition.table) {\n return this.definition.table\n }\n throw new Error(`Entity ${this.definition.label} has no table`)\n }\n\n protected get loggerService(): LoggerServiceInterface | undefined {\n return (this.ctx.services as Partial<ModuleServices>).logger\n }\n\n /**\n * Get all entities with pagination\n */\n abstract findAll(query?: EntityQuery): Promise<PaginatedResult<T>>\n\n /**\n * Get entity by ID\n */\n abstract findById(id: string): Promise<T | null>\n\n // ============================================================================\n // Hooks - Llaman primero a hooks externos, luego internos (subclases)\n // ============================================================================\n\n /**\n * Called before creating an entity\n * Ejecuta hook externo (si existe) y luego permite override en subclases\n * @returns Modified data\n */\n protected async beforeCreate(data: Partial<T>): Promise<Partial<T>> {\n let result = data\n if (this.externalHooks?.beforeCreate) {\n result = await this.externalHooks.beforeCreate(result)\n }\n return this.internalBeforeCreate(result)\n }\n\n /** Override en subclases para lógica personalizada de beforeCreate */\n protected async internalBeforeCreate(data: Partial<T>): Promise<Partial<T>> {\n return data\n }\n\n /**\n * Called after creating an entity\n */\n protected async afterCreate(entity: T): Promise<void> {\n await this.internalAfterCreate(entity)\n if (this.externalHooks?.afterCreate) {\n await this.externalHooks.afterCreate(entity)\n }\n }\n\n /** Override en subclases para lógica personalizada de afterCreate */\n protected async internalAfterCreate(_entity: T): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called before updating an entity\n * @returns Modified data\n */\n protected async beforeUpdate(id: string, data: Partial<T>): Promise<Partial<T>> {\n let result = data\n if (this.externalHooks?.beforeUpdate) {\n result = await this.externalHooks.beforeUpdate(id, result)\n }\n return this.internalBeforeUpdate(id, result)\n }\n\n /** Override en subclases para lógica personalizada de beforeUpdate */\n protected async internalBeforeUpdate(_id: string, data: Partial<T>): Promise<Partial<T>> {\n return data\n }\n\n /**\n * Called after updating an entity\n */\n protected async afterUpdate(entity: T): Promise<void> {\n await this.internalAfterUpdate(entity)\n if (this.externalHooks?.afterUpdate) {\n await this.externalHooks.afterUpdate(entity)\n }\n }\n\n /** Override en subclases para lógica personalizada de afterUpdate */\n protected async internalAfterUpdate(_entity: T): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called before deleting an entity\n */\n protected async beforeDelete(id: string): Promise<void> {\n if (this.externalHooks?.beforeDelete) {\n await this.externalHooks.beforeDelete(id)\n }\n await this.internalBeforeDelete(id)\n }\n\n /** Override en subclases para lógica personalizada de beforeDelete */\n protected async internalBeforeDelete(_id: string): Promise<void> {\n // Override in subclasses\n }\n\n /**\n * Called after deleting an entity\n */\n protected async afterDelete(id: string): Promise<void> {\n await this.internalAfterDelete(id)\n if (this.externalHooks?.afterDelete) {\n await this.externalHooks.afterDelete(id)\n }\n }\n\n /** Override en subclases para lógica personalizada de afterDelete */\n protected async internalAfterDelete(_id: string): Promise<void> {\n // Override in subclasses\n }\n\n // ============================================================================\n // Helpers\n // ============================================================================\n\n /**\n * Build paginated result from items and count\n */\n protected buildPaginatedResult(\n items: T[],\n total: number,\n page: number,\n limit: number\n ): PaginatedResult<T> {\n const totalPages = Math.ceil(total / limit)\n return {\n items,\n total,\n page,\n limit,\n totalPages,\n hasNext: page < totalPages\n }\n }\n\n /**\n * Get pagination params with defaults\n */\n protected getPagination(query?: EntityQuery): { page: number; limit: number; offset: number } {\n const page = Math.max(1, query?.page ?? 1)\n const limit = Math.min(100, Math.max(1, query?.limit ?? 20))\n const offset = (page - 1) * limit\n return { page, limit, offset }\n }\n\n /**\n * Apply sorting to query builder\n */\n protected applySorting(qb: Knex.QueryBuilder, query?: EntityQuery): Knex.QueryBuilder {\n if (query?.sort) {\n const order = query.order ?? 'asc'\n qb.orderBy(query.sort, order)\n } else if ('labelField' in this.definition && this.definition.labelField) {\n // Default sort by label field\n qb.orderBy(this.definition.labelField as string, 'asc')\n }\n return qb\n }\n\n /**\n * Apply search filter to query builder\n * Override in subclasses for entity-specific search\n */\n protected applySearch(qb: Knex.QueryBuilder, search: string): Knex.QueryBuilder {\n if ('labelField' in this.definition && this.definition.labelField) {\n const labelField = this.definition.labelField as string\n qb.where(labelField, 'like', `%${search}%`)\n }\n return qb\n }\n\n /**\n * Apply filters to query builder\n * Override in subclasses for entity-specific filters\n */\n protected applyFilters(qb: Knex.QueryBuilder, filters: Record<string, unknown>): Knex.QueryBuilder {\n for (const [key, value] of Object.entries(filters)) {\n if (value !== undefined && value !== null && value !== '') {\n qb.where(key, value)\n }\n }\n return qb\n }\n\n // ============================================================================\n // CASL Helpers\n // ============================================================================\n\n /**\n * Get sensitive fields from CASL config\n */\n protected get sensitiveFields(): string[] {\n return this.definition.casl?.sensitiveFields ?? []\n }\n\n /**\n * Exclude sensitive fields from entity data\n * Uses definition.casl.sensitiveFields if configured\n *\n * @example\n * // In entity definition:\n * casl: { sensitiveFields: ['password', 'secret'] }\n *\n * // In service:\n * return this.excludeSensitiveFields(user)\n */\n protected excludeSensitiveFields<D extends Record<string, unknown>>(data: D): Partial<D> {\n if (this.sensitiveFields.length === 0) return data\n\n const result = { ...data }\n for (const field of this.sensitiveFields) {\n delete result[field]\n }\n return result\n }\n\n /**\n * Exclude sensitive fields from array of entities\n */\n protected excludeSensitiveFieldsFromArray<D extends Record<string, unknown>>(items: D[]): Partial<D>[] {\n if (this.sensitiveFields.length === 0) return items\n return items.map(item => this.excludeSensitiveFields(item))\n }\n\n // ============================================================================\n // Action Execution\n // ============================================================================\n\n /**\n * Execute an action defined in this entity programmatically\n *\n * Allows invoking EntityActions from other services without HTTP context.\n * NOTE: Does NOT verify CASL permissions - caller is responsible for authorization.\n *\n * @param actionKey - Key of the action to execute\n * @param input - Input for the handler (without _record if recordId is provided)\n * @param recordId - ID of the record (optional, loads automatically)\n * @param options - Additional options\n * @returns Result from the action handler\n *\n * @example\n * // From another service\n * const storageService = ctx.services['storage_files'] as CollectionService\n * const result = await storageService.executeAction('thumbnail', { width: 200 }, fileId)\n */\n async executeAction(\n actionKey: string,\n input: Record<string, unknown> = {},\n recordId?: string,\n options?: { userId?: string; skipValidation?: boolean }\n ): Promise<unknown> {\n // 1. Find action in definition.actions\n const actions = (this.definition as { actions?: EntityAction[] }).actions\n if (!actions?.length) {\n throw new this.errors.NotFoundError('Entity has no actions')\n }\n\n const action = actions.find(a => a.key === actionKey)\n if (!action) {\n throw new this.errors.NotFoundError(`Action \"${actionKey}\" not found`)\n }\n\n // 2. Load record if recordId provided\n let record: Record<string, unknown> | undefined = input['_record'] as Record<string, unknown>\n if (recordId && !record) {\n let query = this.db(this.table).where('id', recordId)\n if (action.select?.length) {\n query = query.select(action.select)\n }\n record = await query.first()\n if (!record) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n }\n\n // 3. Validate input if schema exists and not skipped\n let validatedInput = input\n if (action.inputSchema && !options?.skipValidation) {\n validatedInput = action.inputSchema.parse(input) as Record<string, unknown>\n }\n\n // 4. Extend input with _record and _authUserId\n const extendedInput: Record<string, unknown> = { ...validatedInput }\n if (record) {\n extendedInput['_record'] = record\n }\n if (options?.userId) {\n extendedInput['_authUserId'] = options.userId\n }\n\n // 5. Execute handler (without req/res)\n return action.handler(this.ctx, extendedInput)\n }\n}\n","/**\n * Collection Service - Full CRUD for collection entities\n *\n * Supports:\n * - Full CRUD operations (create, read, update, delete)\n * - Soft delete (optional)\n * - Timestamps (created_at, updated_at)\n * - Audit fields (created_by, updated_by)\n * - Pagination, sorting, search, filters\n */\n\nimport type {\n CollectionEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class CollectionService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: CollectionEntityDefinition\n\n constructor(ctx: ModuleContext, definition: CollectionEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all entities with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n // Build base query\n let qb = this.db(this.table)\n\n // Apply soft delete filter\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting and pagination\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get entity by ID\n */\n async findById(id: string): Promise<T | null> {\n let qb = this.db(this.table).where('id', id)\n\n // Apply soft delete filter\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n const entity = await qb.first<T>()\n return entity ?? null\n }\n\n /**\n * Create new entity\n */\n async create(data: Partial<T>): Promise<T> {\n // Generate ID if not provided\n const dataRecord = data as Record<string, unknown>\n const entityData: Record<string, unknown> = {\n ...data,\n id: dataRecord['id'] ?? this.generateId()\n }\n\n // Add timestamps\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n }\n\n // Run beforeCreate hook\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n\n // Insert\n await this.db(this.table).insert(processedData)\n\n // Fetch created entity\n const entity = await this.findById((processedData as Record<string, unknown>)['id'] as string)\n if (!entity) {\n throw new this.errors.AppError(`${this.definition.label} no encontrado tras crear`, 404)\n }\n\n // Run afterCreate hook\n await this.afterCreate(entity)\n\n return entity\n }\n\n /**\n * Update entity\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n // Check entity exists\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(this.definition.label)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n\n // Update timestamp\n if (this.definition.timestamps) {\n updateData['updated_at'] = nowTimestamp(this.db)\n }\n\n // Run beforeUpdate hook\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n\n // Update\n await this.db(this.table).where('id', id).update(processedData)\n\n // Fetch updated entity\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.AppError(`${this.definition.label} no encontrado tras actualizar`, 404)\n }\n\n // Run afterUpdate hook\n await this.afterUpdate(entity)\n\n return entity\n }\n\n /**\n * Delete entity (soft delete if enabled)\n */\n async delete(id: string): Promise<void> {\n // Check entity exists\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(this.definition.label)\n }\n\n // Run beforeDelete hook\n await this.beforeDelete(id)\n\n if (this.definition.softDelete) {\n // Soft delete\n await this.db(this.table).where('id', id).update({\n deleted_at: nowTimestamp(this.db)\n })\n } else {\n // Hard delete\n await this.db(this.table).where('id', id).delete()\n }\n\n // Run afterDelete hook\n await this.afterDelete(id)\n }\n\n /**\n * Restore soft-deleted entity\n */\n async restore(id: string): Promise<T> {\n if (!this.definition.softDelete) {\n throw new this.errors.AppError('Soft delete not enabled for this entity', 400)\n }\n\n // Find including deleted\n const entity = await this.db(this.table).where('id', id).first<T>()\n if (!entity) {\n throw new this.errors.NotFoundError(this.definition.label)\n }\n\n // Restore\n await this.db(this.table).where('id', id).update({\n deleted_at: null,\n updated_at: nowTimestamp(this.db)\n })\n\n const restored = await this.findById(id)\n if (!restored) {\n throw new this.errors.AppError(`${this.definition.label} no encontrado tras restaurar`, 404)\n }\n\n return restored\n }\n\n /**\n * Find multiple entities by IDs\n */\n async findByIds(ids: string[]): Promise<T[]> {\n if (ids.length === 0) return []\n\n let qb = this.db(this.table).whereIn('id', ids)\n\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n return qb as Promise<T[]>\n }\n\n /**\n * Count entities matching filters\n */\n async count(filters?: Record<string, unknown>): Promise<number> {\n let qb = this.db(this.table)\n\n if (this.definition.softDelete) {\n qb = qb.whereNull('deleted_at')\n }\n\n if (filters) {\n qb = this.applyFilters(qb, filters)\n }\n\n const result = await qb.count('* as count').first<{ count: string | number }>()\n return Number(result?.count ?? 0)\n }\n\n /**\n * Check if entity exists\n */\n async exists(id: string): Promise<boolean> {\n const entity = await this.findById(id)\n return entity !== null\n }\n}\n","/**\n * Single Service - Singleton entities stored in single_records\n *\n * Supports:\n * - Read single config\n * - Update config\n * - Defaults on first read\n *\n * Uses single_records table with key-value storage:\n * { key: 'site_config', value: { siteName: '...', logo: '...' } }\n */\n\nimport type {\n SingleEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nconst SINGLE_RECORDS_TABLE = 'single_records'\n\nexport class SingleService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: SingleEntityDefinition\n\n constructor(ctx: ModuleContext, definition: SingleEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get table - overridden since single entities use sys_settings\n */\n protected override get table(): string {\n return SINGLE_RECORDS_TABLE\n }\n\n /**\n * Get the setting key\n */\n private get key(): string {\n return this.definition.key\n }\n\n /**\n * Get all - returns single item in paginated format\n */\n async findAll(_query?: EntityQuery): Promise<PaginatedResult<T>> {\n const value = await this.findById(this.key)\n\n return {\n items: value ? [value] : [],\n total: value ? 1 : 0,\n page: 1,\n limit: 1,\n totalPages: value ? 1 : 0,\n hasNext: false\n }\n }\n\n /**\n * Get the singleton value\n * @param _id - Ignored, uses definition.key\n */\n async findById(_id: string): Promise<T | null> {\n const row = await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .first<{ key: string; value: string }>()\n\n if (!row) {\n // Return defaults if available\n if (this.definition.defaults) {\n return this.definition.defaults as T\n }\n return null\n }\n\n try {\n const value = JSON.parse(row.value)\n // Merge with defaults\n if (this.definition.defaults) {\n return { ...this.definition.defaults, ...value } as T\n }\n return value as T\n } catch {\n this.logger.warn({ key: this.key }, 'Failed to parse setting value')\n return this.definition.defaults as T ?? null\n }\n }\n\n /**\n * Get the setting - alias for findById\n */\n async get(): Promise<T | null> {\n return this.findById(this.key)\n }\n\n /**\n * Update the singleton value\n */\n async update(_id: string, data: Partial<T>): Promise<T> {\n // Get current value\n const current = await this.get() ?? {}\n\n // Merge with new data\n const newValue = { ...current, ...data }\n\n // Run beforeUpdate hook\n const processedData = await this.beforeUpdate(this.key, newValue as Partial<T>)\n\n // Check if exists\n const exists = await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .first()\n\n const now = nowTimestamp(this.db)\n\n if (exists) {\n // Update\n await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .update({\n value: JSON.stringify(processedData),\n updated_at: now\n })\n } else {\n // Insert\n await this.db(SINGLE_RECORDS_TABLE).insert({\n id: this.generateId(),\n key: this.key,\n value: JSON.stringify(processedData),\n created_at: now,\n updated_at: now\n })\n }\n\n const result = await this.get()\n if (!result) {\n throw new this.errors.AppError('Failed to save setting', 500)\n }\n\n // Run afterUpdate hook\n await this.afterUpdate(result)\n\n return result\n }\n\n /**\n * Set the setting - alias for update\n */\n async set(data: Partial<T>): Promise<T> {\n return this.update(this.key, data)\n }\n\n /**\n * Reset to defaults\n */\n async reset(): Promise<T | null> {\n if (!this.definition.defaults) {\n // Delete if no defaults\n await this.db(SINGLE_RECORDS_TABLE)\n .where('key', this.key)\n .delete()\n return null\n }\n\n // Set to defaults\n return this.update(this.key, this.definition.defaults as Partial<T>)\n }\n}\n","/**\n * Reference Service - Read-only catalog entities with optional admin CRUD\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - Seed initial data\n * - Optional admin CRUD (allowAdminEdit)\n */\n\nimport type {\n ReferenceEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class ReferenceService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ReferenceEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ReferenceEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all reference items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting and pagination\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get reference item by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table).where('id', id).first<T>()\n return entity ?? null\n }\n\n /**\n * Create reference item (only if allowAdminEdit)\n */\n async create(data: Partial<T>): Promise<T> {\n if (!this.definition.allowAdminEdit) {\n throw new this.errors.ForbiddenError('Reference entities are read-only')\n }\n\n const entityData = {\n ...data,\n id: (data as Record<string, unknown>)['id'] ?? this.generateId()\n } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n }\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Entity not found after creation')\n }\n\n await this.afterCreate(entity)\n return entity\n }\n\n /**\n * Update reference item (only if allowAdminEdit)\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n if (!this.definition.allowAdminEdit) {\n throw new this.errors.ForbiddenError('Reference entities are read-only')\n }\n\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n if (this.definition.timestamps) {\n updateData['updated_at'] = nowTimestamp(this.db)\n }\n\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n await this.db(this.table).where('id', id).update(processedData)\n\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found after update`)\n }\n\n await this.afterUpdate(entity)\n return entity\n }\n\n /**\n * Delete reference item (only if allowAdminEdit)\n */\n async delete(id: string): Promise<void> {\n if (!this.definition.allowAdminEdit) {\n throw new this.errors.ForbiddenError('Reference entities are read-only')\n }\n\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n await this.beforeDelete(id)\n await this.db(this.table).where('id', id).delete()\n await this.afterDelete(id)\n }\n\n /**\n * Seed initial data from definition\n */\n async seed(): Promise<number> {\n if (!this.definition.seed || this.definition.seed.length === 0) {\n return 0\n }\n\n let seeded = 0\n\n for (const item of this.definition.seed) {\n const id = item['id'] as string | undefined\n if (!id) continue\n\n const exists = await this.findById(id)\n if (!exists) {\n const data = {\n ...item,\n id\n } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n data['created_at'] = now\n data['updated_at'] = now\n }\n\n await this.db(this.table).insert(data)\n seeded++\n }\n }\n\n this.logger.info({ table: this.table, seeded }, 'Reference data seeded')\n return seeded\n }\n}\n","/**\n * Event Service - Append-only entities for audit logs\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - Append (create) only - no update/delete\n * - Retention policy (cleanup old events)\n */\n\nimport type {\n EventEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class EventService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: EventEntityDefinition\n\n constructor(ctx: ModuleContext, definition: EventEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all events with pagination (newest first by default)\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Events default to newest first\n if (!query?.sort) {\n qb = qb.orderBy('created_at', 'desc')\n } else {\n qb = this.applySorting(qb, query)\n }\n\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get event by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table).where('id', id).first<T>()\n return entity ?? null\n }\n\n /**\n * Append new event (create)\n */\n async create(data: Partial<T>): Promise<T> {\n const entityData = {\n ...data,\n id: (data as Record<string, unknown>)['id'] ?? this.generateId()\n } as Record<string, unknown>\n\n // Events always have timestamps\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Event not found after creation')\n }\n\n await this.afterCreate(entity)\n\n // Run retention cleanup asynchronously\n this.runRetentionCleanup().catch(err => {\n const error = err instanceof Error ? err : new Error('Event retention cleanup failed')\n this.logger.error({ err }, 'Retention cleanup failed')\n this.loggerService?.captureException(error, { table: this.table, type: 'event', action: 'retention' })\n })\n\n return entity\n }\n\n /**\n * Append event - alias for create\n */\n async append(data: Partial<T>): Promise<T> {\n return this.create(data)\n }\n\n /**\n * Update is NOT allowed for events\n */\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Events are immutable and cannot be updated')\n }\n\n /**\n * Delete is NOT allowed for events (use retention policy)\n */\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Events cannot be deleted. Use retention policy.')\n }\n\n /**\n * Run retention cleanup based on definition\n */\n async runRetentionCleanup(): Promise<number> {\n const retention = this.definition.retention\n if (!retention) return 0\n\n let deleted = 0\n\n // Delete by age\n if (retention.days) {\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() - retention.days)\n\n const result = await this.db(this.table)\n .where('created_at', '<', cutoff)\n .delete()\n\n deleted += result\n }\n\n // Delete by max rows (keep newest)\n if (retention.maxRows) {\n const countResult = await this.db(this.table)\n .count('* as count')\n .first<{ count: string | number }>()\n\n const total = Number(countResult?.count ?? 0)\n const toDelete = total - retention.maxRows\n\n if (toDelete > 0) {\n // Get IDs of oldest events to delete\n const oldestIds = await this.db(this.table)\n .select('id')\n .orderBy('created_at', 'asc')\n .limit(toDelete)\n\n if (oldestIds.length > 0) {\n const result = await this.db(this.table)\n .whereIn('id', oldestIds.map(r => r.id))\n .delete()\n\n deleted += result\n }\n }\n }\n\n if (deleted > 0) {\n this.logger.info({ table: this.table, deleted }, 'Event retention cleanup completed')\n }\n\n return deleted\n }\n\n /**\n * Get events in date range\n */\n async findByDateRange(startDate: Date, endDate: Date, query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n .where('created_at', '>=', startDate)\n .where('created_at', '<=', endDate)\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting (default newest first)\n if (!query?.sort) {\n qb = qb.orderBy('created_at', 'desc')\n } else {\n qb = this.applySorting(qb, query)\n }\n\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n}\n","/**\n * Config Service - Scoped configuration entities\n *\n * Supports:\n * - Read config by scope (module, tenant, user)\n * - Update config\n * - Defaults on first read\n */\n\nimport type {\n ConfigEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp } from '../../db/helpers.js'\n\nexport class ConfigService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ConfigEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ConfigEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get all configs with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n let qb = this.db(this.table)\n\n // Apply filters (scope filtering)\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n // Merge with defaults\n const mergedItems = items.map(item => this.mergeWithDefaults(item))\n\n return this.buildPaginatedResult(mergedItems, total, page, limit)\n }\n\n /**\n * Get config by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table).where('id', id).first<T>()\n if (!entity) {\n return null\n }\n return this.mergeWithDefaults(entity)\n }\n\n /**\n * Get config by scope key (e.g., module name, tenant id)\n */\n async findByScope(scopeValue: string): Promise<T | null> {\n const scopeField = this.definition.scopeField ?? 'scope_key'\n\n const entity = await this.db(this.table)\n .where(scopeField, scopeValue)\n .first<T>()\n\n if (!entity) {\n // Return defaults if available\n if (this.definition.defaults) {\n return this.definition.defaults as T\n }\n return null\n }\n\n return this.mergeWithDefaults(entity)\n }\n\n /**\n * Update config\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n const existing = await this.db(this.table).where('id', id).first<T>()\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n updateData['updated_at'] = nowTimestamp(this.db)\n }\n\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n await this.db(this.table).where('id', id).update(processedData)\n\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found after update`)\n }\n\n await this.afterUpdate(entity)\n return entity\n }\n\n /**\n * Update or create config by scope\n */\n async upsertByScope(scopeValue: string, data: Partial<T>): Promise<T> {\n const scopeField = this.definition.scopeField ?? 'scope_key'\n const existing = await this.db(this.table)\n .where(scopeField, scopeValue)\n .first<T>()\n\n if (existing) {\n const id = (existing as Record<string, unknown>)['id'] as string\n return this.update(id, data)\n } else {\n // Create new config\n const entityData = {\n ...this.definition.defaults,\n ...data,\n [scopeField]: scopeValue,\n id: this.generateId()\n } as Record<string, unknown>\n\n if (this.definition.timestamps) {\n const now = nowTimestamp(this.db)\n entityData['created_at'] = now\n entityData['updated_at'] = now\n }\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Config not found after creation')\n }\n\n await this.afterCreate(entity)\n return entity\n }\n }\n\n /**\n * Reset config to defaults\n */\n async resetToDefaults(id: string): Promise<T | null> {\n if (!this.definition.defaults) {\n await this.db(this.table).where('id', id).delete()\n return null\n }\n\n return this.update(id, this.definition.defaults as Partial<T>)\n }\n\n /**\n * Set a config as the default (only one can be default at a time)\n */\n async setAsDefault(id: string): Promise<void> {\n // Verify record exists\n const existing = await this.db(this.table).where('id', id).first()\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found`)\n }\n\n await this.db.transaction(async (trx) => {\n // 1. Unset all is_default\n await trx(this.table).update({ is_default: false })\n\n // 2. Set the selected one as default\n await trx(this.table).where('id', id).update({ is_default: true })\n })\n }\n\n /**\n * Get the default config record\n * Fallback: first record ordered by created_at if no is_default: true\n */\n async getDefault(): Promise<T | null> {\n // 1. Look for the one marked as default\n const defaultRecord = await this.db(this.table)\n .where('is_default', true)\n .first<T>()\n\n if (defaultRecord) {\n return this.mergeWithDefaults(defaultRecord)\n }\n\n // 2. Fallback: first record by created_at\n const firstRecord = await this.db(this.table)\n .orderBy('created_at', 'asc')\n .first<T>()\n\n if (firstRecord) {\n return this.mergeWithDefaults(firstRecord)\n }\n\n // 3. No records: return defaults if available\n if (this.definition.defaults) {\n return this.definition.defaults as T\n }\n\n return null\n }\n\n /**\n * Merge entity with defaults\n */\n private mergeWithDefaults(entity: T): T {\n if (!this.definition.defaults) {\n return entity\n }\n return { ...this.definition.defaults, ...entity } as T\n }\n}\n","/**\n * Temp Service - Temporary entities with TTL auto-cleanup\n *\n * Supports:\n * - Full CRUD\n * - Automatic TTL field management\n * - Cleanup of expired records\n */\n\nimport type {\n TempEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { nowTimestamp, formatTimestamp } from '../../db/helpers.js'\n\nexport class TempService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: TempEntityDefinition\n\n constructor(ctx: ModuleContext, definition: TempEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get the TTL field name\n */\n private get ttlField(): string {\n return this.definition.ttlField ?? 'expires_at'\n }\n\n /**\n * Get all non-expired items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n // Only return non-expired items\n let qb = this.db(this.table)\n .where(this.ttlField, '>', new Date())\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get total count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n // Run cleanup asynchronously\n this.cleanup().catch(err => {\n const error = err instanceof Error ? err : new Error('Temp cleanup failed')\n this.logger.error({ err }, 'Temp cleanup failed')\n this.loggerService?.captureException(error, { table: this.table, type: 'temp', action: 'cleanup' })\n })\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n\n /**\n * Get non-expired item by ID\n */\n async findById(id: string): Promise<T | null> {\n const entity = await this.db(this.table)\n .where('id', id)\n .where(this.ttlField, '>', new Date())\n .first<T>()\n\n return entity ?? null\n }\n\n /**\n * Create with auto TTL\n */\n async create(data: Partial<T>): Promise<T> {\n const now = new Date()\n const expiresAt = new Date(now.getTime() + this.definition.ttl * 1000)\n\n const entityData = {\n ...data,\n id: (data as Record<string, unknown>)['id'] ?? this.generateId(),\n [this.ttlField]: formatTimestamp(this.db, expiresAt),\n ['created_at']: nowTimestamp(this.db)\n } as Record<string, unknown>\n\n const processedData = await this.beforeCreate(entityData as Partial<T>)\n await this.db(this.table).insert(processedData)\n\n const entity = await this.findById(processedData['id'] as string)\n if (!entity) {\n throw new this.errors.NotFoundError('Entity not found after creation')\n }\n\n await this.afterCreate(entity)\n return entity\n }\n\n /**\n * Update and optionally extend TTL\n */\n async update(id: string, data: Partial<T>, extendTtl = false): Promise<T> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found or expired`)\n }\n\n const updateData = { ...data } as Record<string, unknown>\n\n if (extendTtl) {\n const expiresAt = new Date(Date.now() + this.definition.ttl * 1000)\n updateData[this.ttlField] = expiresAt\n }\n\n const processedData = await this.beforeUpdate(id, updateData as Partial<T>)\n await this.db(this.table).where('id', id).update(processedData)\n\n const entity = await this.findById(id)\n if (!entity) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found after update`)\n }\n\n await this.afterUpdate(entity)\n return entity\n }\n\n /**\n * Delete item\n */\n async delete(id: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new this.errors.NotFoundError(`${this.definition.label} not found or expired`)\n }\n\n await this.beforeDelete(id)\n await this.db(this.table).where('id', id).delete()\n await this.afterDelete(id)\n }\n\n /**\n * Extend TTL for an item\n */\n async extendTtl(id: string, additionalSeconds?: number): Promise<T> {\n const ttl = additionalSeconds ?? this.definition.ttl\n const expiresAt = new Date(Date.now() + ttl * 1000)\n\n return this.update(id, { [this.ttlField]: expiresAt } as Partial<T>)\n }\n\n /**\n * Cleanup expired items\n */\n async cleanup(): Promise<number> {\n const result = await this.db(this.table)\n .where(this.ttlField, '<=', new Date())\n .delete()\n\n if (result > 0) {\n this.logger.info({ table: this.table, deleted: result }, 'Temp cleanup completed')\n }\n\n return result\n }\n\n /**\n * Get remaining TTL for an item (in seconds)\n */\n async getRemainingTtl(id: string): Promise<number | null> {\n const entity = await this.db(this.table)\n .select(this.ttlField)\n .where('id', id)\n .first<Record<string, unknown>>()\n\n if (!entity) return null\n\n const expiresAt = entity[this.ttlField] as Date\n const remaining = Math.max(0, (expiresAt.getTime() - Date.now()) / 1000)\n\n return Math.floor(remaining)\n }\n\n /**\n * Check if item exists and is not expired\n */\n async isValid(id: string): Promise<boolean> {\n const entity = await this.findById(id)\n return entity !== null\n }\n}\n","/**\n * View Service - Read-only views with custom queries\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - Custom query builder or SQL VIEW\n */\n\nimport type {\n ViewEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\n\nexport class ViewService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ViewEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ViewEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get the base query builder\n */\n private getBaseQuery() {\n const query = this.definition.query\n\n if (!query) {\n // Use table directly if no custom query\n return this.db(this.table)\n }\n\n if (typeof query === 'string') {\n // Raw SQL query\n return this.db.raw(query)\n }\n\n // Query builder function\n return query(this.db)\n }\n\n /**\n * Get all items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit, offset } = this.getPagination(query)\n\n // For views, we need to handle counting differently\n if (this.definition.query && typeof this.definition.query !== 'string') {\n // Use query builder\n let baseQuery = this.definition.query(this.db)\n\n // Apply search\n if (query?.search && this.definition.labelField) {\n baseQuery = baseQuery.where(this.definition.labelField, 'like', `%${query.search}%`)\n }\n\n // Apply filters\n if (query?.filters) {\n for (const [key, value] of Object.entries(query.filters)) {\n if (value !== undefined && value !== null && value !== '') {\n baseQuery = baseQuery.where(key, value)\n }\n }\n }\n\n // Get count\n const countQuery = this.definition.query(this.db)\n const countResult = await countQuery.count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting\n if (query?.sort) {\n baseQuery = baseQuery.orderBy(query.sort, query.order ?? 'asc')\n } else if (this.definition.labelField) {\n baseQuery = baseQuery.orderBy(this.definition.labelField, 'asc')\n }\n\n // Apply pagination\n baseQuery = baseQuery.limit(limit).offset(offset)\n\n const items = await baseQuery as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n } else {\n // Use table (SQL VIEW or regular table)\n let qb = this.db(this.table)\n\n // Apply search\n if (query?.search) {\n qb = this.applySearch(qb.clone(), query.search)\n }\n\n // Apply filters\n if (query?.filters) {\n qb = this.applyFilters(qb.clone(), query.filters)\n }\n\n // Get count\n const countResult = await qb.clone().count('* as count').first<{ count: string | number }>()\n const total = Number(countResult?.count ?? 0)\n\n // Apply sorting\n qb = this.applySorting(qb, query)\n qb = qb.limit(limit).offset(offset)\n\n const items = await qb as T[]\n\n return this.buildPaginatedResult(items, total, page, limit)\n }\n }\n\n /**\n * Get item by ID\n */\n async findById(id: string): Promise<T | null> {\n if (this.definition.query && typeof this.definition.query !== 'string') {\n // Use query builder\n const entity = await this.definition.query(this.db)\n .where('id', id)\n .first<T>()\n\n return entity ?? null\n } else {\n // Use table\n const entity = await this.db(this.table).where('id', id).first<T>()\n return entity ?? null\n }\n }\n\n /**\n * Create SQL VIEW from definition (for migrations)\n */\n async createView(): Promise<void> {\n const query = this.definition.query\n\n if (!query) {\n this.logger.warn({ table: this.table }, 'No query defined for view')\n return\n }\n\n let sql: string\n\n if (typeof query === 'string') {\n sql = query\n } else {\n // Build query and convert to SQL\n const qb = query(this.db)\n sql = qb.toQuery()\n }\n\n // Create or replace view\n await this.db.raw(`CREATE OR REPLACE VIEW ?? AS ${sql}`, [this.table])\n\n this.logger.info({ table: this.table }, 'View created')\n }\n\n /**\n * Drop SQL VIEW\n */\n async dropView(): Promise<void> {\n await this.db.raw('DROP VIEW IF EXISTS ??', [this.table])\n this.logger.info({ table: this.table }, 'View dropped')\n }\n\n /**\n * Views are read-only\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Views are read-only')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Views are read-only')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Views are read-only')\n }\n}\n","/**\n * Runtime types for entity services\n */\n\nimport type { Router, Request, Response, NextFunction, RequestHandler } from 'express'\nimport type {\n EntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityQuery\n} from '@gzl10/nexus-sdk'\n\nexport type { Request, Response, NextFunction, RequestHandler }\n\n// Re-export EntityQuery from SDK for backwards compatibility\nexport type { EntityQuery }\n\n/**\n * Entity service interface - base contract for all entity services\n */\nexport interface EntityService<T = unknown> {\n /** Get all entities with pagination */\n findAll(query?: EntityQuery): Promise<PaginatedResult<T>>\n\n /** Get single entity by ID */\n findById(id: string): Promise<T | null>\n\n /** Create new entity (optional - throws if not supported) */\n create?(data: Partial<T>): Promise<T>\n\n /** Update entity (optional - throws if not supported) */\n update?(id: string, data: Partial<T>): Promise<T>\n\n /** Delete entity (optional - throws if not supported) */\n delete?(id: string): Promise<void>\n\n /** Get entity definition */\n readonly definition: EntityDefinition\n}\n\n/**\n * Entity controller handler type\n */\nexport type EntityHandler = (req: Request, res: Response) => Promise<void>\n\n/**\n * Entity controller interface\n */\nexport interface EntityController {\n /** List entities */\n list: EntityHandler\n\n /** Get single entity */\n get: EntityHandler\n\n /** Create entity (optional) */\n create?: EntityHandler\n\n /** Update entity (optional) */\n update?: EntityHandler\n\n /** Delete entity (optional) */\n delete?: EntityHandler\n\n /** Execute action (for action entities) */\n execute?: EntityHandler\n}\n\n/**\n * Complete runtime for an entity\n */\nexport interface EntityRuntime<T = unknown> {\n service: EntityService<T>\n controller: EntityController\n router: Router\n}\n\n/**\n * External adapter interface for external entities\n */\nexport interface ExternalAdapter<T = unknown> {\n /** Adapter name */\n name: string\n\n /** Fetch all records */\n findAll(config: Record<string, unknown>, query?: EntityQuery): Promise<PaginatedResult<T>>\n\n /** Fetch single record */\n findById(config: Record<string, unknown>, id: string): Promise<T | null>\n\n /** Create record (optional) */\n create?(config: Record<string, unknown>, data: Partial<T>): Promise<T>\n\n /** Update record (optional) */\n update?(config: Record<string, unknown>, id: string, data: Partial<T>): Promise<T>\n\n /** Delete record (optional) */\n delete?(config: Record<string, unknown>, id: string): Promise<void>\n}\n\n/**\n * Registry of external adapters\n */\nexport const adapterRegistry = new Map<string, ExternalAdapter>()\n\n/**\n * Register an external adapter\n */\nexport function registerAdapter(adapter: ExternalAdapter): void {\n adapterRegistry.set(adapter.name, adapter)\n}\n\n/**\n * Get registered adapter\n */\nexport function getAdapter(name: string): ExternalAdapter | undefined {\n return adapterRegistry.get(name)\n}\n\n/**\n * Service creation context\n */\nexport interface ServiceContext {\n ctx: ModuleContext\n definition: EntityDefinition\n}\n","/**\n * LRU Cache - Least Recently Used cache with TTL support\n *\n * Features:\n * - LRU eviction when max entries reached\n * - TTL expiration per entry\n * - Hit/miss statistics\n * - Prefix-based deletion for invalidation\n */\n\ninterface CacheEntry<T> {\n data: T\n expires: number\n}\n\nexport interface LRUCacheOptions {\n /** Maximum number of entries (default: 100) */\n maxEntries?: number\n /** Default TTL in seconds (default: 60) */\n defaultTTL?: number\n}\n\nexport interface CacheStats {\n hits: number\n misses: number\n hitRate: number\n size: number\n maxEntries: number\n}\n\nexport class LRUCache<T = unknown> {\n private cache: Map<string, CacheEntry<T>>\n private readonly maxEntries: number\n private readonly defaultTTL: number\n\n private hits = 0\n private misses = 0\n\n constructor(options?: LRUCacheOptions) {\n this.cache = new Map()\n this.maxEntries = options?.maxEntries ?? 100\n this.defaultTTL = options?.defaultTTL ?? 60\n }\n\n /**\n * Get value from cache\n * Returns null if not found or expired\n * Moves entry to end (most recently used)\n */\n get(key: string): T | null {\n const entry = this.cache.get(key)\n\n if (!entry) {\n this.misses++\n return null\n }\n\n // Check expiration\n if (entry.expires > 0 && entry.expires < Date.now()) {\n this.cache.delete(key)\n this.misses++\n return null\n }\n\n // Move to end (most recently used)\n this.cache.delete(key)\n this.cache.set(key, entry)\n\n this.hits++\n return entry.data\n }\n\n /**\n * Set value in cache\n * Evicts oldest entry if max entries reached\n * @param ttl TTL in seconds (0 = no expiration, undefined = use default)\n */\n set(key: string, data: T, ttl?: number): void {\n // Delete existing to update position\n this.cache.delete(key)\n\n // Evict oldest if at capacity\n if (this.cache.size >= this.maxEntries) {\n const oldestKey = this.cache.keys().next().value\n if (oldestKey) {\n this.cache.delete(oldestKey)\n }\n }\n\n const actualTTL = ttl ?? this.defaultTTL\n const expires = actualTTL > 0 ? Date.now() + actualTTL * 1000 : 0\n\n this.cache.set(key, { data, expires })\n }\n\n /**\n * Delete specific key\n */\n delete(key: string): boolean {\n return this.cache.delete(key)\n }\n\n /**\n * Delete all keys matching prefix\n * @returns Number of deleted entries\n */\n deleteByPrefix(prefix: string): number {\n let deleted = 0\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key)\n deleted++\n }\n }\n return deleted\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.cache.clear()\n }\n\n /**\n * Check if key exists and is not expired\n */\n has(key: string): boolean {\n const entry = this.cache.get(key)\n if (!entry) return false\n if (entry.expires > 0 && entry.expires < Date.now()) {\n this.cache.delete(key)\n return false\n }\n return true\n }\n\n /**\n * Get current size\n */\n get size(): number {\n return this.cache.size\n }\n\n /**\n * Get cache statistics\n */\n getStats(): CacheStats {\n const total = this.hits + this.misses\n return {\n hits: this.hits,\n misses: this.misses,\n hitRate: total > 0 ? this.hits / total : 0,\n size: this.cache.size,\n maxEntries: this.maxEntries\n }\n }\n\n /**\n * Reset statistics\n */\n resetStats(): void {\n this.hits = 0\n this.misses = 0\n }\n\n /**\n * Prune expired entries\n * Call periodically to clean up memory\n */\n prune(): number {\n const now = Date.now()\n let pruned = 0\n\n for (const [key, entry] of this.cache.entries()) {\n if (entry.expires > 0 && entry.expires < now) {\n this.cache.delete(key)\n pruned++\n }\n }\n\n return pruned\n }\n}\n","import pkg from 'eventemitter2'\nconst { EventEmitter2 } = pkg\n\n// Payload genérico para eventos CRUD de DB\nexport interface DbEventPayload {\n table: string\n action: 'created' | 'updated' | 'deleted'\n data: unknown\n timestamp: Date\n}\n\n// Tipos de eventos\nexport interface NexusEvents {\n // Lifecycle\n 'server.starting': { port: number; host: string }\n 'server.started': { port: number; host: string }\n 'server.stopping': undefined\n 'server.stopped': undefined\n 'server.restarting': undefined\n\n // Database connection\n 'db.connected': { type: 'sqlite' | 'postgresql' | 'mysql' }\n 'db.disconnected': undefined\n\n // Database CRUD (automático via interceptor)\n // Uso: nexusEvents.on('db.users.created', ...) o nexusEvents.on('db.*.*', ...)\n [key: `db.${string}.created`]: DbEventPayload\n [key: `db.${string}.updated`]: DbEventPayload\n [key: `db.${string}.deleted`]: DbEventPayload\n\n // Auth (lógica de negocio, manual)\n 'auth.login': { userId: string; email: string }\n 'auth.logout': { userId: string }\n 'auth.refresh': { userId: string }\n 'auth.failed': { email: string; reason: string }\n\n // Socket.IO\n 'socket.initialized': undefined\n 'socket.user.connected': { userId: string; roleId: string; socketId: string }\n 'socket.user.disconnected': { userId: string; socketId: string }\n\n // Notifications\n 'notifications.sent': { id: string; target_type: string; target_value?: string; sent: number }\n}\n\n// Tipo helper para listeners tipados\nexport type NexusEventName = keyof NexusEvents\nexport type NexusEventPayload<T extends NexusEventName> = NexusEvents[T]\n\n// Emitter singleton\nclass TypedEventEmitter extends EventEmitter2 {\n emitEvent<T extends NexusEventName>(\n event: T,\n ...args: NexusEvents[T] extends undefined ? [] : [NexusEvents[T]]\n ): boolean {\n return this.emit(event, ...args)\n }\n\n onEvent<T extends NexusEventName>(\n event: T,\n listener: NexusEvents[T] extends undefined\n ? () => void\n : (payload: NexusEvents[T]) => void\n ): this {\n this.on(event, listener as (...args: unknown[]) => void)\n return this\n }\n\n onceEvent<T extends NexusEventName>(\n event: T,\n listener: NexusEvents[T] extends undefined\n ? () => void\n : (payload: NexusEvents[T]) => void\n ): this {\n this.once(event, listener as (...args: unknown[]) => void)\n return this\n }\n\n offEvent<T extends NexusEventName>(\n event: T,\n listener: NexusEvents[T] extends undefined\n ? () => void\n : (payload: NexusEvents[T]) => void\n ): this {\n this.off(event, listener as (...args: unknown[]) => void)\n return this\n }\n}\n\nexport const nexusEvents = new TypedEventEmitter({\n wildcard: true,\n delimiter: '.',\n maxListeners: 20,\n verboseMemoryLeak: true\n})\n\n// Re-export para uso directo\nexport { TypedEventEmitter }\n","/**\n * Cache Invalidator - Reactive cache invalidation via events\n *\n * Listens to db.* events and invalidates related cache entries\n */\n\nimport { nexusEvents, type DbEventPayload } from '../events/emitter.js'\nimport type { EventEmitter2 } from 'eventemitter2'\nimport type { LRUCache } from './lru-cache.js'\n\nexport interface InvalidationRule {\n /** Events that trigger invalidation (supports wildcards) */\n events: string[]\n /** Cache prefix to invalidate */\n cachePrefix: string\n}\n\ninterface RegisteredCache {\n name: string\n cache: LRUCache\n}\n\nclass CacheInvalidator {\n private rules: InvalidationRule[] = []\n private caches: RegisteredCache[] = []\n private listeners: Array<{ event: string; handler: (payload: DbEventPayload) => void }> = []\n private initialized = false\n\n /**\n * Register a cache instance\n */\n registerCache(name: string, cache: LRUCache): void {\n // Avoid duplicates\n const existing = this.caches.find(c => c.name === name)\n if (existing) {\n existing.cache = cache\n return\n }\n this.caches.push({ name, cache })\n }\n\n /**\n * Add invalidation rule\n */\n addRule(rule: InvalidationRule): void {\n // Avoid duplicate rules\n const exists = this.rules.some(\n r => r.cachePrefix === rule.cachePrefix &&\n JSON.stringify(r.events) === JSON.stringify(rule.events)\n )\n if (exists) return\n\n this.rules.push(rule)\n\n // If already initialized, add listener immediately\n if (this.initialized) {\n this.attachListenersForRule(rule)\n }\n }\n\n /**\n * Initialize event listeners\n */\n init(): void {\n if (this.initialized) return\n\n for (const rule of this.rules) {\n this.attachListenersForRule(rule)\n }\n\n this.initialized = true\n }\n\n /**\n * Attach listeners for a specific rule\n */\n private attachListenersForRule(rule: InvalidationRule): void {\n for (const eventPattern of rule.events) {\n const handler = (_payload: DbEventPayload) => {\n this.invalidate(rule.cachePrefix)\n }\n\n ;(nexusEvents as unknown as EventEmitter2).on(eventPattern, handler)\n this.listeners.push({ event: eventPattern, handler })\n }\n }\n\n /**\n * Invalidate cache entries by prefix\n */\n private invalidate(prefix: string): void {\n for (const { cache } of this.caches) {\n cache.deleteByPrefix(prefix)\n }\n }\n\n /**\n * Manually invalidate a prefix\n */\n invalidatePrefix(prefix: string): void {\n this.invalidate(prefix)\n }\n\n /**\n * Get all registered rules\n */\n getRules(): InvalidationRule[] {\n return [...this.rules]\n }\n\n /**\n * Get all registered caches\n */\n getCaches(): string[] {\n return this.caches.map(c => c.name)\n }\n\n /**\n * Clear all rules and listeners\n */\n destroy(): void {\n // Remove all listeners\n for (const { event, handler } of this.listeners) {\n ;(nexusEvents as unknown as EventEmitter2).off(event, handler)\n }\n\n this.listeners = []\n this.rules = []\n this.caches = []\n this.initialized = false\n }\n\n /**\n * Reset for testing\n */\n reset(): void {\n this.destroy()\n }\n}\n\n// Singleton instance\nexport const cacheInvalidator = new CacheInvalidator()\n","export { LRUCache, type LRUCacheOptions, type CacheStats } from './lru-cache.js'\nexport { cacheInvalidator, type InvalidationRule } from './cache-invalidator.js'\n","/**\n * External Service - Data from external APIs via adapters\n *\n * Supports:\n * - Read all (paginated)\n * - Read by ID\n * - LRU caching with TTL\n * - Reactive invalidation via events\n * - CRUD via adapter (if supported)\n */\n\nimport type {\n ExternalEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery, ExternalAdapter } from '../types.js'\nimport { getAdapter } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { LRUCache, cacheInvalidator } from '../../core/cache/index.js'\n\n// LRU cache for external results (shared across all external entities)\nconst externalCache = new LRUCache<unknown>({\n maxEntries: 100,\n defaultTTL: 60\n})\n\n// Register cache with invalidator\ncacheInvalidator.registerCache('external', externalCache)\n\nexport class ExternalService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ExternalEntityDefinition\n private adapter: ExternalAdapter<T> | undefined\n\n constructor(ctx: ModuleContext, definition: ExternalEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n this.adapter = getAdapter(definition.adapter) as ExternalAdapter<T> | undefined\n\n // Register invalidation rules if defined\n if (definition.cache?.invalidateOn?.length) {\n cacheInvalidator.addRule({\n events: definition.cache.invalidateOn,\n cachePrefix: `external:${definition.adapter}`\n })\n }\n }\n\n /**\n * Get table - external entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('External entities do not have a local table')\n }\n\n /**\n * Get the adapter config\n */\n private get adapterConfig(): Record<string, unknown> {\n return this.definition.source ?? {}\n }\n\n /**\n * Get cache key for a request\n */\n private getCacheKey(operation: string, id?: string): string {\n const keyField = this.definition.cache?.key ?? 'id'\n const base = `external:${this.definition.adapter}:${operation}`\n return id ? `${base}:${keyField}:${id}` : base\n }\n\n /**\n * Ensure adapter is available\n */\n private ensureAdapter(): ExternalAdapter<T> {\n if (!this.adapter) {\n throw new this.errors.AppError(\n `Adapter '${this.definition.adapter}' not registered. Register it with registerAdapter().`,\n 500\n )\n }\n return this.adapter\n }\n\n /**\n * Get all items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const adapter = this.ensureAdapter()\n\n // Check cache\n const cacheKey = this.getCacheKey('findAll')\n const cached = externalCache.get(cacheKey) as PaginatedResult<T> | null\n if (cached) {\n return cached\n }\n\n const result = await adapter.findAll(this.adapterConfig, query)\n\n // Cache result with entity-specific TTL\n const ttl = this.definition.cache?.ttl\n if (ttl && ttl > 0) {\n externalCache.set(cacheKey, result, ttl)\n }\n\n return result\n }\n\n /**\n * Get item by ID\n */\n async findById(id: string): Promise<T | null> {\n const adapter = this.ensureAdapter()\n\n // Check cache\n const cacheKey = this.getCacheKey('findById', id)\n const cached = externalCache.get(cacheKey) as T | null\n if (cached) {\n return cached\n }\n\n const result = await adapter.findById(this.adapterConfig, id)\n\n // Cache result with entity-specific TTL\n if (result) {\n const ttl = this.definition.cache?.ttl\n if (ttl && ttl > 0) {\n externalCache.set(cacheKey, result, ttl)\n }\n }\n\n return result\n }\n\n /**\n * Create via adapter (if supported)\n */\n async create(data: Partial<T>): Promise<T> {\n const adapter = this.ensureAdapter()\n\n if (!adapter.create) {\n throw new this.errors.ForbiddenError(\n `Adapter '${this.definition.adapter}' does not support create`\n )\n }\n\n const processedData = await this.beforeCreate(data)\n const result = await adapter.create(this.adapterConfig, processedData)\n await this.afterCreate(result)\n\n // Invalidate list cache\n externalCache.delete(this.getCacheKey('findAll'))\n\n return result\n }\n\n /**\n * Update via adapter (if supported)\n */\n async update(id: string, data: Partial<T>): Promise<T> {\n const adapter = this.ensureAdapter()\n\n if (!adapter.update) {\n throw new this.errors.ForbiddenError(\n `Adapter '${this.definition.adapter}' does not support update`\n )\n }\n\n const processedData = await this.beforeUpdate(id, data)\n const result = await adapter.update(this.adapterConfig, id, processedData)\n await this.afterUpdate(result)\n\n // Invalidate caches\n externalCache.delete(this.getCacheKey('findAll'))\n externalCache.delete(this.getCacheKey('findById', id))\n\n return result\n }\n\n /**\n * Delete via adapter (if supported)\n */\n async delete(id: string): Promise<void> {\n const adapter = this.ensureAdapter()\n\n if (!adapter.delete) {\n throw new this.errors.ForbiddenError(\n `Adapter '${this.definition.adapter}' does not support delete`\n )\n }\n\n await this.beforeDelete(id)\n await adapter.delete(this.adapterConfig, id)\n await this.afterDelete(id)\n\n // Invalidate caches\n externalCache.delete(this.getCacheKey('findAll'))\n externalCache.delete(this.getCacheKey('findById', id))\n }\n\n /**\n * Clear all cache for this entity\n */\n clearCache(): void {\n const prefix = `external:${this.definition.adapter}:`\n externalCache.deleteByPrefix(prefix)\n }\n\n /**\n * Refresh data from external source (bypass cache)\n */\n async refresh(query?: EntityQuery): Promise<PaginatedResult<T>> {\n this.clearCache()\n return this.findAll(query)\n }\n\n /**\n * Get cache statistics\n */\n static getCacheStats() {\n return externalCache.getStats()\n }\n}\n","/**\n * Virtual Service - Orchestration of multiple data sources\n *\n * Supports:\n * - Read all (combines multiple sources)\n * - Read by ID\n * - Custom resolver function\n */\n\nimport type {\n VirtualEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery, EntityService } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\n\nexport class VirtualService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: VirtualEntityDefinition\n\n constructor(ctx: ModuleContext, definition: VirtualEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get table - virtual entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('Virtual entities do not have a local table')\n }\n\n /**\n * Get source services from context\n */\n private getSourceServices(): Record<string, EntityService> {\n const sources: Record<string, EntityService> = {}\n\n for (const sourceName of this.definition.sources) {\n const service = this.ctx.services[sourceName] as EntityService | undefined\n if (service) {\n sources[sourceName] = service\n } else {\n this.logger.warn({ source: sourceName }, 'Source service not found')\n }\n }\n\n return sources\n }\n\n /**\n * Fetch data from all sources\n */\n private async fetchSourceData(query?: EntityQuery): Promise<Record<string, unknown[]>> {\n const services = this.getSourceServices()\n const data: Record<string, unknown[]> = {}\n\n await Promise.all(\n Object.entries(services).map(async ([name, service]) => {\n try {\n const result = await service.findAll(query)\n data[name] = result.items\n } catch (err) {\n this.logger.error({ source: name, err }, 'Failed to fetch source data')\n data[name] = []\n }\n })\n )\n\n return data\n }\n\n /**\n * Get all items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit } = this.getPagination(query)\n\n // Fetch data from all sources\n const sourceData = await this.fetchSourceData(query)\n\n // Apply resolver if defined\n let items: unknown[]\n if (this.definition.resolver) {\n const resolved = this.definition.resolver(sourceData, this.ctx)\n items = resolved instanceof Promise ? await resolved : resolved\n } else {\n // Default: merge all sources\n items = Object.values(sourceData).flat()\n }\n\n // Apply search filter\n if (query?.search && this.definition.labelField) {\n const labelField = this.definition.labelField\n const searchLower = query.search.toLowerCase()\n items = items.filter(item => {\n const value = (item as Record<string, unknown>)[labelField]\n return value && String(value).toLowerCase().includes(searchLower)\n })\n }\n\n // Apply sorting\n if (query?.sort) {\n const sortField = query.sort\n const order = query.order ?? 'asc'\n items = items.sort((a, b) => {\n const aVal = (a as Record<string, unknown>)[sortField]\n const bVal = (b as Record<string, unknown>)[sortField]\n if (String(aVal) < String(bVal)) return order === 'asc' ? -1 : 1\n if (String(aVal) > String(bVal)) return order === 'asc' ? 1 : -1\n return 0\n })\n }\n\n // Apply pagination\n const total = items.length\n const offset = (page - 1) * limit\n const paginatedItems = items.slice(offset, offset + limit) as T[]\n\n return this.buildPaginatedResult(paginatedItems, total, page, limit)\n }\n\n /**\n * Get item by ID (search in all sources)\n */\n async findById(id: string): Promise<T | null> {\n const services = this.getSourceServices()\n\n // Search in all sources\n for (const service of Object.values(services)) {\n try {\n const item = await service.findById(id)\n if (item) {\n return item as T\n }\n } catch {\n // Continue to next source\n }\n }\n\n return null\n }\n\n /**\n * Virtual entities are read-only\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Virtual entities are read-only')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Virtual entities are read-only')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Virtual entities are read-only')\n }\n}\n","/**\n * Computed Service - On-demand calculations with optional caching\n *\n * Supports:\n * - Read all (computed on-demand)\n * - Read by ID\n * - LRU caching with TTL\n * - Reactive invalidation via events\n */\n\nimport type {\n ComputedEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\nimport { LRUCache, cacheInvalidator } from '../../core/cache/index.js'\n\n// LRU cache for computed results (shared across all computed entities)\nconst computeCache = new LRUCache<unknown[]>({\n maxEntries: 200,\n defaultTTL: 60\n})\n\n// Register cache with invalidator\ncacheInvalidator.registerCache('computed', computeCache)\n\nexport class ComputedService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ComputedEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ComputedEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n\n // Register invalidation rules if defined\n if (definition.cache?.invalidateOn?.length) {\n cacheInvalidator.addRule({\n events: definition.cache.invalidateOn,\n cachePrefix: `computed:${definition.label}`\n })\n }\n }\n\n /**\n * Get table - computed entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('Computed entities do not have a local table')\n }\n\n /**\n * Get cache key\n */\n private getCacheKey(params?: Record<string, unknown>): string {\n const base = `computed:${this.definition.label}`\n if (!params || Object.keys(params).length === 0) {\n return base\n }\n return `${base}:${JSON.stringify(params)}`\n }\n\n /**\n * Execute compute function\n */\n private async compute(params?: Record<string, unknown>): Promise<unknown[]> {\n if (!this.definition.compute) {\n throw new this.errors.AppError(\n `No compute function defined for ${this.definition.label}`,\n 500\n )\n }\n\n // Check cache\n const cacheKey = this.getCacheKey(params)\n const cached = computeCache.get(cacheKey)\n if (cached) {\n return cached\n }\n\n // Execute compute\n const result = await this.definition.compute(this.ctx, params)\n\n // Cache result with entity-specific TTL\n const ttl = this.definition.cache?.ttl\n if (ttl && ttl > 0) {\n computeCache.set(cacheKey, result, ttl)\n }\n\n return result\n }\n\n /**\n * Get all computed items with pagination\n */\n async findAll(query?: EntityQuery): Promise<PaginatedResult<T>> {\n const { page, limit } = this.getPagination(query)\n\n // Compute data\n let items = await this.compute(query?.filters)\n\n // Apply search filter\n if (query?.search && this.definition.labelField) {\n const labelField = this.definition.labelField\n const searchLower = query.search.toLowerCase()\n items = items.filter(item => {\n const value = (item as Record<string, unknown>)[labelField]\n return value && String(value).toLowerCase().includes(searchLower)\n })\n }\n\n // Apply sorting\n if (query?.sort) {\n const sortField = query.sort\n const order = query.order ?? 'asc'\n items = items.sort((a, b) => {\n const aVal = (a as Record<string, unknown>)[sortField]\n const bVal = (b as Record<string, unknown>)[sortField]\n if (String(aVal) < String(bVal)) return order === 'asc' ? -1 : 1\n if (String(aVal) > String(bVal)) return order === 'asc' ? 1 : -1\n return 0\n })\n }\n\n // Apply pagination\n const total = items.length\n const offset = (page - 1) * limit\n const paginatedItems = items.slice(offset, offset + limit) as T[]\n\n return this.buildPaginatedResult(paginatedItems, total, page, limit)\n }\n\n /**\n * Get computed item by ID\n */\n async findById(id: string): Promise<T | null> {\n const items = await this.compute()\n const item = items.find(i => (i as Record<string, unknown>)['id'] === id)\n return (item as T) ?? null\n }\n\n /**\n * Recompute with specific params\n */\n async recompute(params?: Record<string, unknown>): Promise<T[]> {\n // Clear cache for this computation\n const cacheKey = this.getCacheKey(params)\n computeCache.delete(cacheKey)\n\n return this.compute(params) as Promise<T[]>\n }\n\n /**\n * Clear all cache for this entity\n */\n clearCache(): void {\n const prefix = `computed:${this.definition.label}`\n computeCache.deleteByPrefix(prefix)\n }\n\n /**\n * Get cache statistics\n */\n static getCacheStats() {\n return computeCache.getStats()\n }\n\n /**\n * Computed entities are read-only\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Computed entities are read-only')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Computed entities are read-only')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Computed entities are read-only')\n }\n}\n","/**\n * Action Service - Execute operations/workflows\n *\n * Supports:\n * - Execute action handler\n * - Input validation\n * - Output schema (documentation)\n */\n\nimport type {\n ActionEntityDefinition,\n PaginatedResult,\n ModuleContext,\n EntityServiceHooks,\n Request,\n Response\n} from '@gzl10/nexus-sdk'\nimport type { EntityQuery } from '../types.js'\nimport { BaseEntityService } from './base.service.js'\n\nexport class ActionService<T extends Record<string, unknown> = Record<string, unknown>>\n extends BaseEntityService<T> {\n\n declare readonly definition: ActionEntityDefinition\n\n constructor(ctx: ModuleContext, definition: ActionEntityDefinition, hooks?: EntityServiceHooks<T>) {\n super(ctx, definition, hooks)\n }\n\n /**\n * Get table - action entities don't have a local table\n */\n protected override get table(): string {\n throw new Error('Action entities do not have a local table')\n }\n\n /**\n * Actions don't support findAll\n */\n async findAll(_query?: EntityQuery): Promise<PaginatedResult<T>> {\n return {\n items: [],\n total: 0,\n page: 1,\n limit: 0,\n totalPages: 0,\n hasNext: false\n }\n }\n\n /**\n * Actions don't support findById\n */\n async findById(_id: string): Promise<T | null> {\n return null\n }\n\n /**\n * Execute the action\n * @param input - Body data\n * @param req - Express request (optional, for accessing files, params, etc.)\n * @param res - Express response (optional, for streaming, custom headers, etc.)\n * @returns Result to be sent as JSON, or undefined if handler controlled response\n */\n async execute(input: unknown, req?: Request, res?: Response): Promise<unknown> {\n // Validate input if schema defined\n if (this.definition.inputSchema) {\n try {\n input = this.definition.inputSchema.parse(input)\n } catch (err) {\n throw new this.errors.AppError(\n `Invalid input for action ${this.definition.label}: ${err}`,\n 400\n )\n }\n }\n\n // Check handler exists\n if (!this.definition.handler) {\n throw new this.errors.AppError(\n `No handler defined for action ${this.definition.label}`,\n 500\n )\n }\n\n // Extend input with _authUserId\n let extendedInput = (input ?? {}) as Record<string, unknown>\n\n // Inject authUserId if user is authenticated\n const authReq = req as { user?: { id?: string } }\n if (authReq?.user?.id) {\n extendedInput = { ...extendedInput, _authUserId: authReq.user.id }\n }\n\n // Execute handler with extended input\n const result = await this.definition.handler(this.ctx, extendedInput, req, res)\n\n // Validate output if schema defined (for documentation/debugging)\n if (this.definition.outputSchema && result !== undefined) {\n try {\n this.definition.outputSchema.parse(result)\n } catch (err) {\n this.logger.warn(\n { action: this.definition.label, err },\n 'Action output does not match schema'\n )\n }\n }\n\n return result\n }\n\n /**\n * Get action metadata\n */\n getMetadata(): {\n label: string\n hasInputSchema: boolean\n hasOutputSchema: boolean\n fields: string[]\n } {\n return {\n label: this.definition.label,\n hasInputSchema: !!this.definition.inputSchema,\n hasOutputSchema: !!this.definition.outputSchema,\n fields: Object.keys(this.definition.fields)\n }\n }\n\n /**\n * Actions don't support CRUD\n */\n async create(_data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Use execute() for actions')\n }\n\n async update(_id: string, _data: Partial<T>): Promise<T> {\n throw new this.errors.ForbiddenError('Use execute() for actions')\n }\n\n async delete(_id: string): Promise<void> {\n throw new this.errors.ForbiddenError('Use execute() for actions')\n }\n}\n","/**\n * Schema Builder - Genera schemas Zod desde FieldDefinition en runtime\n *\n * Convierte FieldValidationConfig a validaciones Zod automáticamente\n */\n\nimport { z, type ZodSchema, type ZodObject, type ZodRawShape } from 'zod'\nimport type { FieldDefinition, EntityDefinition, InputType, DbType } from '@gzl10/nexus-sdk'\n\n/**\n * Infer db type from input type for fields without db config\n */\nfunction inferTypeFromInput(input: InputType): DbType {\n switch (input) {\n case 'number':\n case 'decimal':\n return 'decimal'\n case 'checkbox':\n case 'switch':\n return 'boolean'\n case 'date':\n return 'date'\n case 'datetime':\n return 'datetime'\n case 'json':\n return 'json'\n case 'textarea':\n case 'markdown':\n return 'text'\n default:\n return 'string'\n }\n}\n\n/**\n * Build Zod schema for a single field based on its definition\n */\nfunction buildFieldSchema(field: FieldDefinition): ZodSchema {\n const { db, validation } = field\n let schema: ZodSchema\n\n // For fields without db config (actions), infer type from input or use string\n const dbType = db?.type ?? inferTypeFromInput(field.input)\n\n // Determine base type from db.type\n switch (dbType) {\n case 'string':\n case 'text':\n schema = z.string()\n\n // Apply string validations\n if (validation?.min !== undefined) {\n schema = (schema as z.ZodString).min(validation.min)\n }\n if (validation?.max !== undefined) {\n schema = (schema as z.ZodString).max(validation.max)\n }\n if (db?.size && !validation?.max) {\n // Use db.size as max length if no explicit max\n schema = (schema as z.ZodString).max(db.size)\n }\n if (validation?.pattern) {\n schema = (schema as z.ZodString).regex(new RegExp(validation.pattern))\n }\n if (validation?.format) {\n switch (validation.format) {\n case 'email':\n schema = (schema as z.ZodString).email()\n break\n case 'url':\n schema = (schema as z.ZodString).url()\n break\n case 'uuid':\n schema = (schema as z.ZodString).uuid()\n break\n case 'slug':\n schema = (schema as z.ZodString).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)\n break\n }\n }\n if (validation?.enum) {\n schema = z.enum(validation.enum as [string, ...string[]])\n }\n break\n\n case 'integer':\n schema = z.number().int()\n if (validation?.min !== undefined) {\n schema = (schema as z.ZodNumber).min(validation.min)\n }\n if (validation?.max !== undefined) {\n schema = (schema as z.ZodNumber).max(validation.max)\n }\n break\n\n case 'decimal':\n schema = z.number()\n if (validation?.min !== undefined) {\n schema = (schema as z.ZodNumber).min(validation.min)\n }\n if (validation?.max !== undefined) {\n schema = (schema as z.ZodNumber).max(validation.max)\n }\n break\n\n case 'boolean':\n // Coerce numeric/string values to boolean (SQLite stores as 0/1)\n schema = z.preprocess((val) => {\n if (val === 0 || val === '0' || val === 'false') return false\n if (val === 1 || val === '1' || val === 'true') return true\n return val\n }, z.boolean())\n break\n\n case 'date':\n case 'datetime':\n // Accept string (ISO) or Date\n schema = z.union([z.string(), z.date()])\n break\n\n case 'json':\n schema = z.unknown()\n break\n\n case 'uuid':\n schema = z.string().uuid()\n break\n\n default:\n schema = z.unknown()\n }\n\n // Apply nullable if db allows (or no db config = treat as nullable for actions)\n if ((db?.nullable ?? true) && !validation?.required) {\n schema = schema.nullable().optional()\n } else if (!validation?.required) {\n schema = schema.optional()\n }\n\n return schema\n}\n\n/**\n * Fields to exclude from create/update schemas\n */\nconst AUTO_FIELDS = ['id', 'created_at', 'updated_at', 'created_by', 'updated_by']\n\n/**\n * Build Zod schema for entity create operation\n *\n * - Excludes auto-generated fields (id, timestamps, audit) from required validation\n * - Applies required validation\n * - Uses passthrough() to allow custom fields (like custom id)\n */\nexport function buildCreateSchema(definition: EntityDefinition): ZodObject<ZodRawShape> {\n const shape: ZodRawShape = {}\n\n if (!('fields' in definition)) {\n return z.object(shape).passthrough()\n }\n\n for (const [name, field] of Object.entries(definition.fields)) {\n // Skip auto fields - they're optional and handled by service\n if (AUTO_FIELDS.includes(name)) continue\n\n shape[name] = buildFieldSchema(field)\n }\n\n // passthrough allows custom fields like id to be passed to service\n return z.object(shape).passthrough()\n}\n\n/**\n * Build Zod schema for entity update operation\n *\n * - Excludes auto-generated fields\n * - All fields are optional (partial update)\n * - Uses passthrough() to allow custom fields\n */\nexport function buildUpdateSchema(definition: EntityDefinition): ZodObject<ZodRawShape> {\n const shape: ZodRawShape = {}\n\n if (!('fields' in definition)) {\n return z.object(shape).passthrough()\n }\n\n for (const [name, field] of Object.entries(definition.fields)) {\n // Skip auto fields\n if (AUTO_FIELDS.includes(name)) continue\n\n // Make all fields optional for update\n let schema = buildFieldSchema(field)\n if (!schema.isOptional()) {\n schema = schema.optional()\n }\n\n shape[name] = schema\n }\n\n return z.object(shape).passthrough()\n}\n\n/**\n * Cache for compiled schemas (per entity definition)\n */\nconst schemaCache = new WeakMap<EntityDefinition, {\n create: ZodObject<ZodRawShape>\n update: ZodObject<ZodRawShape>\n}>()\n\n/**\n * Get cached schemas for an entity definition\n */\nexport function getSchemas(definition: EntityDefinition): {\n create: ZodObject<ZodRawShape>\n update: ZodObject<ZodRawShape>\n} {\n let cached = schemaCache.get(definition)\n\n if (!cached) {\n cached = {\n create: buildCreateSchema(definition),\n update: buildUpdateSchema(definition)\n }\n schemaCache.set(definition, cached)\n }\n\n return cached\n}\n","export { buildCreateSchema, buildUpdateSchema, getSchemas } from './schema-builder.js'\n","/**\n * Entity Controller - Auto-generated controllers based on entity type\n *\n * Soporte automático:\n * - CASL: Si definition.casl está definido, verifica permisos\n * - Validación: Genera Zod schemas desde definition.fields.validation\n */\n\nimport type { Request, Response } from 'express'\nimport type {\n EntityDefinition,\n ModuleContext,\n AuthRequest,\n EntityAction,\n CollectionEntityDefinition,\n SingleEntityDefinition\n} from '@gzl10/nexus-sdk'\nimport { ZodError } from 'zod'\nimport type { EntityController, EntityService, EntityQuery, EntityHandler } from '../types.js'\nimport { ActionService } from '../services/action.service.js'\nimport { getSchemas } from '../validation/index.js'\n\n/**\n * Capitalize first letter (for inferring CASL subject from table name)\n */\nfunction capitalizeFirst(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\n/**\n * Create controller for an entity service with optional CASL authorization\n */\nexport function createEntityController(\n service: EntityService,\n definition: EntityDefinition,\n ctx: ModuleContext\n): EntityController {\n const type = definition.type ?? 'collection'\n\n // CASL subject (from definition or inferred from table/key name)\n const entityName = 'table' in definition ? definition.table : ('key' in definition ? definition.key : 'entity')\n const caslSubject = definition.casl?.subject ?? capitalizeFirst(entityName ?? 'Entity')\n const hasCasl = !!definition.casl\n\n // Get validation schemas (cached)\n const schemas = getSchemas(definition)\n\n /**\n * Verify CASL permission\n * @throws ForbiddenError if permission denied\n */\n function checkPermission(\n req: Request,\n action: 'read' | 'create' | 'update' | 'delete' | 'manage' | 'execute',\n instance?: unknown\n ): void {\n if (!hasCasl) return // No CASL config = no authorization check\n\n const authReq = req as AuthRequest\n if (!authReq.ability) return // No ability = anonymous access allowed (handled by auth middleware)\n\n const { subject, ForbiddenError: CASLForbiddenError } = ctx.abilities\n\n // If instance provided, check with subject() for conditions support\n const target = instance ? subject(caslSubject, instance as Record<string, unknown>) : caslSubject\n\n try {\n CASLForbiddenError.from(authReq.ability).throwUnlessCan(action, target)\n } catch {\n throw new ctx.errors.ForbiddenError(`No tienes permiso para ${action} ${definition.label}`)\n }\n }\n\n // Base handlers\n const controller: EntityController = {\n /**\n * List entities\n */\n async list(req: Request, res: Response): Promise<void> {\n checkPermission(req, 'read')\n\n // Parse and validate pagination params\n const page = Math.max(1, parseInt(req.query['page'] as string) || 1)\n const limit = Math.min(100, Math.max(1, parseInt(req.query['limit'] as string) || 20))\n\n // Parse filters with error handling\n let filters: Record<string, unknown> | undefined\n if (req.query['filters']) {\n try {\n filters = JSON.parse(req.query['filters'] as string)\n } catch {\n throw new ctx.errors.ValidationError('Invalid filters JSON')\n }\n }\n\n const query: EntityQuery = {\n page,\n limit,\n sort: req.query['sort'] as string | undefined,\n order: (req.query['order'] as 'asc' | 'desc' | undefined) ?? 'asc',\n search: req.query['search'] as string | undefined,\n filters\n }\n\n const result = await service.findAll(query)\n res.json(result)\n },\n\n /**\n * Get single entity\n */\n async get(req: Request, res: Response): Promise<void> {\n const id = req.params['id'] ?? ''\n\n const entity = await service.findById(id)\n\n if (!entity) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n\n // Check permission with instance (for conditions like { id: '${user.id}' })\n checkPermission(req, 'read', entity)\n\n res.json(entity)\n }\n }\n\n // Add create handler if supported\n if (supportsCreate(type)) {\n controller.create = async (req: Request, res: Response): Promise<void> => {\n checkPermission(req, 'create')\n\n if (!service.create) {\n throw new ctx.errors.ForbiddenError(`${definition.label} does not support create`)\n }\n\n // Validate input\n let validated: Record<string, unknown>\n try {\n validated = schemas.create.parse(req.body)\n } catch (error) {\n if (error instanceof ZodError) {\n throw new ctx.errors.ValidationError('Validation failed', error.errors)\n }\n throw error\n }\n\n const entity = await service.create(validated)\n res.status(201).json(entity)\n }\n }\n\n // Add update handler if supported\n if (supportsUpdate(type)) {\n controller.update = async (req: Request, res: Response): Promise<void> => {\n if (!service.update) {\n throw new ctx.errors.ForbiddenError(`${definition.label} does not support update`)\n }\n\n const id = req.params['id'] ?? ''\n\n // First fetch the entity to check permission with instance\n const existing = await service.findById(id)\n if (!existing) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n\n checkPermission(req, 'update', existing)\n\n // Validate input\n let validated: Record<string, unknown>\n try {\n validated = schemas.update.parse(req.body)\n } catch (error) {\n if (error instanceof ZodError) {\n throw new ctx.errors.ValidationError('Validation failed', error.errors)\n }\n throw error\n }\n\n const entity = await service.update(id, validated)\n res.json(entity)\n }\n }\n\n // Add delete handler if supported\n if (supportsDelete(type)) {\n controller.delete = async (req: Request, res: Response): Promise<void> => {\n if (!service.delete) {\n throw new ctx.errors.ForbiddenError(`${definition.label} does not support delete`)\n }\n\n const id = req.params['id'] ?? ''\n\n // First fetch the entity to check permission with instance\n const existing = await service.findById(id)\n if (!existing) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n\n checkPermission(req, 'delete', existing)\n\n await service.delete(id)\n res.status(204).send()\n }\n }\n\n // Add execute handler for actions\n if (type === 'action') {\n controller.execute = async (req: Request, res: Response): Promise<void> => {\n checkPermission(req, 'execute') // Actions require 'execute' permission\n\n const actionService = service as ActionService\n const result = await actionService.execute(req.body, req, res)\n\n // Only send JSON response if handler returned a result\n // (handler may have already sent response for streaming, etc.)\n if (result !== undefined && !res.headersSent) {\n const successStatus = (definition as { successStatus?: number }).successStatus ?? 200\n res.status(successStatus).json(result)\n }\n }\n }\n\n return controller\n}\n\n/**\n * Check if entity type supports create via API\n * Note: 'event' entities are append-only INTERNALLY, not via API\n */\nfunction supportsCreate(type: string): boolean {\n return ['collection', 'temp', 'reference', 'config'].includes(type)\n}\n\n/**\n * Check if entity type supports update\n */\nfunction supportsUpdate(type: string): boolean {\n return ['collection', 'single', 'temp', 'reference', 'config'].includes(type)\n}\n\n/**\n * Check if entity type supports delete\n */\nfunction supportsDelete(type: string): boolean {\n return ['collection', 'temp', 'reference'].includes(type)\n}\n\n/**\n * Create handler for an EntityAction defined in a collection/single entity\n * Injects _record and _authUserId automatically into the input\n */\nexport function createActionHandler(\n action: EntityAction,\n definition: CollectionEntityDefinition | SingleEntityDefinition,\n ctx: ModuleContext\n): EntityHandler {\n // Get table name for querying the record\n const tableName = 'table' in definition ? definition.table : undefined\n\n // CASL subject (from definition or inferred from table/key name)\n const entityName = 'table' in definition ? definition.table : ('key' in definition ? definition.key : 'entity')\n const caslSubject = definition.casl?.subject ?? capitalizeFirst(entityName ?? 'Entity')\n const hasCasl = !!definition.casl || !!action.casl\n\n return async (req: Request, res: Response): Promise<void> => {\n const recordId = req.params['id']\n\n // 1. Load record from database\n let record: Record<string, unknown> | undefined\n if (tableName && recordId) {\n let query = ctx.db(tableName).where('id', recordId)\n if (action.select?.length) {\n query = query.select(action.select)\n }\n record = await query.first()\n\n if (!record) {\n throw new ctx.errors.NotFoundError(`${definition.label} not found`)\n }\n }\n\n // 2. Check CASL permission\n if (hasCasl) {\n const authReq = req as AuthRequest\n if (authReq.ability) {\n const { subject, ForbiddenError: CASLForbiddenError } = ctx.abilities\n const caslAction = action.casl?.action ?? 'execute'\n\n // Use record as subject for conditions support\n const target = record ? subject(caslSubject, record) : caslSubject\n\n try {\n CASLForbiddenError.from(authReq.ability).throwUnlessCan(caslAction, target)\n } catch {\n throw new ctx.errors.ForbiddenError(`No tienes permiso para ${action.label}`)\n }\n }\n }\n\n // 3. Validate input\n let input: Record<string, unknown> = req.body ?? {}\n if (action.inputSchema) {\n try {\n input = action.inputSchema.parse(input) as Record<string, unknown>\n } catch (error) {\n if (error instanceof ZodError) {\n throw new ctx.errors.ValidationError('Validation failed', error.errors)\n }\n throw error\n }\n }\n\n // 4. Extend input with _record and _authUserId\n const extendedInput: Record<string, unknown> = { ...input }\n if (record) {\n extendedInput['_record'] = record\n }\n const userReq = req as { user?: { id?: string } }\n if (userReq.user?.id) {\n extendedInput['_authUserId'] = userReq.user.id\n }\n\n // 5. Execute handler\n const result = await action.handler(ctx, extendedInput, req, res)\n\n // 6. Send response if not already sent\n if (result !== undefined && !res.headersSent) {\n res.json(result)\n }\n }\n}\n","/**\n * Entity Routes - Auto-generated routes based on entity type\n *\n * Soporte CASL automático:\n * - Si definition.casl está definido, aplica auth middleware\n * - La verificación de permisos se hace en el controller\n */\n\nimport type { Router, Request, Response, NextFunction, RequestHandler } from 'express'\nimport type {\n EntityDefinition,\n ActionEntityDefinition,\n ModuleContext,\n CollectionEntityDefinition,\n SingleEntityDefinition\n} from '@gzl10/nexus-sdk'\nimport type { EntityController, EntityHandler } from '../types.js'\nimport { createActionHandler } from '../controllers/entity.controller.js'\n\n/**\n * Create router for an entity controller with optional auth middleware\n */\nexport function createEntityRouter(\n controller: EntityController,\n definition: EntityDefinition,\n ctx: ModuleContext\n): Router {\n const router = ctx.createRouter()\n const type = definition.type ?? 'collection'\n\n // Apply auth middleware if CASL is configured\n if (definition.casl && ctx.middleware['auth']) {\n router.use(ctx.middleware['auth'])\n }\n\n // Special handling for standalone actions (type: 'action')\n if (type === 'action' && controller.execute) {\n const actionDef = definition as ActionEntityDefinition\n const method = actionDef.method ?? 'POST'\n const handlers: RequestHandler[] = []\n\n // Apply custom middleware if defined\n if (actionDef.middleware) {\n const middleware = actionDef.middleware(ctx)\n if (Array.isArray(middleware)) {\n handlers.push(...middleware)\n } else {\n handlers.push(middleware)\n }\n }\n\n // Add the execute handler\n handlers.push(asyncHandler(controller.execute))\n\n // Register route at root path\n if (method === 'GET') {\n router.get('/', ...handlers)\n } else {\n router.post('/', ...handlers)\n }\n\n return router\n }\n\n // List - GET / (not for single entities - they only have one record)\n if (type !== 'single') {\n router.get('/', asyncHandler(controller.list))\n }\n\n // Get by ID - GET /:id (or GET / for single entities)\n if (type === 'single') {\n router.get('/', asyncHandler(controller.get))\n } else {\n router.get('/:id', asyncHandler(controller.get))\n }\n\n // Create - POST /\n if (controller.create) {\n router.post('/', asyncHandler(controller.create))\n }\n\n // Update - PUT /:id\n if (controller.update) {\n if (type === 'single') {\n // Single entities update without ID param\n router.put('/', asyncHandler(controller.update))\n } else {\n router.put('/:id', asyncHandler(controller.update))\n }\n }\n\n // Delete - DELETE /:id\n if (controller.delete) {\n router.delete('/:id', asyncHandler(controller.delete))\n }\n\n // Entity actions - /{key}/:id for collection/single entities\n const entityDef = definition as CollectionEntityDefinition | SingleEntityDefinition\n const entityActions = entityDef.actions\n if (entityActions?.length) {\n for (const action of entityActions) {\n const actionPath = `/${action.key}/:id`\n const handlers: RequestHandler[] = []\n\n // Apply custom middleware if defined\n if (action.middleware) {\n const middleware = action.middleware(ctx)\n if (Array.isArray(middleware)) {\n handlers.push(...middleware)\n } else {\n handlers.push(middleware)\n }\n }\n\n // Add the action handler\n const actionHandler = createActionHandler(action, entityDef, ctx)\n handlers.push(asyncHandler(actionHandler))\n\n // Register route with appropriate method\n const method = action.method ?? 'POST'\n if (method === 'GET') {\n router.get(actionPath, ...handlers)\n } else {\n router.post(actionPath, ...handlers)\n }\n }\n }\n\n return router\n}\n\n/**\n * Wrap async handler to catch errors\n * Express 5 handles this natively, but this is for compatibility\n */\nfunction asyncHandler(\n fn: EntityHandler\n): (req: Request, res: Response, next: NextFunction) => void {\n return (req, res, next) => {\n Promise.resolve(fn(req, res)).catch(next)\n }\n}\n","/**\n * Entity Factory - Creates service, controller, and router from EntityDefinition\n */\n\nimport type { Router } from 'express'\nimport type {\n EntityDefinition,\n CollectionEntityDefinition,\n SingleEntityDefinition,\n ReferenceEntityDefinition,\n EventEntityDefinition,\n ConfigEntityDefinition,\n TempEntityDefinition,\n ViewEntityDefinition,\n ExternalEntityDefinition,\n VirtualEntityDefinition,\n ComputedEntityDefinition,\n ActionEntityDefinition,\n ModuleContext\n} from '@gzl10/nexus-sdk'\nimport type { EntityRuntime, EntityService } from './types.js'\n\n// Import all services\nimport { CollectionService } from './services/collection.service.js'\nimport { SingleService } from './services/single.service.js'\nimport { ReferenceService } from './services/reference.service.js'\nimport { EventService } from './services/event.service.js'\nimport { ConfigService } from './services/config.service.js'\nimport { TempService } from './services/temp.service.js'\nimport { ViewService } from './services/view.service.js'\nimport { ExternalService } from './services/external.service.js'\nimport { VirtualService } from './services/virtual.service.js'\nimport { ComputedService } from './services/computed.service.js'\nimport { ActionService } from './services/action.service.js'\n\n// Import controller and route factory\nimport { createEntityController } from './controllers/entity.controller.js'\nimport { createEntityRouter } from './routes/entity.routes.js'\n\n/**\n * Get entity type with default 'collection'\n */\nfunction getEntityType(definition: EntityDefinition): string {\n return definition.type ?? 'collection'\n}\n\n/**\n * Create service based on entity type\n */\nexport function createEntityService<T = unknown>(\n ctx: ModuleContext,\n definition: EntityDefinition\n): EntityService<T> {\n const type = getEntityType(definition)\n\n switch (type) {\n case 'collection':\n return new CollectionService<Record<string, unknown>>(\n ctx,\n definition as CollectionEntityDefinition\n ) as EntityService<T>\n\n case 'single':\n return new SingleService<Record<string, unknown>>(\n ctx,\n definition as SingleEntityDefinition\n ) as EntityService<T>\n\n case 'reference':\n return new ReferenceService<Record<string, unknown>>(\n ctx,\n definition as ReferenceEntityDefinition\n ) as EntityService<T>\n\n case 'event':\n return new EventService<Record<string, unknown>>(\n ctx,\n definition as EventEntityDefinition\n ) as EntityService<T>\n\n case 'config':\n return new ConfigService<Record<string, unknown>>(\n ctx,\n definition as ConfigEntityDefinition\n ) as EntityService<T>\n\n case 'temp':\n return new TempService<Record<string, unknown>>(\n ctx,\n definition as TempEntityDefinition\n ) as EntityService<T>\n\n case 'view':\n return new ViewService<Record<string, unknown>>(\n ctx,\n definition as ViewEntityDefinition\n ) as EntityService<T>\n\n case 'external':\n return new ExternalService<Record<string, unknown>>(\n ctx,\n definition as ExternalEntityDefinition\n ) as EntityService<T>\n\n case 'virtual':\n return new VirtualService<Record<string, unknown>>(\n ctx,\n definition as VirtualEntityDefinition\n ) as EntityService<T>\n\n case 'computed':\n return new ComputedService<Record<string, unknown>>(\n ctx,\n definition as ComputedEntityDefinition\n ) as EntityService<T>\n\n case 'action':\n return new ActionService<Record<string, unknown>>(\n ctx,\n definition as ActionEntityDefinition\n ) as EntityService<T>\n\n default:\n throw new Error(`Unknown entity type: ${type}`)\n }\n}\n\n/**\n * Create complete runtime (service + controller + router) for an entity\n */\nexport function createEntityRuntime<T = unknown>(\n ctx: ModuleContext,\n definition: EntityDefinition\n): EntityRuntime<T> {\n // Create service\n const service = createEntityService<T>(ctx, definition)\n\n // Create controller\n const controller = createEntityController(service, definition, ctx)\n\n // Create router\n const router = createEntityRouter(controller, definition, ctx)\n\n return { service, controller, router }\n}\n\n/**\n * Create services for all definitions in a module\n */\nexport function createModuleServices(\n ctx: ModuleContext,\n definitions: EntityDefinition[]\n): Map<string, EntityService> {\n const services = new Map<string, EntityService>()\n\n for (const definition of definitions) {\n const key = getServiceKey(definition)\n const service = createEntityService(ctx, definition)\n services.set(key, service)\n }\n\n return services\n}\n\n/**\n * Get the key used to store service in ctx.services\n */\nexport function getServiceKey(definition: EntityDefinition): string {\n if ('table' in definition && definition.table) {\n return definition.table\n }\n if ('key' in definition && definition.key) {\n return definition.key\n }\n return definition.label.toLowerCase().replace(/\\s+/g, '_')\n}\n\n/**\n * Create routers for all definitions in a module\n */\nexport function createModuleRouters(\n ctx: ModuleContext,\n definitions: EntityDefinition[]\n): Router {\n const router = ctx.createRouter()\n\n for (const definition of definitions) {\n const runtime = createEntityRuntime(ctx, definition)\n\n // Mount at entity route\n const route = getEntityRoute(definition)\n router.use(route, runtime.router)\n\n // Register service in context (skip if already exists to avoid overwriting custom services)\n const key = getServiceKey(definition)\n if (ctx.services[key]) {\n ctx.logger.warn(\n { key, entity: definition.label },\n 'Service key already registered, skipping auto-registration to avoid overwriting custom service'\n )\n } else {\n ctx.services[key] = runtime.service\n }\n }\n\n return router\n}\n\n/**\n * Get route path for entity\n * Uses routePrefix if defined, otherwise infers from table/key/label\n */\nfunction getEntityRoute(definition: EntityDefinition): string {\n // Use explicit routePrefix if defined\n if (definition.routePrefix !== undefined) {\n return definition.routePrefix.startsWith('/') ? definition.routePrefix : `/${definition.routePrefix}`\n }\n\n // Infer from table name: cms_posts -> /posts\n if ('table' in definition && definition.table) {\n const tableName = definition.table\n const parts = tableName.split('_')\n // Remove prefix if present\n const name = parts.length > 1 ? parts.slice(1).join('_') : tableName\n return `/${name}`\n }\n\n // Infer from key: site_config -> /site_config\n if ('key' in definition && definition.key) {\n return `/${definition.key}`\n }\n\n // Fallback to label: \"My Entity\" -> /my-entity\n return `/${definition.label.toLowerCase().replace(/\\s+/g, '-')}`\n}\n","import type { SchemaObject } from 'openapi3-ts/oas31'\nimport type { CollectionEntityDefinition, FieldDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * Mapea db.type de EntityDefinition a OpenAPI type\n */\nfunction mapDbType(dbType: string): SchemaObject {\n switch (dbType) {\n case 'string':\n case 'text':\n return { type: 'string' }\n case 'integer':\n return { type: 'integer' }\n case 'float':\n case 'decimal':\n return { type: 'number' }\n case 'boolean':\n return { type: 'boolean' }\n case 'json':\n return { type: 'object' }\n case 'date':\n return { type: 'string', format: 'date' }\n case 'datetime':\n case 'timestamp':\n return { type: 'string', format: 'date-time' }\n default:\n return { type: 'string' }\n }\n}\n\n/**\n * Convierte un FieldDefinition a OpenAPI SchemaObject\n */\nfunction fieldToSchema(field: FieldDefinition): SchemaObject {\n // Default to string for fields without db config (actions, virtual, etc.)\n const dbType = field.db?.type ?? 'string'\n const schema: SchemaObject = {\n ...mapDbType(dbType),\n description: field.label\n }\n\n // Constraints desde validación\n if (field.validation) {\n if (field.validation.min !== undefined) {\n if (schema.type === 'string') {\n schema.minLength = field.validation.min\n } else if (schema.type === 'integer' || schema.type === 'number') {\n schema.minimum = field.validation.min\n }\n }\n if (field.validation.max !== undefined) {\n if (schema.type === 'string') {\n schema.maxLength = field.validation.max\n } else if (schema.type === 'integer' || schema.type === 'number') {\n schema.maximum = field.validation.max\n }\n }\n if (field.validation.enum) {\n schema.enum = field.validation.enum\n }\n if (field.validation.format === 'email') {\n schema.format = 'email'\n }\n if (field.validation.pattern) {\n schema.pattern = field.validation.pattern\n }\n }\n\n return schema\n}\n\n/**\n * Genera OpenAPI Schema desde CollectionEntityDefinition\n */\nexport function entityToSchema(entity: CollectionEntityDefinition): SchemaObject {\n const properties: Record<string, SchemaObject> = {}\n const required: string[] = []\n\n for (const [name, field] of Object.entries(entity.fields)) {\n // Skip password y campos sensibles en output\n if (entity.casl?.sensitiveFields?.includes(name)) {\n continue\n }\n\n properties[name] = fieldToSchema(field)\n\n if (field.validation?.required && field.db && !field.db.nullable) {\n required.push(name)\n }\n }\n\n // Timestamps si están habilitados\n if (entity.timestamps) {\n properties['created_at'] = { type: 'string', format: 'date-time' }\n properties['updated_at'] = { type: 'string', format: 'date-time' }\n }\n\n return {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined\n }\n}\n\n/**\n * Genera schema para input de creación (sin id, sin timestamps)\n */\nexport function entityToCreateSchema(entity: CollectionEntityDefinition): SchemaObject {\n const properties: Record<string, SchemaObject> = {}\n const required: string[] = []\n\n for (const [name, field] of Object.entries(entity.fields)) {\n // Skip id y campos autogenerados\n if (name === 'id') continue\n\n properties[name] = fieldToSchema(field)\n\n if (field.validation?.required) {\n required.push(name)\n }\n }\n\n return {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined\n }\n}\n\n/**\n * Genera schema para input de actualización (todos opcionales)\n */\nexport function entityToUpdateSchema(entity: CollectionEntityDefinition): SchemaObject {\n const properties: Record<string, SchemaObject> = {}\n\n for (const [name, field] of Object.entries(entity.fields)) {\n // Skip id\n if (name === 'id') continue\n\n properties[name] = fieldToSchema(field)\n }\n\n return {\n type: 'object',\n properties\n // Sin required - todo es opcional en update\n }\n}\n","import type { PathItemObject, OperationObject, ResponsesObject } from 'openapi3-ts/oas31'\nimport type { CollectionEntityDefinition } from '@gzl10/nexus-sdk'\n\n/**\n * Respuesta paginada estándar\n */\nconst paginatedResponse = (schemaRef: string): ResponsesObject => ({\n '200': {\n description: 'Lista paginada',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: {\n type: 'array',\n items: { $ref: schemaRef }\n },\n meta: {\n type: 'object',\n properties: {\n total: { type: 'integer' },\n page: { type: 'integer' },\n limit: { type: 'integer' },\n totalPages: { type: 'integer' },\n hasNext: { type: 'boolean' },\n hasPrev: { type: 'boolean' }\n }\n }\n }\n }\n }\n }\n }\n})\n\n/**\n * Respuesta de item único\n */\nconst itemResponse = (schemaRef: string, description: string): ResponsesObject => ({\n '200': {\n description,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: { $ref: schemaRef }\n }\n }\n }\n }\n },\n '404': {\n description: 'No encontrado',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: { type: 'string' },\n code: { type: 'string' }\n }\n }\n }\n }\n }\n})\n\n/**\n * Genera paths CRUD para una CollectionEntityDefinition\n */\nexport function entityToPaths(\n entity: CollectionEntityDefinition,\n basePath: string\n): Record<string, PathItemObject> {\n const schemaRef = `#/components/schemas/${entity.table}`\n const createSchemaRef = `#/components/schemas/${entity.table}Create`\n const updateSchemaRef = `#/components/schemas/${entity.table}Update`\n const tag = entity.label\n\n const paths: Record<string, PathItemObject> = {}\n\n // GET /items (list) y POST /items (create)\n paths[basePath] = {\n get: {\n tags: [tag],\n summary: `Listar ${entity.label}`,\n operationId: `list${capitalize(entity.table)}`,\n parameters: [\n { name: 'page', in: 'query', schema: { type: 'integer', default: 1 } },\n { name: 'limit', in: 'query', schema: { type: 'integer', default: 20 } },\n { name: 'sort', in: 'query', schema: { type: 'string' } },\n { name: 'order', in: 'query', schema: { type: 'string', enum: ['asc', 'desc'] } }\n ],\n responses: paginatedResponse(schemaRef)\n } as OperationObject,\n post: {\n tags: [tag],\n summary: `Crear ${entity.label}`,\n operationId: `create${capitalize(entity.table)}`,\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: createSchemaRef }\n }\n }\n },\n responses: {\n '201': {\n description: 'Creado',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: { $ref: schemaRef }\n }\n }\n }\n }\n },\n '400': {\n description: 'Error de validación',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: { type: 'string' },\n code: { type: 'string' }\n }\n }\n }\n }\n }\n }\n } as OperationObject\n }\n\n // GET /items/:id, PATCH /items/:id, DELETE /items/:id\n paths[`${basePath}/{id}`] = {\n get: {\n tags: [tag],\n summary: `Obtener ${entity.label} por ID`,\n operationId: `get${capitalize(entity.table)}ById`,\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } }\n ],\n responses: itemResponse(schemaRef, `${entity.label} encontrado`)\n } as OperationObject,\n patch: {\n tags: [tag],\n summary: `Actualizar ${entity.label}`,\n operationId: `update${capitalize(entity.table)}`,\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } }\n ],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: updateSchemaRef }\n }\n }\n },\n responses: itemResponse(schemaRef, `${entity.label} actualizado`)\n } as OperationObject,\n delete: {\n tags: [tag],\n summary: `Eliminar ${entity.label}`,\n operationId: `delete${capitalize(entity.table)}`,\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } }\n ],\n responses: {\n '204': { description: 'Eliminado' },\n '404': {\n description: 'No encontrado',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: { type: 'string' },\n code: { type: 'string' }\n }\n }\n }\n }\n }\n }\n } as OperationObject\n }\n\n return paths\n}\n\nfunction capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n","import type { OpenAPIObject, SchemaObject, PathItemObject } from 'openapi3-ts/oas31'\nimport type { CollectionEntityDefinition, ModuleManifest } from '@gzl10/nexus-sdk'\nimport { entityToSchema, entityToCreateSchema, entityToUpdateSchema } from './schema-builder.js'\nimport { entityToPaths } from './path-builder.js'\nimport { getOrderedModules } from '../../engine/index.js'\n\nexport interface OpenAPIConfig {\n title: string\n version: string\n description?: string\n servers?: Array<{ url: string; description?: string }>\n}\n\n/**\n * Genera spec OpenAPI desde los módulos registrados\n */\nexport function generateOpenAPISpec(config: OpenAPIConfig): OpenAPIObject {\n const modules = getOrderedModules()\n\n const schemas: Record<string, SchemaObject> = {}\n const paths: Record<string, PathItemObject> = {}\n const tags: Array<{ name: string; description?: string }> = []\n\n for (const module of modules) {\n processModule(module, schemas, paths, tags)\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: config.title,\n version: config.version,\n description: config.description\n },\n servers: config.servers ?? [{ url: '/api/v1', description: 'API v1' }],\n tags,\n paths,\n components: {\n schemas,\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT'\n }\n }\n },\n security: [{ bearerAuth: [] }]\n }\n}\n\n/**\n * Procesa un módulo y extrae schemas/paths de sus definitions\n */\nfunction processModule(\n module: ModuleManifest,\n schemas: Record<string, SchemaObject>,\n paths: Record<string, PathItemObject>,\n tags: Array<{ name: string; description?: string }>\n): void {\n if (!module.definitions?.length) return\n\n for (const definition of module.definitions) {\n // Solo CollectionEntityDefinition genera CRUD paths\n if (definition.type !== 'collection') continue\n\n const entity = definition as CollectionEntityDefinition\n const basePath = buildBasePath(module, entity)\n\n // Schemas\n schemas[entity.table] = entityToSchema(entity)\n schemas[`${entity.table}Create`] = entityToCreateSchema(entity)\n schemas[`${entity.table}Update`] = entityToUpdateSchema(entity)\n\n // Paths\n const entityPaths = entityToPaths(entity, basePath)\n Object.assign(paths, entityPaths)\n\n // Tag\n if (!tags.find(t => t.name === entity.label)) {\n tags.push({\n name: entity.label,\n description: `Operaciones CRUD para ${entity.label}`\n })\n }\n }\n}\n\n/**\n * Construye el path base para una entidad\n */\nfunction buildBasePath(module: ModuleManifest, entity: CollectionEntityDefinition): string {\n const modulePrefix = module.routePrefix ?? `/${module.name}`\n const entityPrefix = entity.routePrefix ?? `/${entity.table}`\n\n // Si entityPrefix es '/', solo usar modulePrefix\n if (entityPrefix === '/') {\n return modulePrefix\n }\n\n return `${modulePrefix}${entityPrefix}`\n}\n","export { generateOpenAPISpec, type OpenAPIConfig } from './generator.js'\nexport { entityToSchema, entityToCreateSchema, entityToUpdateSchema } from './schema-builder.js'\nexport { entityToPaths } from './path-builder.js'\n","import { z } from 'zod'\nimport type { NexusConfig, ResolvedConfig } from './types.js'\n\nconst envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.coerce.number().default(3000),\n HOME_PATH: z.string().default('/ui'),\n CORS_ORIGIN: z.string().default('http://localhost:3001'),\n BACKEND_URL: z.string().optional(),\n DATABASE_URL: z.string().default('file:./dev.db'),\n ADMIN_EMAIL: z.string().email().optional(),\n ADMIN_PASSWORD: z.string().min(6).optional(),\n COOKIE_DOMAIN: z.string().optional(),\n TZ: z.string().default('UTC'),\n TRUST_PROXY: z.coerce.boolean().default(false)\n})\n\n// Configuración desde env vars (puede ser parcial)\nexport const env = envSchema.parse(process.env)\nexport type Env = z.infer<typeof envSchema>\n\n// Aplicar TZ inmediatamente al cargar el módulo\n// UTC por defecto para consistencia con bases de datos\nprocess.env.TZ = env.TZ\n\n// Configuración global resuelta\nlet resolvedConfig: ResolvedConfig | null = null\n\nexport function resolveConfig(config?: NexusConfig): ResolvedConfig {\n const timezone = config?.timezone ?? env.TZ\n\n // Aplicar timezone al proceso\n process.env.TZ = timezone\n\n resolvedConfig = {\n nodeEnv: env.NODE_ENV,\n port: config?.port ?? env.PORT,\n host: config?.host ?? '0.0.0.0',\n homePath: config?.homePath ?? env.HOME_PATH,\n corsOrigin: (Array.isArray(config?.cors?.origin)\n ? config.cors.origin[0]\n : config?.cors?.origin) ?? env.CORS_ORIGIN,\n databaseUrl: config?.database?.url ?? env.DATABASE_URL,\n adminEmail: config?.admin?.email ?? env.ADMIN_EMAIL,\n adminPassword: config?.admin?.password ?? env.ADMIN_PASSWORD,\n timezone\n }\n\n return resolvedConfig\n}\n\nexport function getConfig(): ResolvedConfig {\n if (!resolvedConfig) {\n return resolveConfig()\n }\n return resolvedConfig\n}\n\nexport function resetConfig(): void {\n resolvedConfig = null\n}\n","import type { Knex } from 'knex'\nimport { nexusEvents } from '../core/events/emitter.js'\n\n// Tablas a ignorar (internas del sistema)\nconst IGNORED_TABLES = new Set(['refresh_tokens', 'knex_migrations', 'knex_migrations_lock'])\n\nexport interface DbEventPayload {\n table: string\n action: 'created' | 'updated' | 'deleted'\n data: unknown\n timestamp: Date\n}\n\nexport function setupQueryInterceptor(knexInstance: Knex): Knex {\n // Interceptar eventos de query para emitir eventos CRUD\n knexInstance.on('query-response', (response, query) => {\n const sql = query.sql?.toLowerCase() ?? ''\n\n // Detectar tipo de operación desde SQL\n let action: string | undefined\n let table: string | undefined\n\n if (sql.startsWith('insert into')) {\n action = 'created'\n table = extractTableFromInsert(sql)\n } else if (sql.startsWith('update')) {\n action = 'updated'\n table = extractTableFromUpdate(sql)\n } else if (sql.startsWith('delete from')) {\n action = 'deleted'\n table = extractTableFromDelete(sql)\n }\n\n // Emitir evento si es operación CRUD válida\n if (action && table && !IGNORED_TABLES.has(table)) {\n nexusEvents.emit(`db.${table}.${action}`, {\n table,\n action,\n data: response,\n timestamp: new Date()\n } as DbEventPayload)\n }\n })\n\n return knexInstance\n}\n\n// Helpers para extraer nombre de tabla del SQL\nfunction extractTableFromInsert(sql: string): string | undefined {\n // INSERT INTO \"users\" ... o INSERT INTO users ...\n const match = sql.match(/insert into\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n\nfunction extractTableFromUpdate(sql: string): string | undefined {\n // UPDATE \"users\" SET ... o UPDATE users SET ...\n const match = sql.match(/update\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n\nfunction extractTableFromDelete(sql: string): string | undefined {\n // DELETE FROM \"users\" ... o DELETE FROM users ...\n const match = sql.match(/delete from\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n","import { dirname, join } from 'path'\nimport { fileURLToPath } from 'url'\nimport { existsSync, readFileSync } from 'fs'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\n/**\n * Busca hacia arriba el package.json de nexus-backend\n */\nfunction findLibRoot(startDir: string): string {\n let dir = startDir\n while (dir !== '/') {\n const pkgPath = join(dir, 'package.json')\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n if (pkg.name === '@gzl10/nexus-backend') {\n return dir\n }\n } catch {\n // Continuar buscando\n }\n }\n dir = dirname(dir)\n }\n // Fallback: subir 2 niveles desde shared/\n return join(startDir, '../..')\n}\n\n// Cache del resultado\nlet _libPath: string | null = null\n\n/**\n * Ruta raíz de la librería nexus-backend\n * - Dev: /proyecto/nexus-backend/\n * - Lib: /proyecto-usuario/node_modules/@gzl10/nexus-backend/\n */\nexport function getLibPath(): string {\n if (!_libPath) {\n _libPath = findLibRoot(__dirname)\n }\n return _libPath\n}\n\n/**\n * Ruta raíz del proyecto del usuario (process.cwd)\n * - Dev: coincide con getLibPath()\n * - Lib: /proyecto-usuario/\n */\nexport function getProjectPath(): string {\n return process.cwd();\n}\n\n/**\n * Busca .env subiendo desde cwd hasta encontrarlo (máx 5 niveles)\n * Útil para monorepos donde el .env está en la raíz\n */\nexport function findEnvFile(): string | null {\n let dir = process.cwd()\n console.log('[findEnvFile] Starting search from cwd:', dir)\n for (let i = 0; i < 5; i++) {\n const envPath = join(dir, '.env')\n console.log(`[findEnvFile] Checking: ${envPath}`, existsSync(envPath) ? '✓ FOUND' : '✗ not found')\n if (existsSync(envPath)) return envPath\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n console.log('[findEnvFile] .env NOT FOUND after 5 levels')\n return null\n}\n","/**\n * Registry de campos boolean por tabla\n *\n * SQLite almacena booleans como 0/1 (INTEGER).\n * Este registry permite convertirlos a true/false en postProcessResponse.\n */\n\n// Map: tabla → Set de columnas boolean\nconst booleanColumns = new Map<string, Set<string>>()\n\n/**\n * Registra una columna como boolean para una tabla\n */\nexport function registerBooleanColumn(table: string, column: string): void {\n if (!booleanColumns.has(table)) {\n booleanColumns.set(table, new Set())\n }\n booleanColumns.get(table)!.add(column)\n}\n\n/**\n * Registra múltiples columnas boolean para una tabla\n */\nexport function registerBooleanColumns(table: string, columns: string[]): void {\n for (const column of columns) {\n registerBooleanColumn(table, column)\n }\n}\n\n/**\n * Obtiene las columnas boolean registradas para una tabla\n */\nexport function getBooleanColumns(table: string): Set<string> | undefined {\n return booleanColumns.get(table)\n}\n\n/**\n * Verifica si una columna es boolean\n */\nexport function isBooleanColumn(table: string, column: string): boolean {\n return booleanColumns.get(table)?.has(column) ?? false\n}\n\n/**\n * Convierte valores 0/1 a boolean para las columnas registradas\n * Solo debe usarse con SQLite\n */\nexport function convertBooleans(\n table: string,\n row: Record<string, unknown>\n): Record<string, unknown> {\n const columns = booleanColumns.get(table)\n if (!columns || columns.size === 0) {\n return row\n }\n\n const result = { ...row }\n for (const column of columns) {\n if (column in result) {\n const value = result[column]\n if (value === 0 || value === 1) {\n result[column] = value === 1\n }\n }\n }\n return result\n}\n\n/**\n * Limpia el registry (útil para tests)\n */\nexport function clearBooleanRegistry(): void {\n booleanColumns.clear()\n}\n","import knex, { type Knex } from 'knex'\nimport { join, dirname, isAbsolute } from 'path'\nimport { mkdirSync } from 'fs'\nimport { getConfig } from './env.js'\nimport { setupQueryInterceptor } from '../db/query-interceptor.js'\nimport { getProjectPath } from '../core/paths.js'\nimport { convertBooleans } from '../db/boolean-registry.js'\n\n/**\n * Extrae el nombre de la tabla de una query SQL SELECT\n */\nfunction extractTableFromSelect(sql: string): string | undefined {\n const match = sql.match(/from\\s+[\"'`]?(\\w+)[\"'`]?/i)\n return match?.[1]\n}\n\n/**\n * postProcessResponse para SQLite: convierte 0/1 → true/false\n * Solo procesa queries SELECT y usa el registry de campos boolean\n */\nfunction sqlitePostProcess(result: unknown, queryContext: { sql?: string }): unknown {\n const sql = queryContext?.sql?.toLowerCase() ?? ''\n if (!sql.startsWith('select')) return result\n\n const table = extractTableFromSelect(sql)\n if (!table) return result\n\n if (Array.isArray(result)) {\n return result.map(row =>\n typeof row === 'object' && row !== null\n ? convertBooleans(table, row as Record<string, unknown>)\n : row\n )\n }\n\n if (typeof result === 'object' && result !== null) {\n return convertBooleans(table, result as Record<string, unknown>)\n }\n\n return result\n}\n\nfunction getDatabaseConfig(): Knex.Config {\n const url = getConfig().databaseUrl\n\n // SQLite in-memory\n if (url === ':memory:') {\n return {\n client: 'better-sqlite3',\n connection: { filename: ':memory:' },\n useNullAsDefault: true,\n postProcessResponse: sqlitePostProcess\n }\n }\n\n // SQLite (default)\n if (url.startsWith('file:') || url.startsWith('sqlite:')) {\n let filename = url.replace(/^(file:|sqlite:)/, '')\n // Rutas relativas se resuelven desde getProjectPath()/data/\n if (!isAbsolute(filename)) {\n filename = join(getProjectPath(), 'data', filename)\n }\n // Asegurar que el directorio existe\n mkdirSync(dirname(filename), { recursive: true })\n return {\n client: 'better-sqlite3',\n connection: { filename },\n useNullAsDefault: true,\n postProcessResponse: sqlitePostProcess\n }\n }\n\n // PostgreSQL\n if (url.startsWith('postgresql://') || url.startsWith('postgres://')) {\n return {\n client: 'pg',\n connection: url,\n pool: { min: 2, max: 10 }\n }\n }\n\n // MySQL\n if (url.startsWith('mysql://')) {\n // Calcular offset del timezone actual (process.env.TZ ya aplicado)\n const offsetMinutes = new Date().getTimezoneOffset()\n const offsetHours = Math.abs(Math.floor(offsetMinutes / 60))\n const offsetMins = Math.abs(offsetMinutes % 60)\n const sign = offsetMinutes <= 0 ? '+' : '-'\n const tzOffset = `${sign}${String(offsetHours).padStart(2, '0')}:${String(offsetMins).padStart(2, '0')}`\n\n return {\n client: 'mysql2',\n connection: {\n uri: url,\n timezone: tzOffset // mysql2 requiere formato \"+HH:MM\"\n },\n pool: { min: 2, max: 10 }\n }\n }\n\n throw new Error(`Unsupported database URL: ${url}`)\n}\n\nconst globalForKnex = globalThis as unknown as { db: Knex | undefined }\n\n/**\n * Inicializa o reinicializa la conexión a la BD\n */\nexport function initDb(): Knex {\n if (!globalForKnex.db) {\n const knexInstance = knex(getDatabaseConfig())\n globalForKnex.db = setupQueryInterceptor(knexInstance)\n }\n return globalForKnex.db\n}\n\n// Crear instancia inicial\ninitDb()\n\n/**\n * Obtiene la instancia actual de la BD\n * Usar en lugar de `db` para soportar restart\n */\nexport function getDb(): Knex {\n return initDb()\n}\n\n// @deprecated Use getDb() para soportar restart\nexport const db = initDb()\n\n// Helper para verificar el tipo de BD\nexport function getDatabaseType(): 'sqlite' | 'postgresql' | 'mysql' {\n const url = getConfig().databaseUrl\n if (url === ':memory:' || url.startsWith('file:') || url.startsWith('sqlite:')) return 'sqlite'\n if (url.startsWith('postgresql://') || url.startsWith('postgres://')) return 'postgresql'\n if (url.startsWith('mysql://')) return 'mysql'\n return 'sqlite'\n}\n\n// Helper para obtener la ruta/URL de la BD (sin credenciales)\nexport function getDatabasePath(): string {\n const url = getConfig().databaseUrl\n if (url === ':memory:') return ':memory:'\n if (url.startsWith('file:') || url.startsWith('sqlite:')) {\n let filename = url.replace(/^(file:|sqlite:)/, '')\n if (!isAbsolute(filename)) {\n filename = join(getProjectPath(), 'data', filename)\n }\n return filename\n }\n // Para PostgreSQL/MySQL, ocultar credenciales\n try {\n const parsed = new URL(url)\n parsed.password = '***'\n return parsed.toString()\n } catch {\n return url.replace(/:\\/\\/[^@]+@/, '://***@')\n }\n}\n\n// Cerrar conexión de BD (para stop/cleanup)\nexport async function destroyDb(): Promise<void> {\n if (globalForKnex.db) {\n await globalForKnex.db.destroy()\n globalForKnex.db = undefined\n }\n}\n","import crypto from 'crypto'\n\n// Genera un ID único similar a cuid\nexport function generateId(): string {\n const timestamp = Date.now().toString(36)\n const randomPart = crypto.randomBytes(8).toString('base64url')\n return `${timestamp}${randomPart}`.slice(0, 25)\n}\n","import type { Request, Response, NextFunction } from 'express'\nimport type { ValidateSchemas } from '@gzl10/nexus-sdk'\n\n// Extender Request para datos validados (Express 5: query/params son readonly)\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n validated?: {\n query?: unknown\n params?: unknown\n }\n }\n }\n}\n\nexport function validate(schemas: ValidateSchemas) {\n return (req: Request, _res: Response, next: NextFunction) => {\n req.validated = {}\n\n if (schemas.body) {\n req.body = schemas.body.parse(req.body)\n }\n if (schemas.query) {\n req.validated.query = schemas.query.parse(req.query)\n }\n if (schemas.params) {\n req.validated.params = schemas.params.parse(req.params)\n }\n next()\n }\n}\n","import { AbilityBuilder, createMongoAbility, type MongoAbility, type RawRuleOf } from '@casl/ability'\nimport type { User, Permission } from '../../modules/users/users.types.js'\nimport type { Actions, Subjects, SubjectStrings, AppAbility } from './ability.types.js'\n\n/**\n * Interpola variables en condiciones de permisos.\n * Soporta: ${user.id}, ${user.email}, etc.\n */\nfunction interpolateConditions(\n conditions: Record<string, unknown>,\n user: User\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const [key, value] of Object.entries(conditions)) {\n if (typeof value === 'string' && value.startsWith('${user.')) {\n const prop = value.slice(7, -1) as keyof User\n result[key] = user[prop]\n } else {\n result[key] = value\n }\n }\n\n return result\n}\n\n/**\n * Construye abilities CASL desde permisos de BD.\n * @param user - Usuario autenticado\n * @param permissions - Permisos del rol del usuario (cargados desde BD)\n */\nexport function defineAbilityFor(user: User, permissions: Permission[]): AppAbility {\n const { can, cannot, build } = new AbilityBuilder<MongoAbility<[Actions, Subjects]>>(createMongoAbility)\n\n for (const perm of permissions) {\n const action = perm.action as Actions\n const subject = perm.subject as SubjectStrings\n const conditions = perm.conditions\n ? interpolateConditions(perm.conditions as Record<string, unknown>, user)\n : undefined\n const fields = perm.fields as string[] | undefined\n\n if (perm.inverted) {\n // cannot(action, subject, fields, conditions) - CASL signature\n if (fields?.length) {\n cannot(action, subject, fields, conditions)\n } else {\n cannot(action, subject, conditions)\n }\n } else {\n // can(action, subject, fields, conditions) - CASL signature\n if (fields?.length) {\n can(action, subject, fields, conditions)\n } else {\n can(action, subject, conditions)\n }\n }\n }\n\n return build()\n}\n\n// Serializar abilities para enviar al frontend\nexport function packRules(ability: AppAbility): RawRuleOf<AppAbility>[] {\n return ability.rules as RawRuleOf<AppAbility>[]\n}\n\n// Reconstruir abilities desde reglas serializadas\nexport function unpackRules(rules: RawRuleOf<AppAbility>[]): AppAbility {\n return createMongoAbility<[Actions, Subjects]>(rules)\n}\n","import { Server as SocketServer, Socket } from 'socket.io'\nimport type { Server as HttpServer } from 'http'\nimport jwt from 'jsonwebtoken'\nimport { getAuthConfig } from '../../modules/auth/auth.config.js'\nimport { nexusEvents } from '../events/emitter.js'\nimport { logger } from '../logger.js'\n\nlet io: SocketServer | null = null\n\n// Mapa de conexiones: userId -> Set<socketId>\nconst userSockets = new Map<string, Set<string>>()\n// Mapa inverso: socketId -> userId\nconst socketUsers = new Map<string, string>()\n\ninterface JwtPayload {\n userId: string\n roleId: string\n}\n\n/**\n * Inicializa Socket.IO en el servidor HTTP\n */\nexport function initSocketIO(httpServer: HttpServer): SocketServer {\n io = new SocketServer(httpServer, {\n cors: { origin: '*', methods: ['GET', 'POST'] },\n path: '/socket.io'\n })\n\n // Middleware de autenticación (opcional - permite guests)\n io.use((socket, next) => {\n const token = socket.handshake.auth?.['token'] || socket.handshake.query?.['token']\n\n if (token && typeof token === 'string') {\n try {\n const payload = jwt.verify(token, getAuthConfig().secret) as JwtPayload\n socket.data.userId = payload.userId\n socket.data.roleId = payload.roleId\n socket.data.authenticated = true\n } catch {\n socket.data.authenticated = false\n }\n } else {\n socket.data.authenticated = false\n }\n next()\n })\n\n io.on('connection', handleConnection)\n\n logger.info('Socket.IO initialized')\n nexusEvents.emitEvent('socket.initialized')\n\n return io\n}\n\nfunction handleConnection(socket: Socket) {\n const { userId, roleId, authenticated } = socket.data\n\n // Registrar conexión\n if (authenticated && userId) {\n if (!userSockets.has(userId)) {\n userSockets.set(userId, new Set())\n }\n userSockets.get(userId)!.add(socket.id)\n socketUsers.set(socket.id, userId)\n\n // Unir a rooms del usuario y del role\n socket.join(`user:${userId}`)\n socket.join(`role:${roleId}`)\n socket.join('authenticated')\n\n logger.debug({ userId, roleId, socketId: socket.id }, 'User connected')\n nexusEvents.emitEvent('socket.user.connected', { userId, roleId, socketId: socket.id })\n }\n\n // Unir a room global (todos, incluyendo guests)\n socket.join('all')\n\n socket.on('disconnect', () => {\n if (userId) {\n userSockets.get(userId)?.delete(socket.id)\n if (userSockets.get(userId)?.size === 0) {\n userSockets.delete(userId)\n }\n socketUsers.delete(socket.id)\n\n logger.debug({ userId, socketId: socket.id }, 'User disconnected')\n nexusEvents.emitEvent('socket.user.disconnected', { userId, socketId: socket.id })\n }\n })\n}\n\n/**\n * Obtiene la instancia de Socket.IO\n * @throws Error si Socket.IO no ha sido inicializado\n */\nexport function getIO(): SocketServer {\n if (!io) throw new Error('Socket.IO not initialized. Call initSocketIO first.')\n return io\n}\n\n/**\n * Verifica si Socket.IO está inicializado\n */\nexport function isSocketIOInitialized(): boolean {\n return io !== null\n}\n\n/**\n * Obtiene los IDs de usuarios conectados\n */\nexport function getConnectedUsers(): string[] {\n return Array.from(userSockets.keys())\n}\n\n/**\n * Verifica si un usuario específico está conectado\n */\nexport function isUserConnected(userId: string): boolean {\n return userSockets.has(userId)\n}\n\n/**\n * Obtiene el número de sockets conectados para un usuario\n */\nexport function getUserSocketCount(userId: string): number {\n return userSockets.get(userId)?.size ?? 0\n}\n\n/**\n * Cierra Socket.IO (para cleanup en tests o shutdown)\n */\nexport function closeSocketIO(): void {\n if (io) {\n io.close()\n io = null\n userSockets.clear()\n socketUsers.clear()\n logger.debug('Socket.IO closed')\n }\n}\n","import { Router } from 'express'\nimport type {\n ModuleContext,\n ModuleMiddlewares,\n EntityDefinition,\n BaseEntityService,\n EntityController,\n CollectionEntityDefinition,\n TempEntityDefinition,\n EventEntityDefinition,\n SingleEntityDefinition,\n ReferenceEntityDefinition,\n ConfigEntityDefinition,\n ViewEntityDefinition,\n ComputedEntityDefinition,\n ExternalEntityDefinition,\n VirtualEntityDefinition,\n ActionEntityDefinition,\n CreateEntityServiceOptions\n} from '@gzl10/nexus-sdk'\nimport { getDb } from '../config/database.js'\nimport { getConfig } from '../config/env.js'\nimport { logger } from '../core/logger.js'\nimport { generateId } from '../core/utils/id.js'\nimport { addTimestamps, addAuditFieldsIfMissing, addConfigDefaultField, addColumnIfMissing, nowTimestamp, formatTimestamp } from '../db/helpers.js'\nimport { validate } from '../core/middleware/validate.middleware.js'\nimport { createRateLimit } from '../core/middleware/rate-limit.middleware.js'\nimport { AppError, NotFoundError, UnauthorizedError, ForbiddenError, ConflictError, ValidationError } from '../core/errors/app-error.js'\nimport { ForbiddenError as CASLForbiddenError, subject } from '@casl/ability'\nimport { defineAbilityFor, packRules } from '../core/abilities/ability.factory.js'\nimport { nexusEvents } from '../core/events/emitter.js'\nimport type { ModuleServices } from '../types/services.js'\nimport { getLibPath, getProjectPath } from '../core/paths.js'\n// Crypto utilities\nimport { hashPassword, verifyPassword, DUMMY_HASH } from '../core/crypto/index.js'\n// Socket.IO utilities\nimport { getIO, isSocketIOInitialized, isUserConnected, getUserSocketCount, getConnectedUsers } from '../core/socket/index.js'\n// Runtime services for createService factory\nimport { CollectionService } from '../runtime/services/collection.service.js'\nimport { TempService } from '../runtime/services/temp.service.js'\nimport { EventService } from '../runtime/services/event.service.js'\nimport { SingleService } from '../runtime/services/single.service.js'\nimport { ReferenceService } from '../runtime/services/reference.service.js'\nimport { ConfigService } from '../runtime/services/config.service.js'\nimport { ViewService } from '../runtime/services/view.service.js'\nimport { ComputedService } from '../runtime/services/computed.service.js'\nimport { ExternalService } from '../runtime/services/external.service.js'\nimport { VirtualService } from '../runtime/services/virtual.service.js'\nimport { ActionService } from '../runtime/services/action.service.js'\n// Runtime controller & router factories\nimport { createEntityController } from '../runtime/controllers/entity.controller.js'\nimport { createEntityRouter } from '../runtime/routes/entity.routes.js'\n// Engine utilities for module/plugin introspection\nimport { getModules, getPlugins, getModuleSubjects, getRegisteredSubjects } from '../engine/index.js'\n\n/**\n * Crea el contexto que se inyecta a los módulos\n * Centraliza las herramientas genéricas para migraciones y seeds\n *\n * Los servicios se registran en el init() de cada módulo:\n * - users: ctx.services.users = createUsersService(ctx)\n * - mail: ctx.services.mail = initMailService(ctx.logger, ctx.services.logger)\n */\nexport function createModuleContext(): ModuleContext {\n // Registry de middlewares con validate y rateLimit como base\n const middleware: ModuleMiddlewares = {\n validate,\n rateLimit: createRateLimit\n }\n\n // Services registry (typed, filled by modules in init())\n const services = {} as ModuleServices\n\n // Cast necesarios para compatibilidad con tipos genéricos del SDK\n // Los tipos concretos (ResolvedConfig, AppAbility, TypedEventEmitter) son compatibles en runtime\n return {\n db: getDb(),\n logger,\n helpers: {\n generateId,\n addTimestamps,\n addAuditFieldsIfMissing,\n addConfigDefaultField,\n addColumnIfMissing,\n getLibPath,\n getProjectPath,\n nowTimestamp,\n formatTimestamp\n },\n crypto: {\n hashPassword,\n verifyPassword,\n DUMMY_HASH\n },\n socket: {\n getIO,\n isInitialized: isSocketIOInitialized,\n isUserConnected,\n getUserSocketCount,\n getConnectedUsers\n },\n engine: {\n getModules,\n getPlugins,\n getModuleSubjects,\n getRegisteredSubjects\n },\n createRouter: () => Router(),\n middleware,\n config: getConfig() as unknown as Record<string, unknown>,\n errors: {\n AppError,\n NotFoundError,\n UnauthorizedError,\n ForbiddenError,\n ConflictError,\n ValidationError\n },\n abilities: {\n defineAbilityFor: defineAbilityFor as ModuleContext['abilities']['defineAbilityFor'],\n packRules: packRules as ModuleContext['abilities']['packRules'],\n subject,\n ForbiddenError: CASLForbiddenError\n },\n events: nexusEvents as unknown as ModuleContext['events'],\n services,\n // Factory para crear servicios de entidades (detecta tipo automáticamente)\n createEntityService: createEntityServiceFactory,\n // Factory para crear controller de entidad\n createEntityController: createEntityControllerFactory,\n // Factory para crear router de entidad\n createEntityRouter: createEntityRouterFactory\n } as ModuleContext\n}\n\n/**\n * Factory function para crear servicios de entidades\n * Se define fuera para evitar problemas de tipado con `this`\n *\n * @param definition - Definición de la entidad\n * @param options - Opciones opcionales, incluyendo hooks para personalizar comportamiento\n */\nfunction createEntityServiceFactory<T extends Record<string, unknown> = Record<string, unknown>>(\n this: ModuleContext,\n definition: EntityDefinition,\n options?: CreateEntityServiceOptions<T>\n): BaseEntityService<T> {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const ctx = this\n const hooks = options?.hooks\n switch (definition.type) {\n case 'collection':\n return new CollectionService<T>(ctx, definition as CollectionEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'temp':\n return new TempService<T>(ctx, definition as TempEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'event':\n return new EventService<T>(ctx, definition as EventEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'single':\n return new SingleService<T>(ctx, definition as SingleEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'reference':\n return new ReferenceService<T>(ctx, definition as ReferenceEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'config':\n return new ConfigService<T>(ctx, definition as ConfigEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'view':\n return new ViewService<T>(ctx, definition as ViewEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'computed':\n return new ComputedService<T>(ctx, definition as ComputedEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'external':\n return new ExternalService<T>(ctx, definition as ExternalEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'virtual':\n return new VirtualService<T>(ctx, definition as VirtualEntityDefinition, hooks) as unknown as BaseEntityService<T>\n case 'action':\n return new ActionService<T>(ctx, definition as ActionEntityDefinition, hooks) as unknown as BaseEntityService<T>\n default:\n throw new Error(`Unknown entity type: ${(definition as EntityDefinition).type}`)\n }\n}\n\n/**\n * Factory function para crear controllers de entidades\n */\nfunction createEntityControllerFactory(\n this: ModuleContext,\n service: BaseEntityService,\n definition: EntityDefinition\n): EntityController {\n return createEntityController(service, definition, this)\n}\n\n/**\n * Factory function para crear routers de entidades\n */\nfunction createEntityRouterFactory(\n this: ModuleContext,\n controller: EntityController,\n definition: EntityDefinition\n): Router {\n return createEntityRouter(controller, definition, this)\n}\n","import type { Request, Response, NextFunction } from 'express'\nimport { ZodError } from 'zod'\nimport { ForbiddenError as CASLForbiddenError } from '@casl/ability'\nimport { AppError } from '../errors/app-error.js'\nimport { env } from '../../config/env.js'\nimport { logger } from '../logger.js'\nimport { captureExceptionSafe } from '../../modules/logger/logger.service.js'\n\nexport function errorMiddleware(\n err: Error,\n req: Request,\n res: Response,\n _next: NextFunction\n) {\n // Log todos los errores en desarrollo\n if (env.NODE_ENV !== 'production') {\n logger.error({ err, url: req.url, method: req.method }, 'Error en request')\n }\n\n // Zod validation errors\n if (err instanceof ZodError) {\n return res.status(400).json({\n error: 'Error de validación',\n details: err.errors.map((e) => ({\n path: e.path.join('.'),\n message: e.message\n }))\n })\n }\n\n // CASL forbidden\n if (err instanceof CASLForbiddenError) {\n return res.status(403).json({\n error: 'No tienes permiso para esta acción'\n })\n }\n\n // Custom app errors\n if (err instanceof AppError) {\n const response: { error: string; details?: unknown } = { error: err.message }\n if (err.details) {\n response.details = err.details\n }\n return res.status(err.statusCode).json(response)\n }\n\n // Unknown errors (siempre loguear)\n logger.error({ err, url: req.url, method: req.method, stack: err.stack }, 'Unhandled error')\n captureExceptionSafe(err, { url: req.url, method: req.method })\n res.status(500).json({\n error: env.NODE_ENV === 'production' ? 'Error interno del servidor' : err.message\n })\n}\n","import express from 'express'\nimport cors from 'cors'\nimport helmet from 'helmet'\nimport compression from 'compression'\nimport cookieParser from 'cookie-parser'\nimport path from 'path'\nimport { randomUUID } from 'crypto'\n\nimport { getOrderedModules } from '../engine/index.js'\nimport { createModuleRouters } from '../runtime/entity-factory.js'\nimport { generateOpenAPISpec } from './openapi/index.js'\nimport { createModuleContext } from '../modules/context.js'\nimport { errorMiddleware } from './middleware/error.middleware.js'\nimport { env, getConfig } from '../config/env.js'\nimport { logger } from './logger.js'\nimport { getProjectPath } from './paths.js'\n\nexport function createApp() {\n const app = express()\n\n // Trust proxy (required behind reverse proxy for rate-limit, secure cookies, etc.)\n if (env.TRUST_PROXY) {\n app.set('trust proxy', true)\n }\n\n // Security\n app.use(helmet({\n contentSecurityPolicy: env.NODE_ENV === 'production' ? undefined : false\n }))\n\n // CORS\n app.use(cors({\n origin: env.CORS_ORIGIN,\n credentials: true,\n allowedHeaders: ['Content-Type', 'Authorization', 'X-Correlation-ID', 'X-Request-ID'],\n exposedHeaders: ['X-Correlation-ID', 'X-Request-ID']\n }))\n\n // Request ID y Correlation ID (siempre activo)\n app.use((req, res, next) => {\n const requestId = randomUUID()\n const correlationId = req.get('X-Correlation-ID') || req.get('X-Request-ID') || requestId\n\n res.setHeader('X-Request-ID', requestId)\n res.setHeader('X-Correlation-ID', correlationId)\n\n req.requestId = requestId\n req.correlationId = correlationId\n\n next()\n })\n\n // HTTP logging (API=debug, rest=trace)\n const logLevel = process.env['LOG_LEVEL']\n if (logLevel === 'debug' || logLevel === 'trace') {\n app.use((req, res, next) => {\n const start = Date.now()\n res.on('finish', () => {\n const ms = Date.now() - start\n const msg = `[${req.correlationId.slice(0, 8)}] ${req.method} ${req.originalUrl} ${res.statusCode} ${ms}ms`\n if (req.originalUrl.startsWith('/api/')) {\n logger.debug(msg)\n } else {\n logger.trace(msg)\n }\n })\n next()\n })\n }\n\n // Compression\n app.use(compression())\n\n // Body parsing\n app.use(express.json())\n app.use(cookieParser())\n\n // API routes (auto-discovery from modules)\n const ctx = createModuleContext()\n const modules = getOrderedModules()\n\n // 1. Inicializar módulos (registrar middlewares, etc.)\n for (const mod of modules) {\n if (mod.init) {\n mod.init(ctx)\n }\n }\n\n // 2. Registrar rutas (ya tienen middlewares disponibles)\n for (const mod of modules) {\n const prefix = mod.routePrefix ?? `/${mod.name}`\n\n // 2a. Rutas custom primero (tienen prioridad, manejan lógica especial)\n if (mod.routes) {\n app.use(`/api/v1${prefix}`, mod.routes(ctx))\n }\n\n // 2b. Rutas automáticas para entities que no necesitan lógica custom\n // Tipos: action, view, computed, virtual, external, reference, event\n if (mod.definitions && mod.definitions.length > 0) {\n const AUTO_MOUNT_TYPES = ['action', 'view', 'computed', 'virtual', 'external', 'reference', 'event']\n const autoMountable = mod.definitions.filter(d => AUTO_MOUNT_TYPES.includes(d.type ?? 'collection'))\n if (autoMountable.length > 0) {\n const autoRouter = createModuleRouters(ctx, autoMountable)\n app.use(`/api/v1${prefix}`, autoRouter)\n }\n }\n }\n\n // Health check\n app.get('/health', (_req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() })\n })\n\n // OpenAPI spec\n app.get('/api/openapi.json', (_req, res) => {\n const spec = generateOpenAPISpec({\n title: 'Nexus API',\n version: '1.0.0',\n description: 'API generada automáticamente desde EntityDefinitions'\n })\n res.json(spec)\n })\n\n // Redirect root to homePath\n app.get('/', (_req, res) => {\n res.redirect(getConfig().homePath)\n })\n\n // Serve static files from public/\n const publicPath = path.join(getProjectPath(), 'public')\n app.use('/public', express.static(publicPath))\n\n // Serve Vue UI\n const uiPath = path.join(getProjectPath(), '../ui/dist')\n\n app.use('/ui', express.static(uiPath))\n app.get('/ui/{*splat}', (_req, res) => {\n res.sendFile(path.join(uiPath, 'index.html'))\n })\n\n // Global error handler (Express 5 async support)\n app.use(errorMiddleware)\n\n return app\n}\n","import net from 'node:net'\nimport { execSync } from 'child_process'\nimport { logger } from '../logger.js'\n\n/**\n * Busca el PID del proceso usando un puerto\n */\nfunction findProcessOnPort(port: number): number | null {\n try {\n // macOS/Linux: lsof\n const output = execSync(`lsof -ti :${port} 2>/dev/null`, { encoding: 'utf-8' })\n const pid = parseInt(output.trim().split('\\n')[0] ?? '', 10)\n return isNaN(pid) ? null : pid\n } catch {\n return null\n }\n}\n\n/**\n * Mata el proceso que está usando un puerto (solo en desarrollo)\n */\nexport function killProcessOnPort(port: number): boolean {\n const pid = findProcessOnPort(port)\n if (!pid) return false\n\n try {\n process.kill(pid, 'SIGTERM')\n logger.warn({ port, pid }, `Killed process ${pid} on port ${port}`)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Verifica si un puerto está disponible\n * En desarrollo, intenta liberar el puerto automáticamente\n */\nexport async function checkPortAvailable(port: number, host = '0.0.0.0'): Promise<void> {\n return new Promise((resolve, reject) => {\n const server = net.createServer()\n\n server.once('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n // En desarrollo, intentar liberar el puerto\n if (process.env['NODE_ENV'] !== 'production') {\n if (killProcessOnPort(port)) {\n // Esperar un poco y reintentar\n setTimeout(() => {\n checkPortAvailable(port, host).then(resolve).catch(reject)\n }, 500)\n return\n }\n }\n logger.error({ port }, `Port ${port} is already in use`)\n reject(new Error(`Port ${port} is already in use`))\n } else {\n reject(err)\n }\n })\n\n server.once('listening', () => {\n server.close(() => resolve())\n })\n\n server.listen(port, host)\n })\n}\n","/**\n * Ejecuta migraciones inteligentes desde EntityDefinitions\n *\n * Características:\n * - Crea tablas nuevas automáticamente\n * - Detecta y añade columnas nuevas (ALTER TABLE ADD)\n * - Detecta cambios de tipo y loguea advertencia (no modifica)\n * - Detecta columnas obsoletas y loguea advertencia (no elimina)\n */\n\nimport type { Knex } from 'knex'\nimport type { ModuleContext, ModuleManifest, FieldDefinition, FieldDbConfig } from '@gzl10/nexus-sdk'\nimport { isPersistentEntity, getEntityName } from '@gzl10/nexus-sdk'\nimport { registerBooleanColumns } from './boolean-registry.js'\n\n/** Campos de sistema que no deben marcarse como obsoletos */\nconst SYSTEM_FIELDS = new Set([\n 'id',\n 'created_at',\n 'updated_at',\n 'created_by',\n 'updated_by',\n 'is_default'\n])\n\n/** Información de columna desde introspección */\ninterface ColumnInfo {\n type: string\n maxLength: number | null\n nullable: boolean\n defaultValue: unknown\n}\n\n/**\n * Ejecuta migración inteligente desde las definitions del módulo\n * Detecta diferencias entre EntityDefinition y estado actual de BD\n */\nexport async function runGeneratedMigration(\n ctx: ModuleContext,\n mod: ModuleManifest\n): Promise<void> {\n const { db, logger, helpers } = ctx\n const { addTimestamps, addAuditFieldsIfMissing, addConfigDefaultField } = helpers\n\n const definitions = mod.definitions ?? []\n const persistentEntities = definitions.filter(isPersistentEntity)\n\n if (persistentEntities.length === 0) {\n return\n }\n\n for (const entity of persistentEntities) {\n const { table, fields } = entity\n const timestamps = 'timestamps' in entity ? entity.timestamps : false\n const audit = 'audit' in entity ? entity.audit : false\n const indexes = 'indexes' in entity ? entity.indexes : undefined\n const name = getEntityName(entity)\n\n // Registrar campos boolean para conversión SQLite 0/1 → true/false\n const booleanFields = Object.entries(fields)\n .filter(([, field]) => field.db?.type === 'boolean')\n .map(([fieldName]) => fieldName)\n if (booleanFields.length > 0) {\n registerBooleanColumns(table, booleanFields)\n }\n\n const tableExists = await db.schema.hasTable(table)\n\n if (!tableExists) {\n // ========================================\n // CREAR TABLA NUEVA\n // ========================================\n await db.schema.createTable(table, (tableBuilder) => {\n for (const [fieldName, field] of Object.entries(fields)) {\n createColumn(tableBuilder, fieldName, field)\n }\n\n if (timestamps) {\n addTimestamps(tableBuilder, db)\n }\n\n if (indexes?.length) {\n for (const idx of indexes) {\n if (idx.unique) {\n tableBuilder.unique(idx.columns)\n } else {\n tableBuilder.index(idx.columns)\n }\n }\n }\n })\n logger.info(`Created table: ${table} (from ${name} definition)`)\n } else {\n // ========================================\n // MIGRACIÓN INTELIGENTE - DIFF DE COLUMNAS\n // ========================================\n const currentColumns = await db(table).columnInfo() as Record<string, ColumnInfo>\n const definedFields = new Set(Object.keys(fields))\n\n // 1. Detectar columnas nuevas → ADD COLUMN\n for (const [fieldName, field] of Object.entries(fields)) {\n // Skip fields without db config (actions, virtual entities, etc.)\n if (!field.db) continue\n\n if (!currentColumns[fieldName]) {\n await addColumn(db, table, fieldName, field, logger)\n } else {\n // 2. Detectar cambios de tipo → WARNING\n const typeChange = detectTypeChange(currentColumns[fieldName]!, field.db)\n if (typeChange) {\n logger.warn(\n `[${table}.${fieldName}] Type mismatch: BD has \"${typeChange.current}\", definition expects \"${typeChange.expected}\". ` +\n `Manual migration required.`\n )\n }\n }\n }\n\n // 3. Detectar columnas obsoletas → WARNING (no eliminar)\n for (const colName of Object.keys(currentColumns)) {\n if (!definedFields.has(colName) && !SYSTEM_FIELDS.has(colName)) {\n logger.warn(\n `[${table}.${colName}] Column exists in DB but not in EntityDefinition. ` +\n `Consider removing manually if no longer needed.`\n )\n }\n }\n }\n\n // Audit fields (siempre intentar añadir si audit: true)\n if (audit) {\n await addAuditFieldsIfMissing(db, table)\n }\n\n // Config entities: añadir campo is_default automáticamente\n if (entity.type === 'config') {\n await addConfigDefaultField(db, table)\n }\n }\n}\n\n/**\n * Añade una columna nueva a tabla existente\n */\nasync function addColumn(\n db: Knex,\n table: string,\n name: string,\n field: FieldDefinition,\n logger: ModuleContext['logger']\n): Promise<void> {\n await db.schema.alterTable(table, (tableBuilder) => {\n createColumn(tableBuilder, name, field, true) // isAlter = true\n })\n logger.info(`Added column: ${table}.${name}`)\n}\n\n/**\n * Detecta si hay cambio de tipo entre BD y definition\n * Retorna null si son compatibles, o un objeto con los tipos si difieren\n */\nfunction detectTypeChange(\n current: ColumnInfo,\n expected: FieldDbConfig\n): { current: string; expected: string } | null {\n const currentType = normalizeDbType(current.type)\n const expectedType = expected.type\n\n // Mapeo de tipos equivalentes\n const equivalentTypes: Record<string, string[]> = {\n string: ['varchar', 'character varying', 'char', 'nvarchar'],\n text: ['text', 'longtext', 'mediumtext', 'clob'],\n integer: ['integer', 'int', 'int4', 'bigint', 'smallint', 'tinyint'],\n decimal: ['decimal', 'numeric', 'real', 'double', 'float'],\n boolean: ['boolean', 'bool', 'tinyint'],\n date: ['date'],\n datetime: ['datetime', 'timestamp', 'timestamptz'],\n json: ['json', 'jsonb', 'text'], // SQLite usa text para JSON\n uuid: ['uuid', 'char', 'varchar'] // SQLite/MySQL usa varchar para UUID\n }\n\n const expectedEquivalents = equivalentTypes[expectedType] ?? [expectedType]\n\n if (expectedEquivalents.includes(currentType)) {\n return null // Tipos compatibles\n }\n\n return { current: currentType, expected: expectedType }\n}\n\n/**\n * Normaliza el tipo de BD a formato consistente\n */\nfunction normalizeDbType(type: string): string {\n return type.toLowerCase().replace(/\\(\\d+\\)/, '').trim()\n}\n\n/**\n * Crea una columna en la tabla según la definición del campo\n * @param isAlter - Si es ALTER TABLE (no aplicar primary key)\n */\nfunction createColumn(\n table: any, // Knex.CreateTableBuilder | Knex.AlterTableBuilder\n name: string,\n field: FieldDefinition,\n isAlter = false\n): void {\n const { db } = field\n if (!db) {\n throw new Error(`Field ${name} has no db config, cannot create column`)\n }\n let column: any\n\n // Tipo base\n switch (db.type) {\n case 'string':\n column = db.size ? table.string(name, db.size) : table.string(name)\n break\n case 'text':\n column = table.text(name)\n break\n case 'integer':\n column = table.integer(name)\n break\n case 'decimal':\n if (db.precision) {\n column = table.decimal(name, db.precision[0], db.precision[1])\n } else {\n column = table.decimal(name)\n }\n break\n case 'boolean':\n column = table.boolean(name)\n break\n case 'date':\n column = table.date(name)\n break\n case 'datetime':\n column = table.datetime(name)\n break\n case 'json':\n column = table.json(name)\n break\n case 'uuid':\n column = table.uuid(name)\n break\n default:\n column = table.string(name)\n }\n\n // Primary key (solo en CREATE, no en ALTER)\n if (name === 'id' && !isAlter) {\n column.primary()\n }\n\n // Nullable - En ALTER TABLE, nuevas columnas deben ser nullable o tener default\n if (isAlter) {\n // Nuevas columnas siempre nullable para evitar errores con datos existentes\n column.nullable()\n } else if (!db.nullable) {\n column.notNullable()\n } else {\n column.nullable()\n }\n\n // Unique (solo en CREATE para evitar errores con datos duplicados)\n if (db.unique && !isAlter) {\n column.unique()\n }\n\n // Default\n if (db.default !== undefined) {\n column.defaultTo(db.default)\n } else if (db.defaultFn === 'now') {\n // Usar fn.now() del cliente Knex para compatibilidad con PostgreSQL\n const knexClient = (table as unknown as { client: { fn: { now: () => unknown } } }).client\n if (knexClient?.fn?.now) {\n column.defaultTo(knexClient.fn.now())\n }\n // Si no hay cliente disponible, no poner default (se manejará en la aplicación)\n }\n\n // Index\n if (db.index && !isAlter) {\n column.index()\n }\n\n // Foreign key (solo en CREATE para evitar errores de integridad)\n if (field.relation && !isAlter) {\n column.references(field.relation.column ?? 'id').inTable(field.relation.table)\n if (field.relation.onDelete) {\n column.onDelete(field.relation.onDelete)\n }\n }\n}\n","import type { Knex } from 'knex'\n\n/**\n * Asegura que existan las tablas de infraestructura del sistema.\n * Se ejecuta ANTES de las migraciones de módulos.\n */\nexport async function ensureSystemTables(db: Knex): Promise<void> {\n // single_records: almacena entities tipo \"single\" (singletons)\n if (!await db.schema.hasTable('single_records')) {\n await db.schema.createTable('single_records', (table) => {\n table.string('id').primary()\n table.string('key').notNullable().unique()\n table.text('value')\n table.timestamp('created_at').defaultTo(db.fn.now())\n table.timestamp('updated_at').defaultTo(db.fn.now())\n table.string('created_by').nullable()\n table.string('updated_by').nullable()\n })\n }\n}\n","import http from 'node:http'\nimport { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { pathToFileURL } from 'node:url'\nimport { createApp } from './app.js'\nimport { destroyDb, getDb, getDatabaseType, getDatabasePath } from '../config/database.js'\nimport { resolveConfig, resetConfig, env } from '../config/env.js'\nimport { nexusEvents } from './events/emitter.js'\nimport { logger, setLoggerInstance } from './logger.js'\nimport { getLoggerConfig } from '../modules/logger/logger.config.js'\nimport { initLoggerService, getPinoLogger } from '../modules/logger/logger.service.js'\nimport { checkPortAvailable } from './utils/net.js'\nimport { loadCoreModules, getOrderedModules, resetStore } from '../engine/index.js'\nimport { initSocketIO, closeSocketIO } from './socket/index.js'\nimport { createModuleContext } from '../modules/context.js'\nimport { getLibPath, getProjectPath } from './paths.js'\nimport { runGeneratedMigration } from '../db/generated-migrate.js'\nimport { ensureSystemTables } from '../db/ensure-system-tables.js'\nimport { cacheInvalidator } from './cache/index.js'\nimport type { NexusConfig } from '../config/types.js'\nimport type { ModuleContext, ModuleManifest } from '@gzl10/nexus-sdk'\n\nlet server: http.Server | null = null\n\nexport type { NexusConfig }\n\n/**\n * Intenta ejecutar el seed de un módulo.\n * 1. Si mod.seed está definido, lo usa directamente\n * 2. Si no, intenta auto-detectar {name}.seed.js en el directorio del módulo\n */\nasync function runModuleSeed(mod: ModuleManifest, ctx: ModuleContext): Promise<boolean> {\n // Seed explícito en manifest\n if (mod.seed) {\n await mod.seed(ctx)\n return true\n }\n\n // Auto-detección: buscar {name}.seed.js en dist/modules/{name}/\n const seedPath = join(getLibPath(), 'dist', 'modules', mod.name, `${mod.name}.seed.js`)\n if (!existsSync(seedPath)) {\n return false\n }\n\n try {\n const seedModule = await import(pathToFileURL(seedPath).href)\n if (typeof seedModule.seed === 'function') {\n await seedModule.seed(ctx)\n return true\n }\n } catch (err) {\n logger.warn({ module: mod.name, err }, 'Failed to load auto-detected seed')\n }\n\n return false\n}\n\nasync function runMigrationsAndSeeds(): Promise<void> {\n // Inicializar logger antes de cualquier log para evitar múltiples instancias de pino-pretty\n initLoggerService(getLoggerConfig())\n setLoggerInstance(getPinoLogger())\n\n // Cargar módulos core antes de usarlos\n loadCoreModules()\n\n const ctx = createModuleContext()\n const modules = getOrderedModules()\n\n logger.info({ type: getDatabaseType(), path: getDatabasePath() }, 'Database ready')\n\n // Asegurar tablas de sistema antes de migraciones de módulos\n await ensureSystemTables(getDb())\n\n logger.info('Running migrations...')\n for (const mod of modules) {\n if (mod.migrate) {\n // Usar migración manual si existe\n await mod.migrate(ctx)\n } else if (mod.definitions?.length) {\n // Fallback: generar y ejecutar migración desde definitions\n await runGeneratedMigration(ctx, mod)\n }\n }\n\n logger.info('Running seeds...')\n for (const mod of modules) {\n await runModuleSeed(mod, ctx)\n }\n}\n\nexport async function start(config?: NexusConfig): Promise<http.Server> {\n if (server) {\n throw new Error('Server already running. Call stop() first.')\n }\n\n const resolved = resolveConfig(config)\n\n // Verificar puerto disponible antes de iniciar\n await checkPortAvailable(resolved.port, resolved.host)\n\n nexusEvents.emitEvent('server.starting', { port: resolved.port, host: resolved.host })\n\n // Ejecutar migraciones y seeds antes de iniciar\n await runMigrationsAndSeeds()\n\n // Inicializar cache invalidator (escucha eventos db.*)\n cacheInvalidator.init()\n\n const app = createApp()\n\n return new Promise((resolve) => {\n server = app.listen(resolved.port, resolved.host, () => {\n // Inicializar Socket.IO después de que el servidor esté escuchando\n initSocketIO(server!)\n\n const baseUrl = env.BACKEND_URL || `http://localhost:${resolved.port}`\n logger.info({ libPath: getLibPath(), projectPath: getProjectPath() }, 'Paths')\n logger.info(`API: ${baseUrl}/api/v1`)\n logger.info(`UI: ${baseUrl}/ui`)\n logger.info({ port: resolved.port, mode: resolved.nodeEnv }, 'Server started')\n nexusEvents.emitEvent('server.started', { port: resolved.port, host: resolved.host })\n resolve(server!)\n })\n })\n}\n\nexport async function stop(): Promise<void> {\n if (!server) return\n\n nexusEvents.emitEvent('server.stopping')\n\n // Limpiar cache invalidator\n cacheInvalidator.destroy()\n\n // Cerrar Socket.IO antes del servidor HTTP\n closeSocketIO()\n\n await new Promise<void>((resolve, reject) => {\n server!.close((err) => {\n if (err) reject(err)\n else resolve()\n })\n })\n\n await destroyDb()\n nexusEvents.emitEvent('db.disconnected')\n\n resetConfig()\n resetStore()\n server = null\n nexusEvents.emitEvent('server.stopped')\n logger.info('Server stopped')\n}\n\nexport async function restart(config?: NexusConfig): Promise<http.Server> {\n nexusEvents.emitEvent('server.restarting')\n await stop()\n return start(config)\n}\n\nexport function isRunning(): boolean {\n return server !== null\n}\n\n// Graceful shutdown handlers\nfunction setupGracefulShutdown() {\n let shuttingDown = false\n\n const shutdown = async (signal: string) => {\n if (shuttingDown) return\n shuttingDown = true\n\n logger.info({ signal }, 'Graceful shutdown initiated')\n\n try {\n await stop()\n process.exit(0)\n } catch (err) {\n logger.fatal({ err }, 'Error during shutdown')\n process.exit(1)\n }\n }\n\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n process.on('SIGINT', () => shutdown('SIGINT'))\n}\n\nsetupGracefulShutdown()\n","/**\n * Carga .env antes de cualquier otro import del proyecto\n * Este archivo SOLO importa de node/npm, nunca de archivos locales\n */\nimport { existsSync } from 'fs'\nimport { join, dirname } from 'path'\nimport { config } from 'dotenv'\n\nlet dir = process.cwd()\nconsole.log('[env-loader] Starting search from cwd:', dir)\n\nfor (let i = 0; i < 3; i++) {\n const envPath = join(dir, '.env')\n const exists = existsSync(envPath)\n console.log(`[env-loader] Checking: ${envPath}`, exists ? '✓ FOUND' : '✗ not found')\n if (exists) {\n config({ path: envPath })\n console.log('[env-loader] Loaded:', envPath)\n break\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n}\n","// Cargar .env PRIMERO - este import no tiene deps locales\nimport './env-loader.js'\n\n// Server lifecycle\nexport { start, stop, restart, isRunning } from './core/server.js'\nexport type { NexusConfig } from './core/server.js'\n\n// Core exports\nexport { createApp } from './core/app.js'\nexport { db, getDb, destroyDb, getDatabaseType } from './config/database.js'\nexport { getConfig } from './config/env.js'\nexport type { ResolvedConfig } from './config/types.js'\n\n// Module system (engine)\nexport { registerModule, registerPlugin, getModules, getModule, getOrderedModules } from './engine/index.js'\nexport { getRegisteredSubjects, isValidSubject, getPlugin, getPlugins, loadCoreModules } from './engine/index.js'\n\n// Runtime - Auto-generated services, controllers, routes\nexport {\n createEntityRuntime,\n createEntityService,\n createModuleServices,\n createModuleRouters,\n getServiceKey,\n registerAdapter,\n getAdapter\n} from './runtime/index.js'\nexport type {\n EntityService,\n EntityController,\n EntityRuntime,\n EntityQuery,\n ExternalAdapter,\n EntityHandler\n} from './runtime/index.js'\n// Service classes (for extension)\nexport { BaseEntityService } from './runtime/index.js'\nexport { CollectionService } from './runtime/index.js'\nexport { SingleService } from './runtime/index.js'\nexport { ReferenceService } from './runtime/index.js'\nexport { EventService } from './runtime/index.js'\nexport { ConfigService } from './runtime/index.js'\nexport { TempService } from './runtime/index.js'\nexport { ViewService } from './runtime/index.js'\nexport { ExternalService } from './runtime/index.js'\nexport { VirtualService } from './runtime/index.js'\nexport { ComputedService } from './runtime/index.js'\nexport { ActionService } from './runtime/index.js'\nexport type {\n ModuleManifest,\n ModuleContext,\n EntityDefinition,\n ModuleRequirements,\n ModuleMiddlewares,\n ModuleAbilities,\n ContextHelpers,\n ValidateSchemas,\n PluginManifest,\n Category,\n Request,\n Response,\n NextFunction,\n RequestHandler,\n Router,\n CookieOptions\n} from '@gzl10/nexus-sdk'\n\n// Pagination & Auth types\nexport type { PaginatedResult, PaginationParams, AuthRequest } from './types/index.js'\n\n// Entity models\nexport type { User, Role, Permission } from './modules/users/users.types.js'\nexport type { UserWithoutPassword, UserWithRole, UserPresence, RoleWithPermissions, RoleWithCounts } from './modules/users/users.service.js'\nexport type { RefreshToken, AuthAudit } from './modules/auth/auth.types.js'\nexport type { JwtPayload, TokenPair } from './modules/auth/jwt.utils.js'\n\n// CASL abilities\nexport { defineAbilityFor, packRules, unpackRules } from './core/abilities/ability.factory.js'\nexport type { AppAbility, Actions, Subjects, SubjectStrings, SubjectRegistry } from './core/abilities/ability.types.js'\n\n// Events\nexport { nexusEvents } from './core/events/emitter.js'\nexport type { NexusEvents, NexusEventName, NexusEventPayload, DbEventPayload } from './core/events/emitter.js'\n\n// Socket.IO\nexport {\n getIO,\n initSocketIO,\n isSocketIOInitialized,\n getConnectedUsers,\n isUserConnected,\n getUserSocketCount,\n closeSocketIO\n} from './core/socket/index.js'\n\n// Notifications\nexport {\n NotificationService,\n getNotificationService,\n initNotificationService\n} from './modules/notifications/index.js'\nexport type {\n NotificationType,\n NotificationPriority,\n NotificationTarget,\n SendNotificationInput,\n Notification,\n NotificationPayload\n} from './modules/notifications/index.js'\n\n// Paths (rutas de librería y proyecto)\nexport { getLibPath, getProjectPath, findEnvFile } from './core/paths.js'\n\n// Auto-start si se ejecuta directamente (CLI mode)\nif (import.meta.url === `file://${process.argv[1]}`) {\n const { start } = await import('./core/server.js')\n start()\n}\n","/**\n * Runtime - Auto-generated services, controllers, and routes for entities\n *\n * Usage:\n * ```typescript\n * import { createEntityRuntime, createModuleRouters } from './runtime/index.js'\n *\n * // Create runtime for a single entity\n * const runtime = createEntityRuntime(ctx, postEntity)\n * app.use('/posts', runtime.router)\n *\n * // Create routers for all entities in a module\n * const router = createModuleRouters(ctx, module.definitions)\n * app.use('/api/cms', router)\n * ```\n */\n\n// Types\nexport * from './types.js'\n\n// Entity Factory\nexport {\n createEntityService,\n createEntityRuntime,\n createModuleServices,\n createModuleRouters,\n getServiceKey\n} from './entity-factory.js'\n\n// Services\nexport { BaseEntityService } from './services/base.service.js'\nexport { CollectionService } from './services/collection.service.js'\nexport { SingleService } from './services/single.service.js'\nexport { ReferenceService } from './services/reference.service.js'\nexport { EventService } from './services/event.service.js'\nexport { ConfigService } from './services/config.service.js'\nexport { TempService } from './services/temp.service.js'\nexport { ViewService } from './services/view.service.js'\nexport { ExternalService } from './services/external.service.js'\nexport { VirtualService } from './services/virtual.service.js'\nexport { ComputedService } from './services/computed.service.js'\nexport { ActionService } from './services/action.service.js'\n\n// Controllers\nexport { createEntityController } from './controllers/entity.controller.js'\n\n// Routes\nexport { createEntityRouter } from './routes/entity.routes.js'\n\n// Validation\nexport { buildCreateSchema, buildUpdateSchema, getSchemas } from './validation/index.js'\n"],"mappings":"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","names":["subject","subject","require","pino","config","loggerInstance","config","config","logger","init_logger","config","join","existsSync","db","cpus","existsSync","join","dirname","config","dir","path","createHash","extname","config","path","join","existsSync","mkdirSync","path","db","config","db","db","logger","generateId","projectPath","config","TABLE","type","DEFAULT_MAX_SIZE","rateLimit","config","multer","config","db","logger","generateId","TABLE","DEFAULT_MAX_SIZE","seed","z","verifyPassword","hashPassword","z","validate","CASLForbiddenError","db","generateId","nowTimestamp","hashPassword","isUserConnected","getUserSocketCount","seed","db","logger","generateId","config","hashPassword","seed","pino","createRequire","hasPinoPretty","require","z","path","config","db","generateId","nowTimestamp","crypto","verifyPassword","DUMMY_HASH","defineAbilityFor","packRules","USERS","ROLES","config","z","validate","jwt","defineAbilityFor","USERS","seed","db","logger","generateId","seed","getModuleSubjects","z","existsSync","join","logger","config","nodemailer","getConfigByScope","config","subject","seed","db","logger","generateId","seed","type","io","z","io","config","path","z","init_logger","getTableAndSubject","subject","z","db","type","subject","CASLForbiddenError","type","type","init_schema_builder","config","init_schema_builder","init_schema_builder","z","config","dirname","join","existsSync","readFileSync","dir","pkg","join","dirname","isAbsolute","mkdirSync","crypto","subject","jwt","ZodError","CASLForbiddenError","start","server","db","logger","addTimestamps","addAuditFieldsIfMissing","addConfigDefaultField","type","db","join","existsSync","config","start"]}
|