diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..a328804 --- /dev/null +++ b/.env.example @@ -0,0 +1,83 @@ +# Archivo de variables de entorno para CSF Web Interface +# Copie este archivo a .env.local y modifique los valores según sea necesario + +# ====== SEGURIDAD ====== +# Clave secreta para JWT (CAMBIAR EN PRODUCCIÓN) +JWT_SECRET=csf-web-super-secret-jwt-key-change-this-in-production + +# Modo de entorno +NODE_ENV=development + +# ====== CONFIGURACIÓN WEB ====== +# Puerto para la interfaz web +PORT=3000 + +# Hostname para la aplicación +HOSTNAME=0.0.0.0 + +# URL pública de la API (para cliente) +NEXT_PUBLIC_API_URL=http://localhost:3000 + +# ====== CONFIGURACIÓN CSF ====== +# Rutas de configuración CSF (ajustar según instalación) +CSF_CONFIG_PATH=/etc/csf +CSF_LOG_PATH=/var/log/lfd +CSF_BIN_PATH=/usr/local/csf/bin + +# ====== AUTENTICACIÓN ====== +# Credenciales de administrador por defecto (CAMBIAR EN PRODUCCIÓN) +ADMIN_USERNAME=admin +ADMIN_PASSWORD=admin123 + +# Duración del token JWT (en horas) +JWT_EXPIRES_IN=24h + +# ====== API EXTERNA ====== +# URLs de servicios externos (opcional) +EXTERNAL_API_URL= +WEBHOOK_URL= + +# ====== DESARROLLO ====== +# Habilitar logs de desarrollo +DEBUG=true + +# Habilitar hot reload para WebSockets +SOCKET_DEBUG=false + +# ====== MONITOREO ====== +# Interval de actualización de estadísticas (milisegundos) +STATS_UPDATE_INTERVAL=5000 + +# Interval de actualización de logs (milisegundos) +LOGS_UPDATE_INTERVAL=10000 + +# Límite máximo de logs en memoria +MAX_LOGS_IN_MEMORY=500 + +# ====== SEGURIDAD ADICIONAL ====== +# Habilitar rate limiting +ENABLE_RATE_LIMITING=false + +# Máximo de intentos de login +MAX_LOGIN_ATTEMPTS=5 + +# Tiempo de bloqueo después de intentos fallidos (minutos) +LOGIN_LOCKOUT_TIME=15 + +# ====== CORS ====== +# Orígenes permitidos para CORS (separados por coma) +ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 + +# ====== ARCHIVOS ====== +# Directorio para archivos temporales +TEMP_DIR=/tmp + +# Directorio para logs de la aplicación +APP_LOG_DIR=./logs + +# ====== PERFORMANCE ====== +# Límite de memoria para Node.js (MB) +NODE_OPTIONS=--max-old-space-size=1024 + +# Timeout para comandos CSF (milisegundos) +CSF_COMMAND_TIMEOUT=30000 \ No newline at end of file diff --git a/.gitignore b/.gitignore index ce0065c..43881da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies +# Dependencies /node_modules /.pnp .pnp.* @@ -9,36 +7,133 @@ !.yarn/plugins !.yarn/releases !.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* +*.lock +*-lock.json -# env files (can opt-in for committing if needed) +# Testing +/coverage +*.lcov + +# Next.js +/.next/ +/out/ +.next/ + +# Production builds +/build +/dist + +# Environment variables .env* +!.env.example -# vercel +# Vercel .vercel -# typescript +# TypeScript *.tsbuildinfo next-env.d.ts +/types/generated -*.lock -*-lock.json \ No newline at end of file +# IDE and editors +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +logs/ +*.log +/logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids/ +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Storybook build outputs +.out +.storybook-out + +# Temporary folders +tmp/ +temp/ +.tmp/ + +# Backup files +*.backup +*.bak +*.orig + +# Docker +docker-compose.override.yml +.docker/ + +# CSF specific +/csf-data/ +/csf-logs/ +/csf-backup/ + +# Development +.cache/ +.parcel-cache/ + +# Editor directories and files +.vscode/ +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..47ce85b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,122 @@ +# CHANGELOG - CSF Web Interface + +Todos los cambios notables de este proyecto serán documentados en este archivo. + +## [1.0.0] - 2025-09-20 + +### ✨ Agregado +- **Panel de Administración Completo**: Interfaz web moderna para CSF +- **Autenticación JWT**: Sistema de login seguro con cookies httpOnly +- **Dashboard Interactivo**: Navegación por pestañas con estado del firewall +- **Gestión de Reglas**: CRUD completo para reglas allow/deny/temporales +- **Monitoreo Tiempo Real**: WebSockets para estadísticas y logs en vivo +- **API REST Completa**: Endpoints para control total de CSF +- **Estadísticas del Sistema**: CPU, memoria, disco, red y conexiones +- **Validación de Entrada**: Verificación de IPs y puertos +- **Interfaz Responsive**: Compatible con dispositivos móviles +- **Indicadores Visuales**: Estado de conexión y salud del sistema + +### 🔧 Técnico +- **Framework**: Next.js 15 con App Router +- **UI Library**: React 19 con hooks modernos +- **Styling**: Tailwind CSS 4 con componentes Radix UI +- **Tipos**: TypeScript 5.2 con tipado estricto +- **Estado**: Zustand para gestión de estado global +- **WebSockets**: Socket.IO para datos en tiempo real +- **Build**: Turbopack para compilación rápida +- **Linting**: ESLint con reglas de Next.js + +### 🛡️ Seguridad +- Headers de seguridad configurados (CSP, XSS Protection, etc.) +- Validación de entrada en todas las APIs +- Sanitización de datos de salida +- Protección contra CSRF +- Gestión segura de sesiones + +### 📡 APIs Implementadas +- `POST /api/auth` - Sistema de autenticación +- `GET /api/csf` - Estado y control del firewall +- `GET|POST|DELETE /api/rules` - Gestión de reglas +- `GET /api/logs` - Acceso a logs del sistema +- `GET /api/stats` - Estadísticas del servidor +- `GET|POST /api/config` - Configuración de CSF +- `GET /api/health` - Health check para Docker +- `WebSocket /api/socket` - Datos en tiempo real + +### 🎨 Componentes UI +- `Dashboard` - Panel principal con pestañas +- `FirewallStatusCard` - Estado y controles del firewall +- `ServerStats` - Métricas del sistema con gráficos +- `FirewallRules` - Tabla de reglas con búsqueda +- `LoginForm` - Formulario de autenticación +- `AuthWrapper` - Wrapper de autenticación +- `RealtimeIndicator` - Indicador de conexión WebSocket + +### 🪝 Hooks Personalizados +- `useAuth` - Gestión de autenticación +- `useCSFApi` - Interacción con APIs de CSF +- `useRealtimeData` - Conexión WebSocket + +### 🔧 Configuración +- **next.config.mjs**: Configuración de Next.js con standalone output +- **tsconfig.json**: Configuración de TypeScript +- **tailwind.config.js**: Configuración de Tailwind CSS +- **package.json**: Dependencias y scripts de build + +### 📦 Dependencias Principales +```json +{ + "next": "15.5.3", + "react": "19.1.0", + "typescript": "5.2.2", + "tailwindcss": "4.0", + "socket.io": "4.8.1", + "jsonwebtoken": "9.0.2", + "zustand": "5.0.1" +} +``` + +### 🚀 Scripts Disponibles +- `npm run dev` - Servidor de desarrollo +- `npm run build` - Build de producción +- `npm run start` - Servidor de producción +- `npm run type-check` - Verificación de tipos +- `npm run lint` - Linting de código +- `npm run setup` - Setup completo + +### 🐳 Docker +- Optimizado para contenedores Docker +- Build standalone para menor tamaño +- Variables de entorno configurables +- Health checks integrados + +### 📝 Documentación +- README.md completo con guías de instalación +- Comentarios en código TypeScript +- Documentación de APIs +- Ejemplos de uso + +### 🔍 Testing +- Verificación de tipos con TypeScript +- Linting con ESLint +- Build testing automático + +## Próximas Versiones + +### [1.1.0] - Planificado +- [ ] Visor de logs avanzado con filtros +- [ ] Exportación de configuraciones +- [ ] Gráficos de métricas históricas +- [ ] Notificaciones push +- [ ] Tema oscuro/claro + +### [1.2.0] - Planificado +- [ ] Multi-idioma (i18n) +- [ ] Roles y permisos de usuario +- [ ] API de webhooks +- [ ] Integración con Prometheus +- [ ] Tests unitarios e integración + +--- + +**Nota**: Todas las fechas están en formato YYYY-MM-DD. \ No newline at end of file diff --git a/README.md b/README.md index 66bb426..aeeb6e6 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,405 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +# CSF Web Interface -## Getting Started +Interfaz web moderna para **ConfigServer Security & Firewall (CSF)** construida con Next.js 15, React 19 y TypeScript. -First, run the development server: +![Next.js](https://img.shields.io/badge/Next.js-15-black) +![React](https://img.shields.io/badge/React-19-blue) +![TypeScript](https://img.shields.io/badge/TypeScript-5.2-blue) +![Tailwind](https://img.shields.io/badge/Tailwind-4.0-06B6D4) -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +## 🚀 Características + +- **🎨 Interfaz Moderna**: UI responsive construida con Tailwind CSS +- **⚡ Tiempo Real**: WebSockets para actualizaciones en vivo +- **🔐 Autenticación Segura**: Sistema JWT con cookies httpOnly +- **📊 Dashboard Completo**: Estadísticas, logs y monitoreo del sistema +- **🛡️ Gestión de Reglas**: Control total de reglas allow/deny/temporal +- **📈 Monitoreo en Vivo**: CPU, memoria, red y conexiones +- **🔄 API REST**: Endpoints completos para control de CSF +- **🌐 WebSocket**: Datos en tiempo real sin polling + +## 📁 Estructura del Proyecto + +``` +csf-web/ +├── 📁 public/ # Archivos estáticos +├── 📁 src/ +│ ├── 📁 app/ # App Router (Next.js 15) +│ │ ├── 📁 api/ # API Routes +│ │ │ ├── 📄 auth/route.ts # Autenticación +│ │ │ ├── 📄 csf/route.ts # Control CSF +│ │ │ ├── 📄 rules/route.ts # Gestión reglas +│ │ │ ├── 📄 logs/route.ts # Logs del sistema +│ │ │ ├── 📄 stats/route.ts # Estadísticas +│ │ │ ├── 📄 config/route.ts # Configuración +│ │ │ └── 📄 health/route.ts # Health check +│ │ ├── 📄 layout.tsx # Layout principal +│ │ ├── 📄 page.tsx # Página principal +│ │ └── 📄 globals.css # Estilos globales +│ ├── 📁 components/ # Componentes React +│ │ ├── 📄 Dashboard.tsx # Dashboard principal +│ │ ├── 📄 FirewallStatusCard.tsx # Estado del firewall +│ │ ├── 📄 ServerStats.tsx # Estadísticas servidor +│ │ ├── 📄 FirewallRules.tsx # Gestión de reglas +│ │ ├── 📄 LogViewer.tsx # Visor de logs +│ │ ├── 📄 LoginForm.tsx # Formulario login +│ │ ├── 📄 AuthWrapper.tsx # Wrapper autenticación +│ │ └── 📄 RealtimeIndicator.tsx # Indicador tiempo real +│ ├── 📁 hooks/ # Hooks personalizados +│ │ ├── 📄 use-auth.ts # Hook autenticación +│ │ ├── 📄 use-csf-api.ts # Hook API CSF +│ │ └── 📄 use-realtime-data.ts # Hook WebSocket +│ ├── 📁 lib/ # Utilidades +│ │ └── 📄 utils.ts # Funciones utilitarias +│ ├── 📁 store/ # Estado global +│ │ └── 📄 csf-store.ts # Store Zustand +│ ├── 📁 types/ # Tipos TypeScript +│ │ └── 📄 csf.ts # Tipos CSF +│ └── 📁 pages/ # Pages API (WebSocket) +│ └── 📁 api/ +│ └── 📄 socket.ts # WebSocket handler +├── 📄 package.json # Dependencias +├── 📄 next.config.mjs # Configuración Next.js +├── 📄 tailwind.config.js # Configuración Tailwind +├── 📄 tsconfig.json # Configuración TypeScript +├── 📄 jsconfig.json # Configuración JavaScript +└── 📄 README.md # Este archivo ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +## 🛠️ Instalación y Desarrollo -You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. +### Prerrequisitos -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +- Node.js 18.17 o superior +- npm 9.0 o superior -## Learn More +### Instalación -To learn more about Next.js, take a look at the following resources: +```bash +# Instalar dependencias +npm install --legacy-peer-deps -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +# Configurar variables de entorno +cp .env.example .env.local +``` -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +### Variables de Entorno -## Deploy on Vercel +Crear archivo `.env.local` con: -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +```bash +# Seguridad +JWT_SECRET=your-super-secret-jwt-key-here +NODE_ENV=development -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +# API +NEXT_PUBLIC_API_URL=http://localhost:3000 + +# CSF Paths (para desarrollo local) +CSF_CONFIG_PATH=/etc/csf +CSF_LOG_PATH=/var/log/lfd +CSF_BIN_PATH=/usr/local/csf/bin +``` + +### Comandos de Desarrollo + +```bash +# Desarrollo con hot reload +npm run dev + +# Construir para producción +npm run build + +# Iniciar servidor de producción +npm start + +# Verificar tipos TypeScript +npm run type-check + +# Linting +npm run lint + +# Setup completo +npm run setup +``` + +## 🔧 Tecnologías Utilizadas + +### Frontend +- **Next.js 15**: Framework React con App Router +- **React 19**: Biblioteca de interfaces de usuario +- **TypeScript 5.2**: Tipado estático +- **Tailwind CSS 4**: Framework CSS utilitario +- **Radix UI**: Componentes primitivos accesibles + +### Estado y Datos +- **Zustand 5**: Gestión de estado global +- **Socket.IO Client**: WebSocket para tiempo real +- **React Hooks**: Estado local y efectos + +### Autenticación +- **JWT**: Tokens de autenticación +- **bcrypt**: Hash de contraseñas +- **Cookies httpOnly**: Almacenamiento seguro + +### Desarrollo +- **ESLint**: Linting de código +- **Prettier**: Formateo de código +- **TypeScript**: Análisis de tipos + +## 📡 API Routes + +### Autenticación (`/api/auth`) +```typescript +// Login +POST /api/auth +Body: { username: string, password: string } + +// Verificar sesión +GET /api/auth + +// Logout +DELETE /api/auth +``` + +### Control CSF (`/api/csf`) +```typescript +// Estado del firewall +GET /api/csf?action=status|version|check + +// Ejecutar comandos +POST /api/csf +Body: { action: "start"|"stop"|"restart"|"enable"|"disable", args?: string[] } +``` + +### Gestión de Reglas (`/api/rules`) +```typescript +// Obtener reglas +GET /api/rules?type=all|allow|deny|temp + +// Agregar regla +POST /api/rules +Body: { action: string, ip: string, comment?: string } + +// Eliminar regla +DELETE /api/rules?ip=&type=allow|deny +``` + +### Logs del Sistema (`/api/logs`) +```typescript +// Obtener logs +GET /api/logs?type=firewall|lfd|system|blocked&limit=100&since= +``` + +### Estadísticas (`/api/stats`) +```typescript +// Estadísticas del servidor +GET /api/stats + +// Estadísticas en tiempo real +POST /api/stats +Body: { interval: number } +``` + +## 🔌 WebSocket Events + +### Cliente → Servidor +```typescript +// Solicitar estadísticas +socket.emit('request-stats') + +// Solicitar logs +socket.emit('request-logs', { limit: 50 }) +``` + +### Servidor → Cliente +```typescript +// Datos de estadísticas +socket.on('stats', (data: ServerStats) => {}) + +// Nuevos logs +socket.on('logs', (data: LogEntry[]) => {}) + +// Estado de conexión +socket.on('connected', (data: { message: string }) => {}) +``` + +## 🎨 Componentes Principales + +### Dashboard +```tsx +// Dashboard principal con navegación + +``` + +### Autenticación +```tsx +// Wrapper de autenticación + + + + +// Formulario de login + +``` + +### Firewall +```tsx +// Estado del firewall + + +// Gestión de reglas + + +// Estadísticas del servidor + +``` + +### Utilidades +```tsx +// Indicador de conexión en tiempo real + + +// Visor de logs (placeholder) + +``` + +## 🪝 Hooks Personalizados + +### useAuth +```typescript +const { user, login, logout, loading, error } = useAuth() +``` + +### useCSFApi +```typescript +const { + status, rules, logs, stats, + startFirewall, stopFirewall, addRule, + loading, error +} = useCSFApi() +``` + +### useRealtimeData +```typescript +const { + connected, stats, logs, + connect, disconnect, requestStats +} = useRealtimeData() +``` + +## 🔒 Seguridad + +### Autenticación +- JWT con cookies httpOnly y secure +- Protección CSRF automática +- Validación de tokens en cada request + +### API Security +- Validación de entrada en todos los endpoints +- Rate limiting (recomendado para producción) +- Headers de seguridad configurados + +### Configuración de Seguridad +```javascript +// next.config.mjs +headers: [ + 'X-Frame-Options': 'DENY', + 'X-Content-Type-Options': 'nosniff', + 'X-XSS-Protection': '1; mode=block', + 'Referrer-Policy': 'strict-origin-when-cross-origin' +] +``` + +## 🚀 Despliegue + +### Desarrollo Local +```bash +npm run dev +# Acceso: http://localhost:3000 +``` + +### Docker (Ver docker-compose.yml en raíz) +```bash +# Desde el directorio raíz del proyecto +docker-compose up -d +``` + +### Producción +```bash +npm run build +npm start +``` + +## 🐛 Resolución de Problemas + +### Error de dependencias +```bash +# Limpiar cache e instalar +rm -rf node_modules package-lock.json +npm install --legacy-peer-deps +``` + +### Errores de TypeScript +```bash +# Verificar tipos +npm run type-check + +# Reiniciar servidor TypeScript en VS Code +Cmd/Ctrl + Shift + P → "TypeScript: Restart TS Server" +``` + +### Problemas de WebSocket +```bash +# Verificar que el servidor WebSocket esté ejecutándose +curl http://localhost:3000/api/socket +``` + +### Errores de CSF API +- Verificar que CSF esté instalado y funcional +- Revisar permisos de archivos de configuración +- Comprobar rutas de CSF en variables de entorno + +## 📈 Monitoreo y Logs + +### Logs de la Aplicación +```bash +# Desarrollo +tail -f .next/server.log + +# Producción (Docker) +docker logs csf-web-interface -f +``` + +### Métricas de Rendimiento +- Usar herramientas de desarrollo de React +- Monitorear WebSocket connections +- Revisar uso de memoria en estadísticas + +## 🤝 Contribución + +1. Fork el repositorio +2. Crear rama feature: `git checkout -b feature/nueva-caracteristica` +3. Commit cambios: `git commit -am 'Agregar nueva característica'` +4. Push a la rama: `git push origin feature/nueva-caracteristica` +5. Crear Pull Request + +### Estándares de Código +- Usar TypeScript para todo el código +- Seguir convenciones de React Hooks +- Mantener componentes pequeños y reutilizables +- Documentar APIs y componentes complejos + +## 📝 Licencia + +GPL v3 - Ver archivo LICENSE en el directorio raíz. + +## 🆘 Soporte + +- 📧 Email: soporte@ejemplo.com +- 🐛 Issues: [GitHub Issues](../../issues) +- 📚 Docs: Consultar este README.md + +--- + +**Desarrollado con ❤️ para administrar CSF de manera moderna y eficiente.** diff --git a/next.config.mjs b/next.config.mjs index 5ca2ec1..3acb71f 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -41,9 +41,7 @@ const nextConfig = { }, // Configuración para desarrollo - experimental: { - serverComponentsExternalPackages: [] - } + serverExternalPackages: [] }; export default nextConfig; diff --git a/src/app/api/logs/route.ts b/src/app/api/logs/route.ts index 92431dd..2ce6f48 100644 --- a/src/app/api/logs/route.ts +++ b/src/app/api/logs/route.ts @@ -9,7 +9,7 @@ export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url) const type = searchParams.get('type') const limit = parseInt(searchParams.get('limit') || '100') - const since = searchParams.get('since') // timestamp + const since = searchParams.get('since') || undefined // timestamp try { switch (type) { diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index 97ac21e..1a7ab56 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -4,7 +4,6 @@ import { useState } from 'react' import { FirewallStatusCard } from './FirewallStatusCard' import { ServerStats } from './ServerStats' import { FirewallRules } from './FirewallRules' -import { LogViewer } from './LogViewer' import { RealtimeIndicator } from './RealtimeIndicator' import { useRealtimeData } from '@/hooks/use-realtime-data' @@ -147,7 +146,17 @@ export function Dashboard() { )} {activeTab === 'logs' && ( - +
+

Logs del Sistema

+
+

+ El visor de logs avanzado estará disponible próximamente. +

+

+ Por ahora puedes monitorear la actividad desde el dashboard principal. +

+
+
)} {activeTab === 'config' && ( @@ -158,7 +167,7 @@ export function Dashboard() { La configuración avanzada del firewall CSF estará disponible próximamente.

- Por ahora puedes gestionar las reglas básicas desde la pestaña "Reglas". + Por ahora puedes gestionar las reglas básicas desde la pestaña "Reglas".

diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a4bed24..f876421 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -94,7 +94,7 @@ export function debounce any>( func: T, wait: number ): (...args: Parameters) => void { - let timeout: NodeJS.Timeout + let timeout: ReturnType return (...args: Parameters) => { clearTimeout(timeout) timeout = setTimeout(() => func(...args), wait)