@gzl10/nexus-backend 0.1.4
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/README.md +80 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +30 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +561 -0
- package/dist/index.js +2267 -0
- package/dist/index.js.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/modules/system/system.controller.ts","../src/modules/system/system.routes.ts","../src/modules/system/index.ts","../src/modules/roles/roles.migrate.ts","../src/modules/roles/roles.seed.ts","../src/modules/roles/roles.service.ts","../src/modules/roles/roles.controller.ts","../src/modules/roles/roles.schemas.ts","../src/modules/roles/roles.routes.ts","../src/modules/roles/index.ts","../src/modules/users/users.migrate.ts","../src/modules/auth/auth.utils.ts","../src/modules/users/users.seed.ts","../src/modules/users/users.service.ts","../src/modules/users/users.controller.ts","../src/modules/users/users.schemas.ts","../src/modules/users/users.routes.ts","../src/modules/users/index.ts","../src/modules/auth/auth.migrate.ts","../src/config/env.ts","../src/modules/auth/jwt.utils.ts","../src/modules/auth/auth.service.ts","../src/modules/auth/auth.controller.ts","../src/modules/auth/auth.schemas.ts","../src/modules/auth/auth.routes.ts","../src/modules/auth/auth.middleware.ts","../src/modules/auth/index.ts","../src/modules/index.ts","../src/events/emitter.ts","../src/db/query-interceptor.ts","../src/config/database.ts","../src/shared/logger.ts","../src/shared/utils/id.ts","../src/db/helpers.ts","../src/shared/middleware/validate.middleware.ts","../src/shared/errors/app-error.ts","../src/shared/abilities/ability.factory.ts","../src/shared/mail/mail.service.ts","../src/shared/mail/index.ts","../src/modules/context.ts","../src/shared/middleware/error.middleware.ts","../src/app.ts","../src/shared/utils/net.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["import type { Request, Response, ModuleContext } from '../module.types.js'\nimport { getModules } from '../index.js'\n\n/**\n * DTO de validación JSON Schema para respuesta API\n */\ninterface FieldValidationDTO {\n type?: 'string' | 'number' | 'integer' | 'boolean'\n minLength?: number\n maxLength?: number\n minimum?: number\n maximum?: number\n pattern?: string\n format?: 'email' | 'uri' | 'date' | 'date-time' | 'uuid'\n errorMessage?: string\n}\n\n/**\n * DTO de campo de formulario para respuesta API\n */\ninterface FormFieldDTO {\n label: string\n type: string\n required?: boolean\n placeholder?: string\n createOnly?: boolean\n disabled?: boolean\n hidden?: boolean\n optionsEndpoint?: string\n optionValue?: string\n optionLabel?: string\n validation?: FieldValidationDTO\n}\n\n/**\n * DTO de entidad para respuesta API\n */\ninterface ModuleEntityDTO {\n name: string\n label: string\n listFields: Record<string, string>\n formFields?: Record<string, FormFieldDTO>\n labelField: string\n routePrefix?: string\n editMode?: 'modal' | 'page'\n listType?: 'table' | 'list' | 'grid' | 'masonry'\n}\n\n/**\n * DTO de módulo para respuesta API (sin funciones)\n */\ninterface ModuleDTO {\n name: string\n code: string\n label: string\n icon?: string\n description?: string\n version?: string\n type: string\n category: string\n dependencies: string[]\n routePrefix: string\n subjects: string[]\n entities: ModuleEntityDTO[]\n hasRoutes: boolean\n hasMigrate: boolean\n hasSeed: boolean\n hasInit: boolean\n}\n\nfunction toModuleDTO(mod: ReturnType<typeof getModules>[number]): ModuleDTO {\n return {\n name: mod.name,\n code: mod.code,\n label: mod.label,\n icon: mod.icon,\n description: mod.description,\n version: mod.version,\n type: mod.type ?? 'core',\n category: mod.category ?? '',\n dependencies: mod.dependencies ?? [],\n routePrefix: mod.routePrefix ?? `/${mod.name}`,\n subjects: mod.subjects ?? [],\n entities: mod.entities ?? [],\n hasRoutes: !!mod.routes,\n hasMigrate: !!mod.migrate,\n hasSeed: !!mod.seed,\n hasInit: !!mod.init\n }\n}\n\nexport function createSystemController(ctx: ModuleContext) {\n const { errors } = ctx\n\n return {\n /**\n * GET /system/modules\n * Lista todos los módulos registrados\n */\n listModules(_req: Request, res: Response) {\n const modules = getModules().map(toModuleDTO)\n res.json({ data: modules, total: modules.length })\n },\n\n /**\n * GET /system/modules/:code\n * Obtiene un módulo por código\n */\n getModule(req: Request<{ code: string }>, res: Response) {\n const { code } = req.params\n const mod = getModules().find((m) => m.code === code.toUpperCase())\n\n if (!mod) {\n throw new errors.NotFoundError('Módulo no encontrado')\n }\n\n res.json({ data: toModuleDTO(mod) })\n }\n }\n}\n","import type { ModuleContext } from '../module.types.js'\nimport { createSystemController } from './system.controller.js'\n\nexport function createSystemRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const controller = createSystemController(ctx)\n\n // Endpoints públicos (no requieren auth)\n router.get('/modules', controller.listModules)\n router.get('/modules/:code', controller.getModule)\n\n return router\n}\n","import type { ModuleManifest } from '../module.types.js'\nimport { createSystemRoutes } from './system.routes.js'\n\nexport const systemModule: ModuleManifest = {\n name: 'system',\n code: 'SYS',\n label: 'System',\n icon: 'mdi:cog-outline',\n description: 'System configuration, module registry, and platform metadata',\n type: 'core',\n dependencies: [],\n routes: createSystemRoutes,\n routePrefix: '/system',\n subjects: []\n}\n\nexport default systemModule\n","import type { ModuleContext } from '../module.types.js'\n\nexport async function migrate(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers } = ctx\n const { addTimestamps, addAuditFieldsIfMissing } = helpers\n\n // Tabla rol_roles\n if (!(await db.schema.hasTable('rol_roles'))) {\n await db.schema.createTable('rol_roles', (table) => {\n table.string('id').primary()\n table.string('name', 50).unique().notNullable()\n table.string('description', 255)\n table.boolean('is_system').defaultTo(false)\n addTimestamps(table, db)\n })\n logger.info('Created table: rol_roles')\n }\n\n // Tabla rol_role_permissions\n if (!(await db.schema.hasTable('rol_role_permissions'))) {\n await db.schema.createTable('rol_role_permissions', (table) => {\n table.string('id').primary()\n table.string('role_id').notNullable().references('id').inTable('rol_roles').onDelete('CASCADE')\n table.string('action', 20).notNullable()\n table.string('subject', 50).notNullable()\n table.json('conditions')\n table.json('fields')\n table.boolean('inverted').defaultTo(false)\n addTimestamps(table, db)\n table.unique(['role_id', 'action', 'subject'])\n })\n logger.info('Created table: rol_role_permissions')\n }\n\n // Campos de auditoría\n await addAuditFieldsIfMissing(db, 'rol_roles')\n await addAuditFieldsIfMissing(db, 'rol_role_permissions')\n}\n","import type { ModuleContext } from '../module.types.js'\n\n/**\n * Crea los roles de sistema y sus permisos si no existen\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, generateId } = ctx\n\n // Solo crear roles si la tabla está vacía\n const existingRoles = await db('rol_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('rol_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('rol_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: 'UsrUser', 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: 'UsrUser', conditions: JSON.stringify({ id: '${user.id}' }), inverted: false }\n ]\n await db('rol_role_permissions').insert(permissions)\n logger.info('Inserted permissions for system roles')\n}\n","import type { ModuleContext } from '../module.types.js'\nimport type { CreateRoleInput, UpdateRoleInput, PermissionInput, RoleQuery } from './roles.schemas.js'\nimport type { Role, RolePermission, RoleWithPermissions, RoleWithCounts } from './roles.models.js'\nimport type { PaginatedResult } from '../../types/index.js'\n\nexport function createRolesService(ctx: ModuleContext) {\n const { db, errors, generateId } = ctx\n\n return {\n async findAllPermissions(query: RoleQuery): Promise<PaginatedResult<RolePermission & { role: { name: string } }>> {\n const { page, limit } = query\n const offset = (page - 1) * limit\n\n const baseQuery = db('rol_role_permissions')\n .select(\n 'rol_role_permissions.*',\n 'rol_roles.name as role_name'\n )\n .leftJoin('rol_roles', 'rol_role_permissions.role_id', 'rol_roles.id')\n\n const [permissions, countResult] = await Promise.all([\n baseQuery.clone().orderBy('rol_roles.name', 'asc').orderBy('subject', 'asc').limit(limit).offset(offset),\n db('rol_role_permissions').count('* as count').first<{ count: string | number }>()\n ])\n\n const total = Number(countResult?.count ?? 0)\n\n const items = permissions.map((p) => ({\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 role: { name: p.role_name }\n }))\n\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 async findAll(query: RoleQuery): Promise<PaginatedResult<RoleWithCounts>> {\n const { page, limit } = query\n const offset = (page - 1) * limit\n\n // Subqueries para evitar N+1\n const permissionsCountSubquery = db('rol_role_permissions')\n .count('*')\n .whereRaw('rol_role_permissions.role_id = rol_roles.id')\n .as('permissions_count')\n\n const usersCountSubquery = db('usr_users')\n .count('*')\n .whereRaw('usr_users.role_id = rol_roles.id')\n .as('users_count')\n\n const baseQuery = db('rol_roles')\n .select('rol_roles.*', permissionsCountSubquery, usersCountSubquery)\n\n const [roles, countResult] = await Promise.all([\n baseQuery.clone().orderBy('name', 'asc').limit(limit).offset(offset),\n baseQuery.clone().count('* as count').first<{ count: string | number }>()\n ])\n\n const total = Number(countResult?.count ?? 0)\n\n const items = roles.map((role) => ({\n ...role,\n permissions_count: Number(role.permissions_count ?? 0),\n users_count: Number(role.users_count ?? 0)\n }))\n\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 async findById(id: string): Promise<RoleWithPermissions> {\n const role = await db<Role>('rol_roles').where({ id }).first()\n if (!role) throw new errors.NotFoundError('Rol')\n\n const permissions = await db<RolePermission>('rol_role_permissions')\n .where({ role_id: id })\n .orderBy('subject', 'asc')\n .orderBy('action', 'asc')\n\n // Parse JSON conditions and fields\n const parsedPermissions = permissions.map((p) => ({\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 }))\n\n return { ...role, permissions: parsedPermissions }\n },\n\n async findByName(name: string): Promise<Role | undefined> {\n return db<Role>('rol_roles').where({ name }).first()\n },\n\n async getPermissionsByRoleId(roleId: string): Promise<RolePermission[]> {\n const permissions = await db<RolePermission>('rol_role_permissions').where({ role_id: roleId })\n\n return permissions.map((p) => ({\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 }))\n },\n\n async create(input: CreateRoleInput, userId?: string): Promise<Role> {\n // Operación atómica con transacción\n return db.transaction(async (trx) => {\n const existing = await trx<Role>('rol_roles').where({ name: input.name }).first()\n if (existing) {\n throw new errors.ConflictError('Ya existe un rol con ese nombre')\n }\n\n const id = generateId()\n\n await trx('rol_roles').insert({\n id,\n name: input.name,\n description: input.description || null,\n is_system: false,\n created_by: userId ?? null\n })\n\n const role = await trx<Role>('rol_roles').where({ id }).first()\n return role!\n })\n },\n\n async update(id: string, input: UpdateRoleInput, userId?: string): Promise<Role> {\n // Operación atómica con transacción\n return db.transaction(async (trx) => {\n const role = await trx<Role>('rol_roles').where({ id }).first()\n if (!role) throw new errors.NotFoundError('Rol')\n\n if (role.is_system) {\n throw new errors.ForbiddenError('No se pueden modificar roles del sistema')\n }\n\n if (input.name && input.name !== role.name) {\n const existing = await trx<Role>('rol_roles').where({ name: input.name }).first()\n if (existing) {\n throw new errors.ConflictError('Ya existe un rol con ese nombre')\n }\n }\n\n await trx('rol_roles').where({ id }).update({\n ...input,\n updated_at: new Date(),\n updated_by: userId ?? null\n })\n\n const updated = await trx<Role>('rol_roles').where({ id }).first()\n return updated!\n })\n },\n\n async delete(id: string): Promise<void> {\n const role = await db<Role>('rol_roles').where({ id }).first()\n if (!role) throw new errors.NotFoundError('Rol')\n\n if (role.is_system) {\n throw new errors.ForbiddenError('No se pueden eliminar roles del sistema')\n }\n\n // Check if role has users\n const usersCount = await db('usr_users')\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 await db('rol_roles').where({ id }).delete()\n },\n\n async updatePermissions(id: string, permissions: PermissionInput[], userId?: string): Promise<RoleWithPermissions> {\n // Operación atómica con transacción\n return db.transaction(async (trx) => {\n const role = await trx<Role>('rol_roles').where({ id }).first()\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 // Delete existing permissions\n await trx('rol_role_permissions').where({ role_id: id }).delete()\n\n // Insert new permissions\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,\n created_by: userId ?? null\n }))\n\n await trx('rol_role_permissions').insert(permissionsData)\n }\n\n // Update role's updated_by\n await trx('rol_roles').where({ id }).update({\n updated_at: new Date(),\n updated_by: userId ?? null\n })\n\n // Return role with permissions (fuera de transacción para leer datos finales)\n const updatedRole = await trx<Role>('rol_roles').where({ id }).first()\n const updatedPermissions = await trx<RolePermission>('rol_role_permissions')\n .where({ role_id: id })\n .orderBy('subject', 'asc')\n .orderBy('action', 'asc')\n\n const parsedPermissions = updatedPermissions.map((p) => ({\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 }))\n\n return { ...updatedRole!, permissions: parsedPermissions }\n })\n }\n }\n}\n","import type { Request, Response, ModuleContext } from '../module.types.js'\nimport { createRolesService } from './roles.service.js'\nimport type { CreateRoleInput, UpdateRoleInput, UpdatePermissionsInput, RoleParams, RoleQuery } from './roles.schemas.js'\nimport type { AuthRequest } from '../module.types.js'\n\nexport function createRolesController(ctx: ModuleContext) {\n const { ForbiddenError: CASLForbiddenError } = ctx.abilities\n const rolesService = createRolesService(ctx)\n\n return {\n async findAllPermissions(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('read', 'RolRolePermission')\n\n const result = await rolesService.findAllPermissions(req.validated?.query as RoleQuery)\n res.json({ success: true, data: result })\n },\n\n async findAll(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('read', 'RolRole')\n\n const result = await rolesService.findAll(req.validated?.query as RoleQuery)\n res.json({ success: true, data: result })\n },\n\n async findById(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('read', 'RolRole')\n\n const { id } = req.validated?.params as RoleParams\n const role = await rolesService.findById(id)\n res.json({ success: true, data: role })\n },\n\n async create(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('create', 'RolRole')\n\n const role = await rolesService.create(req.body as CreateRoleInput, authReq.user.id)\n res.status(201).json({ success: true, data: role })\n },\n\n async update(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('update', 'RolRole')\n\n const { id } = req.validated?.params as RoleParams\n const role = await rolesService.update(id, req.body as UpdateRoleInput, authReq.user.id)\n res.json({ success: true, data: role })\n },\n\n async delete(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('delete', 'RolRole')\n\n const { id } = req.validated?.params as RoleParams\n await rolesService.delete(id)\n res.json({ success: true, message: 'Rol eliminado' })\n },\n\n async updatePermissions(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('update', 'RolRole')\n\n const { id } = req.validated?.params as RoleParams\n const { permissions } = req.body as UpdatePermissionsInput\n const role = await rolesService.updatePermissions(id, permissions, authReq.user.id)\n res.json({ success: true, data: role })\n }\n }\n}\n","import { z } from 'zod'\n\nexport const createRoleSchema = z.object({\n name: z.string()\n .min(2, 'Nombre mínimo 2 caracteres')\n .max(50, 'Nombre máximo 50 caracteres')\n .regex(/^[A-Z_]+$/, 'Solo mayúsculas y guion bajo'),\n description: z.string().max(255).optional()\n})\n\nexport const updateRoleSchema = z.object({\n name: z.string()\n .min(2, 'Nombre mínimo 2 caracteres')\n .max(50, 'Nombre máximo 50 caracteres')\n .regex(/^[A-Z_]+$/, 'Solo mayúsculas y guion bajo')\n .optional(),\n description: z.string().max(255).optional()\n})\n\nexport const permissionSchema = z.object({\n action: z.enum(['manage', 'create', 'read', 'update', 'delete']),\n subject: z.enum(['UsrUser', 'PstPost', 'RolRole', 'RolRolePermission', 'all']),\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\nexport const roleParamsSchema = z.object({\n id: z.string().min(1)\n})\n\nexport const roleQuerySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n limit: z.coerce.number().min(1).max(100).default(10)\n})\n\nexport type CreateRoleInput = z.infer<typeof createRoleSchema>\nexport type UpdateRoleInput = z.infer<typeof updateRoleSchema>\nexport type PermissionInput = z.infer<typeof permissionSchema>\nexport type UpdatePermissionsInput = z.infer<typeof updatePermissionsSchema>\nexport type RoleParams = z.infer<typeof roleParamsSchema>\nexport type RoleQuery = z.infer<typeof roleQuerySchema>\n","import type { ModuleContext } from '../module.types.js'\nimport { createRolesController } from './roles.controller.js'\nimport {\n createRoleSchema,\n updateRoleSchema,\n updatePermissionsSchema,\n roleParamsSchema,\n roleQuerySchema\n} from './roles.schemas.js'\n\nexport function createRolesRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { validate, auth } = ctx.middleware\n const controller = createRolesController(ctx)\n\n // Todas las rutas requieren autenticación\n router.use(auth!)\n\n router.get('/', validate({ query: roleQuerySchema }), controller.findAll)\n router.get('/permissions', validate({ query: roleQuerySchema }), controller.findAllPermissions)\n router.get('/:id', validate({ params: roleParamsSchema }), controller.findById)\n router.post('/', validate({ body: createRoleSchema }), controller.create)\n router.put('/:id', validate({ params: roleParamsSchema, body: updateRoleSchema }), controller.update)\n router.delete('/:id', validate({ params: roleParamsSchema }), controller.delete)\n router.put('/:id/permissions', validate({ params: roleParamsSchema, body: updatePermissionsSchema }), controller.updatePermissions)\n\n return router\n}\n","import type { ModuleManifest } from '../module.types.js'\nimport { migrate } from './roles.migrate.js'\nimport { seed } from './roles.seed.js'\nimport { createRolesRoutes } from './roles.routes.js'\n\nexport const rolesModule: ModuleManifest = {\n name: \"roles\",\n code: \"ROL\",\n label: \"Roles\",\n icon: \"mdi:shield-outline\",\n description:\n \"Role definitions and CASL-based permission rules for access control\",\n type: \"core\",\n dependencies: [],\n migrate,\n seed,\n routes: createRolesRoutes,\n routePrefix: \"/roles\",\n subjects: [\"RolRole\", \"RolRolePermission\"],\n entities: [\n {\n name: \"RolRole\",\n label: \"Roles\",\n listType: \"list\",\n listFields: {\n name: \"Name\",\n description: \"Description\",\n },\n formFields: {\n name: {\n label: \"Name\",\n type: \"text\",\n required: true,\n placeholder: \"ADMIN_ROLE\",\n validation: {\n minLength: 2,\n maxLength: 50,\n pattern: \"^[A-Z][A-Z0-9_]*$\",\n errorMessage: \"Use UPPER_SNAKE_CASE (e.g., ADMIN_ROLE)\",\n },\n },\n description: {\n label: \"Description\",\n type: \"textarea\",\n placeholder: \"Role description...\",\n validation: {\n maxLength: 500,\n },\n },\n },\n labelField: \"name\",\n },\n {\n name: \"RolRolePermission\",\n label: \"Permissions\",\n routePrefix: \"/roles/permissions\",\n listFields: {\n action: \"Action\",\n subject: \"Subject\",\n \"role.name\": \"Role\",\n },\n labelField: \"action\",\n },\n ],\n};\n\nexport default rolesModule\n","import type { ModuleContext } from '../module.types.js'\n\nexport async function migrate(ctx: ModuleContext): Promise<void> {\n const { db, logger, helpers } = ctx\n const { addTimestamps, addAuditFieldsIfMissing, addColumnIfMissing } = helpers\n\n // Tabla usr_users\n if (!(await db.schema.hasTable('usr_users'))) {\n await db.schema.createTable('usr_users', (table) => {\n table.string('id').primary()\n table.string('email').unique().notNullable()\n table.string('password').notNullable()\n table.string('name').notNullable()\n table.string('role_id').notNullable().references('id').inTable('rol_roles')\n addTimestamps(table, db)\n })\n logger.info('Created table: usr_users')\n }\n\n // Migración legacy: usr_users.role (enum) -> usr_users.role_id (FK)\n await migrateLegacyRoleColumn(ctx)\n\n // Añadir metadata si no existe\n await addColumnIfMissing(db, 'usr_users', 'metadata', (table) => {\n table.json('metadata').nullable()\n })\n\n // Campos de auditoría\n await addAuditFieldsIfMissing(db, 'usr_users')\n}\n\n/**\n * Migra el campo usr_users.role (enum legacy) a usr_users.role_id (FK)\n * Solo se ejecuta si existe la columna role pero no role_id\n */\nasync function migrateLegacyRoleColumn(ctx: ModuleContext): Promise<void> {\n const { db, logger, dbType } = ctx\n\n const hasRoleColumn = await db.schema.hasColumn('usr_users', 'role')\n const hasRoleIdColumn = await db.schema.hasColumn('usr_users', 'role_id')\n\n if (!hasRoleColumn || hasRoleIdColumn) return\n\n logger.info('Migrating usr_users.role to usr_users.role_id...')\n\n // Get role IDs\n const roles = await db('rol_roles').select('id', 'name')\n const roleMap = Object.fromEntries(roles.map((r: { id: string; name: string }) => [r.name, r.id]))\n\n // Add role_id column\n await db.schema.alterTable('usr_users', (table) => {\n table.string('role_id').references('id').inTable('rol_roles')\n })\n\n // Migrate data\n for (const [roleName, roleId] of Object.entries(roleMap)) {\n await db('usr_users').where('role', roleName).update({ role_id: roleId })\n }\n\n // Make role_id NOT NULL and drop role column\n if (dbType === 'sqlite') {\n // SQLite workaround: recreate table\n await db.raw(`\n CREATE TABLE usr_users_new (\n id TEXT PRIMARY KEY,\n email TEXT UNIQUE NOT NULL,\n password TEXT NOT NULL,\n name TEXT NOT NULL,\n role_id TEXT NOT NULL REFERENCES rol_roles(id),\n created_at TEXT DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `)\n await db.raw(`\n INSERT INTO usr_users_new (id, email, password, name, role_id, created_at, updated_at)\n SELECT id, email, password, name, role_id, created_at, updated_at FROM usr_users\n `)\n await db.raw('DROP TABLE usr_users')\n await db.raw('ALTER TABLE usr_users_new RENAME TO usr_users')\n } else {\n await db.schema.alterTable('usr_users', (table) => {\n table.dropColumn('role')\n })\n }\n\n logger.info('Migration completed: usr_users.role -> usr_users.role_id')\n}\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","import type { ModuleContext } from '../module.types.js'\nimport { hashPassword } from '../auth/auth.utils.js'\n\n/**\n * Crea el usuario administrador inicial si no existe\n */\nexport async function seed(ctx: ModuleContext): Promise<void> {\n const { db, logger, generateId } = ctx\n\n const email = process.env['ADMIN_EMAIL'] || 'admin@example.com'\n const password = process.env['ADMIN_PASSWORD'] || 'admin123'\n\n const existing = await db('usr_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('rol_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('usr_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 { ModuleContext } from '../module.types.js'\nimport { hashPassword } from '../auth/auth.utils.js'\nimport type { CreateUserInput, UpdateUserInput, UserQuery } from './users.schemas.js'\nimport type { User, UserWithoutPassword, UserWithRole } from './users.models.js'\nimport type { Role } from '../roles/roles.models.js'\nimport type { PaginatedResult } from '../../types/index.js'\n\nfunction excludePassword(user: User): UserWithoutPassword {\n const { password: _, ...rest } = user\n return rest\n}\n\n/** Tipo interno para filas con JOIN de rol */\ninterface UserWithRoleRow extends User {\n role_name: string\n role_description: string | null\n role_is_system: boolean\n role_created_at: Date\n role_updated_at: Date\n}\n\n/** Helper DRY: mapea fila con JOIN a UserWithRole */\nfunction buildUserWithRole(row: UserWithRoleRow): 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 return {\n ...user,\n role: user.role_id\n ? ({\n id: user.role_id,\n name: role_name,\n description: role_description,\n is_system: role_is_system,\n created_at: role_created_at,\n updated_at: role_updated_at\n } as Role)\n : null\n } as UserWithRole\n}\n\n/** Columnas SELECT para JOIN con rol (reutilizable) */\nconst USER_WITH_ROLE_COLUMNS = [\n 'usr_users.*',\n 'rol_roles.name as role_name',\n 'rol_roles.description as role_description',\n 'rol_roles.is_system as role_is_system',\n 'rol_roles.created_at as role_created_at',\n 'rol_roles.updated_at as role_updated_at'\n]\n\nexport function createUsersService(ctx: ModuleContext) {\n const { db, errors, generateId } = ctx\n\n return {\n async findAll(query: UserQuery): Promise<PaginatedResult<UserWithRole>> {\n const { page, limit, role_id } = query\n const offset = (page - 1) * limit\n\n let baseQuery = db('usr_users')\n .select(...USER_WITH_ROLE_COLUMNS)\n .leftJoin('rol_roles', 'usr_users.role_id', 'rol_roles.id')\n\n if (role_id) {\n baseQuery = baseQuery.where('usr_users.role_id', role_id)\n }\n\n // Reutilizar baseQuery para count (evita race condition)\n const [users, countResult] = await Promise.all([\n baseQuery.clone().orderBy('usr_users.created_at', 'desc').limit(limit).offset(offset),\n baseQuery.clone().count('* as count').first<{ count: string | number }>()\n ])\n\n const total = Number(countResult?.count ?? 0)\n const items = (users as UserWithRoleRow[]).map(buildUserWithRole)\n\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 async findById(id: string): Promise<UserWithoutPassword> {\n const user = await db<User>('usr_users').where({ id }).first()\n if (!user) throw new errors.NotFoundError('Usuario')\n return excludePassword(user)\n },\n\n async findByIdWithRole(id: string): Promise<UserWithRole> {\n const row = await db('usr_users')\n .select(...USER_WITH_ROLE_COLUMNS)\n .leftJoin('rol_roles', 'usr_users.role_id', 'rol_roles.id')\n .where('usr_users.id', id)\n .first<UserWithRoleRow>()\n\n if (!row) throw new errors.NotFoundError('Usuario')\n return buildUserWithRole(row)\n },\n\n async findByIdWithPassword(id: string): Promise<User> {\n const user = await db<User>('usr_users').where({ id }).first()\n if (!user) throw new errors.NotFoundError('Usuario')\n return user\n },\n\n async create(input: CreateUserInput, userId?: string): Promise<UserWithoutPassword> {\n const existing = await db<User>('usr_users').where({ email: input.email }).first()\n\n if (existing) {\n throw new errors.ConflictError('El email ya está en uso')\n }\n\n // Validate role exists\n const role = await db<Role>('rol_roles').where({ id: input.role_id }).first()\n if (!role) {\n throw new errors.NotFoundError('Rol')\n }\n\n const hashedPassword = await hashPassword(input.password)\n const id = generateId()\n\n await db('usr_users').insert({\n id,\n email: input.email,\n password: hashedPassword,\n name: input.name,\n role_id: input.role_id,\n created_by: userId ?? null\n })\n\n const user = await db<User>('usr_users').where({ id }).first()\n return excludePassword(user!)\n },\n\n async update(id: string, input: UpdateUserInput, userId?: string): Promise<UserWithoutPassword> {\n // Verificar que existe\n const currentUser = await db<User>('usr_users').where({ id }).first()\n if (!currentUser) throw new errors.NotFoundError('Usuario')\n\n // Operación atómica con transacción\n return db.transaction(async (trx) => {\n // Validar email único (si cambia)\n if (input.email && input.email !== currentUser.email) {\n const existing = await trx<User>('usr_users')\n .where({ email: input.email })\n .whereNot({ id })\n .first()\n if (existing) {\n throw new errors.ConflictError('El email ya está en uso')\n }\n }\n\n // Validar rol existe (si cambia)\n if (input.role_id) {\n const role = await trx<Role>('rol_roles').where({ id: input.role_id }).first()\n if (!role) {\n throw new errors.NotFoundError('Rol')\n }\n }\n\n const data: Record<string, unknown> = {\n ...input,\n updated_at: new Date(),\n updated_by: userId ?? null\n }\n\n if (input.password) {\n data['password'] = await hashPassword(input.password)\n }\n\n await trx('usr_users').where({ id }).update(data)\n\n const user = await trx<User>('usr_users').where({ id }).first()\n return excludePassword(user!)\n })\n },\n\n async delete(id: string): Promise<void> {\n const user = await db<User>('usr_users').where({ id }).first()\n if (!user) throw new errors.NotFoundError('Usuario')\n await db('usr_users').where({ id }).delete()\n }\n }\n}\n","import type { Request, Response, ModuleContext } from '../module.types.js'\nimport { createUsersService } from './users.service.js'\nimport type { CreateUserInput, UpdateUserInput, UserParams, UserQuery } from './users.schemas.js'\nimport type { AuthRequest } from '../module.types.js'\n\nexport function createUsersController(ctx: ModuleContext) {\n const { errors, abilities } = ctx\n const { subject, ForbiddenError: CASLForbiddenError } = abilities\n const usersService = createUsersService(ctx)\n\n return {\n async findAll(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('read', 'UsrUser')\n\n const result = await usersService.findAll(req.validated?.query as UserQuery)\n res.json({ success: true, data: result })\n },\n\n async findById(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const { id } = req.validated?.params as UserParams\n\n const user = await usersService.findById(id)\n\n // Verificar permiso con instancia del usuario\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('read', subject('UsrUser', user))\n\n res.json({ success: true, data: user })\n },\n\n async create(req: Request, res: Response) {\n const authReq = req as AuthRequest\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('create', 'UsrUser')\n\n const user = await usersService.create(req.body as CreateUserInput, authReq.user.id)\n res.status(201).json({ success: true, data: user })\n },\n\n async update(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const { id } = req.validated?.params as UserParams\n const input = req.body as UpdateUserInput\n\n const user = await usersService.findById(id)\n\n // Verificar permiso con instancia del usuario\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('update', subject('UsrUser', user))\n\n // Solo quien puede gestionar usuarios puede cambiar roles\n if (input.role_id && !authReq.ability.can('manage', 'UsrUser')) {\n throw new errors.ForbiddenError('No tienes permiso para cambiar roles')\n }\n\n const updated = await usersService.update(id, input, authReq.user.id)\n res.json({ success: true, data: updated })\n },\n\n async delete(req: Request, res: Response) {\n const authReq = req as AuthRequest\n const { id } = req.validated?.params as UserParams\n\n const user = await usersService.findById(id)\n\n // Verificar permiso con instancia del usuario\n CASLForbiddenError.from(authReq.ability).throwUnlessCan('delete', subject('UsrUser', user))\n\n // No puede eliminarse a sí mismo\n if (authReq.user.id === id) {\n throw new errors.ForbiddenError('No puedes eliminarte a ti mismo')\n }\n\n await usersService.delete(id)\n res.json({ success: true, message: 'Usuario eliminado' })\n }\n }\n}\n","import { z } from 'zod'\n\nexport const createUserSchema = z.object({\n email: z.string().email('Email inválido'),\n password: z.string().min(6, 'Password mínimo 6 caracteres'),\n name: z.string().min(1, 'Nombre requerido'),\n role_id: z.string().min(1, 'Rol requerido'),\n metadata: z.record(z.unknown()).nullable().optional()\n})\n\nexport const updateUserSchema = z.object({\n email: z.string().email('Email inválido').optional(),\n password: z.string().min(6, 'Password mínimo 6 caracteres').optional(),\n name: z.string().min(1, 'Nombre requerido').optional(),\n role_id: z.string().min(1).optional(),\n metadata: z.record(z.unknown()).nullable().optional()\n})\n\nexport const userParamsSchema = z.object({\n id: z.string().min(1)\n})\n\nexport const userQuerySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n limit: z.coerce.number().min(1).max(100).default(10),\n role_id: z.string().optional()\n})\n\nexport type CreateUserInput = z.infer<typeof createUserSchema>\nexport type UpdateUserInput = z.infer<typeof updateUserSchema>\nexport type UserParams = z.infer<typeof userParamsSchema>\nexport type UserQuery = z.infer<typeof userQuerySchema>\n","import type { ModuleContext } from '../module.types.js'\nimport { createUsersController } from './users.controller.js'\nimport { createUserSchema, updateUserSchema, userParamsSchema, userQuerySchema } from './users.schemas.js'\n\nexport function createUsersRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { validate, auth } = ctx.middleware\n const controller = createUsersController(ctx)\n\n // Todas las rutas requieren autenticación\n router.use(auth!)\n\n router.get('/', validate({ query: userQuerySchema }), controller.findAll)\n router.get('/:id', validate({ params: userParamsSchema }), controller.findById)\n router.post('/', validate({ body: createUserSchema }), controller.create)\n router.put('/:id', validate({ params: userParamsSchema, body: updateUserSchema }), controller.update)\n router.delete('/:id', validate({ params: userParamsSchema }), controller.delete)\n\n return router\n}\n","import type { ModuleManifest } from '../module.types.js'\nimport { migrate } from './users.migrate.js'\nimport { seed } from './users.seed.js'\nimport { createUsersRoutes } from './users.routes.js'\n\nexport const usersModule: ModuleManifest = {\n name: 'users',\n code: 'USR',\n label: 'Users',\n icon: 'mdi:account-group-outline',\n description: 'User accounts, authentication profiles, and role assignments',\n type: 'core',\n dependencies: ['roles'],\n migrate,\n seed,\n routes: createUsersRoutes,\n routePrefix: '/users',\n subjects: ['UsrUser'],\n entities: [\n {\n name: 'UsrUser',\n label: 'Users',\n listFields: {\n name: 'Name',\n email: 'Email',\n 'role.name': 'Role'\n },\n formFields: {\n name: { label: 'Name', type: 'text', required: true },\n email: { label: 'Email', type: 'email', required: true },\n password: { label: 'Password', type: 'password', required: true, createOnly: true },\n role_id: {\n label: 'Role',\n type: 'select',\n required: true,\n optionsEndpoint: '/roles',\n optionValue: 'id',\n optionLabel: 'name'\n }\n },\n labelField: 'name'\n }\n ]\n}\n\nexport default usersModule\n","import type { ModuleContext } from '../module.types.js'\n\nexport async function migrate(ctx: ModuleContext): Promise<void> {\n const { db, logger } = ctx\n\n // Tabla auth_refresh_tokens\n if (!(await db.schema.hasTable('auth_refresh_tokens'))) {\n await db.schema.createTable('auth_refresh_tokens', (table) => {\n table.string('id').primary()\n table.string('token').unique().notNullable()\n table.string('user_id').notNullable().references('id').inTable('usr_users').onDelete('CASCADE')\n table.timestamp('expires_at').notNullable()\n table.timestamp('created_at').defaultTo(db.fn.now())\n\n table.index('user_id')\n table.index('expires_at')\n })\n logger.info('Created table: auth_refresh_tokens')\n }\n\n // auth_refresh_tokens no necesita campos de auditoría (tokens de sistema)\n}\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 JWT_SECRET: z.string().min(32).optional(),\n JWT_ACCESS_EXPIRES: z.string().default('15m'),\n JWT_REFRESH_EXPIRES: z.string().default('7d'),\n ADMIN_EMAIL: z.string().email().optional(),\n ADMIN_PASSWORD: z.string().min(6).optional(),\n COOKIE_DOMAIN: z.string().optional(),\n // SMTP\n SMTP_HOST: z.string().default('kendra.server.arpa'),\n SMTP_PORT: z.coerce.number().default(1025),\n SMTP_SECURE: z.coerce.boolean().default(false),\n SMTP_USER: z.string().optional(),\n SMTP_PASS: z.string().optional(),\n SMTP_FROM: z.string().default('noreply@nexus.local')\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// Configuración global resuelta\nlet resolvedConfig: ResolvedConfig | null = null\n\nexport function resolveConfig(config?: NexusConfig): ResolvedConfig {\n const jwtSecret = config?.jwt?.secret ?? env.JWT_SECRET\n if (!jwtSecret || jwtSecret.length < 32) {\n throw new Error('JWT_SECRET must be at least 32 characters. Provide via config.jwt.secret or JWT_SECRET env var.')\n }\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 jwtSecret,\n jwtAccessExpires: config?.jwt?.accessExpires ?? env.JWT_ACCESS_EXPIRES,\n jwtRefreshExpires: config?.jwt?.refreshExpires ?? env.JWT_REFRESH_EXPIRES,\n adminEmail: config?.admin?.email ?? env.ADMIN_EMAIL,\n adminPassword: config?.admin?.password ?? env.ADMIN_PASSWORD,\n smtp: {\n host: config?.smtp?.host ?? env.SMTP_HOST,\n port: config?.smtp?.port ?? env.SMTP_PORT,\n secure: config?.smtp?.secure ?? env.SMTP_SECURE,\n auth: (config?.smtp?.auth ?? env.SMTP_USER)\n ? { user: config?.smtp?.auth?.user ?? env.SMTP_USER!, pass: config?.smtp?.auth?.pass ?? env.SMTP_PASS! }\n : undefined,\n from: config?.smtp?.from ?? env.SMTP_FROM\n }\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 jwt from 'jsonwebtoken'\nimport crypto from 'crypto'\nimport { getConfig } from '../../config/env.js'\nimport type { JwtPayload, TokenPair } from './auth.models.js'\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 = getConfig()\n return jwt.sign(payload, config.jwtSecret, {\n expiresIn: config.jwtAccessExpires 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(getConfig().jwtRefreshExpires)\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, getConfig().jwtSecret) as JwtPayload\n}\n","import type { ModuleContext } from '../module.types.js'\nimport { createRolesService } from '../roles/roles.service.js'\nimport { generateTokenPair, getRefreshTokenExpiration } from './jwt.utils.js'\nimport { verifyPassword, DUMMY_HASH } from './auth.utils.js'\nimport type { LoginInput } from './auth.schemas.js'\nimport type { User } from '../users/users.models.js'\nimport type { Role } from '../roles/roles.models.js'\n\nexport function createAuthService(ctx: ModuleContext) {\n const { db, errors, generateId, abilities, events } = ctx\n const { defineAbilityFor, packRules } = abilities\n const rolesService = createRolesService(ctx)\n\n async function getUserWithRole(userId: string) {\n const user = await db<User & { role_name: string; role_description: string | null; role_is_system: boolean }>('usr_users')\n .leftJoin('rol_roles', 'usr_users.role_id', 'rol_roles.id')\n .where('usr_users.id', userId)\n .select(\n 'usr_users.*',\n 'rol_roles.name as role_name',\n 'rol_roles.description as role_description',\n 'rol_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 } as Role\n }\n }\n\n return {\n async login(input: LoginInput) {\n const user = await db<User>('usr_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 events.emitEvent('auth.failed', {\n email: input.email,\n reason: user ? 'invalid_password' : 'user_not_found'\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('auth_refresh_tokens').insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration()\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 return {\n user: userWithRole,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n abilities: packRules(ability)\n }\n },\n\n async refresh(refreshToken: string) {\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('auth_refresh_tokens').where({ token: refreshToken })\n if (ctx.dbType !== '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('auth_refresh_tokens').where({ id: storedToken.id }).delete()\n throw new errors.UnauthorizedError('Refresh token expirado')\n }\n\n const user = await trx<User>('usr_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\n await trx('auth_refresh_tokens').where({ id: storedToken.id }).delete()\n await trx('auth_refresh_tokens').insert({\n id: generateId(),\n token: tokens.refreshToken,\n user_id: user.id,\n expires_at: getRefreshTokenExpiration()\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 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) {\n const deleted = await db('auth_refresh_tokens').where({ token: refreshToken }).delete()\n if (deleted > 0 && userId) {\n events.emitEvent('auth.logout', { userId })\n }\n return deleted > 0\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('auth_refresh_tokens')\n .where('expires_at', '<', new Date())\n .delete()\n return deleted\n }\n }\n}\n","import type { Request, Response, CookieOptions, ModuleContext } from '../module.types.js'\nimport { createAuthService } from './auth.service.js'\nimport type { LoginInput } from './auth.schemas.js'\nimport type { AuthRequest } from '../module.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 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 }\n }\n\n return {\n async login(req: Request, res: Response) {\n const result = await authService.login(req.body as LoginInput)\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 success: true,\n data: {\n user: result.user,\n accessToken: result.accessToken,\n abilities: result.abilities\n }\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)\n\n res.cookie('refreshToken', result.refreshToken, getCookieOptions(req))\n res.json({\n success: true,\n data: {\n accessToken: result.accessToken,\n abilities: result.abilities\n }\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)\n }\n\n res.clearCookie('refreshToken', { path: '/api/v1' })\n res.json({ success: true, message: 'Session closed' })\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({ success: true, data: result })\n }\n }\n}\n","import { z } from 'zod'\n\nexport const loginSchema = z.object({\n email: z.string().email('Email inválido'),\n password: z.string().min(1, 'Password requerido')\n})\n\nexport type LoginInput = z.infer<typeof loginSchema>\n","import type { ModuleContext } from '../module.types.js'\nimport { createAuthController } from './auth.controller.js'\nimport { loginSchema } from './auth.schemas.js'\n\nexport function createAuthRoutes(ctx: ModuleContext) {\n const router = ctx.createRouter()\n const { validate, auth } = ctx.middleware\n const controller = createAuthController(ctx)\n\n router.post('/login', validate({ body: loginSchema }), controller.login)\n router.post('/refresh', controller.refresh)\n router.post('/logout', auth!, controller.logout)\n router.get('/me', auth!, controller.me)\n\n return router\n}\n","import jwt from 'jsonwebtoken'\nimport type { Request, Response, NextFunction, RequestHandler, ModuleContext } from '../module.types.js'\nimport { createRolesService } from '../roles/roles.service.js'\nimport type { JwtPayload } from './auth.models.js'\nimport type { User } from '../users/users.models.js'\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 { config, errors, abilities } = ctx\n const { defineAbilityFor } = abilities\n const rolesService = createRolesService(ctx)\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, config.jwtSecret) as JwtPayload\n\n const user = await ctx.db<User>('usr_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)\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 { config, abilities } = ctx\n const { defineAbilityFor } = abilities\n const rolesService = createRolesService(ctx)\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, config.jwtSecret) as JwtPayload\n\n const user = await ctx.db<User>('usr_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)\n }\n } catch {\n // Token inválido, continuar sin autenticación\n }\n\n next()\n }\n}\n","import type { ModuleManifest } from '../module.types.js'\nimport { migrate } from './auth.migrate.js'\nimport { createAuthRoutes } from './auth.routes.js'\nimport { createAuthMiddleware, createOptionalAuthMiddleware } from './auth.middleware.js'\n\nexport const authModule: ModuleManifest = {\n name: 'auth',\n code: '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 dependencies: ['users'],\n migrate,\n init: (ctx) => {\n // Registrar middlewares para uso de otros módulos\n ctx.registerMiddleware('auth', createAuthMiddleware(ctx))\n ctx.registerMiddleware('optionalAuth', createOptionalAuthMiddleware(ctx))\n },\n routes: createAuthRoutes,\n routePrefix: '/auth',\n subjects: []\n}\n\nexport default authModule\n","import type { ModuleManifest } from './module.types.js'\n\n// Módulos core\nimport { systemModule } from './system/index.js'\nimport { rolesModule } from './roles/index.js'\nimport { usersModule } from './users/index.js'\nimport { authModule } from './auth/index.js'\n\n/**\n * Valida las convenciones de nombrado de un módulo\n * - code: UPPERCASE (ej: 'USR', 'PST')\n * - subjects: deben empezar con Code (ej: 'UsrUser', 'PstPost')\n */\nfunction validateModuleConventions(mod: ModuleManifest): void {\n const errors: string[] = []\n\n // Validar code es uppercase\n if (!/^[A-Z]+$/.test(mod.code)) {\n errors.push(`code debe ser UPPERCASE (recibido: '${mod.code}')`)\n }\n\n // Validar subjects empiezan con Code (primera letra mayúscula, resto minúsculas)\n const codePrefix = mod.code.charAt(0) + mod.code.slice(1).toLowerCase()\n for (const subject of mod.subjects ?? []) {\n if (!subject.startsWith(codePrefix)) {\n errors.push(`subject '${subject}' debe empezar con '${codePrefix}' (patrón: {Code}{Entity})`)\n }\n }\n\n // Validar entities.name también siguen el patrón\n for (const entity of mod.entities ?? []) {\n if (!entity.name.startsWith(codePrefix)) {\n errors.push(`entity.name '${entity.name}' debe empezar con '${codePrefix}' (patrón: {Code}{Entity})`)\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Módulo '${mod.name}' viola convenciones de nombrado:\\n - ${errors.join('\\n - ')}`)\n }\n}\n\n/** Módulos registrados */\nconst modules: ModuleManifest[] = []\n\n// Registrar módulos core con validación\n;[systemModule, rolesModule, usersModule, authModule].forEach(mod => {\n validateModuleConventions(mod)\n modules.push(mod)\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(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 modules.forEach(visit)\n return sorted\n}\n\n/**\n * Registrar módulo dinámicamente (para plugins)\n */\nexport function registerModule(mod: ModuleManifest): void {\n validateModuleConventions(mod)\n modules.push(mod)\n}\n\n/**\n * Obtener todos los módulos registrados\n */\nexport function getModules(): ModuleManifest[] {\n return [...modules]\n}\n\n/**\n * Obtener módulo por nombre\n */\nexport function getModule(name: string): ModuleManifest | undefined {\n return modules.find(m => m.name === name)\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 const subjects = new Set<string>(['all'])\n for (const mod of modules) {\n // Subjects explícitos del manifest\n for (const subject of mod.subjects ?? []) {\n subjects.add(subject)\n }\n // Subjects inferidos desde entities (elimina redundancia)\n for (const entity of mod.entities ?? []) {\n subjects.add(entity.name)\n }\n }\n return [...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 getRegisteredSubjects().includes(subject)\n}\n\n// Re-export types\nexport type { ModuleManifest } from './module.types.js'\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\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","import type { Knex } from 'knex'\nimport { nexusEvents } from '../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 knex, { type Knex } from 'knex'\nimport { env } from './env.js'\nimport { setupQueryInterceptor } from '../db/query-interceptor.js'\n\nfunction getDatabaseConfig(): Knex.Config {\n const url = env.DATABASE_URL\n\n // SQLite (default)\n if (url.startsWith('file:') || url.startsWith('sqlite:')) {\n const filename = url.replace(/^(file:|sqlite:)/, '')\n return {\n client: 'better-sqlite3',\n connection: { filename },\n useNullAsDefault: true\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 return {\n client: 'mysql2',\n connection: url,\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// Crear instancia con interceptor de eventos CRUD\nconst knexInstance = globalForKnex.db ?? knex(getDatabaseConfig())\nexport const db = globalForKnex.db ? knexInstance : setupQueryInterceptor(knexInstance)\n\nif (env.NODE_ENV !== 'production') {\n globalForKnex.db = db\n}\n\n// Helper para verificar el tipo de BD\nexport function getDatabaseType(): 'sqlite' | 'postgresql' | 'mysql' {\n const url = env.DATABASE_URL\n if (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// 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 pino from 'pino'\n\nconst isDev = process.env['NODE_ENV'] !== 'production'\n\nexport const logger = pino({\n level: process.env['LOG_LEVEL'] || 'info',\n transport: isDev\n ? { target: 'pino-pretty', options: { colorize: true } }\n : undefined\n})\n\nexport const createChildLogger = (context: string) => logger.child({ context })\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 { Knex } from 'knex'\nimport { logger } from '../shared/logger.js'\n\n/**\n * Añade campos de timestamp a una tabla durante su creación\n */\nexport function addTimestamps(table: Knex.CreateTableBuilder, db: Knex) {\n table.timestamp('created_at').defaultTo(db.fn.now())\n table.timestamp('updated_at').defaultTo(db.fn.now())\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 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","import type { Request, Response, NextFunction } from 'express'\nimport type { ZodSchema } from 'zod'\n\ninterface ValidateOptions {\n body?: ZodSchema\n query?: ZodSchema\n params?: ZodSchema\n}\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: ValidateOptions) {\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","export class AppError extends Error {\n public readonly statusCode: number\n\n constructor(message: string, statusCode: number = 400) {\n super(message)\n this.statusCode = statusCode\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","import { AbilityBuilder, createMongoAbility, type MongoAbility, type RawRuleOf } from '@casl/ability'\nimport type { User } from '../../modules/users/users.models.js'\nimport type { RolePermission } from '../../modules/roles/roles.models.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: RolePermission[]): 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 nodemailer, { type Transporter } from 'nodemailer'\nimport { readFileSync, existsSync } from 'fs'\nimport { dirname, join } from 'path'\nimport { fileURLToPath } from 'url'\nimport type { SmtpConfig } from '../../config/types.js'\nimport type { Logger } from 'pino'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst TEMPLATE_PATH = join(__dirname, 'templates', 'base.html')\nconst LOGO_PATH = join(__dirname, '../../../public/logo.png')\n\nexport interface MailAction {\n label: string\n url: string\n}\n\nexport interface SendMailOptions {\n to: string | string[]\n subject: string\n title?: string\n message?: string\n actions?: MailAction[]\n html?: string\n text?: string\n from?: string\n replyTo?: string\n logoUrl?: string\n attachments?: Array<{\n filename: string\n content: Buffer | string\n contentType?: string\n }>\n}\n\nexport interface SendMailResult {\n messageId: string\n accepted: string[]\n rejected: string[]\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\n constructor(config: SmtpConfig, logger: Logger) {\n this.defaultFrom = config.from\n this.logger = logger.child({ service: 'mail' })\n this.template = readFileSync(TEMPLATE_PATH, 'utf-8')\n\n // Cargar logo como base64 data URI\n if (existsSync(LOGO_PATH)) {\n const logoBase64 = readFileSync(LOGO_PATH).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 this.logger.warn({ error, to, subject: options.subject }, 'Failed to send email (continuing)')\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) - caso especial con contenido generado\n if (options.actions?.length) {\n const actionsHtml = options.actions.map(a =>\n `<a href=\"${a.url}\" style=\"display:inline-block; background-color:#18181b; 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 this.logger.warn({ error }, 'SMTP connection failed (emails may not work)')\n return false\n }\n }\n}\n","export { MailService, type SendMailOptions, type SendMailResult, type MailAction } from './mail.service.js'\n","import { Router } from 'express'\nimport type { RequestHandler } from 'express'\nimport type { ModuleContext, ModuleMiddlewares } from './module.types.js'\nimport { db, getDatabaseType } from '../config/database.js'\nimport { getConfig } from '../config/env.js'\nimport { logger } from '../shared/logger.js'\nimport { generateId } from '../shared/utils/id.js'\nimport { addTimestamps, addAuditFieldsIfMissing, addColumnIfMissing } from '../db/helpers.js'\nimport { validate } from '../shared/middleware/validate.middleware.js'\nimport { AppError, NotFoundError, UnauthorizedError, ForbiddenError, ConflictError } from '../shared/errors/app-error.js'\nimport { ForbiddenError as CASLForbiddenError, subject } from '@casl/ability'\nimport { defineAbilityFor, packRules } from '../shared/abilities/ability.factory.js'\nimport { nexusEvents } from '../events/emitter.js'\nimport { MailService } from '../shared/mail/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 */\nexport function createModuleContext(): ModuleContext {\n // Registry de middlewares con validate como base\n const middleware: ModuleMiddlewares = {\n validate\n }\n\n return {\n db,\n logger,\n generateId,\n dbType: getDatabaseType(),\n helpers: {\n addTimestamps,\n addAuditFieldsIfMissing,\n addColumnIfMissing\n },\n createRouter: () => Router(),\n middleware,\n registerMiddleware: (name: string, handler: RequestHandler) => {\n middleware[name] = handler\n },\n config: getConfig(),\n errors: {\n AppError,\n NotFoundError,\n UnauthorizedError,\n ForbiddenError,\n ConflictError\n },\n abilities: {\n defineAbilityFor,\n packRules,\n subject,\n ForbiddenError: CASLForbiddenError\n },\n events: nexusEvents,\n mail: new MailService(getConfig().smtp, logger)\n }\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'\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 success: false,\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 success: false,\n error: 'No tienes permiso para esta acción'\n })\n }\n\n // Custom app errors\n if (err instanceof AppError) {\n return res.status(err.statusCode).json({\n success: false,\n error: err.message\n })\n }\n\n // Unknown errors (siempre loguear)\n logger.error({ err, url: req.url, method: req.method, stack: err.stack }, 'Unhandled error')\n res.status(500).json({\n success: false,\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 { fileURLToPath } from 'url'\nimport { randomUUID } from 'crypto'\n\nimport { getModules } from './modules/index.js'\nimport { createModuleContext } from './modules/context.js'\nimport { errorMiddleware } from './shared/middleware/error.middleware.js'\nimport { env, getConfig } from './config/env.js'\nimport { logger } from './shared/logger.js'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nexport function createApp() {\n const app = express()\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 = getModules()\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 if (mod.routes) {\n const prefix = mod.routePrefix ?? `/${mod.name}`\n app.use(`/api/v1${prefix}`, mod.routes(ctx))\n }\n }\n\n // Health check\n app.get('/health', (_req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() })\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(__dirname, '../public')\n app.use('/public', express.static(publicPath))\n\n // Serve Vue UI\n const uiPath = path.join(__dirname, '../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 { logger } from '../logger.js'\n\n/**\n * Verifica si un puerto está disponible\n * @throws Error si el puerto está en uso\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 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","import http from 'node:http'\nimport { createApp } from './app.js'\nimport { destroyDb } from './config/database.js'\nimport { resolveConfig, resetConfig, env } from './config/env.js'\nimport { nexusEvents } from './events/emitter.js'\nimport { logger } from './shared/logger.js'\nimport { checkPortAvailable } from './shared/utils/net.js'\nimport { getOrderedModules } from './modules/index.js'\nimport { createModuleContext } from './modules/context.js'\nimport type { NexusConfig } from './config/types.js'\n\nlet server: http.Server | null = null\n\nexport type { NexusConfig }\n\nasync function runMigrationsAndSeeds(): Promise<void> {\n const ctx = createModuleContext()\n const modules = getOrderedModules()\n\n logger.info('Running migrations...')\n for (const mod of modules) {\n if (mod.migrate) {\n await mod.migrate(ctx)\n }\n }\n\n logger.info('Running seeds...')\n for (const mod of modules) {\n if (mod.seed) {\n await mod.seed(ctx)\n }\n }\n\n logger.info('Database ready')\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 const app = createApp()\n\n return new Promise((resolve) => {\n server = app.listen(resolved.port, resolved.host, () => {\n const baseUrl = env.BACKEND_URL || `http://localhost:${resolved.port}`\n logger.info({ port: resolved.port, mode: resolved.nodeEnv }, 'Server started')\n logger.info(`API: ${baseUrl}/api/v1`)\n logger.info(`UI: ${baseUrl}/ui`)\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 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 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.error({ 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","import 'dotenv/config'\n\n// Server lifecycle\nexport { start, stop, restart, isRunning } from './server.js'\nexport type { NexusConfig } from './server.js'\n\n// Core exports\nexport { createApp } from './app.js'\nexport { db, destroyDb, getDatabaseType } from './config/database.js'\nexport { getConfig } from './config/env.js'\nexport type { ResolvedConfig } from './config/types.js'\n\n// Module system\nexport { registerModule, getModules, getModule, getOrderedModules } from './modules/index.js'\nexport { getRegisteredSubjects, isValidSubject } from './modules/index.js'\nexport type {\n ModuleManifest,\n ModuleContext,\n ModuleEntity,\n ModuleRequirements,\n ModuleMiddlewares,\n ModuleErrors,\n ModuleAbilities,\n MigrationHelpers,\n ValidateOptions,\n PluginManifest\n} from './modules/module.types.js'\n\n// Express types (re-exported for plugins)\nexport type { Request, Response, NextFunction, RequestHandler, Router, CookieOptions } from './modules/module.types.js'\n\n// Pagination & Auth types\nexport type { PaginatedResult, PaginationParams, AuthRequest } from './types/index.js'\n\n// Entity models\nexport type { User, UserWithoutPassword, UserWithRole } from './modules/users/users.models.js'\nexport type { Role, RolePermission, RoleWithPermissions, RoleWithCounts } from './modules/roles/roles.models.js'\nexport type { RefreshToken, JwtPayload, TokenPair } from './modules/auth/auth.models.js'\n\n// CASL abilities\nexport { defineAbilityFor, packRules, unpackRules } from './shared/abilities/ability.factory.js'\nexport type { AppAbility, Actions, Subjects, SubjectStrings, SubjectRegistry } from './shared/abilities/ability.types.js'\n\n// Events\nexport { nexusEvents } from './events/emitter.js'\nexport type { NexusEvents, NexusEventName, NexusEventPayload, DbEventPayload } from './events/emitter.js'\n\n// Auto-start si se ejecuta directamente (CLI mode)\nif (import.meta.url === `file://${process.argv[1]}`) {\n const { start } = await import('./server.js')\n start()\n}\n"],"mappings":";;;;;;;;;;;AAsEA,SAAS,YAAY,KAAuD;AAC1E,SAAO;AAAA,IACL,MAAM,IAAI;AAAA,IACV,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,MAAM,IAAI;AAAA,IACV,aAAa,IAAI;AAAA,IACjB,SAAS,IAAI;AAAA,IACb,MAAM,IAAI,QAAQ;AAAA,IAClB,UAAU,IAAI,YAAY;AAAA,IAC1B,cAAc,IAAI,gBAAgB,CAAC;AAAA,IACnC,aAAa,IAAI,eAAe,IAAI,IAAI,IAAI;AAAA,IAC5C,UAAU,IAAI,YAAY,CAAC;AAAA,IAC3B,UAAU,IAAI,YAAY,CAAC;AAAA,IAC3B,WAAW,CAAC,CAAC,IAAI;AAAA,IACjB,YAAY,CAAC,CAAC,IAAI;AAAA,IAClB,SAAS,CAAC,CAAC,IAAI;AAAA,IACf,SAAS,CAAC,CAAC,IAAI;AAAA,EACjB;AACF;AAEO,SAAS,uBAAuB,KAAoB;AACzD,QAAM,EAAE,OAAO,IAAI;AAEnB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKL,YAAY,MAAe,KAAe;AACxC,YAAMA,WAAU,WAAW,EAAE,IAAI,WAAW;AAC5C,UAAI,KAAK,EAAE,MAAMA,UAAS,OAAOA,SAAQ,OAAO,CAAC;AAAA,IACnD;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,UAAU,KAAgC,KAAe;AACvD,YAAM,EAAE,KAAK,IAAI,IAAI;AACrB,YAAM,MAAM,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,YAAY,CAAC;AAElE,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,OAAO,cAAc,yBAAsB;AAAA,MACvD;AAEA,UAAI,KAAK,EAAE,MAAM,YAAY,GAAG,EAAE,CAAC;AAAA,IACrC;AAAA,EACF;AACF;AAvHA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACEO,SAAS,mBAAmB,KAAoB;AACrD,QAAM,SAAS,IAAI,aAAa;AAChC,QAAM,aAAa,uBAAuB,GAAG;AAG7C,SAAO,IAAI,YAAY,WAAW,WAAW;AAC7C,SAAO,IAAI,kBAAkB,WAAW,SAAS;AAEjD,SAAO;AACT;AAZA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACDA,IAGa;AAHb;AAAA;AAAA;AACA;AAEO,IAAM,eAA+B;AAAA,MAC1C,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,cAAc,CAAC;AAAA,MACf,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,UAAU,CAAC;AAAA,IACb;AAAA;AAAA;;;ACZA,eAAsB,QAAQ,KAAmC;AAC/D,QAAM,EAAE,IAAAC,KAAI,QAAAC,SAAQ,QAAQ,IAAI;AAChC,QAAM,EAAE,eAAAC,gBAAe,yBAAAC,yBAAwB,IAAI;AAGnD,MAAI,CAAE,MAAMH,IAAG,OAAO,SAAS,WAAW,GAAI;AAC5C,UAAMA,IAAG,OAAO,YAAY,aAAa,CAAC,UAAU;AAClD,YAAM,OAAO,IAAI,EAAE,QAAQ;AAC3B,YAAM,OAAO,QAAQ,EAAE,EAAE,OAAO,EAAE,YAAY;AAC9C,YAAM,OAAO,eAAe,GAAG;AAC/B,YAAM,QAAQ,WAAW,EAAE,UAAU,KAAK;AAC1C,MAAAE,eAAc,OAAOF,GAAE;AAAA,IACzB,CAAC;AACD,IAAAC,QAAO,KAAK,0BAA0B;AAAA,EACxC;AAGA,MAAI,CAAE,MAAMD,IAAG,OAAO,SAAS,sBAAsB,GAAI;AACvD,UAAMA,IAAG,OAAO,YAAY,wBAAwB,CAAC,UAAU;AAC7D,YAAM,OAAO,IAAI,EAAE,QAAQ;AAC3B,YAAM,OAAO,SAAS,EAAE,YAAY,EAAE,WAAW,IAAI,EAAE,QAAQ,WAAW,EAAE,SAAS,SAAS;AAC9F,YAAM,OAAO,UAAU,EAAE,EAAE,YAAY;AACvC,YAAM,OAAO,WAAW,EAAE,EAAE,YAAY;AACxC,YAAM,KAAK,YAAY;AACvB,YAAM,KAAK,QAAQ;AACnB,YAAM,QAAQ,UAAU,EAAE,UAAU,KAAK;AACzC,MAAAE,eAAc,OAAOF,GAAE;AACvB,YAAM,OAAO,CAAC,WAAW,UAAU,SAAS,CAAC;AAAA,IAC/C,CAAC;AACD,IAAAC,QAAO,KAAK,qCAAqC;AAAA,EACnD;AAGA,QAAME,yBAAwBH,KAAI,WAAW;AAC7C,QAAMG,yBAAwBH,KAAI,sBAAsB;AAC1D;AArCA;AAAA;AAAA;AAAA;AAAA;;;ACKA,eAAsB,KAAK,KAAmC;AAC5D,QAAM,EAAE,IAAAI,KAAI,QAAAC,SAAQ,YAAAC,YAAW,IAAI;AAGnC,QAAM,gBAAgB,MAAMF,IAAG,WAAW,EAAE,MAAM,YAAY,EAAE,MAAkC;AAClG,MAAI,OAAO,eAAe,SAAS,CAAC,IAAI,EAAG;AAG3C,QAAM,cAAc;AAAA,IAClB,EAAE,IAAIE,YAAW,GAAG,MAAM,SAAS,aAAa,mCAAmC,WAAW,KAAK;AAAA,IACnG,EAAE,IAAIA,YAAW,GAAG,MAAM,UAAU,aAAa,yCAAyC,WAAW,KAAK;AAAA,IAC1G,EAAE,IAAIA,YAAW,GAAG,MAAM,UAAU,aAAa,gBAAgB,WAAW,KAAK;AAAA,EACnF;AACA,QAAMF,IAAG,WAAW,EAAE,OAAO,WAAW;AACxC,EAAAC,QAAO,KAAK,8CAA8C;AAG1D,QAAM,QAAQ,MAAMD,IAAG,WAAW,EAAE,OAAO,MAAM,MAAM;AACvD,QAAM,UAAU,OAAO,YAAY,MAAM,IAAI,CAAC,MAAoC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;AAEjG,QAAM,cAAc;AAAA;AAAA,IAElB,EAAE,IAAIE,YAAW,GAAG,SAAS,QAAQ,OAAO,GAAG,QAAQ,UAAU,SAAS,OAAO,YAAY,MAAM,UAAU,MAAM;AAAA;AAAA,IAEnH,EAAE,IAAIA,YAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,QAAQ,QAAQ,SAAS,WAAW,YAAY,MAAM,UAAU,MAAM;AAAA,IACtH,EAAE,IAAIA,YAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,QAAQ,UAAU,SAAS,WAAW,YAAY,MAAM,UAAU,MAAM;AAAA,IACxH,EAAE,IAAIA,YAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,QAAQ,QAAQ,SAAS,WAAW,YAAY,MAAM,UAAU,MAAM;AAAA,IACtH,EAAE,IAAIA,YAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,QAAQ,UAAU,SAAS,WAAW,YAAY,KAAK,UAAU,EAAE,WAAW,aAAa,CAAC,GAAG,UAAU,MAAM;AAAA,IAC/J,EAAE,IAAIA,YAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,QAAQ,UAAU,SAAS,WAAW,YAAY,KAAK,UAAU,EAAE,WAAW,aAAa,CAAC,GAAG,UAAU,MAAM;AAAA;AAAA,IAE/J,EAAE,IAAIA,YAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,QAAQ,QAAQ,SAAS,WAAW,YAAY,KAAK,UAAU,EAAE,QAAQ,YAAY,CAAC,GAAG,UAAU,MAAM;AAAA,IACzJ,EAAE,IAAIA,YAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,QAAQ,QAAQ,SAAS,WAAW,YAAY,KAAK,UAAU,EAAE,IAAI,aAAa,CAAC,GAAG,UAAU,MAAM;AAAA,EACxJ;AACA,QAAMF,IAAG,sBAAsB,EAAE,OAAO,WAAW;AACnD,EAAAC,QAAO,KAAK,uCAAuC;AACrD;AAxCA;AAAA;AAAA;AAAA;AAAA;;;ACKO,SAAS,mBAAmB,KAAoB;AACrD,QAAM,EAAE,IAAAE,KAAI,QAAQ,YAAAC,YAAW,IAAI;AAEnC,SAAO;AAAA,IACL,MAAM,mBAAmB,OAAyF;AAChH,YAAM,EAAE,MAAM,MAAM,IAAI;AACxB,YAAM,UAAU,OAAO,KAAK;AAE5B,YAAM,YAAYD,IAAG,sBAAsB,EACxC;AAAA,QACC;AAAA,QACA;AAAA,MACF,EACC,SAAS,aAAa,gCAAgC,cAAc;AAEvE,YAAM,CAAC,aAAa,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,QACnD,UAAU,MAAM,EAAE,QAAQ,kBAAkB,KAAK,EAAE,QAAQ,WAAW,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,MAAM;AAAA,QACvGA,IAAG,sBAAsB,EAAE,MAAM,YAAY,EAAE,MAAkC;AAAA,MACnF,CAAC;AAED,YAAM,QAAQ,OAAO,aAAa,SAAS,CAAC;AAE5C,YAAM,QAAQ,YAAY,IAAI,CAAC,OAAO;AAAA,QACpC,GAAG;AAAA,QACH,YAAY,OAAO,EAAE,eAAe,WAAW,KAAK,MAAM,EAAE,UAAU,IAAI,EAAE;AAAA,QAC5E,QAAQ,OAAO,EAAE,WAAW,WAAW,KAAK,MAAM,EAAE,MAAM,IAAI,EAAE;AAAA,QAChE,MAAM,EAAE,MAAM,EAAE,UAAU;AAAA,MAC5B,EAAE;AAEF,YAAM,aAAa,KAAK,KAAK,QAAQ,KAAK;AAC1C,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ,OAA4D;AACxE,YAAM,EAAE,MAAM,MAAM,IAAI;AACxB,YAAM,UAAU,OAAO,KAAK;AAG5B,YAAM,2BAA2BA,IAAG,sBAAsB,EACvD,MAAM,GAAG,EACT,SAAS,6CAA6C,EACtD,GAAG,mBAAmB;AAEzB,YAAM,qBAAqBA,IAAG,WAAW,EACtC,MAAM,GAAG,EACT,SAAS,kCAAkC,EAC3C,GAAG,aAAa;AAEnB,YAAM,YAAYA,IAAG,WAAW,EAC7B,OAAO,eAAe,0BAA0B,kBAAkB;AAErE,YAAM,CAAC,OAAO,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC7C,UAAU,MAAM,EAAE,QAAQ,QAAQ,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,MAAM;AAAA,QACnE,UAAU,MAAM,EAAE,MAAM,YAAY,EAAE,MAAkC;AAAA,MAC1E,CAAC;AAED,YAAM,QAAQ,OAAO,aAAa,SAAS,CAAC;AAE5C,YAAM,QAAQ,MAAM,IAAI,CAAC,UAAU;AAAA,QACjC,GAAG;AAAA,QACH,mBAAmB,OAAO,KAAK,qBAAqB,CAAC;AAAA,QACrD,aAAa,OAAO,KAAK,eAAe,CAAC;AAAA,MAC3C,EAAE;AAEF,YAAM,aAAa,KAAK,KAAK,QAAQ,KAAK;AAC1C,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,IAA0C;AACvD,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC7D,UAAI,CAAC,KAAM,OAAM,IAAI,OAAO,cAAc,KAAK;AAE/C,YAAM,cAAc,MAAMA,IAAmB,sBAAsB,EAChE,MAAM,EAAE,SAAS,GAAG,CAAC,EACrB,QAAQ,WAAW,KAAK,EACxB,QAAQ,UAAU,KAAK;AAG1B,YAAM,oBAAoB,YAAY,IAAI,CAAC,OAAO;AAAA,QAChD,GAAG;AAAA,QACH,YAAY,OAAO,EAAE,eAAe,WAAW,KAAK,MAAM,EAAE,UAAU,IAAI,EAAE;AAAA,QAC5E,QAAQ,OAAO,EAAE,WAAW,WAAW,KAAK,MAAM,EAAE,MAAM,IAAI,EAAE;AAAA,MAClE,EAAE;AAEF,aAAO,EAAE,GAAG,MAAM,aAAa,kBAAkB;AAAA,IACnD;AAAA,IAEA,MAAM,WAAW,MAAyC;AACxD,aAAOA,IAAS,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;AAAA,IACrD;AAAA,IAEA,MAAM,uBAAuB,QAA2C;AACtE,YAAM,cAAc,MAAMA,IAAmB,sBAAsB,EAAE,MAAM,EAAE,SAAS,OAAO,CAAC;AAE9F,aAAO,YAAY,IAAI,CAAC,OAAO;AAAA,QAC7B,GAAG;AAAA,QACH,YAAY,OAAO,EAAE,eAAe,WAAW,KAAK,MAAM,EAAE,UAAU,IAAI,EAAE;AAAA,QAC5E,QAAQ,OAAO,EAAE,WAAW,WAAW,KAAK,MAAM,EAAE,MAAM,IAAI,EAAE;AAAA,MAClE,EAAE;AAAA,IACJ;AAAA,IAEA,MAAM,OAAO,OAAwB,QAAgC;AAEnE,aAAOA,IAAG,YAAY,OAAO,QAAQ;AACnC,cAAM,WAAW,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,MAAM,MAAM,KAAK,CAAC,EAAE,MAAM;AAChF,YAAI,UAAU;AACZ,gBAAM,IAAI,OAAO,cAAc,iCAAiC;AAAA,QAClE;AAEA,cAAM,KAAKC,YAAW;AAEtB,cAAM,IAAI,WAAW,EAAE,OAAO;AAAA,UAC5B;AAAA,UACA,MAAM,MAAM;AAAA,UACZ,aAAa,MAAM,eAAe;AAAA,UAClC,WAAW;AAAA,UACX,YAAY,UAAU;AAAA,QACxB,CAAC;AAED,cAAM,OAAO,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC9D,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,OAAO,IAAY,OAAwB,QAAgC;AAE/E,aAAOD,IAAG,YAAY,OAAO,QAAQ;AACnC,cAAM,OAAO,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC9D,YAAI,CAAC,KAAM,OAAM,IAAI,OAAO,cAAc,KAAK;AAE/C,YAAI,KAAK,WAAW;AAClB,gBAAM,IAAI,OAAO,eAAe,0CAA0C;AAAA,QAC5E;AAEA,YAAI,MAAM,QAAQ,MAAM,SAAS,KAAK,MAAM;AAC1C,gBAAM,WAAW,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,MAAM,MAAM,KAAK,CAAC,EAAE,MAAM;AAChF,cAAI,UAAU;AACZ,kBAAM,IAAI,OAAO,cAAc,iCAAiC;AAAA,UAClE;AAAA,QACF;AAEA,cAAM,IAAI,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;AAAA,UAC1C,GAAG;AAAA,UACH,YAAY,oBAAI,KAAK;AAAA,UACrB,YAAY,UAAU;AAAA,QACxB,CAAC;AAED,cAAM,UAAU,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AACjE,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,OAAO,IAA2B;AACtC,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC7D,UAAI,CAAC,KAAM,OAAM,IAAI,OAAO,cAAc,KAAK;AAE/C,UAAI,KAAK,WAAW;AAClB,cAAM,IAAI,OAAO,eAAe,yCAAyC;AAAA,MAC3E;AAGA,YAAM,aAAa,MAAMA,IAAG,WAAW,EACpC,MAAM,EAAE,SAAS,GAAG,CAAC,EACrB,MAAM,YAAY,EAClB,MAAkC;AAErC,UAAI,OAAO,YAAY,SAAS,CAAC,IAAI,GAAG;AACtC,cAAM,IAAI,OAAO,cAAc,oDAAoD;AAAA,MACrF;AAEA,YAAMA,IAAG,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;AAAA,IAC7C;AAAA,IAEA,MAAM,kBAAkB,IAAY,aAAgC,QAA+C;AAEjH,aAAOA,IAAG,YAAY,OAAO,QAAQ;AACnC,cAAM,OAAO,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC9D,YAAI,CAAC,KAAM,OAAM,IAAI,OAAO,cAAc,KAAK;AAE/C,YAAI,KAAK,aAAa,KAAK,SAAS,SAAS;AAC3C,gBAAM,IAAI,OAAO,eAAe,mDAAmD;AAAA,QACrF;AAGA,cAAM,IAAI,sBAAsB,EAAE,MAAM,EAAE,SAAS,GAAG,CAAC,EAAE,OAAO;AAGhE,YAAI,YAAY,SAAS,GAAG;AAC1B,gBAAM,kBAAkB,YAAY,IAAI,CAAC,OAAO;AAAA,YAC9C,IAAIC,YAAW;AAAA,YACf,SAAS;AAAA,YACT,QAAQ,EAAE;AAAA,YACV,SAAS,EAAE;AAAA,YACX,YAAY,EAAE,aAAa,KAAK,UAAU,EAAE,UAAU,IAAI;AAAA,YAC1D,QAAQ,EAAE,SAAS,KAAK,UAAU,EAAE,MAAM,IAAI;AAAA,YAC9C,UAAU,EAAE;AAAA,YACZ,YAAY,UAAU;AAAA,UACxB,EAAE;AAEF,gBAAM,IAAI,sBAAsB,EAAE,OAAO,eAAe;AAAA,QAC1D;AAGA,cAAM,IAAI,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;AAAA,UAC1C,YAAY,oBAAI,KAAK;AAAA,UACrB,YAAY,UAAU;AAAA,QACxB,CAAC;AAGD,cAAM,cAAc,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AACrE,cAAM,qBAAqB,MAAM,IAAoB,sBAAsB,EACxE,MAAM,EAAE,SAAS,GAAG,CAAC,EACrB,QAAQ,WAAW,KAAK,EACxB,QAAQ,UAAU,KAAK;AAE1B,cAAM,oBAAoB,mBAAmB,IAAI,CAAC,OAAO;AAAA,UACvD,GAAG;AAAA,UACH,YAAY,OAAO,EAAE,eAAe,WAAW,KAAK,MAAM,EAAE,UAAU,IAAI,EAAE;AAAA,UAC5E,QAAQ,OAAO,EAAE,WAAW,WAAW,KAAK,MAAM,EAAE,MAAM,IAAI,EAAE;AAAA,QAClE,EAAE;AAEF,eAAO,EAAE,GAAG,aAAc,aAAa,kBAAkB;AAAA,MAC3D,CAAC;AAAA,IACH;AAAA,EACF;AACF;AApPA;AAAA;AAAA;AAAA;AAAA;;;ACKO,SAAS,sBAAsB,KAAoB;AACxD,QAAM,EAAE,gBAAgBC,oBAAmB,IAAI,IAAI;AACnD,QAAM,eAAe,mBAAmB,GAAG;AAE3C,SAAO;AAAA,IACL,MAAM,mBAAmB,KAAc,KAAe;AACpD,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,QAAQ,mBAAmB;AAEnF,YAAM,SAAS,MAAM,aAAa,mBAAmB,IAAI,WAAW,KAAkB;AACtF,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,CAAC;AAAA,IAC1C;AAAA,IAEA,MAAM,QAAQ,KAAc,KAAe;AACzC,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,QAAQ,SAAS;AAEzE,YAAM,SAAS,MAAM,aAAa,QAAQ,IAAI,WAAW,KAAkB;AAC3E,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,CAAC;AAAA,IAC1C;AAAA,IAEA,MAAM,SAAS,KAAc,KAAe;AAC1C,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,QAAQ,SAAS;AAEzE,YAAM,EAAE,GAAG,IAAI,IAAI,WAAW;AAC9B,YAAM,OAAO,MAAM,aAAa,SAAS,EAAE;AAC3C,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,KAAK,CAAC;AAAA,IACxC;AAAA,IAEA,MAAM,OAAO,KAAc,KAAe;AACxC,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,UAAU,SAAS;AAE3E,YAAM,OAAO,MAAM,aAAa,OAAO,IAAI,MAAyB,QAAQ,KAAK,EAAE;AACnF,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,MAAM,MAAM,KAAK,CAAC;AAAA,IACpD;AAAA,IAEA,MAAM,OAAO,KAAc,KAAe;AACxC,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,UAAU,SAAS;AAE3E,YAAM,EAAE,GAAG,IAAI,IAAI,WAAW;AAC9B,YAAM,OAAO,MAAM,aAAa,OAAO,IAAI,IAAI,MAAyB,QAAQ,KAAK,EAAE;AACvF,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,KAAK,CAAC;AAAA,IACxC;AAAA,IAEA,MAAM,OAAO,KAAc,KAAe;AACxC,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,UAAU,SAAS;AAE3E,YAAM,EAAE,GAAG,IAAI,IAAI,WAAW;AAC9B,YAAM,aAAa,OAAO,EAAE;AAC5B,UAAI,KAAK,EAAE,SAAS,MAAM,SAAS,gBAAgB,CAAC;AAAA,IACtD;AAAA,IAEA,MAAM,kBAAkB,KAAc,KAAe;AACnD,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,UAAU,SAAS;AAE3E,YAAM,EAAE,GAAG,IAAI,IAAI,WAAW;AAC9B,YAAM,EAAE,YAAY,IAAI,IAAI;AAC5B,YAAM,OAAO,MAAM,aAAa,kBAAkB,IAAI,aAAa,QAAQ,KAAK,EAAE;AAClF,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,KAAK,CAAC;AAAA,IACxC;AAAA,EACF;AACF;AAvEA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACDA,SAAS,SAAS;AAAlB,IAEa,kBAQA,kBASA,kBAQA,yBAIA,kBAIA;AAnCb;AAAA;AAAA;AAEO,IAAM,mBAAmB,EAAE,OAAO;AAAA,MACvC,MAAM,EAAE,OAAO,EACZ,IAAI,GAAG,+BAA4B,EACnC,IAAI,IAAI,gCAA6B,EACrC,MAAM,aAAa,iCAA8B;AAAA,MACpD,aAAa,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,IAC5C,CAAC;AAEM,IAAM,mBAAmB,EAAE,OAAO;AAAA,MACvC,MAAM,EAAE,OAAO,EACZ,IAAI,GAAG,+BAA4B,EACnC,IAAI,IAAI,gCAA6B,EACrC,MAAM,aAAa,iCAA8B,EACjD,SAAS;AAAA,MACZ,aAAa,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,IAC5C,CAAC;AAEM,IAAM,mBAAmB,EAAE,OAAO;AAAA,MACvC,QAAQ,EAAE,KAAK,CAAC,UAAU,UAAU,QAAQ,UAAU,QAAQ,CAAC;AAAA,MAC/D,SAAS,EAAE,KAAK,CAAC,WAAW,WAAW,WAAW,qBAAqB,KAAK,CAAC;AAAA,MAC7E,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,MAC3C,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,MACrC,UAAU,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,IACrC,CAAC;AAEM,IAAM,0BAA0B,EAAE,OAAO;AAAA,MAC9C,aAAa,EAAE,MAAM,gBAAgB;AAAA,IACvC,CAAC;AAEM,IAAM,mBAAmB,EAAE,OAAO;AAAA,MACvC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACtB,CAAC;AAEM,IAAM,kBAAkB,EAAE,OAAO;AAAA,MACtC,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,MACxC,OAAO,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,IACrD,CAAC;AAAA;AAAA;;;AC5BM,SAAS,kBAAkB,KAAoB;AACpD,QAAM,SAAS,IAAI,aAAa;AAChC,QAAM,EAAE,UAAAC,WAAU,KAAK,IAAI,IAAI;AAC/B,QAAM,aAAa,sBAAsB,GAAG;AAG5C,SAAO,IAAI,IAAK;AAEhB,SAAO,IAAI,KAAKA,UAAS,EAAE,OAAO,gBAAgB,CAAC,GAAG,WAAW,OAAO;AACxE,SAAO,IAAI,gBAAgBA,UAAS,EAAE,OAAO,gBAAgB,CAAC,GAAG,WAAW,kBAAkB;AAC9F,SAAO,IAAI,QAAQA,UAAS,EAAE,QAAQ,iBAAiB,CAAC,GAAG,WAAW,QAAQ;AAC9E,SAAO,KAAK,KAAKA,UAAS,EAAE,MAAM,iBAAiB,CAAC,GAAG,WAAW,MAAM;AACxE,SAAO,IAAI,QAAQA,UAAS,EAAE,QAAQ,kBAAkB,MAAM,iBAAiB,CAAC,GAAG,WAAW,MAAM;AACpG,SAAO,OAAO,QAAQA,UAAS,EAAE,QAAQ,iBAAiB,CAAC,GAAG,WAAW,MAAM;AAC/E,SAAO,IAAI,oBAAoBA,UAAS,EAAE,QAAQ,kBAAkB,MAAM,wBAAwB,CAAC,GAAG,WAAW,iBAAiB;AAElI,SAAO;AACT;AA3BA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;;;ACFA,IAKa;AALb;AAAA;AAAA;AACA;AACA;AACA;AAEO,IAAM,cAA8B;AAAA,MACzC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aACE;AAAA,MACF,MAAM;AAAA,MACN,cAAc,CAAC;AAAA,MACf;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,UAAU,CAAC,WAAW,mBAAmB;AAAA,MACzC,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,UAAU;AAAA,UACV,YAAY;AAAA,YACV,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,YAAY;AAAA,YACV,MAAM;AAAA,cACJ,OAAO;AAAA,cACP,MAAM;AAAA,cACN,UAAU;AAAA,cACV,aAAa;AAAA,cACb,YAAY;AAAA,gBACV,WAAW;AAAA,gBACX,WAAW;AAAA,gBACX,SAAS;AAAA,gBACT,cAAc;AAAA,cAChB;AAAA,YACF;AAAA,YACA,aAAa;AAAA,cACX,OAAO;AAAA,cACP,MAAM;AAAA,cACN,aAAa;AAAA,cACb,YAAY;AAAA,gBACV,WAAW;AAAA,cACb;AAAA,YACF;AAAA,UACF;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,aAAa;AAAA,UACb,YAAY;AAAA,YACV,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,aAAa;AAAA,UACf;AAAA,UACA,YAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;AC9DA,eAAsBC,SAAQ,KAAmC;AAC/D,QAAM,EAAE,IAAAC,KAAI,QAAAC,SAAQ,QAAQ,IAAI;AAChC,QAAM,EAAE,eAAAC,gBAAe,yBAAAC,0BAAyB,oBAAAC,oBAAmB,IAAI;AAGvE,MAAI,CAAE,MAAMJ,IAAG,OAAO,SAAS,WAAW,GAAI;AAC5C,UAAMA,IAAG,OAAO,YAAY,aAAa,CAAC,UAAU;AAClD,YAAM,OAAO,IAAI,EAAE,QAAQ;AAC3B,YAAM,OAAO,OAAO,EAAE,OAAO,EAAE,YAAY;AAC3C,YAAM,OAAO,UAAU,EAAE,YAAY;AACrC,YAAM,OAAO,MAAM,EAAE,YAAY;AACjC,YAAM,OAAO,SAAS,EAAE,YAAY,EAAE,WAAW,IAAI,EAAE,QAAQ,WAAW;AAC1E,MAAAE,eAAc,OAAOF,GAAE;AAAA,IACzB,CAAC;AACD,IAAAC,QAAO,KAAK,0BAA0B;AAAA,EACxC;AAGA,QAAM,wBAAwB,GAAG;AAGjC,QAAMG,oBAAmBJ,KAAI,aAAa,YAAY,CAAC,UAAU;AAC/D,UAAM,KAAK,UAAU,EAAE,SAAS;AAAA,EAClC,CAAC;AAGD,QAAMG,yBAAwBH,KAAI,WAAW;AAC/C;AAMA,eAAe,wBAAwB,KAAmC;AACxE,QAAM,EAAE,IAAAA,KAAI,QAAAC,SAAQ,OAAO,IAAI;AAE/B,QAAM,gBAAgB,MAAMD,IAAG,OAAO,UAAU,aAAa,MAAM;AACnE,QAAM,kBAAkB,MAAMA,IAAG,OAAO,UAAU,aAAa,SAAS;AAExE,MAAI,CAAC,iBAAiB,gBAAiB;AAEvC,EAAAC,QAAO,KAAK,kDAAkD;AAG9D,QAAM,QAAQ,MAAMD,IAAG,WAAW,EAAE,OAAO,MAAM,MAAM;AACvD,QAAM,UAAU,OAAO,YAAY,MAAM,IAAI,CAAC,MAAoC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;AAGjG,QAAMA,IAAG,OAAO,WAAW,aAAa,CAAC,UAAU;AACjD,UAAM,OAAO,SAAS,EAAE,WAAW,IAAI,EAAE,QAAQ,WAAW;AAAA,EAC9D,CAAC;AAGD,aAAW,CAAC,UAAU,MAAM,KAAK,OAAO,QAAQ,OAAO,GAAG;AACxD,UAAMA,IAAG,WAAW,EAAE,MAAM,QAAQ,QAAQ,EAAE,OAAO,EAAE,SAAS,OAAO,CAAC;AAAA,EAC1E;AAGA,MAAI,WAAW,UAAU;AAEvB,UAAMA,IAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAUZ;AACD,UAAMA,IAAG,IAAI;AAAA;AAAA;AAAA,KAGZ;AACD,UAAMA,IAAG,IAAI,sBAAsB;AACnC,UAAMA,IAAG,IAAI,+CAA+C;AAAA,EAC9D,OAAO;AACL,UAAMA,IAAG,OAAO,WAAW,aAAa,CAAC,UAAU;AACjD,YAAM,WAAW,MAAM;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,EAAAC,QAAO,KAAK,0DAA0D;AACxE;AAtFA;AAAA;AAAA;AAAA;AAAA;;;ACAA,OAAO,YAAY;AAaZ,SAAS,aAAa,UAAmC;AAC9D,SAAO,OAAO,KAAK,UAAU,WAAW;AAC1C;AAKO,SAAS,eAAe,UAAkB,MAAgC;AAC/E,SAAO,OAAO,QAAQ,UAAU,IAAI;AACtC;AAtBA,IAEM,aAMO;AARb;AAAA;AAAA;AAEA,IAAM,cAAc;AAMb,IAAM,aAAa;AAAA;AAAA;;;ACF1B,eAAsBI,MAAK,KAAmC;AAC5D,QAAM,EAAE,IAAAC,KAAI,QAAAC,SAAQ,YAAAC,YAAW,IAAI;AAEnC,QAAM,QAAQ,QAAQ,IAAI,aAAa,KAAK;AAC5C,QAAM,WAAW,QAAQ,IAAI,gBAAgB,KAAK;AAElD,QAAM,WAAW,MAAMF,IAAG,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;AAC9D,MAAI,UAAU;AACZ,IAAAC,QAAO,KAAK,EAAE,MAAM,GAAG,2BAA2B;AAClD;AAAA,EACF;AAGA,QAAM,YAAY,MAAMD,IAAG,WAAW,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC,EAAE,MAAM;AACvE,MAAI,CAAC,WAAW;AACd,IAAAC,QAAO,MAAM,6CAA6C;AAC1D,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AAEA,QAAM,iBAAiB,MAAM,aAAa,QAAQ;AAElD,QAAMD,IAAG,WAAW,EAAE,OAAO;AAAA,IAC3B,IAAIE,YAAW;AAAA,IACf;AAAA,IACA,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,UAAU;AAAA,EACrB,CAAC;AAED,EAAAD,QAAO,KAAK,EAAE,MAAM,GAAG,oBAAoB;AAC7C;AApCA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACMA,SAAS,gBAAgB,MAAiC;AACxD,QAAM,EAAE,UAAU,GAAG,GAAG,KAAK,IAAI;AACjC,SAAO;AACT;AAYA,SAAS,kBAAkB,KAAoC;AAC7D,QAAM;AAAA,IACJ,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM,KAAK,UACN;AAAA,MACC,IAAI,KAAK;AAAA,MACT,MAAM;AAAA,MACN,aAAa;AAAA,MACb,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,YAAY;AAAA,IACd,IACA;AAAA,EACN;AACF;AAYO,SAAS,mBAAmB,KAAoB;AACrD,QAAM,EAAE,IAAAE,KAAI,QAAQ,YAAAC,YAAW,IAAI;AAEnC,SAAO;AAAA,IACL,MAAM,QAAQ,OAA0D;AACtE,YAAM,EAAE,MAAM,OAAO,QAAQ,IAAI;AACjC,YAAM,UAAU,OAAO,KAAK;AAE5B,UAAI,YAAYD,IAAG,WAAW,EAC3B,OAAO,GAAG,sBAAsB,EAChC,SAAS,aAAa,qBAAqB,cAAc;AAE5D,UAAI,SAAS;AACX,oBAAY,UAAU,MAAM,qBAAqB,OAAO;AAAA,MAC1D;AAGA,YAAM,CAAC,OAAO,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC7C,UAAU,MAAM,EAAE,QAAQ,wBAAwB,MAAM,EAAE,MAAM,KAAK,EAAE,OAAO,MAAM;AAAA,QACpF,UAAU,MAAM,EAAE,MAAM,YAAY,EAAE,MAAkC;AAAA,MAC1E,CAAC;AAED,YAAM,QAAQ,OAAO,aAAa,SAAS,CAAC;AAC5C,YAAM,QAAS,MAA4B,IAAI,iBAAiB;AAEhE,YAAM,aAAa,KAAK,KAAK,QAAQ,KAAK;AAC1C,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,IAA0C;AACvD,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC7D,UAAI,CAAC,KAAM,OAAM,IAAI,OAAO,cAAc,SAAS;AACnD,aAAO,gBAAgB,IAAI;AAAA,IAC7B;AAAA,IAEA,MAAM,iBAAiB,IAAmC;AACxD,YAAM,MAAM,MAAMA,IAAG,WAAW,EAC7B,OAAO,GAAG,sBAAsB,EAChC,SAAS,aAAa,qBAAqB,cAAc,EACzD,MAAM,gBAAgB,EAAE,EACxB,MAAuB;AAE1B,UAAI,CAAC,IAAK,OAAM,IAAI,OAAO,cAAc,SAAS;AAClD,aAAO,kBAAkB,GAAG;AAAA,IAC9B;AAAA,IAEA,MAAM,qBAAqB,IAA2B;AACpD,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC7D,UAAI,CAAC,KAAM,OAAM,IAAI,OAAO,cAAc,SAAS;AACnD,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,OAAwB,QAA+C;AAClF,YAAM,WAAW,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,OAAO,MAAM,MAAM,CAAC,EAAE,MAAM;AAEjF,UAAI,UAAU;AACZ,cAAM,IAAI,OAAO,cAAc,4BAAyB;AAAA,MAC1D;AAGA,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,IAAI,MAAM,QAAQ,CAAC,EAAE,MAAM;AAC5E,UAAI,CAAC,MAAM;AACT,cAAM,IAAI,OAAO,cAAc,KAAK;AAAA,MACtC;AAEA,YAAM,iBAAiB,MAAM,aAAa,MAAM,QAAQ;AACxD,YAAM,KAAKC,YAAW;AAEtB,YAAMD,IAAG,WAAW,EAAE,OAAO;AAAA,QAC3B;AAAA,QACA,OAAO,MAAM;AAAA,QACb,UAAU;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,YAAY,UAAU;AAAA,MACxB,CAAC;AAED,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC7D,aAAO,gBAAgB,IAAK;AAAA,IAC9B;AAAA,IAEA,MAAM,OAAO,IAAY,OAAwB,QAA+C;AAE9F,YAAM,cAAc,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AACpE,UAAI,CAAC,YAAa,OAAM,IAAI,OAAO,cAAc,SAAS;AAG1D,aAAOA,IAAG,YAAY,OAAO,QAAQ;AAEnC,YAAI,MAAM,SAAS,MAAM,UAAU,YAAY,OAAO;AACpD,gBAAM,WAAW,MAAM,IAAU,WAAW,EACzC,MAAM,EAAE,OAAO,MAAM,MAAM,CAAC,EAC5B,SAAS,EAAE,GAAG,CAAC,EACf,MAAM;AACT,cAAI,UAAU;AACZ,kBAAM,IAAI,OAAO,cAAc,4BAAyB;AAAA,UAC1D;AAAA,QACF;AAGA,YAAI,MAAM,SAAS;AACjB,gBAAM,OAAO,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,IAAI,MAAM,QAAQ,CAAC,EAAE,MAAM;AAC7E,cAAI,CAAC,MAAM;AACT,kBAAM,IAAI,OAAO,cAAc,KAAK;AAAA,UACtC;AAAA,QACF;AAEA,cAAM,OAAgC;AAAA,UACpC,GAAG;AAAA,UACH,YAAY,oBAAI,KAAK;AAAA,UACrB,YAAY,UAAU;AAAA,QACxB;AAEA,YAAI,MAAM,UAAU;AAClB,eAAK,UAAU,IAAI,MAAM,aAAa,MAAM,QAAQ;AAAA,QACtD;AAEA,cAAM,IAAI,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,IAAI;AAEhD,cAAM,OAAO,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC9D,eAAO,gBAAgB,IAAK;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,OAAO,IAA2B;AACtC,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AAC7D,UAAI,CAAC,KAAM,OAAM,IAAI,OAAO,cAAc,SAAS;AACnD,YAAMA,IAAG,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;AAAA,IAC7C;AAAA,EACF;AACF;AAnMA,IAiDM;AAjDN;AAAA;AAAA;AACA;AAgDA,IAAM,yBAAyB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;;;ACnDO,SAAS,sBAAsB,KAAoB;AACxD,QAAM,EAAE,QAAQ,UAAU,IAAI;AAC9B,QAAM,EAAE,SAAAE,UAAS,gBAAgBC,oBAAmB,IAAI;AACxD,QAAM,eAAe,mBAAmB,GAAG;AAE3C,SAAO;AAAA,IACL,MAAM,QAAQ,KAAc,KAAe;AACzC,YAAM,UAAU;AAChB,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,QAAQ,SAAS;AAEzE,YAAM,SAAS,MAAM,aAAa,QAAQ,IAAI,WAAW,KAAkB;AAC3E,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,CAAC;AAAA,IAC1C;AAAA,IAEA,MAAM,SAAS,KAAc,KAAe;AAC1C,YAAM,UAAU;AAChB,YAAM,EAAE,GAAG,IAAI,IAAI,WAAW;AAE9B,YAAM,OAAO,MAAM,aAAa,SAAS,EAAE;AAG3C,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,QAAQD,SAAQ,WAAW,IAAI,CAAC;AAExF,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,KAAK,CAAC;AAAA,IACxC;AAAA,IAEA,MAAM,OAAO,KAAc,KAAe;AACxC,YAAM,UAAU;AAChB,MAAAC,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,UAAU,SAAS;AAE3E,YAAM,OAAO,MAAM,aAAa,OAAO,IAAI,MAAyB,QAAQ,KAAK,EAAE;AACnF,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,MAAM,MAAM,KAAK,CAAC;AAAA,IACpD;AAAA,IAEA,MAAM,OAAO,KAAc,KAAe;AACxC,YAAM,UAAU;AAChB,YAAM,EAAE,GAAG,IAAI,IAAI,WAAW;AAC9B,YAAM,QAAQ,IAAI;AAElB,YAAM,OAAO,MAAM,aAAa,SAAS,EAAE;AAG3C,MAAAA,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,UAAUD,SAAQ,WAAW,IAAI,CAAC;AAG1F,UAAI,MAAM,WAAW,CAAC,QAAQ,QAAQ,IAAI,UAAU,SAAS,GAAG;AAC9D,cAAM,IAAI,OAAO,eAAe,sCAAsC;AAAA,MACxE;AAEA,YAAM,UAAU,MAAM,aAAa,OAAO,IAAI,OAAO,QAAQ,KAAK,EAAE;AACpE,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,QAAQ,CAAC;AAAA,IAC3C;AAAA,IAEA,MAAM,OAAO,KAAc,KAAe;AACxC,YAAM,UAAU;AAChB,YAAM,EAAE,GAAG,IAAI,IAAI,WAAW;AAE9B,YAAM,OAAO,MAAM,aAAa,SAAS,EAAE;AAG3C,MAAAC,oBAAmB,KAAK,QAAQ,OAAO,EAAE,eAAe,UAAUD,SAAQ,WAAW,IAAI,CAAC;AAG1F,UAAI,QAAQ,KAAK,OAAO,IAAI;AAC1B,cAAM,IAAI,OAAO,eAAe,iCAAiC;AAAA,MACnE;AAEA,YAAM,aAAa,OAAO,EAAE;AAC5B,UAAI,KAAK,EAAE,SAAS,MAAM,SAAS,oBAAoB,CAAC;AAAA,IAC1D;AAAA,EACF;AACF;AA5EA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACDA,SAAS,KAAAE,UAAS;AAAlB,IAEa,kBAQA,kBAQA,kBAIA;AAtBb;AAAA;AAAA;AAEO,IAAM,mBAAmBA,GAAE,OAAO;AAAA,MACvC,OAAOA,GAAE,OAAO,EAAE,MAAM,mBAAgB;AAAA,MACxC,UAAUA,GAAE,OAAO,EAAE,IAAI,GAAG,iCAA8B;AAAA,MAC1D,MAAMA,GAAE,OAAO,EAAE,IAAI,GAAG,kBAAkB;AAAA,MAC1C,SAASA,GAAE,OAAO,EAAE,IAAI,GAAG,eAAe;AAAA,MAC1C,UAAUA,GAAE,OAAOA,GAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,IACtD,CAAC;AAEM,IAAM,mBAAmBA,GAAE,OAAO;AAAA,MACvC,OAAOA,GAAE,OAAO,EAAE,MAAM,mBAAgB,EAAE,SAAS;AAAA,MACnD,UAAUA,GAAE,OAAO,EAAE,IAAI,GAAG,iCAA8B,EAAE,SAAS;AAAA,MACrE,MAAMA,GAAE,OAAO,EAAE,IAAI,GAAG,kBAAkB,EAAE,SAAS;AAAA,MACrD,SAASA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MACpC,UAAUA,GAAE,OAAOA,GAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,IACtD,CAAC;AAEM,IAAM,mBAAmBA,GAAE,OAAO;AAAA,MACvC,IAAIA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACtB,CAAC;AAEM,IAAM,kBAAkBA,GAAE,OAAO;AAAA,MACtC,MAAMA,GAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,MACxC,OAAOA,GAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,MACnD,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,CAAC;AAAA;AAAA;;;ACtBM,SAAS,kBAAkB,KAAoB;AACpD,QAAM,SAAS,IAAI,aAAa;AAChC,QAAM,EAAE,UAAAC,WAAU,KAAK,IAAI,IAAI;AAC/B,QAAM,aAAa,sBAAsB,GAAG;AAG5C,SAAO,IAAI,IAAK;AAEhB,SAAO,IAAI,KAAKA,UAAS,EAAE,OAAO,gBAAgB,CAAC,GAAG,WAAW,OAAO;AACxE,SAAO,IAAI,QAAQA,UAAS,EAAE,QAAQ,iBAAiB,CAAC,GAAG,WAAW,QAAQ;AAC9E,SAAO,KAAK,KAAKA,UAAS,EAAE,MAAM,iBAAiB,CAAC,GAAG,WAAW,MAAM;AACxE,SAAO,IAAI,QAAQA,UAAS,EAAE,QAAQ,kBAAkB,MAAM,iBAAiB,CAAC,GAAG,WAAW,MAAM;AACpG,SAAO,OAAO,QAAQA,UAAS,EAAE,QAAQ,iBAAiB,CAAC,GAAG,WAAW,MAAM;AAE/E,SAAO;AACT;AAnBA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;;;ACFA,IAKa;AALb;AAAA;AAAA;AACA;AACA;AACA;AAEO,IAAM,cAA8B;AAAA,MACzC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,cAAc,CAAC,OAAO;AAAA,MACtB,SAAAC;AAAA,MACA,MAAAC;AAAA,MACA,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,UAAU,CAAC,SAAS;AAAA,MACpB,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,YAAY;AAAA,YACV,MAAM;AAAA,YACN,OAAO;AAAA,YACP,aAAa;AAAA,UACf;AAAA,UACA,YAAY;AAAA,YACV,MAAM,EAAE,OAAO,QAAQ,MAAM,QAAQ,UAAU,KAAK;AAAA,YACpD,OAAO,EAAE,OAAO,SAAS,MAAM,SAAS,UAAU,KAAK;AAAA,YACvD,UAAU,EAAE,OAAO,YAAY,MAAM,YAAY,UAAU,MAAM,YAAY,KAAK;AAAA,YAClF,SAAS;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,cACN,UAAU;AAAA,cACV,iBAAiB;AAAA,cACjB,aAAa;AAAA,cACb,aAAa;AAAA,YACf;AAAA,UACF;AAAA,UACA,YAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;ACzCA,eAAsBC,SAAQ,KAAmC;AAC/D,QAAM,EAAE,IAAAC,KAAI,QAAAC,QAAO,IAAI;AAGvB,MAAI,CAAE,MAAMD,IAAG,OAAO,SAAS,qBAAqB,GAAI;AACtD,UAAMA,IAAG,OAAO,YAAY,uBAAuB,CAAC,UAAU;AAC5D,YAAM,OAAO,IAAI,EAAE,QAAQ;AAC3B,YAAM,OAAO,OAAO,EAAE,OAAO,EAAE,YAAY;AAC3C,YAAM,OAAO,SAAS,EAAE,YAAY,EAAE,WAAW,IAAI,EAAE,QAAQ,WAAW,EAAE,SAAS,SAAS;AAC9F,YAAM,UAAU,YAAY,EAAE,YAAY;AAC1C,YAAM,UAAU,YAAY,EAAE,UAAUA,IAAG,GAAG,IAAI,CAAC;AAEnD,YAAM,MAAM,SAAS;AACrB,YAAM,MAAM,YAAY;AAAA,IAC1B,CAAC;AACD,IAAAC,QAAO,KAAK,oCAAoC;AAAA,EAClD;AAGF;AArBA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,KAAAC,UAAS;AAgCX,SAAS,cAAc,QAAsC;AAClE,QAAM,YAAY,QAAQ,KAAK,UAAU,IAAI;AAC7C,MAAI,CAAC,aAAa,UAAU,SAAS,IAAI;AACvC,UAAM,IAAI,MAAM,iGAAiG;AAAA,EACnH;AAEA,mBAAiB;AAAA,IACf,SAAS,IAAI;AAAA,IACb,MAAM,QAAQ,QAAQ,IAAI;AAAA,IAC1B,MAAM,QAAQ,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY,IAAI;AAAA,IAClC,aAAa,MAAM,QAAQ,QAAQ,MAAM,MAAM,IAC3C,OAAO,KAAK,OAAO,CAAC,IACpB,QAAQ,MAAM,WAAW,IAAI;AAAA,IACjC,aAAa,QAAQ,UAAU,OAAO,IAAI;AAAA,IAC1C;AAAA,IACA,kBAAkB,QAAQ,KAAK,iBAAiB,IAAI;AAAA,IACpD,mBAAmB,QAAQ,KAAK,kBAAkB,IAAI;AAAA,IACtD,YAAY,QAAQ,OAAO,SAAS,IAAI;AAAA,IACxC,eAAe,QAAQ,OAAO,YAAY,IAAI;AAAA,IAC9C,MAAM;AAAA,MACJ,MAAM,QAAQ,MAAM,QAAQ,IAAI;AAAA,MAChC,MAAM,QAAQ,MAAM,QAAQ,IAAI;AAAA,MAChC,QAAQ,QAAQ,MAAM,UAAU,IAAI;AAAA,MACpC,MAAO,QAAQ,MAAM,QAAQ,IAAI,YAC7B,EAAE,MAAM,QAAQ,MAAM,MAAM,QAAQ,IAAI,WAAY,MAAM,QAAQ,MAAM,MAAM,QAAQ,IAAI,UAAW,IACrG;AAAA,MACJ,MAAM,QAAQ,MAAM,QAAQ,IAAI;AAAA,IAClC;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,YAA4B;AAC1C,MAAI,CAAC,gBAAgB;AACnB,WAAO,cAAc;AAAA,EACvB;AACA,SAAO;AACT;AAEO,SAAS,cAAoB;AAClC,mBAAiB;AACnB;AA3EA,IAGM,WAuBO,KAIT;AA9BJ;AAAA;AAAA;AAGA,IAAM,YAAYA,GAAE,OAAO;AAAA,MACzB,UAAUA,GAAE,KAAK,CAAC,eAAe,cAAc,MAAM,CAAC,EAAE,QAAQ,aAAa;AAAA,MAC7E,MAAMA,GAAE,OAAO,OAAO,EAAE,QAAQ,GAAI;AAAA,MACpC,WAAWA,GAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,MACnC,aAAaA,GAAE,OAAO,EAAE,QAAQ,uBAAuB;AAAA,MACvD,aAAaA,GAAE,OAAO,EAAE,SAAS;AAAA,MACjC,cAAcA,GAAE,OAAO,EAAE,QAAQ,eAAe;AAAA,MAChD,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,MACxC,oBAAoBA,GAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,MAC5C,qBAAqBA,GAAE,OAAO,EAAE,QAAQ,IAAI;AAAA,MAC5C,aAAaA,GAAE,OAAO,EAAE,MAAM,EAAE,SAAS;AAAA,MACzC,gBAAgBA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MAC3C,eAAeA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA,MAEnC,WAAWA,GAAE,OAAO,EAAE,QAAQ,oBAAoB;AAAA,MAClD,WAAWA,GAAE,OAAO,OAAO,EAAE,QAAQ,IAAI;AAAA,MACzC,aAAaA,GAAE,OAAO,QAAQ,EAAE,QAAQ,KAAK;AAAA,MAC7C,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,MAC/B,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,MAC/B,WAAWA,GAAE,OAAO,EAAE,QAAQ,qBAAqB;AAAA,IACrD,CAAC;AAGM,IAAM,MAAM,UAAU,MAAM,QAAQ,GAAG;AAI9C,IAAI,iBAAwC;AAAA;AAAA;;;AC9B5C,OAAO,SAAS;AAChB,OAAO,YAAY;AAInB,SAAS,gBAAgB,KAAqB;AAC5C,QAAM,QAAQ,IAAI,MAAM,iBAAiB;AACzC,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAQ,SAAS,MAAM,CAAC,GAAI,EAAE;AACpC,QAAM,OAAO,MAAM,CAAC;AAEpB,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAK,aAAO;AAAA,IACjB,KAAK;AAAK,aAAO,QAAQ;AAAA,IACzB,KAAK;AAAK,aAAO,QAAQ,KAAK;AAAA,IAC9B,KAAK;AAAK,aAAO,QAAQ,KAAK,KAAK;AAAA,IACnC;AAAS,aAAO;AAAA,EAClB;AACF;AAEO,SAAS,oBAAoB,SAA6B;AAC/D,QAAM,SAAS,UAAU;AACzB,SAAO,IAAI,KAAK,SAAS,OAAO,WAAW;AAAA,IACzC,WAAW,OAAO;AAAA,EACpB,CAAC;AACH;AAEO,SAAS,uBAA+B;AAC7C,SAAO,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAC9C;AAEO,SAAS,4BAAkC;AAChD,QAAM,UAAU,gBAAgB,UAAU,EAAE,iBAAiB;AAC7D,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,UAAU,GAAI;AAC7C;AAEO,SAAS,kBAAkB,SAAgC;AAChE,SAAO;AAAA,IACL,aAAa,oBAAoB,OAAO;AAAA,IACxC,cAAc,qBAAqB;AAAA,EACrC;AACF;AA1CA;AAAA;AAAA;AAEA;AAAA;AAAA;;;ACMO,SAAS,kBAAkB,KAAoB;AACpD,QAAM,EAAE,IAAAC,KAAI,QAAQ,YAAAC,aAAY,WAAW,OAAO,IAAI;AACtD,QAAM,EAAE,kBAAAC,mBAAkB,WAAAC,WAAU,IAAI;AACxC,QAAM,eAAe,mBAAmB,GAAG;AAE3C,iBAAe,gBAAgB,QAAgB;AAC7C,UAAM,OAAO,MAAMH,IAA2F,WAAW,EACtH,SAAS,aAAa,qBAAqB,cAAc,EACzD,MAAM,gBAAgB,MAAM,EAC5B;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EACC,MAAM;AAET,QAAI,CAAC,KAAM,QAAO;AAElB,UAAM,EAAE,WAAW,kBAAkB,gBAAgB,UAAU,GAAG,GAAG,oBAAoB,IAAI;AAE7F,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,QACJ,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,QACb,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,MAAM,OAAmB;AAC7B,YAAM,OAAO,MAAMA,IAAS,WAAW,EAAE,MAAM,EAAE,OAAO,MAAM,MAAM,CAAC,EAAE,MAAM;AAG7E,YAAM,cAAc,MAAM,YAAY;AACtC,YAAM,gBAAgB,MAAM,eAAe,MAAM,UAAU,WAAW;AAEtE,UAAI,CAAC,QAAQ,CAAC,eAAe;AAC3B,eAAO,UAAU,eAAe;AAAA,UAC9B,OAAO,MAAM;AAAA,UACb,QAAQ,OAAO,qBAAqB;AAAA,QACtC,CAAC;AACD,cAAM,IAAI,OAAO,kBAAkB,2BAAwB;AAAA,MAC7D;AAEA,YAAM,SAAS,kBAAkB;AAAA,QAC/B,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,MACf,CAAC;AAGD,YAAMA,IAAG,qBAAqB,EAAE,OAAO;AAAA,QACrC,IAAIC,YAAW;AAAA,QACf,OAAO,OAAO;AAAA,QACd,SAAS,KAAK;AAAA,QACd,YAAY,0BAA0B;AAAA,MACxC,CAAC;AAGD,YAAM,cAAc,MAAM,aAAa,uBAAuB,KAAK,OAAO;AAC1E,YAAM,UAAUC,kBAAiB,MAAM,WAAW;AAGlD,YAAM,eAAe,MAAM,gBAAgB,KAAK,EAAE;AAElD,aAAO,UAAU,cAAc,EAAE,QAAQ,KAAK,IAAI,OAAO,KAAK,MAAM,CAAC;AAErE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,WAAWC,WAAU,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ,cAAsB;AAElC,YAAM,SAAS,MAAMH,IAAG,YAAY,OAAO,QAAQ;AAEjD,YAAI,QAAQ,IAAI,qBAAqB,EAAE,MAAM,EAAE,OAAO,aAAa,CAAC;AACpE,YAAI,IAAI,WAAW,UAAU;AAC3B,kBAAQ,MAAM,UAAU;AAAA,QAC1B;AACA,cAAM,cAAc,MAAM,MAAM,MAAM;AAEtC,YAAI,CAAC,aAAa;AAChB,gBAAM,IAAI,OAAO,kBAAkB,2BAAwB;AAAA,QAC7D;AAEA,YAAI,IAAI,KAAK,YAAY,UAAU,IAAI,oBAAI,KAAK,GAAG;AACjD,gBAAM,IAAI,qBAAqB,EAAE,MAAM,EAAE,IAAI,YAAY,GAAG,CAAC,EAAE,OAAO;AACtE,gBAAM,IAAI,OAAO,kBAAkB,wBAAwB;AAAA,QAC7D;AAEA,cAAM,OAAO,MAAM,IAAU,WAAW,EAAE,MAAM,EAAE,IAAI,YAAY,QAAQ,CAAC,EAAE,MAAM;AACnF,YAAI,CAAC,MAAM;AACT,gBAAM,IAAI,OAAO,kBAAkB,uBAAuB;AAAA,QAC5D;AAEA,cAAM,SAAS,kBAAkB;AAAA,UAC/B,QAAQ,KAAK;AAAA,UACb,OAAO,KAAK;AAAA,UACZ,QAAQ,KAAK;AAAA,QACf,CAAC;AAGD,cAAM,IAAI,qBAAqB,EAAE,MAAM,EAAE,IAAI,YAAY,GAAG,CAAC,EAAE,OAAO;AACtE,cAAM,IAAI,qBAAqB,EAAE,OAAO;AAAA,UACtC,IAAIC,YAAW;AAAA,UACf,OAAO,OAAO;AAAA,UACd,SAAS,KAAK;AAAA,UACd,YAAY,0BAA0B;AAAA,QACxC,CAAC;AAED,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB,CAAC;AAGD,YAAM,cAAc,MAAM,aAAa,uBAAuB,OAAO,KAAK,OAAO;AACjF,YAAM,UAAUC,kBAAiB,OAAO,MAAM,WAAW;AAEzD,aAAO,UAAU,gBAAgB,EAAE,QAAQ,OAAO,KAAK,GAAG,CAAC;AAE3D,aAAO;AAAA,QACL,aAAa,OAAO,OAAO;AAAA,QAC3B,cAAc,OAAO,OAAO;AAAA,QAC5B,WAAWC,WAAU,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,IAEA,MAAM,OAAO,cAAsB,QAAiB;AAClD,YAAM,UAAU,MAAMH,IAAG,qBAAqB,EAAE,MAAM,EAAE,OAAO,aAAa,CAAC,EAAE,OAAO;AACtF,UAAI,UAAU,KAAK,QAAQ;AACzB,eAAO,UAAU,eAAe,EAAE,OAAO,CAAC;AAAA,MAC5C;AACA,aAAO,UAAU;AAAA,IACnB;AAAA,IAEA,MAAM,GAAG,QAAgB;AACvB,YAAM,eAAe,MAAM,gBAAgB,MAAM;AAEjD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,OAAO,cAAc,SAAS;AAAA,MAC1C;AAGA,YAAM,cAAc,MAAM,aAAa,uBAAuB,aAAa,OAAO;AAClF,YAAM,UAAUE,kBAAiB,cAAc,WAAW;AAE1D,aAAO;AAAA,QACL,MAAM;AAAA,QACN,WAAWC,WAAU,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,IAEA,MAAM,uBAAuB;AAC3B,YAAM,UAAU,MAAMH,IAAG,qBAAqB,EAC3C,MAAM,cAAc,KAAK,oBAAI,KAAK,CAAC,EACnC,OAAO;AACV,aAAO;AAAA,IACT;AAAA,EACF;AACF;AA9KA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;;;ACEO,SAAS,qBAAqB,KAAoB;AACvD,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,cAAc,kBAAkB,GAAG;AAEzC,WAAS,iBAAiB,KAA6B;AACrD,UAAM,WAAW,IAAI,UAAU,IAAI,IAAI,mBAAmB,MAAM;AAChE,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU,WAAW,WAAW;AAAA,MAChC,MAAM;AAAA,MACN,QAAQ,IAAI,KAAK,KAAK,KAAK;AAAA;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,MAAM,KAAc,KAAe;AACvC,YAAM,SAAS,MAAM,YAAY,MAAM,IAAI,IAAkB;AAG7D,UAAI,OAAO,gBAAgB,OAAO,cAAc,iBAAiB,GAAG,CAAC;AAGrE,UAAI,KAAK;AAAA,QACP,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,MAAM,OAAO;AAAA,UACb,aAAa,OAAO;AAAA,UACpB,WAAW,OAAO;AAAA,QACpB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,QAAQ,KAAc,KAAe;AACzC,YAAM,eAAe,IAAI,UAAU,cAAc;AACjD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,OAAO,kBAAkB,wBAAwB;AAAA,MAC7D;AAEA,YAAM,SAAS,MAAM,YAAY,QAAQ,YAAY;AAErD,UAAI,OAAO,gBAAgB,OAAO,cAAc,iBAAiB,GAAG,CAAC;AACrE,UAAI,KAAK;AAAA,QACP,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,aAAa,OAAO;AAAA,UACpB,WAAW,OAAO;AAAA,QACpB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,OAAO,KAAc,KAAe;AACxC,YAAM,eAAe,IAAI,UAAU,cAAc;AACjD,YAAM,UAAU;AAEhB,UAAI,cAAc;AAChB,cAAM,YAAY,OAAO,cAAc,QAAQ,MAAM,EAAE;AAAA,MACzD;AAEA,UAAI,YAAY,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACnD,UAAI,KAAK,EAAE,SAAS,MAAM,SAAS,iBAAiB,CAAC;AAAA,IACvD;AAAA,IAEA,MAAM,GAAG,KAAc,KAAe;AACpC,YAAM,UAAU;AAChB,YAAM,SAAS,MAAM,YAAY,GAAG,QAAQ,KAAK,EAAE;AACnD,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,OAAO,CAAC;AAAA,IAC1C;AAAA,EACF;AACF;AA1EA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACDA,SAAS,KAAAI,UAAS;AAAlB,IAEa;AAFb;AAAA;AAAA;AAEO,IAAM,cAAcA,GAAE,OAAO;AAAA,MAClC,OAAOA,GAAE,OAAO,EAAE,MAAM,mBAAgB;AAAA,MACxC,UAAUA,GAAE,OAAO,EAAE,IAAI,GAAG,oBAAoB;AAAA,IAClD,CAAC;AAAA;AAAA;;;ACDM,SAAS,iBAAiB,KAAoB;AACnD,QAAM,SAAS,IAAI,aAAa;AAChC,QAAM,EAAE,UAAAC,WAAU,KAAK,IAAI,IAAI;AAC/B,QAAM,aAAa,qBAAqB,GAAG;AAE3C,SAAO,KAAK,UAAUA,UAAS,EAAE,MAAM,YAAY,CAAC,GAAG,WAAW,KAAK;AACvE,SAAO,KAAK,YAAY,WAAW,OAAO;AAC1C,SAAO,KAAK,WAAW,MAAO,WAAW,MAAM;AAC/C,SAAO,IAAI,OAAO,MAAO,WAAW,EAAE;AAEtC,SAAO;AACT;AAfA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;;;ACFA,OAAOC,UAAS;AAUT,SAAS,qBAAqB,KAAoC;AACvE,QAAM,EAAE,QAAQ,QAAQ,UAAU,IAAI;AACtC,QAAM,EAAE,kBAAAC,kBAAiB,IAAI;AAC7B,QAAM,eAAe,mBAAmB,GAAG;AAE3C,SAAO,OAAO,KAAc,MAAgB,SAAuB;AACjE,UAAM,aAAa,IAAI,QAAQ;AAE/B,QAAI,CAAC,YAAY,WAAW,SAAS,GAAG;AACtC,YAAM,IAAI,OAAO,kBAAkB,wBAAwB;AAAA,IAC7D;AAEA,UAAM,QAAQ,WAAW,MAAM,CAAC;AAEhC,QAAI;AACF,YAAM,UAAUD,KAAI,OAAO,OAAO,OAAO,SAAS;AAElD,YAAM,OAAO,MAAM,IAAI,GAAS,WAAW,EAAE,MAAM,EAAE,IAAI,QAAQ,OAAO,CAAC,EAAE,MAAM;AAEjF,UAAI,CAAC,MAAM;AACT,cAAM,IAAI,OAAO,kBAAkB,uBAAuB;AAAA,MAC5D;AAGA,YAAM,cAAc,MAAM,aAAa,uBAAuB,KAAK,OAAO;AAE1E,UAAI,OAAO;AACX,UAAI,UAAUC,kBAAiB,MAAM,WAAW;AAChD,WAAK;AAAA,IACP,SAAS,OAAO;AACd,UAAI,iBAAiBD,KAAI,mBAAmB;AAC1C,cAAM,IAAI,OAAO,kBAAkB,mBAAgB;AAAA,MACrD;AACA,UAAI,iBAAiBA,KAAI,mBAAmB;AAC1C,cAAM,IAAI,OAAO,kBAAkB,gBAAgB;AAAA,MACrD;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAMO,SAAS,6BAA6B,KAAoC;AAC/E,QAAM,EAAE,QAAQ,UAAU,IAAI;AAC9B,QAAM,EAAE,kBAAAC,kBAAiB,IAAI;AAC7B,QAAM,eAAe,mBAAmB,GAAG;AAE3C,SAAO,OAAO,KAAc,MAAgB,SAAuB;AACjE,UAAM,aAAa,IAAI,QAAQ;AAE/B,QAAI,CAAC,YAAY,WAAW,SAAS,GAAG;AACtC,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,QAAQ,WAAW,MAAM,CAAC;AAEhC,QAAI;AACF,YAAM,UAAUD,KAAI,OAAO,OAAO,OAAO,SAAS;AAElD,YAAM,OAAO,MAAM,IAAI,GAAS,WAAW,EAAE,MAAM,EAAE,IAAI,QAAQ,OAAO,CAAC,EAAE,MAAM;AAEjF,UAAI,MAAM;AACR,cAAM,cAAc,MAAM,aAAa,uBAAuB,KAAK,OAAO;AAC1E,YAAI,OAAO;AACX,YAAI,UAAUC,kBAAiB,MAAM,WAAW;AAAA,MAClD;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,SAAK;AAAA,EACP;AACF;AArFA;AAAA;AAAA;AAEA;AAAA;AAAA;;;ACFA,IAKa;AALb;AAAA;AAAA;AACA;AACA;AACA;AAEO,IAAM,aAA6B;AAAA,MACxC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,cAAc,CAAC,OAAO;AAAA,MACtB,SAAAC;AAAA,MACA,MAAM,CAAC,QAAQ;AAEb,YAAI,mBAAmB,QAAQ,qBAAqB,GAAG,CAAC;AACxD,YAAI,mBAAmB,gBAAgB,6BAA6B,GAAG,CAAC;AAAA,MAC1E;AAAA,MACA,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,UAAU,CAAC;AAAA,IACb;AAAA;AAAA;;;ACTA,SAAS,0BAA0B,KAA2B;AAC5D,QAAM,SAAmB,CAAC;AAG1B,MAAI,CAAC,WAAW,KAAK,IAAI,IAAI,GAAG;AAC9B,WAAO,KAAK,uCAAuC,IAAI,IAAI,IAAI;AAAA,EACjE;AAGA,QAAM,aAAa,IAAI,KAAK,OAAO,CAAC,IAAI,IAAI,KAAK,MAAM,CAAC,EAAE,YAAY;AACtE,aAAWC,YAAW,IAAI,YAAY,CAAC,GAAG;AACxC,QAAI,CAACA,SAAQ,WAAW,UAAU,GAAG;AACnC,aAAO,KAAK,YAAYA,QAAO,uBAAuB,UAAU,+BAA4B;AAAA,IAC9F;AAAA,EACF;AAGA,aAAW,UAAU,IAAI,YAAY,CAAC,GAAG;AACvC,QAAI,CAAC,OAAO,KAAK,WAAW,UAAU,GAAG;AACvC,aAAO,KAAK,gBAAgB,OAAO,IAAI,uBAAuB,UAAU,+BAA4B;AAAA,IACtG;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,IAAI,MAAM,cAAW,IAAI,IAAI;AAAA,MAA0C,OAAO,KAAK,QAAQ,CAAC,EAAE;AAAA,EACtG;AACF;AAeO,SAAS,oBAAsC;AACpD,QAAM,SAA2B,CAAC;AAClC,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,YAAY,IAAI,IAAI,QAAQ,IAAI,OAAK,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvD,WAAS,MAAM,KAAqB;AAClC,QAAI,QAAQ,IAAI,IAAI,IAAI,EAAG;AAC3B,YAAQ,IAAI,IAAI,IAAI;AAEpB,eAAW,OAAO,IAAI,gBAAgB,CAAC,GAAG;AACxC,YAAM,SAAS,UAAU,IAAI,GAAG;AAChC,UAAI,OAAQ,OAAM,MAAM;AAAA,IAC1B;AACA,WAAO,KAAK,GAAG;AAAA,EACjB;AAEA,UAAQ,QAAQ,KAAK;AACrB,SAAO;AACT;AAKO,SAAS,eAAe,KAA2B;AACxD,4BAA0B,GAAG;AAC7B,UAAQ,KAAK,GAAG;AAClB;AAKO,SAAS,aAA+B;AAC7C,SAAO,CAAC,GAAG,OAAO;AACpB;AAKO,SAAS,UAAU,MAA0C;AAClE,SAAO,QAAQ,KAAK,OAAK,EAAE,SAAS,IAAI;AAC1C;AAMO,SAAS,wBAAkC;AAChD,QAAM,WAAW,oBAAI,IAAY,CAAC,KAAK,CAAC;AACxC,aAAW,OAAO,SAAS;AAEzB,eAAWA,YAAW,IAAI,YAAY,CAAC,GAAG;AACxC,eAAS,IAAIA,QAAO;AAAA,IACtB;AAEA,eAAW,UAAU,IAAI,YAAY,CAAC,GAAG;AACvC,eAAS,IAAI,OAAO,IAAI;AAAA,IAC1B;AAAA,EACF;AACA,SAAO,CAAC,GAAG,QAAQ;AACrB;AAKO,SAAS,eAAeA,UAA0B;AACvD,SAAO,sBAAsB,EAAE,SAASA,QAAO;AACjD;AAxHA,IA0CM;AA1CN;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAoCA,IAAM,UAA4B,CAAC;AAGlC,KAAC,cAAc,aAAa,aAAa,UAAU,EAAE,QAAQ,SAAO;AACnE,gCAA0B,GAAG;AAC7B,cAAQ,KAAK,GAAG;AAAA,IAClB,CAAC;AAAA;AAAA;;;AChDD,OAAO,SAAS;AAAhB,IACQ,eAyCF,mBAuCO;AAjFb;AAAA;AAAA;AACA,KAAM,EAAE,kBAAkB;AAyC1B,IAAM,oBAAN,cAAgC,cAAc;AAAA,MAC5C,UACE,UACG,MACM;AACT,eAAO,KAAK,KAAK,OAAO,GAAG,IAAI;AAAA,MACjC;AAAA,MAEA,QACE,OACA,UAGM;AACN,aAAK,GAAG,OAAO,QAAwC;AACvD,eAAO;AAAA,MACT;AAAA,MAEA,UACE,OACA,UAGM;AACN,aAAK,KAAK,OAAO,QAAwC;AACzD,eAAO;AAAA,MACT;AAAA,MAEA,SACE,OACA,UAGM;AACN,aAAK,IAAI,OAAO,QAAwC;AACxD,eAAO;AAAA,MACT;AAAA,IACF;AAEO,IAAM,cAAc,IAAI,kBAAkB;AAAA,MAC/C,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc;AAAA,MACd,mBAAmB;AAAA,IACrB,CAAC;AAAA;AAAA;;;ACzEM,SAAS,sBAAsBC,eAA0B;AAE9D,EAAAA,cAAa,GAAG,kBAAkB,CAAC,UAAU,UAAU;AACrD,UAAM,MAAM,MAAM,KAAK,YAAY,KAAK;AAGxC,QAAI;AACJ,QAAI;AAEJ,QAAI,IAAI,WAAW,aAAa,GAAG;AACjC,eAAS;AACT,cAAQ,uBAAuB,GAAG;AAAA,IACpC,WAAW,IAAI,WAAW,QAAQ,GAAG;AACnC,eAAS;AACT,cAAQ,uBAAuB,GAAG;AAAA,IACpC,WAAW,IAAI,WAAW,aAAa,GAAG;AACxC,eAAS;AACT,cAAQ,uBAAuB,GAAG;AAAA,IACpC;AAGA,QAAI,UAAU,SAAS,CAAC,eAAe,IAAI,KAAK,GAAG;AACjD,kBAAY,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI;AAAA,QACxC;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAmB;AAAA,IACrB;AAAA,EACF,CAAC;AAED,SAAOA;AACT;AAGA,SAAS,uBAAuB,KAAiC;AAE/D,QAAM,QAAQ,IAAI,MAAM,kCAAkC;AAC1D,SAAO,QAAQ,CAAC;AAClB;AAEA,SAAS,uBAAuB,KAAiC;AAE/D,QAAM,QAAQ,IAAI,MAAM,6BAA6B;AACrD,SAAO,QAAQ,CAAC;AAClB;AAEA,SAAS,uBAAuB,KAAiC;AAE/D,QAAM,QAAQ,IAAI,MAAM,kCAAkC;AAC1D,SAAO,QAAQ,CAAC;AAClB;AAhEA,IAIM;AAJN;AAAA;AAAA;AACA;AAGA,IAAM,iBAAiB,oBAAI,IAAI,CAAC,kBAAkB,mBAAmB,sBAAsB,CAAC;AAAA;AAAA;;;ACJ5F,OAAO,UAAyB;AAIhC,SAAS,oBAAiC;AACxC,QAAM,MAAM,IAAI;AAGhB,MAAI,IAAI,WAAW,OAAO,KAAK,IAAI,WAAW,SAAS,GAAG;AACxD,UAAM,WAAW,IAAI,QAAQ,oBAAoB,EAAE;AACnD,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY,EAAE,SAAS;AAAA,MACvB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAGA,MAAI,IAAI,WAAW,eAAe,KAAK,IAAI,WAAW,aAAa,GAAG;AACpE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG;AAAA,IAC1B;AAAA,EACF;AAGA,MAAI,IAAI,WAAW,UAAU,GAAG;AAC9B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,6BAA6B,GAAG,EAAE;AACpD;AAaO,SAAS,kBAAqD;AACnE,QAAM,MAAM,IAAI;AAChB,MAAI,IAAI,WAAW,OAAO,KAAK,IAAI,WAAW,SAAS,EAAG,QAAO;AACjE,MAAI,IAAI,WAAW,eAAe,KAAK,IAAI,WAAW,aAAa,EAAG,QAAO;AAC7E,MAAI,IAAI,WAAW,UAAU,EAAG,QAAO;AACvC,SAAO;AACT;AAGA,eAAsB,YAA2B;AAC/C,MAAI,cAAc,IAAI;AACpB,UAAM,cAAc,GAAG,QAAQ;AAC/B,kBAAc,KAAK;AAAA,EACrB;AACF;AA/DA,IAsCM,eAGA,cACO;AA1Cb;AAAA;AAAA;AACA;AACA;AAoCA,IAAM,gBAAgB;AAGtB,IAAM,eAAe,cAAc,MAAM,KAAK,kBAAkB,CAAC;AAC1D,IAAM,KAAK,cAAc,KAAK,eAAe,sBAAsB,YAAY;AAEtF,QAAI,IAAI,aAAa,cAAc;AACjC,oBAAc,KAAK;AAAA,IACrB;AAAA;AAAA;;;AC9CA,OAAO,UAAU;AAAjB,IAEM,OAEO;AAJb;AAAA;AAAA;AAEA,IAAM,QAAQ,QAAQ,IAAI,UAAU,MAAM;AAEnC,IAAM,SAAS,KAAK;AAAA,MACzB,OAAO,QAAQ,IAAI,WAAW,KAAK;AAAA,MACnC,WAAW,QACP,EAAE,QAAQ,eAAe,SAAS,EAAE,UAAU,KAAK,EAAE,IACrD;AAAA,IACN,CAAC;AAAA;AAAA;;;ACTD,OAAOC,aAAY;AAGZ,SAAS,aAAqB;AACnC,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,aAAaA,QAAO,YAAY,CAAC,EAAE,SAAS,WAAW;AAC7D,SAAO,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,EAAE;AAChD;AAPA;AAAA;AAAA;AAAA;AAAA;;;ACMO,SAAS,cAAc,OAAgCC,KAAU;AACtE,QAAM,UAAU,YAAY,EAAE,UAAUA,IAAG,GAAG,IAAI,CAAC;AACnD,QAAM,UAAU,YAAY,EAAE,UAAUA,IAAG,GAAG,IAAI,CAAC;AACrD;AAMA,eAAsB,wBAAwBA,KAAU,WAAkC;AACxF,MAAI,CAAE,MAAMA,IAAG,OAAO,UAAU,WAAW,YAAY,GAAI;AACzD,UAAMA,IAAG,OAAO,WAAW,WAAW,CAAC,UAAU;AAE/C,YAAM,OAAO,YAAY,EAAE,SAAS;AACpC,YAAM,OAAO,YAAY,EAAE,SAAS;AAAA,IACtC,CAAC;AACD,WAAO,KAAK,0BAA0B,SAAS,EAAE;AAAA,EACnD;AACF;AAKA,eAAsB,mBACpBA,KACA,WACA,YACA,eACkB;AAClB,MAAI,CAAE,MAAMA,IAAG,OAAO,UAAU,WAAW,UAAU,GAAI;AACvD,UAAMA,IAAG,OAAO,WAAW,WAAW,aAAa;AACnD,WAAO,KAAK,iBAAiB,SAAS,IAAI,UAAU,EAAE;AACtD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAzCA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACqBO,SAAS,SAAS,SAA0B;AACjD,SAAO,CAAC,KAAc,MAAgB,SAAuB;AAC3D,QAAI,YAAY,CAAC;AAEjB,QAAI,QAAQ,MAAM;AAChB,UAAI,OAAO,QAAQ,KAAK,MAAM,IAAI,IAAI;AAAA,IACxC;AACA,QAAI,QAAQ,OAAO;AACjB,UAAI,UAAU,QAAQ,QAAQ,MAAM,MAAM,IAAI,KAAK;AAAA,IACrD;AACA,QAAI,QAAQ,QAAQ;AAClB,UAAI,UAAU,SAAS,QAAQ,OAAO,MAAM,IAAI,MAAM;AAAA,IACxD;AACA,SAAK;AAAA,EACP;AACF;AArCA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAa,UAWA,eAOA,mBAOA,gBAOA;AAhCb;AAAA;AAAA;AAAO,IAAM,WAAN,cAAuB,MAAM;AAAA,MAClB;AAAA,MAEhB,YAAY,SAAiB,aAAqB,KAAK;AACrD,cAAM,OAAO;AACb,aAAK,aAAa;AAClB,aAAK,OAAO;AACZ,cAAM,kBAAkB,MAAM,KAAK,WAAW;AAAA,MAChD;AAAA,IACF;AAEO,IAAM,gBAAN,cAA4B,SAAS;AAAA,MAC1C,YAAY,WAAmB,WAAW;AACxC,cAAM,GAAG,QAAQ,kBAAkB,GAAG;AACtC,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAEO,IAAM,oBAAN,cAAgC,SAAS;AAAA,MAC9C,YAAY,UAAkB,iBAAiB;AAC7C,cAAM,SAAS,GAAG;AAClB,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAEO,IAAM,iBAAN,cAA6B,SAAS;AAAA,MAC3C,YAAY,UAAkB,mBAAmB;AAC/C,cAAM,SAAS,GAAG;AAClB,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAEO,IAAM,gBAAN,cAA4B,SAAS;AAAA,MAC1C,YAAY,UAAkB,aAAa;AACzC,cAAM,SAAS,GAAG;AAClB,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAAA;AAAA;;;ACrCA,SAAS,gBAAgB,0BAA6D;AAStF,SAAS,sBACP,YACA,MACyB;AACzB,QAAM,SAAkC,CAAC;AAEzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,OAAO,UAAU,YAAY,MAAM,WAAW,SAAS,GAAG;AAC5D,YAAM,OAAO,MAAM,MAAM,GAAG,EAAE;AAC9B,aAAO,GAAG,IAAI,KAAK,IAAI;AAAA,IACzB,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,iBAAiB,MAAY,aAA2C;AACtF,QAAM,EAAE,KAAK,QAAQ,MAAM,IAAI,IAAI,eAAkD,kBAAkB;AAEvG,aAAW,QAAQ,aAAa;AAC9B,UAAM,SAAS,KAAK;AACpB,UAAMC,WAAU,KAAK;AACrB,UAAM,aAAa,KAAK,aACpB,sBAAsB,KAAK,YAAuC,IAAI,IACtE;AACJ,UAAM,SAAS,KAAK;AAEpB,QAAI,KAAK,UAAU;AAEjB,UAAI,QAAQ,QAAQ;AAClB,eAAO,QAAQA,UAAS,QAAQ,UAAU;AAAA,MAC5C,OAAO;AACL,eAAO,QAAQA,UAAS,UAAU;AAAA,MACpC;AAAA,IACF,OAAO;AAEL,UAAI,QAAQ,QAAQ;AAClB,YAAI,QAAQA,UAAS,QAAQ,UAAU;AAAA,MACzC,OAAO;AACL,YAAI,QAAQA,UAAS,UAAU;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM;AACf;AAGO,SAAS,UAAU,SAA8C;AACtE,SAAO,QAAQ;AACjB;AAGO,SAAS,YAAY,OAA4C;AACtE,SAAO,mBAAwC,KAAK;AACtD;AAvEA;AAAA;AAAA;AAAA;AAAA;;;ACAA,OAAO,gBAAsC;AAC7C,SAAS,cAAc,kBAAkB;AACzC,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAH9B,IAOM,WACA,eACA,WA+BO;AAxCb;AAAA;AAAA;AAOA,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,IAAM,gBAAgB,KAAK,WAAW,aAAa,WAAW;AAC9D,IAAM,YAAY,KAAK,WAAW,0BAA0B;AA+BrD,IAAM,cAAN,MAAkB;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAER,YAAY,QAAoBC,SAAgB;AAC9C,aAAK,cAAc,OAAO;AAC1B,aAAK,SAASA,QAAO,MAAM,EAAE,SAAS,OAAO,CAAC;AAC9C,aAAK,WAAW,aAAa,eAAe,OAAO;AAGnD,YAAI,WAAW,SAAS,GAAG;AACzB,gBAAM,aAAa,aAAa,SAAS,EAAE,SAAS,QAAQ;AAC5D,eAAK,iBAAiB,yBAAyB,UAAU;AAAA,QAC3D,OAAO;AACL,eAAK,iBAAiB;AAAA,QACxB;AAEA,aAAK,cAAc,WAAW,gBAAgB;AAAA,UAC5C,MAAM,OAAO;AAAA,UACb,MAAM,OAAO;AAAA,UACb,QAAQ,OAAO;AAAA,UACf,MAAM,OAAO;AAAA;AAAA,UAEb,GAAI,OAAO,OAAO,CAAC,IAAI,EAAE,WAAW,KAAK;AAAA,QAC3C,CAAC;AAAA,MACH;AAAA,MAEA,MAAM,KAAK,SAA0D;AACnE,cAAM,OAAO,QAAQ,QAAQ,KAAK;AAClC,cAAM,KAAK,MAAM,QAAQ,QAAQ,EAAE,IAAI,QAAQ,GAAG,KAAK,IAAI,IAAI,QAAQ;AAGvE,cAAM,OAAQ,QAAQ,SAAS,QAAQ,UACnC,KAAK,eAAe,OAAO,IAC3B,QAAQ;AAEZ,aAAK,OAAO,KAAK,EAAE,IAAI,SAAS,QAAQ,QAAQ,GAAG,eAAe;AAElE,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,YAAY,SAAS;AAAA,YAC7C;AAAA,YACA;AAAA,YACA,SAAS,QAAQ;AAAA,YACjB,MAAM,QAAQ;AAAA,YACd;AAAA,YACA,SAAS,QAAQ;AAAA,YACjB,aAAa,QAAQ;AAAA,UACvB,CAAC;AAED,eAAK,OAAO;AAAA,YACV,EAAE,WAAW,OAAO,WAAW,UAAU,OAAO,SAAS;AAAA,YACzD;AAAA,UACF;AAEA,iBAAO;AAAA,YACL,WAAW,OAAO;AAAA,YAClB,UAAU,OAAO;AAAA,YACjB,UAAU,OAAO;AAAA,UACnB;AAAA,QACF,SAAS,OAAO;AACd,eAAK,OAAO,KAAK,EAAE,OAAO,IAAI,SAAS,QAAQ,QAAQ,GAAG,mCAAmC;AAC7F,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEQ,eAAe,SAAkC;AACvD,YAAI,OAAO,KAAK;AAGhB,eAAO,KAAK,QAAQ,oBAAoB,QAAQ,OAAO;AACvD,eAAO,KAAK,QAAQ,oBAAoB,QAAQ,WAAW,KAAK,cAAc;AAC9E,eAAO,KAAK,QAAQ,kBAAiB,oBAAI,KAAK,GAAE,YAAY,EAAE,SAAS,CAAC;AAGxE,eAAO,KAAK,wBAAwB,MAAM,SAAS,QAAQ,KAAK;AAChE,eAAO,KAAK,wBAAwB,MAAM,WAAW,QAAQ,OAAO;AAGpE,YAAI,QAAQ,SAAS,QAAQ;AAC3B,gBAAM,cAAc,QAAQ,QAAQ;AAAA,YAAI,OACtC,YAAY,EAAE,GAAG,qKAAqK,EAAE,KAAK;AAAA,UAC/L,EAAE,KAAK,EAAE;AACT,iBAAO,KAAK;AAAA,YAAQ;AAAA,YAA8C,CAAC,GAAG,YACpE,QAAQ,QAAQ,oBAAoB,WAAW;AAAA,UACjD;AAAA,QACF,OAAO;AACL,iBAAO,KAAK,QAAQ,4CAA4C,EAAE;AAAA,QACpE;AAEA,eAAO;AAAA,MACT;AAAA,MAEQ,wBAAwB,MAAc,MAAc,OAAwB;AAClF,cAAM,UAAU,IAAI,OAAO,aAAa,IAAI,uCAAuC,GAAG;AACtF,YAAI,OAAO;AACT,iBAAO,KAAK;AAAA,YAAQ;AAAA,YAAS,CAAC,GAAG,YAC/B,QAAQ,QAAQ,IAAI,OAAO,SAAS,IAAI,UAAU,GAAG,GAAG,KAAK;AAAA,UAC/D;AAAA,QACF;AACA,eAAO,KAAK,QAAQ,SAAS,EAAE;AAAA,MACjC;AAAA,MAEA,MAAM,SAA2B;AAC/B,YAAI;AACF,gBAAM,KAAK,YAAY,OAAO;AAC9B,eAAK,OAAO,KAAK,0BAA0B;AAC3C,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,eAAK,OAAO,KAAK,EAAE,MAAM,GAAG,8CAA8C;AAC1E,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;AC3JA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,cAAc;AAUvB,SAAS,kBAAkB,oBAAoB,eAAe;AASvD,SAAS,sBAAqC;AAEnD,QAAM,aAAgC;AAAA,IACpC;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,gBAAgB;AAAA,IACxB,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,cAAc,MAAM,OAAO;AAAA,IAC3B;AAAA,IACA,oBAAoB,CAAC,MAAc,YAA4B;AAC7D,iBAAW,IAAI,IAAI;AAAA,IACrB;AAAA,IACA,QAAQ,UAAU;AAAA,IAClB,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,IAClB;AAAA,IACA,QAAQ;AAAA,IACR,MAAM,IAAI,YAAY,UAAU,EAAE,MAAM,MAAM;AAAA,EAChD;AACF;AAzDA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;;;ACZA,SAAS,gBAAgB;AACzB,SAAS,kBAAkBC,2BAA0B;AAK9C,SAAS,gBACd,KACA,KACA,KACA,OACA;AAEA,MAAI,IAAI,aAAa,cAAc;AACjC,WAAO,MAAM,EAAE,KAAK,KAAK,IAAI,KAAK,QAAQ,IAAI,OAAO,GAAG,kBAAkB;AAAA,EAC5E;AAGA,MAAI,eAAe,UAAU;AAC3B,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MAC1B,SAAS;AAAA,MACT,OAAO;AAAA,MACP,SAAS,IAAI,OAAO,IAAI,CAAC,OAAO;AAAA,QAC9B,MAAM,EAAE,KAAK,KAAK,GAAG;AAAA,QACrB,SAAS,EAAE;AAAA,MACb,EAAE;AAAA,IACJ,CAAC;AAAA,EACH;AAGA,MAAI,eAAeA,qBAAoB;AACrC,WAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MAC1B,SAAS;AAAA,MACT,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,MAAI,eAAe,UAAU;AAC3B,WAAO,IAAI,OAAO,IAAI,UAAU,EAAE,KAAK;AAAA,MACrC,SAAS;AAAA,MACT,OAAO,IAAI;AAAA,IACb,CAAC;AAAA,EACH;AAGA,SAAO,MAAM,EAAE,KAAK,KAAK,IAAI,KAAK,QAAQ,IAAI,QAAQ,OAAO,IAAI,MAAM,GAAG,iBAAiB;AAC3F,MAAI,OAAO,GAAG,EAAE,KAAK;AAAA,IACnB,SAAS;AAAA,IACT,OAAO,IAAI,aAAa,eAAe,+BAA+B,IAAI;AAAA,EAC5E,CAAC;AACH;AApDA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;;;ACLA,OAAO,aAAa;AACpB,OAAO,UAAU;AACjB,OAAO,YAAY;AACnB,OAAO,iBAAiB;AACxB,OAAO,kBAAkB;AACzB,OAAO,UAAU;AACjB,SAAS,iBAAAC,sBAAqB;AAC9B,SAAS,kBAAkB;AAUpB,SAAS,YAAY;AAC1B,QAAM,MAAM,QAAQ;AAGpB,MAAI,IAAI,OAAO;AAAA,IACb,uBAAuB,IAAI,aAAa,eAAe,SAAY;AAAA,EACrE,CAAC,CAAC;AAGF,MAAI,IAAI,KAAK;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB,CAAC,gBAAgB,iBAAiB,oBAAoB,cAAc;AAAA,IACpF,gBAAgB,CAAC,oBAAoB,cAAc;AAAA,EACrD,CAAC,CAAC;AAGF,MAAI,IAAI,CAAC,KAAK,KAAK,SAAS;AAC1B,UAAM,YAAY,WAAW;AAC7B,UAAM,gBAAgB,IAAI,IAAI,kBAAkB,KAAK,IAAI,IAAI,cAAc,KAAK;AAEhF,QAAI,UAAU,gBAAgB,SAAS;AACvC,QAAI,UAAU,oBAAoB,aAAa;AAE/C,QAAI,YAAY;AAChB,QAAI,gBAAgB;AAEpB,SAAK;AAAA,EACP,CAAC;AAGD,QAAM,WAAW,QAAQ,IAAI,WAAW;AACxC,MAAI,aAAa,WAAW,aAAa,SAAS;AAChD,QAAI,IAAI,CAAC,KAAK,KAAK,SAAS;AAC1B,YAAMC,SAAQ,KAAK,IAAI;AACvB,UAAI,GAAG,UAAU,MAAM;AACrB,cAAM,KAAK,KAAK,IAAI,IAAIA;AACxB,cAAM,MAAM,IAAI,IAAI,cAAc,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM,IAAI,IAAI,WAAW,IAAI,IAAI,UAAU,IAAI,EAAE;AACvG,YAAI,IAAI,YAAY,WAAW,OAAO,GAAG;AACvC,iBAAO,MAAM,GAAG;AAAA,QAClB,OAAO;AACL,iBAAO,MAAM,GAAG;AAAA,QAClB;AAAA,MACF,CAAC;AACD,WAAK;AAAA,IACP,CAAC;AAAA,EACH;AAGA,MAAI,IAAI,YAAY,CAAC;AAGrB,MAAI,IAAI,QAAQ,KAAK,CAAC;AACtB,MAAI,IAAI,aAAa,CAAC;AAGtB,QAAM,MAAM,oBAAoB;AAChC,QAAMC,WAAU,WAAW;AAG3B,aAAW,OAAOA,UAAS;AACzB,QAAI,IAAI,MAAM;AACZ,UAAI,KAAK,GAAG;AAAA,IACd;AAAA,EACF;AAGA,aAAW,OAAOA,UAAS;AACzB,QAAI,IAAI,QAAQ;AACd,YAAM,SAAS,IAAI,eAAe,IAAI,IAAI,IAAI;AAC9C,UAAI,IAAI,UAAU,MAAM,IAAI,IAAI,OAAO,GAAG,CAAC;AAAA,IAC7C;AAAA,EACF;AAGA,MAAI,IAAI,WAAW,CAAC,MAAM,QAAQ;AAChC,QAAI,KAAK,EAAE,QAAQ,MAAM,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,CAAC;AAAA,EAChE,CAAC;AAGD,MAAI,IAAI,KAAK,CAAC,MAAM,QAAQ;AAC1B,QAAI,SAAS,UAAU,EAAE,QAAQ;AAAA,EACnC,CAAC;AAGD,QAAM,aAAa,KAAK,KAAKC,YAAW,WAAW;AACnD,MAAI,IAAI,WAAW,QAAQ,OAAO,UAAU,CAAC;AAG7C,QAAM,SAAS,KAAK,KAAKA,YAAW,YAAY;AAEhD,MAAI,IAAI,OAAO,QAAQ,OAAO,MAAM,CAAC;AACrC,MAAI,IAAI,gBAAgB,CAAC,MAAM,QAAQ;AACrC,QAAI,SAAS,KAAK,KAAK,QAAQ,YAAY,CAAC;AAAA,EAC9C,CAAC;AAGD,MAAI,IAAI,eAAe;AAEvB,SAAO;AACT;AArHA,IAeMA;AAfN;AAAA;AAAA;AASA;AACA;AACA;AACA;AACA;AAEA,IAAMA,aAAY,KAAK,QAAQH,eAAc,YAAY,GAAG,CAAC;AAAA;AAAA;;;ACf7D,OAAO,SAAS;AAOhB,eAAsB,mBAAmB,MAAc,OAAO,WAA0B;AACtF,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAMI,UAAS,IAAI,aAAa;AAEhC,IAAAA,QAAO,KAAK,SAAS,CAAC,QAA+B;AACnD,UAAI,IAAI,SAAS,cAAc;AAC7B,eAAO,MAAM,EAAE,KAAK,GAAG,QAAQ,IAAI,oBAAoB;AACvD,eAAO,IAAI,MAAM,QAAQ,IAAI,oBAAoB,CAAC;AAAA,MACpD,OAAO;AACL,eAAO,GAAG;AAAA,MACZ;AAAA,IACF,CAAC;AAED,IAAAA,QAAO,KAAK,aAAa,MAAM;AAC7B,MAAAA,QAAO,MAAM,MAAM,QAAQ,CAAC;AAAA,IAC9B,CAAC;AAED,IAAAA,QAAO,OAAO,MAAM,IAAI;AAAA,EAC1B,CAAC;AACH;AA1BA;AAAA;AAAA;AACA;AAAA;AAAA;;;ACDA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA,eAAe,wBAAuC;AACpD,QAAM,MAAM,oBAAoB;AAChC,QAAMC,WAAU,kBAAkB;AAElC,SAAO,KAAK,uBAAuB;AACnC,aAAW,OAAOA,UAAS;AACzB,QAAI,IAAI,SAAS;AACf,YAAM,IAAI,QAAQ,GAAG;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,KAAK,kBAAkB;AAC9B,aAAW,OAAOA,UAAS;AACzB,QAAI,IAAI,MAAM;AACZ,YAAM,IAAI,KAAK,GAAG;AAAA,IACpB;AAAA,EACF;AAEA,SAAO,KAAK,gBAAgB;AAC9B;AAEA,eAAsB,MAAM,QAA4C;AACtE,MAAI,QAAQ;AACV,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,QAAM,WAAW,cAAc,MAAM;AAGrC,QAAM,mBAAmB,SAAS,MAAM,SAAS,IAAI;AAErD,cAAY,UAAU,mBAAmB,EAAE,MAAM,SAAS,MAAM,MAAM,SAAS,KAAK,CAAC;AAGrF,QAAM,sBAAsB;AAE5B,QAAM,MAAM,UAAU;AAEtB,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,aAAS,IAAI,OAAO,SAAS,MAAM,SAAS,MAAM,MAAM;AACtD,YAAM,UAAU,IAAI,eAAe,oBAAoB,SAAS,IAAI;AACpE,aAAO,KAAK,EAAE,MAAM,SAAS,MAAM,MAAM,SAAS,QAAQ,GAAG,gBAAgB;AAC7E,aAAO,KAAK,QAAQ,OAAO,SAAS;AACpC,aAAO,KAAK,OAAO,OAAO,KAAK;AAC/B,kBAAY,UAAU,kBAAkB,EAAE,MAAM,SAAS,MAAM,MAAM,SAAS,KAAK,CAAC;AACpF,cAAQ,MAAO;AAAA,IACjB,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,OAAsB;AAC1C,MAAI,CAAC,OAAQ;AAEb,cAAY,UAAU,iBAAiB;AAEvC,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,WAAQ,MAAM,CAAC,QAAQ;AACrB,UAAI,IAAK,QAAO,GAAG;AAAA,UACd,SAAQ;AAAA,IACf,CAAC;AAAA,EACH,CAAC;AAED,QAAM,UAAU;AAChB,cAAY,UAAU,iBAAiB;AAEvC,cAAY;AACZ,WAAS;AACT,cAAY,UAAU,gBAAgB;AACtC,SAAO,KAAK,gBAAgB;AAC9B;AAEA,eAAsB,QAAQ,QAA4C;AACxE,cAAY,UAAU,mBAAmB;AACzC,QAAM,KAAK;AACX,SAAO,MAAM,MAAM;AACrB;AAEO,SAAS,YAAqB;AACnC,SAAO,WAAW;AACpB;AAGA,SAAS,wBAAwB;AAC/B,MAAI,eAAe;AAEnB,QAAM,WAAW,OAAO,WAAmB;AACzC,QAAI,aAAc;AAClB,mBAAe;AAEf,WAAO,KAAK,EAAE,OAAO,GAAG,6BAA6B;AAErD,QAAI;AACF,YAAM,KAAK;AACX,cAAQ,KAAK,CAAC;AAAA,IAChB,SAAS,KAAK;AACZ,aAAO,MAAM,EAAE,IAAI,GAAG,uBAAuB;AAC7C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAEA,UAAQ,GAAG,WAAW,MAAM,SAAS,SAAS,CAAC;AAC/C,UAAQ,GAAG,UAAU,MAAM,SAAS,QAAQ,CAAC;AAC/C;AArHA,IAWI;AAXJ;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,IAAI,SAA6B;AA4GjC,0BAAsB;AAAA;AAAA;;;ACpHtB;AAIA;AACA;AACA;AAIA;AACA;AA0BA;AAIA;AA5CA,OAAO;AAgDP,IAAI,YAAY,QAAQ,UAAU,QAAQ,KAAK,CAAC,CAAC,IAAI;AACnD,QAAM,EAAE,OAAAC,OAAM,IAAI,MAAM;AACxB,EAAAA,OAAM;AACR;","names":["modules","db","logger","addTimestamps","addAuditFieldsIfMissing","db","logger","generateId","db","generateId","CASLForbiddenError","validate","migrate","db","logger","addTimestamps","addAuditFieldsIfMissing","addColumnIfMissing","seed","db","logger","generateId","db","generateId","subject","CASLForbiddenError","z","validate","migrate","seed","migrate","db","logger","z","db","generateId","defineAbilityFor","packRules","z","validate","jwt","defineAbilityFor","migrate","subject","knexInstance","crypto","db","subject","logger","CASLForbiddenError","fileURLToPath","start","modules","__dirname","server","modules","start"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gzl10/nexus-backend",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"nexus": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"ui/dist"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"keywords": [
|
|
22
|
+
"baas",
|
|
23
|
+
"backend",
|
|
24
|
+
"backend-as-a-service",
|
|
25
|
+
"express",
|
|
26
|
+
"express5",
|
|
27
|
+
"api",
|
|
28
|
+
"rest",
|
|
29
|
+
"knex",
|
|
30
|
+
"sqlite",
|
|
31
|
+
"postgresql",
|
|
32
|
+
"mysql",
|
|
33
|
+
"casl",
|
|
34
|
+
"authorization",
|
|
35
|
+
"authentication",
|
|
36
|
+
"jwt"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@casl/ability": "^6.7.5",
|
|
40
|
+
"bcryptjs": "^2.4.3",
|
|
41
|
+
"better-sqlite3": "^11.0.0",
|
|
42
|
+
"commander": "^14.0.2",
|
|
43
|
+
"compression": "^1.8.0",
|
|
44
|
+
"consola": "^3.4.2",
|
|
45
|
+
"cookie-parser": "^1.4.7",
|
|
46
|
+
"cors": "^2.8.5",
|
|
47
|
+
"dotenv": "^16.5.0",
|
|
48
|
+
"eventemitter2": "^6.4.9",
|
|
49
|
+
"express": "^5.2.1",
|
|
50
|
+
"helmet": "^8.0.0",
|
|
51
|
+
"jsonwebtoken": "^9.0.2",
|
|
52
|
+
"knex": "^3.1.0",
|
|
53
|
+
"nodemailer": "^7.0.12",
|
|
54
|
+
"pino": "^10.1.0",
|
|
55
|
+
"zod": "^3.24.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@eslint/js": "^9.39.2",
|
|
59
|
+
"@types/bcryptjs": "^2.4.0",
|
|
60
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
61
|
+
"@types/compression": "^1.7.0",
|
|
62
|
+
"@types/cookie-parser": "^1.4.10",
|
|
63
|
+
"@types/cors": "^2.8.0",
|
|
64
|
+
"@types/express": "^5.0.0",
|
|
65
|
+
"@types/jsonwebtoken": "^9.0.0",
|
|
66
|
+
"@types/node": "^22.0.0",
|
|
67
|
+
"@types/nodemailer": "^7.0.4",
|
|
68
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
69
|
+
"concurrently": "^9.2.1",
|
|
70
|
+
"cross-env": "^10.1.0",
|
|
71
|
+
"eslint": "^9.17.0",
|
|
72
|
+
"pino-pretty": "^13.1.3",
|
|
73
|
+
"tsup": "^8.3.0",
|
|
74
|
+
"tsx": "^4.19.0",
|
|
75
|
+
"typescript": "^5.7.0",
|
|
76
|
+
"typescript-eslint": "^8.51.0",
|
|
77
|
+
"vitest": "^4.0.16"
|
|
78
|
+
},
|
|
79
|
+
"scripts": {
|
|
80
|
+
"dev": "concurrently -n backend,ui -c blue,green \"pnpm dev:backend\" \"pnpm dev:ui\"",
|
|
81
|
+
"dev:tunnel": "cross-env BACKEND_URL=https://nexus.tunnel.gzl10.com concurrently -n backend,ui,tunnel -c blue,green,magenta \"pnpm dev:backend\" \"pnpm dev:ui\" \"frpc -c frpc.toml\"",
|
|
82
|
+
"dev:backend": "tsx watch src/index.ts",
|
|
83
|
+
"dev:ui": "pnpm --filter nexus-ui build:watch",
|
|
84
|
+
"build": "tsup && pnpm run build:ui",
|
|
85
|
+
"build:ui": "pnpm --filter nexus-ui build",
|
|
86
|
+
"start": "node dist/index.js",
|
|
87
|
+
"db:migrate": "tsx src/db/migrate.ts",
|
|
88
|
+
"db:seed": "tsx src/db/seed.ts",
|
|
89
|
+
"typecheck": "tsc --noEmit",
|
|
90
|
+
"lint": "eslint src",
|
|
91
|
+
"test": "vitest run",
|
|
92
|
+
"test:watch": "vitest",
|
|
93
|
+
"test:coverage": "vitest run --coverage",
|
|
94
|
+
"kill:dev": "pkill -9 -f 'tsx.*watch' || true",
|
|
95
|
+
"clean": "rm -rf node_modules pnpm-lock.yaml dist"
|
|
96
|
+
}
|
|
97
|
+
}
|