@saulwade/swl-ses 1.0.0
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/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nextjs-testing
|
|
3
|
+
description: >
|
|
4
|
+
Testing Next.js con Vitest, React Testing Library, Playwright y MSW.
|
|
5
|
+
Cubre Server Components, Server Actions, page objects E2E y mocking de API.
|
|
6
|
+
Cargar cuando se escriban tests de componentes, integración o E2E en Next.js.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
herramientasPermitidas: [Read]
|
|
9
|
+
exclusiones:
|
|
10
|
+
- "No cargar para tests React puros fuera del contexto de Next.js (Vite, CRA, Remix) — los mocks del router de Next.js y los Server Components son específicos del framework."
|
|
11
|
+
- "No cargar para implementar la lógica del componente que se está testando — si aún no está implementado, cargar `nextjs-experto` primero; los tests se escriben sobre código existente."
|
|
12
|
+
- "No cargar para configurar Playwright en un proyecto no-Next.js — Playwright funciona con cualquier web app, pero este skill cubre la configuración específica de Next.js con `next/server` y Server Actions."
|
|
13
|
+
- "No cargar para cobertura de código o análisis de calidad de tests existentes — para métricas de calidad cargar `checklist-calidad`."
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
---
|
|
16
|
+
# Next.js Testing — Vitest, RTL, Playwright y MSW
|
|
17
|
+
|
|
18
|
+
El App Router introduce complejidad de testing: Server Components son async,
|
|
19
|
+
los Server Actions requieren contexto de servidor, y el router de Next.js necesita
|
|
20
|
+
mocks específicos. Este skill cubre la configuración y los patrones para cada tipo
|
|
21
|
+
de test en proyectos Next.js modernos.
|
|
22
|
+
|
|
23
|
+
## Cuándo cargar este skill
|
|
24
|
+
|
|
25
|
+
Invoca `Skill("nextjs-testing")` cuando:
|
|
26
|
+
|
|
27
|
+
- Se configuren Vitest o Jest para un proyecto Next.js
|
|
28
|
+
- Se escriban tests de componentes con React Testing Library
|
|
29
|
+
- Se implementen tests E2E con Playwright
|
|
30
|
+
- Se mockeen APIs externas con MSW en tests
|
|
31
|
+
- Se prueben Server Actions o route handlers
|
|
32
|
+
|
|
33
|
+
## Cuándo NO cargar
|
|
34
|
+
|
|
35
|
+
- El proyecto usa React sin Next.js (Vite, CRA, Remix) — los mocks de `next/navigation` y los patrones de Server Components son específicos de Next.js.
|
|
36
|
+
- El componente que se quiere testear no está implementado aún — primero implementar con `nextjs-experto`, luego escribir tests.
|
|
37
|
+
- La pregunta es sobre configurar Playwright en un proyecto no-Next.js — Playwright funciona con cualquier web app pero este skill cubre integración con `next/server` y Server Actions.
|
|
38
|
+
- La pregunta es sobre cobertura de código o análisis de calidad de tests existentes — para métricas de calidad cargar `checklist-calidad`.
|
|
39
|
+
|
|
40
|
+
## Conceptos clave
|
|
41
|
+
|
|
42
|
+
### Qué testear en Next.js
|
|
43
|
+
|
|
44
|
+
Server Components: testear la lógica de transformación de datos y el HTML
|
|
45
|
+
renderizado. Client Components: testear interacciones, estado y callbacks.
|
|
46
|
+
Server Actions: testear validación, mutaciones y revalidación. E2E: testear
|
|
47
|
+
flujos completos de usuario en el browser real.
|
|
48
|
+
|
|
49
|
+
### Vitest vs Jest
|
|
50
|
+
|
|
51
|
+
Vitest es la opción moderna: compatible con Vite, más rápido, soporte nativo
|
|
52
|
+
de ESM. Jest requiere más configuración para Next.js con App Router. Ambos son
|
|
53
|
+
compatibles con React Testing Library.
|
|
54
|
+
|
|
55
|
+
### MSW (Mock Service Worker)
|
|
56
|
+
|
|
57
|
+
MSW intercepta requests HTTP a nivel de Service Worker (browser) o a nivel de
|
|
58
|
+
Node.js (tests). Permite definir handlers una vez y usarlos en tests de unidad,
|
|
59
|
+
integracion y en el browser de desarrollo.
|
|
60
|
+
|
|
61
|
+
### Estrategia de cobertura por capas
|
|
62
|
+
|
|
63
|
+
Testear Next.js requiere una estrategia sistemática por capas. Cada capa cubre
|
|
64
|
+
un tipo de riesgo distinto — no son intercambiables:
|
|
65
|
+
|
|
66
|
+
| Capa | Qué testea | Herramienta | Ejemplo |
|
|
67
|
+
|------|-----------|-------------|---------|
|
|
68
|
+
| **Componente** | UI aislada, interacciones, estados visuales | Vitest + RTL | `render(<Boton />)` + click + assert texto |
|
|
69
|
+
| **Página (RSC)** | Data fetching + transformación + render | Vitest (async) | `await Pagina({params})` + assert contenido |
|
|
70
|
+
| **Hook** | Lógica reutilizable, efectos, estado | `renderHook` | `renderHook(() => useFiltros())` + act |
|
|
71
|
+
| **Integración** | Server Actions, validación + mutación + revalidación | Vitest + mocks BD | `await crearProducto(formData)` + assert BD |
|
|
72
|
+
| **E2E** | Flujos completos de usuario en browser real | Playwright | Navegar → llenar form → submit → verificar |
|
|
73
|
+
|
|
74
|
+
**Regla de proporción**: ~60% componente/página, ~25% integración, ~15% E2E.
|
|
75
|
+
Los tests E2E son lentos y frágiles — cubrir solo los flujos críticos de negocio.
|
|
76
|
+
Los tests de componente son baratos — cubrir todas las variantes de estado.
|
|
77
|
+
|
|
78
|
+
## Reglas obligatorias
|
|
79
|
+
|
|
80
|
+
### Configurar next/jest o Vitest correctamente antes de escribir cualquier test
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
// vitest.config.ts
|
|
84
|
+
import { defineConfig } from 'vitest/config';
|
|
85
|
+
import react from '@vitejs/plugin-react';
|
|
86
|
+
import path from 'path';
|
|
87
|
+
|
|
88
|
+
export default defineConfig({
|
|
89
|
+
plugins: [react()],
|
|
90
|
+
test: {
|
|
91
|
+
environment: 'jsdom',
|
|
92
|
+
setupFiles: ['./tests/setup.ts'],
|
|
93
|
+
globals: true,
|
|
94
|
+
},
|
|
95
|
+
resolve: {
|
|
96
|
+
alias: { '@': path.resolve(__dirname, './') },
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Mockear next/navigation y next/router SIEMPRE en tests de componentes
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// tests/setup.ts
|
|
105
|
+
vi.mock('next/navigation', () => ({
|
|
106
|
+
useRouter: () => ({ push: vi.fn(), replace: vi.fn(), prefetch: vi.fn() }),
|
|
107
|
+
useSearchParams: () => new URLSearchParams(),
|
|
108
|
+
usePathname: () => '/',
|
|
109
|
+
}));
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Sin este mock, cualquier componente que importe de `next/navigation` fallará.
|
|
113
|
+
|
|
114
|
+
### MSW handlers en archivo centralizado, no inline en cada test
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// tests/msw/handlers.ts
|
|
118
|
+
import { http, HttpResponse } from 'msw';
|
|
119
|
+
|
|
120
|
+
export const handlers = [
|
|
121
|
+
http.get('/api/productos', () => {
|
|
122
|
+
return HttpResponse.json({ data: [{ id: 1, nombre: 'Laptop' }] });
|
|
123
|
+
}),
|
|
124
|
+
http.post('/api/productos', async ({ request }) => {
|
|
125
|
+
const body = await request.json();
|
|
126
|
+
return HttpResponse.json({ data: { id: 99, ...body } }, { status: 201 });
|
|
127
|
+
}),
|
|
128
|
+
];
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Patrones recomendados
|
|
132
|
+
|
|
133
|
+
### Testing de Client Component con interacciones
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
137
|
+
import userEvent from '@testing-library/user-event';
|
|
138
|
+
import FormularioProducto from '@/components/FormularioProducto';
|
|
139
|
+
|
|
140
|
+
describe('FormularioProducto', () => {
|
|
141
|
+
it('envia el formulario con datos validos', async () => {
|
|
142
|
+
const user = userEvent.setup();
|
|
143
|
+
const mockSubmit = vi.fn();
|
|
144
|
+
|
|
145
|
+
render(<FormularioProducto onSubmit={mockSubmit} />);
|
|
146
|
+
|
|
147
|
+
await user.type(screen.getByLabelText('Nombre'), 'Laptop Pro');
|
|
148
|
+
await user.type(screen.getByLabelText('Precio'), '25000');
|
|
149
|
+
await user.click(screen.getByRole('button', { name: /guardar/i }));
|
|
150
|
+
|
|
151
|
+
await waitFor(() => {
|
|
152
|
+
expect(mockSubmit).toHaveBeenCalledWith({
|
|
153
|
+
nombre: 'Laptop Pro',
|
|
154
|
+
precio: 25000,
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('muestra error cuando el nombre esta vacio', async () => {
|
|
160
|
+
const user = userEvent.setup();
|
|
161
|
+
render(<FormularioProducto onSubmit={vi.fn()} />);
|
|
162
|
+
|
|
163
|
+
await user.click(screen.getByRole('button', { name: /guardar/i }));
|
|
164
|
+
|
|
165
|
+
expect(screen.getByText('El nombre es requerido')).toBeInTheDocument();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Testing de Server Component (async)
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { render, screen } from '@testing-library/react';
|
|
174
|
+
import ListaProductos from '@/app/productos/page';
|
|
175
|
+
|
|
176
|
+
// Mockear la función de fetch de datos
|
|
177
|
+
vi.mock('@/lib/api', () => ({
|
|
178
|
+
obtenerProductos: vi.fn().mockResolvedValue([
|
|
179
|
+
{ id: 1, nombre: 'Laptop', precio: 25000 },
|
|
180
|
+
{ id: 2, nombre: 'Mouse', precio: 500 },
|
|
181
|
+
]),
|
|
182
|
+
}));
|
|
183
|
+
|
|
184
|
+
it('renderiza lista de productos', async () => {
|
|
185
|
+
const ui = await ListaProductos({});
|
|
186
|
+
render(ui);
|
|
187
|
+
|
|
188
|
+
expect(screen.getByText('Laptop')).toBeInTheDocument();
|
|
189
|
+
expect(screen.getByText('Mouse')).toBeInTheDocument();
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Testing de Server Action
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { crearProducto } from '@/app/actions/productos';
|
|
197
|
+
import { db } from '@/lib/db';
|
|
198
|
+
|
|
199
|
+
vi.mock('@/lib/db');
|
|
200
|
+
vi.mock('@/lib/auth', () => ({
|
|
201
|
+
auth: vi.fn().mockResolvedValue({ user: { id: '1', rol: 'admin' } }),
|
|
202
|
+
}));
|
|
203
|
+
|
|
204
|
+
describe('crearProducto', () => {
|
|
205
|
+
it('crea producto con datos validos', async () => {
|
|
206
|
+
const formData = new FormData();
|
|
207
|
+
formData.append('nombre', 'Laptop Pro');
|
|
208
|
+
formData.append('precio', '25000');
|
|
209
|
+
|
|
210
|
+
const resultado = await crearProducto(formData);
|
|
211
|
+
|
|
212
|
+
expect(resultado).not.toHaveProperty('error');
|
|
213
|
+
expect(db.producto.create).toHaveBeenCalled();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('retorna errores de validacion con datos invalidos', async () => {
|
|
217
|
+
const formData = new FormData();
|
|
218
|
+
formData.append('nombre', ''); // invalido
|
|
219
|
+
|
|
220
|
+
const resultado = await crearProducto(formData);
|
|
221
|
+
|
|
222
|
+
expect(resultado?.error?.nombre).toBeDefined();
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Playwright Page Object para E2E
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// tests/e2e/pages/ProductosPage.ts
|
|
231
|
+
import { Page, Locator } from '@playwright/test';
|
|
232
|
+
|
|
233
|
+
export class ProductosPage {
|
|
234
|
+
readonly page: Page;
|
|
235
|
+
readonly botonNuevo: Locator;
|
|
236
|
+
readonly tablaProductos: Locator;
|
|
237
|
+
|
|
238
|
+
constructor(page: Page) {
|
|
239
|
+
this.page = page;
|
|
240
|
+
this.botonNuevo = page.getByRole('button', { name: 'Nuevo producto' });
|
|
241
|
+
this.tablaProductos = page.getByRole('table', { name: 'Productos' });
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async navegar() {
|
|
245
|
+
await this.page.goto('/dashboard/productos');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async crearProducto(nombre: string, precio: number) {
|
|
249
|
+
await this.botonNuevo.click();
|
|
250
|
+
await this.page.getByLabel('Nombre').fill(nombre);
|
|
251
|
+
await this.page.getByLabel('Precio').fill(precio.toString());
|
|
252
|
+
await this.page.getByRole('button', { name: 'Guardar' }).click();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// tests/e2e/productos.spec.ts
|
|
257
|
+
import { test, expect } from '@playwright/test';
|
|
258
|
+
import { ProductosPage } from './pages/ProductosPage';
|
|
259
|
+
|
|
260
|
+
test('admin puede crear un producto', async ({ page }) => {
|
|
261
|
+
const productosPage = new ProductosPage(page);
|
|
262
|
+
await productosPage.navegar();
|
|
263
|
+
await productosPage.crearProducto('Laptop Pro', 25000);
|
|
264
|
+
|
|
265
|
+
await expect(page.getByText('Laptop Pro')).toBeVisible();
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### MSW en tests de integración con servidor Node
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// tests/setup.ts
|
|
273
|
+
import { setupServer } from 'msw/node';
|
|
274
|
+
import { handlers } from './msw/handlers';
|
|
275
|
+
|
|
276
|
+
const server = setupServer(...handlers);
|
|
277
|
+
|
|
278
|
+
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
|
|
279
|
+
afterEach(() => server.resetHandlers());
|
|
280
|
+
afterAll(() => server.close());
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Anti-patrones conocidos
|
|
284
|
+
|
|
285
|
+
### getByTestId como primera opción
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// MAL — acoplado a detalles de implementación
|
|
289
|
+
screen.getByTestId('boton-submit');
|
|
290
|
+
|
|
291
|
+
// BIEN — accesible y más semántico
|
|
292
|
+
screen.getByRole('button', { name: /guardar/i });
|
|
293
|
+
screen.getByLabelText('Email');
|
|
294
|
+
screen.getByText('Confirmar pedido');
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Prioridad: getByRole > getByLabelText > getByPlaceholderText > getByText > getByTestId.
|
|
298
|
+
|
|
299
|
+
### Snapshot tests para componentes que cambian frecuentemente
|
|
300
|
+
|
|
301
|
+
Los snapshots se desactualizan y se actualizan sin revisar el cambio real.
|
|
302
|
+
Preferir assertions específicas sobre el contenido crítico.
|
|
303
|
+
|
|
304
|
+
## Gotchas / Errores comunes no obvios
|
|
305
|
+
|
|
306
|
+
**`vi.mock('next/navigation')` no afecta si se importa antes del mock**: si el componente bajo test importa `useRouter` en el nivel de módulo antes de que `vi.mock` se evalúe, el mock no se aplica. Causa: Vitest hoistea los `vi.mock()` al inicio del archivo, pero en algunos setups con transformaciones el orden puede fallar. Fix: asegurarse que `vi.mock('next/navigation', ...)` está en el archivo de setup global (`tests/setup.ts`) y se carga antes de cualquier import del componente.
|
|
307
|
+
|
|
308
|
+
**Server Component async no se puede renderizar directamente con `render()`**: `render(<MiServerComponent />)` falla con `Objects are not valid as a React child (found: [object Promise])` porque RTL no sabe manejar un componente async. Causa: React Testing Library en su versión estable no soporta async Server Components directamente. Fix: `await` el componente primero (`const ui = await MiServerComponent({params})`), luego `render(ui)`.
|
|
309
|
+
|
|
310
|
+
**MSW con `onUnhandledRequest: 'error'` falla en tests que hacen fetches a rutas internas de Next.js**: el test lanza error porque `_next/static/...` o rutas internas del framework generan requests que MSW no tiene handlers para. Causa: Next.js en modo test puede generar requests internos. Fix: usar `onUnhandledRequest: 'warn'` o agregar handlers para las rutas internas de Next.js, o filtrar con una función: `onUnhandledRequest: (req) => { if (!req.url.includes('_next')) throw new Error(...) }`.
|
|
311
|
+
|
|
312
|
+
**`userEvent.setup()` debe llamarse fuera del `it()` o re-instanciarse por test**: compartir una instancia de `userEvent` entre tests causa que el estado del puntero/teclado se acumule entre tests, causando comportamiento impredecible. Causa: `userEvent.setup()` crea un estado de dispositivo virtual que persiste. Fix: llamar `const user = userEvent.setup()` dentro de cada `it()` o en `beforeEach`, no al nivel de `describe`.
|
|
313
|
+
|
|
314
|
+
## Checklist de verificación
|
|
315
|
+
|
|
316
|
+
- [ ] Vitest/Jest configurado con next/jest transform o plugin react
|
|
317
|
+
- [ ] next/navigation mockeado en setup global de tests
|
|
318
|
+
- [ ] MSW handlers en archivo centralizado
|
|
319
|
+
- [ ] Tests de Client Component usan userEvent (no fireEvent para interacciones)
|
|
320
|
+
- [ ] Server Actions testeadas con FormData real
|
|
321
|
+
- [ ] E2E con Page Objects para reutilizar selectores
|
|
322
|
+
- [ ] `onUnhandledRequest: 'error'` en MSW para detectar fetches sin handler
|
|
323
|
+
|
|
324
|
+
## Referencias
|
|
325
|
+
|
|
326
|
+
- [Testing Next.js](https://nextjs.org/docs/app/building-your-application/testing)
|
|
327
|
+
- [MSW](https://mswjs.io/docs)
|
|
328
|
+
- [Playwright](https://playwright.dev/docs/intro)
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: node-experto
|
|
3
|
+
description: Node.js y TypeScript backend moderno. Cubre patterns de Express/Fastify/NestJS, error handling middleware, streams y buffers, worker threads y clustering, Prisma/Drizzle ORM, validación con Zod, graceful shutdown y anti-patrones críticos como callback hell y event loop blocking.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
herramientasPermitidas: [Read, Write, Glob]
|
|
6
|
+
exclusiones:
|
|
7
|
+
- "No cargar para aplicaciones Next.js con App Router — Next.js tiene patrones de Server Components, SSR y caché que difieren del backend Node puro; cargar `nextjs-experto`."
|
|
8
|
+
- "No cargar para proyectos NestJS con DI compleja — NestJS tiene su propio sistema de módulos y decoradores que merece su skill; cargar `nestjs-experto`."
|
|
9
|
+
- "No cargar para scripting Python o backend no-JS — este skill cubre el stack Node.js específicamente."
|
|
10
|
+
- "No cargar para errores de compilación TypeScript o tsconfig — para esos cargar `build-errors-typescript`; este skill asume que el código compila."
|
|
11
|
+
evolvable: true # default para skill estandar
|
|
12
|
+
---
|
|
13
|
+
# Node.js Experto — Backend TypeScript Moderno
|
|
14
|
+
|
|
15
|
+
## Cuándo NO cargar
|
|
16
|
+
|
|
17
|
+
- El proyecto usa Next.js App Router — los patrones de Server Components, SSR y caché son específicos de Next.js; cargar `nextjs-experto`.
|
|
18
|
+
- El proyecto usa NestJS con inyección de dependencias, decoradores y módulos — NestJS tiene su propio sistema opinionado; cargar `nestjs-experto`.
|
|
19
|
+
- El backend es Python, Go, Java u otro lenguaje no-JS — este skill cubre Node.js específicamente.
|
|
20
|
+
- La pregunta es sobre errores de compilación TypeScript o tsconfig — cargar `build-errors-typescript`; este skill asume que el código compila.
|
|
21
|
+
|
|
22
|
+
## Filosofía
|
|
23
|
+
|
|
24
|
+
Node.js es monohilo y asíncrono. Todo el rendimiento depende de
|
|
25
|
+
**no bloquear el event loop**. Operaciones I/O siempre asíncronas,
|
|
26
|
+
CPU-intensivo en worker threads, errores siempre manejados.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Frameworks: Cuándo Usar Cuál
|
|
31
|
+
|
|
32
|
+
| Framework | Usar cuando |
|
|
33
|
+
|-----------|------------|
|
|
34
|
+
| **Fastify** | API de alto rendimiento, microservicio |
|
|
35
|
+
| **Express** | Proyecto legacy, equipo familiarizado |
|
|
36
|
+
| **NestJS** | Aplicación empresarial grande, DI, estructura opinionada |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Error Handling — Reglas Obligatorias
|
|
41
|
+
|
|
42
|
+
1. **Jerarquía de errores tipados**: `AppError` > `ValidationError`, `NotFoundError`, etc.
|
|
43
|
+
2. **Error middleware SIEMPRE al final** de la cadena.
|
|
44
|
+
3. **`asyncHandler` wrapper** para capturar errores async sin try/catch repetido.
|
|
45
|
+
4. **Errores operacionales** (400, 404): respuesta descriptiva al cliente.
|
|
46
|
+
5. **Errores no esperados** (500): log completo, respuesta genérica. NUNCA stack traces al cliente.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
export class AppError extends Error {
|
|
50
|
+
constructor(
|
|
51
|
+
public readonly message: string,
|
|
52
|
+
public readonly statusCode: number,
|
|
53
|
+
public readonly code: string,
|
|
54
|
+
public readonly isOperational = true,
|
|
55
|
+
) {
|
|
56
|
+
super(message);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class NotFoundError extends AppError {
|
|
61
|
+
constructor(resource: string, id: string) {
|
|
62
|
+
super(`${resource} con id ${id} no encontrado`, 404, 'NOT_FOUND');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Streams — Reglas
|
|
70
|
+
|
|
71
|
+
- SIEMPRE usar `pipeline()` de `stream/promises` (maneja errores y backpressure).
|
|
72
|
+
- Para archivos grandes: NUNCA cargar todo en memoria. Usar streams.
|
|
73
|
+
- Para respuestas HTTP grandes: `Readable.from()` con generador async.
|
|
74
|
+
- Concatenar buffers con `Buffer.concat()`, NUNCA con `+=` de strings.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Worker Threads y Clustering
|
|
79
|
+
|
|
80
|
+
- CPU-intensivo SIEMPRE en worker threads, NUNCA en el hilo principal.
|
|
81
|
+
- Pool de workers con Piscina para reutilización.
|
|
82
|
+
- Clustering: un worker por CPU core con auto-restart en muerte.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## ORM — Prisma y Drizzle
|
|
87
|
+
|
|
88
|
+
- **Prisma**: singleton con `globalThis` para evitar múltiples conexiones.
|
|
89
|
+
- **Transacciones**: `prisma.$transaction()` para operaciones atómicas.
|
|
90
|
+
- **Drizzle**: esquema tipado con `pgTable`, queries type-safe.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Validación con Zod
|
|
95
|
+
|
|
96
|
+
- Schemas reutilizables con `z.infer<typeof Schema>` para tipos.
|
|
97
|
+
- Middleware `validar(schema)` que parsea y lanza `ValidationError` automáticamente.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Graceful Shutdown — OBLIGATORIO
|
|
102
|
+
|
|
103
|
+
1. Dejar de aceptar nuevas conexiones: `server.close()`
|
|
104
|
+
2. Cerrar conexiones a BD: `prisma.$disconnect()`
|
|
105
|
+
3. Timeout de seguridad (10s) para forzar cierre.
|
|
106
|
+
4. Capturar `SIGTERM`, `SIGINT`, `unhandledRejection`, `uncaughtException`.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Anti-patrones Críticos
|
|
111
|
+
|
|
112
|
+
| Anti-patrón | Corrección |
|
|
113
|
+
|-------------|------------|
|
|
114
|
+
| Callback hell | async/await |
|
|
115
|
+
| `crypto.pbkdf2Sync` en handler | Worker thread |
|
|
116
|
+
| `promise.then()` sin `.catch()` | asyncHandler o try/catch |
|
|
117
|
+
| `require()` dinámico en hot path | Importar al inicio |
|
|
118
|
+
| Operaciones síncronas de fs en requests | `fs.promises.*` |
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// MAL: bloquea el event loop
|
|
122
|
+
const hash = crypto.pbkdf2Sync(pass, salt, 100000, 64, 'sha512');
|
|
123
|
+
|
|
124
|
+
// BIEN: en worker thread
|
|
125
|
+
const hash = await pool.run({ pass, salt });
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Checklist Node.js
|
|
131
|
+
|
|
132
|
+
- [ ] NUNCA bloquear el event loop con operaciones síncronas
|
|
133
|
+
- [ ] Error middleware al final de la cadena
|
|
134
|
+
- [ ] Graceful shutdown implementado
|
|
135
|
+
- [ ] CPU-intensivo en worker threads
|
|
136
|
+
- [ ] Streams para archivos/respuestas grandes
|
|
137
|
+
- [ ] Validación de input con Zod
|
|
138
|
+
- [ ] Singleton de Prisma client
|
|
139
|
+
- [ ] `unhandledRejection` y `uncaughtException` capturados
|
|
140
|
+
|
|
141
|
+
Para implementaciones completas de Fastify, Express, streams, workers, ORMs, Zod y graceful shutdown, ver [recursos/patrones-completos.md](recursos/patrones-completos.md).
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Gotchas de JSDoc y comentarios multilínea
|
|
146
|
+
|
|
147
|
+
### NUNCA usar glob `*` dentro de bloques `/** */`
|
|
148
|
+
|
|
149
|
+
**Problema**: El patrón `habilidades/*/SKILL.md` dentro de un bloque JSDoc `/** ... */`
|
|
150
|
+
es interpretado por el parser JS como cierre del comentario en `*/`.
|
|
151
|
+
Produce `SyntaxError: Unexpected identifier` al cargar el módulo.
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
// MAL — el */ en "habilidades/*/SKILL.md" cierra el bloque JSDoc prematuramente
|
|
155
|
+
/**
|
|
156
|
+
* Scannea habilidades/*/SKILL.md y extrae metadata.
|
|
157
|
+
* ^ este */ cierra el comentario aquí
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
// BIEN — usar <nombre> o texto descriptivo sin glob en JSDoc
|
|
161
|
+
/**
|
|
162
|
+
* Scannea habilidades/<nombre>/SKILL.md y extrae metadata.
|
|
163
|
+
*/
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Este mismo anti-patrón aplica a cualquier ruta con `*/` dentro de `/** */`:
|
|
167
|
+
`src/*/index.js`, `dist/**/*.js`, etc.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Patrones de I/O para observabilidad
|
|
172
|
+
|
|
173
|
+
### JSONL + `appendFileSync` para streams de eventos de alta frecuencia
|
|
174
|
+
|
|
175
|
+
Para archivos de telemetría, auditoría o logs append-only, `fs.appendFileSync` es
|
|
176
|
+
superior a escritura atómica JSON:
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
// MAL para eventos frecuentes — lee y reescribe todo el archivo cada vez
|
|
180
|
+
const eventos = JSON.parse(fs.readFileSync(archivo, 'utf8'));
|
|
181
|
+
eventos.push(nuevoEvento);
|
|
182
|
+
fs.writeFileSync(archivo, JSON.stringify(eventos, null, 2));
|
|
183
|
+
|
|
184
|
+
// BIEN — append-only O(1), sin leer el archivo existente
|
|
185
|
+
fs.appendFileSync(archivo, JSON.stringify(nuevoEvento) + '\n', 'utf8');
|
|
186
|
+
|
|
187
|
+
// Para leer de vuelta: parsear línea a línea
|
|
188
|
+
const eventos = fs.readFileSync(archivo, 'utf8')
|
|
189
|
+
.split('\n').filter(Boolean).map(l => JSON.parse(l));
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Usar `atomicWriteJSON` para archivos de estado (mutation frecuente).
|
|
193
|
+
Usar `appendFileSync` para archivos de eventos (solo escritura secuencial).
|
|
194
|
+
|
|
195
|
+
### Webhook fire-and-forget con `http`/`https` nativo (zero-deps)
|
|
196
|
+
|
|
197
|
+
Para exportaciones opcionales (OTLP, audit webhooks, Slack, Datadog):
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
const http = require('http');
|
|
201
|
+
const https = require('https');
|
|
202
|
+
|
|
203
|
+
function enviarWebhookAsync(url, payload) {
|
|
204
|
+
if (!url) return; // No lanzar si no está configurado
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
const body = JSON.stringify(payload);
|
|
208
|
+
const parsed = new URL(url);
|
|
209
|
+
const modulo = parsed.protocol === 'https:' ? https : http;
|
|
210
|
+
|
|
211
|
+
const req = modulo.request({
|
|
212
|
+
hostname: parsed.hostname,
|
|
213
|
+
port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
|
|
214
|
+
path: parsed.pathname + (parsed.search || ''),
|
|
215
|
+
method: 'POST',
|
|
216
|
+
headers: {
|
|
217
|
+
'Content-Type': 'application/json',
|
|
218
|
+
'Content-Length': Buffer.byteLength(body),
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
req.on('error', () => {}); // Silencioso — nunca interrumpir el flujo principal
|
|
222
|
+
req.write(body);
|
|
223
|
+
req.end();
|
|
224
|
+
} catch (_) {}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Verificar siempre `process.env.WEBHOOK_URL` antes de llamar — sin config requerida.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Scripts dual-use: librería + CLI
|
|
233
|
+
|
|
234
|
+
### `require.main === module` para scripts en `scripts/lib/`
|
|
235
|
+
|
|
236
|
+
Permite que el mismo archivo funcione como librería importable Y como CLI
|
|
237
|
+
sin duplicar lógica:
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
// scripts/lib/mi-script.js
|
|
241
|
+
function miFuncion(cwd) { /* ... */ }
|
|
242
|
+
module.exports = { miFuncion };
|
|
243
|
+
|
|
244
|
+
// Solo se ejecuta cuando se invoca directamente con `node scripts/lib/mi-script.js`
|
|
245
|
+
// NO se ejecuta cuando otro módulo lo importa con require('./mi-script')
|
|
246
|
+
if (require.main === module) {
|
|
247
|
+
const args = process.argv.slice(2);
|
|
248
|
+
const query = args.filter(a => !a.startsWith('--'))[0] || '';
|
|
249
|
+
const resultado = miFuncion(process.cwd(), query);
|
|
250
|
+
process.stdout.write(JSON.stringify(resultado, null, 2) + '\n');
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Gotchas / Errores comunes no obvios
|
|
257
|
+
|
|
258
|
+
**Prisma Client creado en cada request agota el pool de conexiones**: instanciar `new PrismaClient()` dentro de un handler crea una nueva pool por cada request. En producción esto provoca `Too many connections` en la BD. Fix: exportar un singleton con el patrón `globalThis.__prisma || new PrismaClient()` y reutilizarlo en todos los handlers.
|
|
259
|
+
|
|
260
|
+
**`unhandledRejection` no captura errores en callbacks síncronos dentro de Promises**: el handler `process.on('unhandledRejection', ...)` captura promesas rechazadas sin `.catch()`, pero no captura errores lanzados en código síncrono dentro de un `Promise` executor si ese error no se propaga al reject. Causa: `new Promise((resolve, reject) => { throw new Error('X') })` sí se captura, pero `setTimeout(() => { throw new Error('X') }, 0)` dentro de una promesa no. Fix: usar `uncaughtException` también, y never usar setTimeout con código que puede lanzar dentro de promesas.
|
|
261
|
+
|
|
262
|
+
**`stream.pipeline()` no limpia streams en versiones < Node 16 con errores en mitad del pipe**: en Node 14, un error en un transform stream intermedio deja el readable stream sin destruir, causando memory leak. Fix: usar Node 18+ o agregar listeners de `error` en cada stream del pipeline manualmente en proyectos que deben soportar Node 14/16.
|
|
263
|
+
|
|
264
|
+
**Zod `.parse()` vs `.safeParse()` en middleware**: usar `schema.parse(body)` en un middleware Express lanza una excepción no capturada si no hay un try/catch, y el error llega al cliente con stack trace completo. Fix: usar siempre `schema.safeParse(body)` en middleware y verificar `result.success` antes de continuar; pasar `result.error` al error handler con `next(result.error)`.
|
|
265
|
+
|
|
266
|
+
**`response.json()` sobre body vacío lanza `SyntaxError: Unexpected end of JSON input`**: cuando el servidor responde con 204 No Content, 205 Reset Content, o con `Content-Length: 0`, el body está vacío — `fetch(...).then(r => r.json())` falla en el cliente porque JSON.parse sobre string vacío lanza excepción. Causa: el contrato de fetch no verifica el status antes de parsear; el cliente asume que siempre hay JSON. Fix: verificar status y Content-Length antes de parsear: `if (r.status === 204 || r.status === 205 || r.headers.get('content-length') === '0') return null;`. Si el servidor FastAPI retorna 200 con body vacío por bug, considerar helper `await r.text()` antes y `JSON.parse` con try/catch — o mejor, devolver 204 explícito en endpoints que no retornan cuerpo.
|