Compare commits
22 Commits
1db7b228bd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 858e2d9dd4 | |||
| fc90b0df00 | |||
| 8f454e89ba | |||
| 5f956cdac9 | |||
| 1c85ce772b | |||
| 1e421864fa | |||
| bfa0ab4394 | |||
| 7cfc1724d3 | |||
| a81e273364 | |||
| 7c877e03ba | |||
| 7d2a72b166 | |||
| e596342950 | |||
| 37612a7b81 | |||
| 1972b016a8 | |||
| 582977fc7a | |||
| 700c47277d | |||
| 8ac0979c67 | |||
| ef6dcc7c63 | |||
| 9464a944e4 | |||
| 835b1881a7 | |||
| 1c44bb1617 | |||
| 1fde3c5cab |
@@ -0,0 +1,45 @@
|
|||||||
|
# 🚀 Changelog e Relatório de Melhorias - CloneWeb Pro (Maio 2026)
|
||||||
|
|
||||||
|
Este documento registra todas as alterações, otimizações de arquitetura e correções de bugs implementadas no sistema **CloneWeb Pro** para habilitar a orquestração autônoma de agentes de Inteligência Artificial e garantir a clonagem de alta fidelidade em servidores VPS e Coolify.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Resumo Executivo das Implementações
|
||||||
|
|
||||||
|
### 1. 🤖 Integração de Inteligência Artificial (MiniMax 2.7)
|
||||||
|
|
||||||
|
* **Configuração de Ambiente (`.env`):** Correção da formatação do arquivo `.env`, separando as variáveis `LOG_LEVEL` e `MINIMAX_API_KEY` em linhas distintas.
|
||||||
|
* **Otimização de API e Modelo (`web-interface/server.js`):** Atualização do endpoint de comunicação para a URL oficial padrão compatível com OpenAI (`https://api.minimax.io/v1/chat/completions`) e configuração do modelo de raciocínio avançado `MiniMax-M2.7`.
|
||||||
|
* **Filtro de Raciocínio (`<think>`):** Implementação de um tratador de resposta via regex no backend para remover automaticamente as tags `<think>...</think>` geradas pelo modelo M2.7. Isso previne falhas de parseamento JSON no frontend.
|
||||||
|
* **Chave Única Corporativa:** Validação de que a assinatura mensal única do MiniMax 2.7 atende perfeitamente à demanda de todos os agentes trabalhando de forma simultânea ou sequencial, eliminando a necessidade de gerenciar múltiplas chaves.
|
||||||
|
|
||||||
|
### 2. 🧠 Orquestração e Habilidades dos Agentes (`web-interface/public/agents-panel.js`)
|
||||||
|
|
||||||
|
Substituição completa dos fluxos de simulação (mockups) por chamadas reais de IA integradas às *skills* do sistema:
|
||||||
|
|
||||||
|
* **Agente Scout:** Configurado para realizar prospecção e análise de mercado real baseada no nicho e na localização fornecidos.
|
||||||
|
* **Agente Designer:** Integrado às *skills* `clone-website`, `firecrawl-website-design-clone` e `performance` para aplicar diretrizes de redesign premium (glassmorphism, dark mode moderno, animações e tipografia avançada).
|
||||||
|
* **Agente Outreach:** Atua como copywriter especialista em vendas B2B, redigindo e-mails frios altamente persuasivos e personalizados para os problemas específicos de cada alvo.
|
||||||
|
* **Orchestrator:** Remoção de temporizadores simulados (`setTimeout`) em favor de um pipeline autônomo ponta a ponta. O Orchestrator agora analisa o alvo, define a estratégia, comanda a clonagem via `/api/smart-clone`, aplica o redesign e gera o copy de prospecção em uma única execução contínua.
|
||||||
|
|
||||||
|
### 3. 📁 Armazenamento, Espelhamento e Acesso na VPS
|
||||||
|
|
||||||
|
* **Espelhamento na Área de Trabalho (`web-interface/server.js`):** Implementação de um mecanismo de sincronização automática nos endpoints `smart-clone` e `wget-clone`. Ao concluir uma clonagem, os arquivos são copiados automaticamente para `/root/Desktop/Clonados`, permitindo acesso visual instantâneo via RDP/VNC na VPS.
|
||||||
|
* **Mapeamento de Volumes no Docker (`docker-compose.yml`):** Adição dos volumes `./cloned-sites:/app/cloned-sites` e `/root/Desktop/Clonados:/root/Desktop/Clonados` para os serviços `api-gateway` e `crawler-service`. Isso garante que contêineres rodando no Coolify ou Docker Compose espelhem os arquivos em tempo real para o sistema de arquivos host da VPS.
|
||||||
|
* **Abertura Nativa de Pastas (`web-interface/public/app-new.js`):** Conexão do botão "Abrir Pasta" ao endpoint real `/api/open-folder`, acionando o comando `xdg-open` para abrir o gerenciador de arquivos nativo da VPS na pasta do clone.
|
||||||
|
|
||||||
|
### 4. 🐛 Correções de Bugs Críticos de Clonagem e UI
|
||||||
|
|
||||||
|
* **Correção do Bug `0 arquivos` e `0 B` (`app-new.js`, `wget-cloner.js`, `smart-cloner.js`):** Harmonização das propriedades de retorno da API. O frontend agora faz a leitura correta dos metadados através da checagem robusta de `data.data?.files || data.data?.cloneInfo?.fileCount`, exibindo o tamanho e a contagem real de arquivos no painel.
|
||||||
|
* **Correção do Erro `Route not found` / 404 (`simple-crawler/wget-cloner.js`):** Eliminação do problema onde o WGET criava uma subpasta com o nome do domínio dentro do diretório do clone. Adicionado um script de pós-processamento que move automaticamente os arquivos da subpasta para a raiz do diretório do clone assim que o download termina.
|
||||||
|
* **Bypass de Proteção Antibot no Wget (`wget-cloner.js`):** Inclusão dos cabeçalhos `--user-agent` (simulando Google Chrome 122) e `--span-hosts` nos argumentos do WGET para evitar bloqueios 403/503 em sites protegidos por Cloudflare ou CDNs.
|
||||||
|
* **Normalização de Caminhos no Windows/Linux (`app-new.js`):** Implementação de `replace(/\\/g, '/')` na extração do nome do site para garantir que registros gerados no Windows abram perfeitamente no servidor Linux.
|
||||||
|
|
||||||
|
### 5. 🚀 Infraestrutura de Git e Deploy Automático
|
||||||
|
|
||||||
|
* **Limpeza de Repositório:** Remoção de um diretório `.git` aninhado incorretamente dentro da pasta `WEBCLONE` que corrompia o rast minimalista de submódulos.
|
||||||
|
* **Deploy Contínuo (`update.sh`):** Validação e execução de rotina de atualização automatizada que realiza o push limpo para o Gitea (`git.reifonas.cloud`), acionando instantaneamente os webhooks de build e deploy no Coolify.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Documentação gerada automaticamente após conclusão e validação de todas as etapas.*
|
||||||
@@ -68,6 +68,8 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./services/api-gateway:/app
|
- ./services/api-gateway:/app
|
||||||
- /app/node_modules
|
- /app/node_modules
|
||||||
|
- ./cloned-sites:/app/cloned-sites
|
||||||
|
- /root/Desktop/Clonados:/root/Desktop/Clonados
|
||||||
|
|
||||||
# Crawler Service
|
# Crawler Service
|
||||||
crawler-service:
|
crawler-service:
|
||||||
@@ -87,6 +89,8 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./services/crawler:/app
|
- ./services/crawler:/app
|
||||||
- /app/node_modules
|
- /app/node_modules
|
||||||
|
- ./cloned-sites:/app/cloned-sites
|
||||||
|
- /root/Desktop/Clonados:/root/Desktop/Clonados
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
|||||||
Generated
+253
-240
@@ -29,13 +29,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.27.1",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
||||||
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
|
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.27.1",
|
"@babel/helper-validator-identifier": "^7.28.5",
|
||||||
"js-tokens": "^4.0.0",
|
"js-tokens": "^4.0.0",
|
||||||
"picocolors": "^1.1.1"
|
"picocolors": "^1.1.1"
|
||||||
},
|
},
|
||||||
@@ -44,9 +44,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz",
|
||||||
"integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
|
"integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -54,21 +54,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/core": {
|
"node_modules/@babel/core": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
|
||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.29.0",
|
||||||
"@babel/helper-compilation-targets": "^7.27.2",
|
"@babel/helper-compilation-targets": "^7.28.6",
|
||||||
"@babel/helper-module-transforms": "^7.28.3",
|
"@babel/helper-module-transforms": "^7.28.6",
|
||||||
"@babel/helpers": "^7.28.4",
|
"@babel/helpers": "^7.28.6",
|
||||||
"@babel/parser": "^7.28.5",
|
"@babel/parser": "^7.29.0",
|
||||||
"@babel/template": "^7.27.2",
|
"@babel/template": "^7.28.6",
|
||||||
"@babel/traverse": "^7.28.5",
|
"@babel/traverse": "^7.29.0",
|
||||||
"@babel/types": "^7.28.5",
|
"@babel/types": "^7.29.0",
|
||||||
"@jridgewell/remapping": "^2.3.5",
|
"@jridgewell/remapping": "^2.3.5",
|
||||||
"convert-source-map": "^2.0.0",
|
"convert-source-map": "^2.0.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
@@ -95,14 +95,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
|
||||||
"integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
|
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.28.5",
|
"@babel/parser": "^7.29.0",
|
||||||
"@babel/types": "^7.28.5",
|
"@babel/types": "^7.29.0",
|
||||||
"@jridgewell/gen-mapping": "^0.3.12",
|
"@jridgewell/gen-mapping": "^0.3.12",
|
||||||
"@jridgewell/trace-mapping": "^0.3.28",
|
"@jridgewell/trace-mapping": "^0.3.28",
|
||||||
"jsesc": "^3.0.2"
|
"jsesc": "^3.0.2"
|
||||||
@@ -112,13 +112,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets": {
|
"node_modules/@babel/helper-compilation-targets": {
|
||||||
"version": "7.27.2",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
|
||||||
"integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
|
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.27.2",
|
"@babel/compat-data": "^7.28.6",
|
||||||
"@babel/helper-validator-option": "^7.27.1",
|
"@babel/helper-validator-option": "^7.27.1",
|
||||||
"browserslist": "^4.24.0",
|
"browserslist": "^4.24.0",
|
||||||
"lru-cache": "^5.1.1",
|
"lru-cache": "^5.1.1",
|
||||||
@@ -149,29 +149,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-imports": {
|
"node_modules/@babel/helper-module-imports": {
|
||||||
"version": "7.27.1",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
|
||||||
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
|
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/traverse": "^7.27.1",
|
"@babel/traverse": "^7.28.6",
|
||||||
"@babel/types": "^7.27.1"
|
"@babel/types": "^7.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-transforms": {
|
"node_modules/@babel/helper-module-transforms": {
|
||||||
"version": "7.28.3",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
|
||||||
"integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
|
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-module-imports": "^7.27.1",
|
"@babel/helper-module-imports": "^7.28.6",
|
||||||
"@babel/helper-validator-identifier": "^7.27.1",
|
"@babel/helper-validator-identifier": "^7.28.5",
|
||||||
"@babel/traverse": "^7.28.3"
|
"@babel/traverse": "^7.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -181,9 +181,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-plugin-utils": {
|
"node_modules/@babel/helper-plugin-utils": {
|
||||||
"version": "7.27.1",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
|
||||||
"integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
|
"integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -221,27 +221,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helpers": {
|
"node_modules/@babel/helpers": {
|
||||||
"version": "7.28.4",
|
"version": "7.29.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
|
||||||
"integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
|
"integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.27.2",
|
"@babel/template": "^7.28.6",
|
||||||
"@babel/types": "^7.28.4"
|
"@babel/types": "^7.29.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
|
||||||
"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
|
"integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.28.5"
|
"@babel/types": "^7.29.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@@ -306,13 +306,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-import-attributes": {
|
"node_modules/@babel/plugin-syntax-import-attributes": {
|
||||||
"version": "7.27.1",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz",
|
||||||
"integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==",
|
"integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.27.1"
|
"@babel/helper-plugin-utils": "^7.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -348,13 +348,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-jsx": {
|
"node_modules/@babel/plugin-syntax-jsx": {
|
||||||
"version": "7.27.1",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz",
|
||||||
"integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
|
"integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.27.1"
|
"@babel/helper-plugin-utils": "^7.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -474,13 +474,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-typescript": {
|
"node_modules/@babel/plugin-syntax-typescript": {
|
||||||
"version": "7.27.1",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz",
|
||||||
"integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
|
"integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.27.1"
|
"@babel/helper-plugin-utils": "^7.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -490,33 +490,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.27.2",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
||||||
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
|
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.28.6",
|
||||||
"@babel/parser": "^7.27.2",
|
"@babel/parser": "^7.28.6",
|
||||||
"@babel/types": "^7.27.1"
|
"@babel/types": "^7.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
|
||||||
"integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
|
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.29.0",
|
||||||
"@babel/helper-globals": "^7.28.0",
|
"@babel/helper-globals": "^7.28.0",
|
||||||
"@babel/parser": "^7.28.5",
|
"@babel/parser": "^7.29.0",
|
||||||
"@babel/template": "^7.27.2",
|
"@babel/template": "^7.28.6",
|
||||||
"@babel/types": "^7.28.5",
|
"@babel/types": "^7.29.0",
|
||||||
"debug": "^4.3.1"
|
"debug": "^4.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -524,9 +524,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
||||||
"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
|
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1084,9 +1084,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.9.0",
|
"version": "4.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
|
||||||
"integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
|
"integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1233,9 +1233,9 @@
|
|||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/@ioredis/commands": {
|
"node_modules/@ioredis/commands": {
|
||||||
"version": "1.4.0",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz",
|
||||||
"integrity": "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==",
|
"integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@istanbuljs/load-nyc-config": {
|
"node_modules/@istanbuljs/load-nyc-config": {
|
||||||
@@ -1346,9 +1346,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@istanbuljs/schema": {
|
"node_modules/@istanbuljs/schema": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz",
|
||||||
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
"integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1900,9 +1900,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sinclair/typebox": {
|
"node_modules/@sinclair/typebox": {
|
||||||
"version": "0.27.8",
|
"version": "0.27.10",
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz",
|
||||||
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
|
"integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -2077,9 +2077,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/express-serve-static-core": {
|
"node_modules/@types/express-serve-static-core": {
|
||||||
"version": "4.19.7",
|
"version": "4.19.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz",
|
||||||
"integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==",
|
"integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2183,9 +2183,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.19.27",
|
"version": "20.19.41",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz",
|
||||||
"integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==",
|
"integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2193,9 +2193,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
"version": "6.14.0",
|
"version": "6.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz",
|
||||||
"integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
|
"integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -2268,9 +2268,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/superagent": {
|
"node_modules/@types/superagent": {
|
||||||
"version": "8.1.9",
|
"version": "8.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.10.tgz",
|
||||||
"integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==",
|
"integrity": "sha512-nbt4IWXABhW0jGmmpRzCFNlbmwCTzZ2gTUsNIr+X+ItdqPms+PAJZbWsNzpS2USqXjcoNLQcO6nXo60zcPQiIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2519,9 +2519,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ungap/structured-clone": {
|
"node_modules/@ungap/structured-clone": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz",
|
||||||
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
|
"integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@@ -2539,9 +2539,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -2562,9 +2562,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn-walk": {
|
"node_modules/acorn-walk": {
|
||||||
"version": "8.3.4",
|
"version": "8.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
|
||||||
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2875,13 +2875,16 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.9.11",
|
"version": "2.10.32",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz",
|
||||||
"integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==",
|
"integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"baseline-browser-mapping": "dist/cli.js"
|
"baseline-browser-mapping": "dist/cli.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bcryptjs": {
|
"node_modules/bcryptjs": {
|
||||||
@@ -2904,9 +2907,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.20.4",
|
"version": "1.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz",
|
||||||
"integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==",
|
"integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bytes": "~3.1.2",
|
"bytes": "~3.1.2",
|
||||||
@@ -2917,7 +2920,7 @@
|
|||||||
"http-errors": "~2.0.1",
|
"http-errors": "~2.0.1",
|
||||||
"iconv-lite": "~0.4.24",
|
"iconv-lite": "~0.4.24",
|
||||||
"on-finished": "~2.4.1",
|
"on-finished": "~2.4.1",
|
||||||
"qs": "~6.14.0",
|
"qs": "~6.15.1",
|
||||||
"raw-body": "~2.5.3",
|
"raw-body": "~2.5.3",
|
||||||
"type-is": "~1.6.18",
|
"type-is": "~1.6.18",
|
||||||
"unpipe": "~1.0.0"
|
"unpipe": "~1.0.0"
|
||||||
@@ -2936,6 +2939,18 @@
|
|||||||
"ms": "2.0.0"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/body-parser/node_modules/iconv-lite": {
|
||||||
|
"version": "0.4.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/body-parser/node_modules/ms": {
|
"node_modules/body-parser/node_modules/ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
@@ -2971,9 +2986,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.28.1",
|
"version": "4.28.2",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
||||||
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
|
"integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2991,11 +3006,11 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.10.12",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001782",
|
||||||
"electron-to-chromium": "^1.5.263",
|
"electron-to-chromium": "^1.5.328",
|
||||||
"node-releases": "^2.0.27",
|
"node-releases": "^2.0.36",
|
||||||
"update-browserslist-db": "^1.2.0"
|
"update-browserslist-db": "^1.2.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"browserslist": "cli.js"
|
"browserslist": "cli.js"
|
||||||
@@ -3117,9 +3132,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001761",
|
"version": "1.0.30001793",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
|
||||||
"integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==",
|
"integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3165,9 +3180,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cheerio": {
|
"node_modules/cheerio": {
|
||||||
"version": "1.1.2",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz",
|
||||||
"integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==",
|
"integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cheerio-select": "^2.1.0",
|
"cheerio-select": "^2.1.0",
|
||||||
@@ -3175,11 +3190,11 @@
|
|||||||
"domhandler": "^5.0.3",
|
"domhandler": "^5.0.3",
|
||||||
"domutils": "^3.2.2",
|
"domutils": "^3.2.2",
|
||||||
"encoding-sniffer": "^0.2.1",
|
"encoding-sniffer": "^0.2.1",
|
||||||
"htmlparser2": "^10.0.0",
|
"htmlparser2": "^10.1.0",
|
||||||
"parse5": "^7.3.0",
|
"parse5": "^7.3.0",
|
||||||
"parse5-htmlparser2-tree-adapter": "^7.1.0",
|
"parse5-htmlparser2-tree-adapter": "^7.1.0",
|
||||||
"parse5-parser-stream": "^7.1.2",
|
"parse5-parser-stream": "^7.1.2",
|
||||||
"undici": "^7.12.0",
|
"undici": "^7.19.0",
|
||||||
"whatwg-mimetype": "^4.0.0"
|
"whatwg-mimetype": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3483,9 +3498,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cors": {
|
"node_modules/cors": {
|
||||||
"version": "2.8.5",
|
"version": "2.8.6",
|
||||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
|
||||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
"integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"object-assign": "^4",
|
"object-assign": "^4",
|
||||||
@@ -3493,6 +3508,10 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/create-jest": {
|
"node_modules/create-jest": {
|
||||||
@@ -3597,9 +3616,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dedent": {
|
"node_modules/dedent": {
|
||||||
"version": "1.7.1",
|
"version": "1.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz",
|
||||||
"integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==",
|
"integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -3863,9 +3882,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.267",
|
"version": "1.5.361",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz",
|
||||||
"integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
|
"integrity": "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@@ -3917,18 +3936,6 @@
|
|||||||
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
|
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/encoding-sniffer/node_modules/iconv-lite": {
|
|
||||||
"version": "0.6.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
|
||||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/entities": {
|
"node_modules/entities": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
@@ -3970,9 +3977,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/es-object-atoms": {
|
"node_modules/es-object-atoms": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
|
||||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
"integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0"
|
"es-errors": "^1.3.0"
|
||||||
@@ -4211,9 +4218,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esquery": {
|
"node_modules/esquery": {
|
||||||
"version": "1.6.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
|
||||||
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
|
"integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -4316,14 +4323,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.22.1",
|
"version": "4.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz",
|
||||||
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
|
"integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.3.8",
|
"accepts": "~1.3.8",
|
||||||
"array-flatten": "1.1.1",
|
"array-flatten": "1.1.1",
|
||||||
"body-parser": "~1.20.3",
|
"body-parser": "~1.20.5",
|
||||||
"content-disposition": "~0.5.4",
|
"content-disposition": "~0.5.4",
|
||||||
"content-type": "~1.0.4",
|
"content-type": "~1.0.4",
|
||||||
"cookie": "~0.7.1",
|
"cookie": "~0.7.1",
|
||||||
@@ -4342,7 +4349,7 @@
|
|||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
"path-to-regexp": "~0.1.12",
|
"path-to-regexp": "~0.1.12",
|
||||||
"proxy-addr": "~2.0.7",
|
"proxy-addr": "~2.0.7",
|
||||||
"qs": "~6.14.0",
|
"qs": "~6.15.1",
|
||||||
"range-parser": "~1.2.1",
|
"range-parser": "~1.2.1",
|
||||||
"safe-buffer": "5.2.1",
|
"safe-buffer": "5.2.1",
|
||||||
"send": "~0.19.0",
|
"send": "~0.19.0",
|
||||||
@@ -4511,9 +4518,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/filelist": {
|
"node_modules/filelist": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz",
|
||||||
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
|
"integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimatch": "^5.0.1"
|
"minimatch": "^5.0.1"
|
||||||
@@ -4852,7 +4859,7 @@
|
|||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
@@ -5026,9 +5033,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
@@ -5054,9 +5061,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/htmlparser2": {
|
"node_modules/htmlparser2": {
|
||||||
"version": "10.0.0",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
|
||||||
"integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==",
|
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
{
|
{
|
||||||
@@ -5068,14 +5075,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"domelementtype": "^2.3.0",
|
"domelementtype": "^2.3.0",
|
||||||
"domhandler": "^5.0.3",
|
"domhandler": "^5.0.3",
|
||||||
"domutils": "^3.2.1",
|
"domutils": "^3.2.2",
|
||||||
"entities": "^6.0.0"
|
"entities": "^7.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/htmlparser2/node_modules/entities": {
|
"node_modules/htmlparser2/node_modules/entities": {
|
||||||
"version": "6.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
||||||
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
|
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12"
|
"node": ">=0.12"
|
||||||
@@ -5128,12 +5135,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safer-buffer": ">= 2.1.2 < 3"
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@@ -5214,12 +5221,12 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/ioredis": {
|
"node_modules/ioredis": {
|
||||||
"version": "5.8.2",
|
"version": "5.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.1.tgz",
|
||||||
"integrity": "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==",
|
"integrity": "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ioredis/commands": "1.4.0",
|
"@ioredis/commands": "1.5.1",
|
||||||
"cluster-key-slot": "^1.1.0",
|
"cluster-key-slot": "^1.1.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"denque": "^2.1.0",
|
"denque": "^2.1.0",
|
||||||
@@ -5273,13 +5280,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.16.1",
|
"version": "2.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
|
||||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
"integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hasown": "^2.0.2"
|
"hasown": "^2.0.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -6629,9 +6636,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/msgpackr": {
|
"node_modules/msgpackr": {
|
||||||
"version": "1.11.8",
|
"version": "1.11.12",
|
||||||
"resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.12.tgz",
|
||||||
"integrity": "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==",
|
"integrity": "sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"msgpackr-extract": "^3.0.2"
|
"msgpackr-extract": "^3.0.2"
|
||||||
@@ -6705,11 +6712,14 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.27",
|
"version": "2.0.46",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz",
|
||||||
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
|
"integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -7192,9 +7202,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.7.4",
|
"version": "3.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
|
||||||
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
|
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -7423,9 +7433,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.14.2",
|
"version": "6.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
|
||||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
"integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"side-channel": "^1.1.0"
|
"side-channel": "^1.1.0"
|
||||||
@@ -7488,6 +7498,18 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/raw-body/node_modules/iconv-lite": {
|
||||||
|
"version": "0.4.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
||||||
@@ -7569,12 +7591,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.11",
|
"version": "1.22.12",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
|
||||||
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
|
"integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
"is-core-module": "^2.16.1",
|
"is-core-module": "^2.16.1",
|
||||||
"path-parse": "^1.0.7",
|
"path-parse": "^1.0.7",
|
||||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
@@ -7728,9 +7751,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.7.3",
|
"version": "7.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
|
||||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
"integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@@ -7878,13 +7901,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/side-channel-list": {
|
"node_modules/side-channel-list": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
|
||||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
"integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
"object-inspect": "^1.13.3"
|
"object-inspect": "^1.13.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -8308,19 +8331,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ts-jest": {
|
"node_modules/ts-jest": {
|
||||||
"version": "29.4.6",
|
"version": "29.4.11",
|
||||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz",
|
||||||
"integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==",
|
"integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bs-logger": "^0.2.6",
|
"bs-logger": "^0.2.6",
|
||||||
"fast-json-stable-stringify": "^2.1.0",
|
"fast-json-stable-stringify": "^2.1.0",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.9",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"lodash.memoize": "^4.1.2",
|
"lodash.memoize": "^4.1.2",
|
||||||
"make-error": "^1.3.6",
|
"make-error": "^1.3.6",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.8.0",
|
||||||
"type-fest": "^4.41.0",
|
"type-fest": "^4.41.0",
|
||||||
"yargs-parser": "^21.1.1"
|
"yargs-parser": "^21.1.1"
|
||||||
},
|
},
|
||||||
@@ -8337,7 +8360,7 @@
|
|||||||
"babel-jest": "^29.0.0 || ^30.0.0",
|
"babel-jest": "^29.0.0 || ^30.0.0",
|
||||||
"jest": "^29.0.0 || ^30.0.0",
|
"jest": "^29.0.0 || ^30.0.0",
|
||||||
"jest-util": "^29.0.0 || ^30.0.0",
|
"jest-util": "^29.0.0 || ^30.0.0",
|
||||||
"typescript": ">=4.3 <6"
|
"typescript": ">=4.3 <7"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@babel/core": {
|
"@babel/core": {
|
||||||
@@ -8500,9 +8523,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tsx": {
|
"node_modules/tsx": {
|
||||||
"version": "4.22.1",
|
"version": "4.22.3",
|
||||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz",
|
||||||
"integrity": "sha512-TvncJykhxAzFCk0VQZKBTClall4Pm7qXDSodb6uxi8QFa8X8mT6ABjxxsQ2opDRYxG7AzcRWXaFtruz5HJKuWg==",
|
"integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -8801,6 +8824,7 @@
|
|||||||
"version": "8.3.2",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
|
"deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
@@ -8851,6 +8875,7 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
||||||
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
||||||
|
"deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"iconv-lite": "0.6.3"
|
"iconv-lite": "0.6.3"
|
||||||
@@ -8859,18 +8884,6 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/whatwg-encoding/node_modules/iconv-lite": {
|
|
||||||
"version": "0.6.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
|
||||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/whatwg-mimetype": {
|
"node_modules/whatwg-mimetype": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"playwright": "^1.60.0",
|
"playwright": "^1.60.0",
|
||||||
"playwright-extra": "^4.3.6",
|
"playwright-extra": "^4.3.6",
|
||||||
|
"puppeteer": "^22.10.0",
|
||||||
"puppeteer-extra-plugin-stealth": "^2.11.2"
|
"puppeteer-extra-plugin-stealth": "^2.11.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class SmartCloner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async cloneSite(url, maxPages = 20) {
|
async cloneSite(url, maxPages = 20, customFolderName = null) {
|
||||||
console.log(`\n🚀 INICIANDO DEEP SMART CLONE: ${url}`);
|
console.log(`\n🚀 INICIANDO DEEP SMART CLONE: ${url}`);
|
||||||
console.log(`📂 Limite de páginas: ${maxPages}\n`);
|
console.log(`📂 Limite de páginas: ${maxPages}\n`);
|
||||||
|
|
||||||
@@ -82,7 +82,8 @@ class SmartCloner {
|
|||||||
const urlObj = new URL(url);
|
const urlObj = new URL(url);
|
||||||
const siteName = this.sanitizeFilename(urlObj.hostname);
|
const siteName = this.sanitizeFilename(urlObj.hostname);
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
const siteDir = path.join(this.baseOutputDir, `${siteName}_${timestamp}`);
|
const finalFolderName = customFolderName ? this.sanitizeFilename(customFolderName) : `${siteName}_${timestamp}`;
|
||||||
|
const siteDir = path.join(this.baseOutputDir, finalFolderName);
|
||||||
this.ensureDirectoryExists(siteDir);
|
this.ensureDirectoryExists(siteDir);
|
||||||
|
|
||||||
browser = await chromium.launch({
|
browser = await chromium.launch({
|
||||||
@@ -333,7 +334,10 @@ self.addEventListener('fetch', (event) => {
|
|||||||
`;
|
`;
|
||||||
fs.writeFileSync(path.join(siteDir, 'mock-sw.js'), swCode);
|
fs.writeFileSync(path.join(siteDir, 'mock-sw.js'), swCode);
|
||||||
|
|
||||||
return { success: true, path: siteDir, pagesCloned: pageCount };
|
var countFiles = function(dir) { var ts=0,fc=0; (function rec(d){if(!fs.existsSync(d))return;fs.readdirSync(d).forEach(function(i){var p=path.join(d,i),s=fs.statSync(p);if(s.isDirectory()&&i.indexOf("cloned-sites")==-1&&i.indexOf(".versions")==-1)rec(p);else if(!s.isDirectory()){ts+=s.size;fc++;}});})(dir);return{fileCount:fc,totalSize:ts};};
|
||||||
|
const stats = countFiles(siteDir);
|
||||||
|
|
||||||
|
return { success: true, path: siteDir, pagesCloned: pageCount, files: stats.fileCount, size: stats.totalSize };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('❌ Erro Deep Clone:', e);
|
console.error('❌ Erro Deep Clone:', e);
|
||||||
return { success: false, error: e.message };
|
return { success: false, error: e.message };
|
||||||
@@ -365,10 +369,12 @@ if (require.main === module) {
|
|||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const urlArg = args.find(arg => arg.startsWith('--url='));
|
const urlArg = args.find(arg => arg.startsWith('--url='));
|
||||||
const url = urlArg ? urlArg.split('=')[1] : args[0];
|
const url = urlArg ? urlArg.split('=')[1] : args[0];
|
||||||
|
const folderArg = args.find(arg => arg.startsWith('--folderName='));
|
||||||
|
const folderName = folderArg ? folderArg.split('=')[1] : null;
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
const cloner = new SmartCloner();
|
const cloner = new SmartCloner();
|
||||||
cloner.cloneSite(url).then(res => {
|
cloner.cloneSite(url, 20, folderName).then(res => {
|
||||||
console.log(JSON.stringify(res, null, 2));
|
console.log(JSON.stringify(res, null, 2));
|
||||||
process.exit(res.success ? 0 : 1);
|
process.exit(res.success ? 0 : 1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class WgetCloner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async cloneWebsite(url) {
|
async cloneWebsite(url, customFolderName = null) {
|
||||||
console.log(`\n${'='.repeat(60)}`);
|
console.log(`\n${'='.repeat(60)}`);
|
||||||
console.log(`🚀 CLONAGEM PROFISSIONAL COM WGET`);
|
console.log(`🚀 CLONAGEM PROFISSIONAL COM WGET`);
|
||||||
console.log(`${'='.repeat(60)}`);
|
console.log(`${'='.repeat(60)}`);
|
||||||
@@ -98,7 +98,8 @@ class WgetCloner {
|
|||||||
const urlObj = new URL(url);
|
const urlObj = new URL(url);
|
||||||
const siteName = this.sanitizeFilename(urlObj.hostname);
|
const siteName = this.sanitizeFilename(urlObj.hostname);
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
const siteDir = path.join(this.baseOutputDir, `${siteName}_${timestamp}`);
|
const finalFolderName = customFolderName ? this.sanitizeFilename(customFolderName) : `${siteName}_${timestamp}`;
|
||||||
|
const siteDir = path.join(this.baseOutputDir, finalFolderName);
|
||||||
this.ensureDirectoryExists(siteDir);
|
this.ensureDirectoryExists(siteDir);
|
||||||
|
|
||||||
console.log(`📁 Salvando em: ${siteDir}\n`);
|
console.log(`📁 Salvando em: ${siteDir}\n`);
|
||||||
@@ -112,6 +113,8 @@ class WgetCloner {
|
|||||||
'--convert-links', // Converter links para locais
|
'--convert-links', // Converter links para locais
|
||||||
'--restrict-file-names=windows', // Nomes compatíveis com Windows
|
'--restrict-file-names=windows', // Nomes compatíveis com Windows
|
||||||
'--domains=' + urlObj.hostname, // Apenas este domínio
|
'--domains=' + urlObj.hostname, // Apenas este domínio
|
||||||
|
'--span-hosts', // Permitir redirecionamentos entre subdomínios/CDN
|
||||||
|
'--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"',
|
||||||
'--no-parent', // Não subir diretórios
|
'--no-parent', // Não subir diretórios
|
||||||
'--no-check-certificate', // Ignorar SSL
|
'--no-check-certificate', // Ignorar SSL
|
||||||
'-e', 'robots=off', // Ignorar robots.txt
|
'-e', 'robots=off', // Ignorar robots.txt
|
||||||
@@ -161,6 +164,15 @@ class WgetCloner {
|
|||||||
console.log(`${'='.repeat(60)}`);
|
console.log(`${'='.repeat(60)}`);
|
||||||
console.log(`📁 Localização: ${siteDir}`);
|
console.log(`📁 Localização: ${siteDir}`);
|
||||||
|
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
// Mover arquivos do subdiretório do domínio para a raiz do siteDir
|
||||||
|
try {
|
||||||
|
const domainDir = path.join(siteDir, urlObj.hostname);
|
||||||
|
if (fs.existsSync(domainDir)) {
|
||||||
|
execSync(`cp -r "${domainDir}"/* "${siteDir}"/ 2>/dev/null && rm -rf "${domainDir}"`);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
// Baixar imagens faltantes manualmente
|
// Baixar imagens faltantes manualmente
|
||||||
console.log(`\n🔍 Verificando imagens faltantes...`);
|
console.log(`\n🔍 Verificando imagens faltantes...`);
|
||||||
this.downloadMissingImages(siteDir, url).then(() => {
|
this.downloadMissingImages(siteDir, url).then(() => {
|
||||||
@@ -203,6 +215,8 @@ class WgetCloner {
|
|||||||
directory: siteDir,
|
directory: siteDir,
|
||||||
method: 'wget',
|
method: 'wget',
|
||||||
exitCode: code,
|
exitCode: code,
|
||||||
|
files: stats.fileCount,
|
||||||
|
size: stats.totalSize,
|
||||||
cloneInfo: info
|
cloneInfo: info
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -315,13 +329,13 @@ class WgetCloner {
|
|||||||
// API
|
// API
|
||||||
app.post('/wget-clone', async (req, res) => {
|
app.post('/wget-clone', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { url } = req.body;
|
const { url, folderName } = req.body;
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return res.status(400).json({ error: 'URL obrigatória' });
|
return res.status(400).json({ error: 'URL obrigatória' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloner = new WgetCloner();
|
const cloner = new WgetCloner();
|
||||||
const result = await cloner.cloneWebsite(url);
|
const result = await cloner.cloneWebsite(url, folderName);
|
||||||
|
|
||||||
res.json({ success: true, data: result });
|
res.json({ success: true, data: result });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -17,4 +17,8 @@ git commit -m "$COMMIT_MESSAGE" || echo "Nenhuma mudança para comitar."
|
|||||||
# Se não houver origin ou for local, ele ignora falhas suavemente.
|
# Se não houver origin ou for local, ele ignora falhas suavemente.
|
||||||
git push origin main || git push || echo "Aviso: Push falhou ou repositório não tem remoto configurado."
|
git push origin main || git push || echo "Aviso: Push falhou ou repositório não tem remoto configurado."
|
||||||
|
|
||||||
echo "Atualização concluída!"
|
echo "Acionando o deploy no Coolify..."
|
||||||
|
curl -X POST -s -H "Authorization: Bearer 12|wbepNILQe24LAOjfEUmMROgU93F6uG1zuwPLwrRi786bca03" "http://localhost:8000/api/v1/deploy?uuid=at22zt4l2pv5at9cfkl2feh7"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Atualização e Deploy concluídos!"
|
||||||
|
|||||||
@@ -178,13 +178,70 @@ function updateScoutStatus(status) {
|
|||||||
// DESIGNER AGENT - Redesign Ultra-Moderno
|
// DESIGNER AGENT - Redesign Ultra-Moderno
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
|
async function loadDesignerClonesSelect() {
|
||||||
|
const inputUrl = document.getElementById('designUrl');
|
||||||
|
if (!inputUrl) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/clones');
|
||||||
|
const result = await response.json();
|
||||||
|
if (!result.success || !result.data?.clones) return;
|
||||||
|
|
||||||
|
const clones = result.data.clones;
|
||||||
|
|
||||||
|
// Criar o select
|
||||||
|
const select = document.createElement('select');
|
||||||
|
select.id = 'designerCloneSelect';
|
||||||
|
select.className = 'form-control mb-3';
|
||||||
|
select.style.cssText = 'background: rgba(255, 255, 255, 0.05); border: 1px solid var(--ai-border-glass); color: #f3f4f6; border-radius: 12px; padding: 12px 16px; margin-bottom: 16px; font-family: "Inter", sans-serif; cursor: pointer; width: 100%;';
|
||||||
|
|
||||||
|
let optionsHtml = '<option value="">-- Selecione um site já clonado para Redesign --</option>';
|
||||||
|
clones.forEach(c => {
|
||||||
|
const dateStr = c.cloneInfo?.clonedAt ? new Date(c.cloneInfo.clonedAt).toLocaleDateString('pt-BR') : '';
|
||||||
|
optionsHtml += `<option value="${c.id}">${c.baseUrl} ${dateStr ? `(Clonado em ${dateStr})` : ''}</option>`;
|
||||||
|
});
|
||||||
|
select.innerHTML = optionsHtml;
|
||||||
|
|
||||||
|
// Inserir antes do inputUrl
|
||||||
|
inputUrl.parentNode.insertBefore(select, inputUrl);
|
||||||
|
|
||||||
|
// Adicionar evento para desabilitar/limpar o input de URL quando um clone é selecionado
|
||||||
|
select.addEventListener('change', () => {
|
||||||
|
if (select.value) {
|
||||||
|
inputUrl.value = '';
|
||||||
|
inputUrl.placeholder = 'Site selecionado acima. (Ou limpe o select para usar URL nova)';
|
||||||
|
inputUrl.disabled = true;
|
||||||
|
agentsState.designer.currentClone = {
|
||||||
|
directory: 'cloned-sites/' + select.value,
|
||||||
|
name: select.value.split('_')[0],
|
||||||
|
url: 'https://' + select.value.split('_')[0]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
inputUrl.disabled = false;
|
||||||
|
inputUrl.placeholder = 'https://exemplo.com (Para clonar novo site)';
|
||||||
|
agentsState.designer.currentClone = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Erro ao carregar lista de clones no Designer:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function startDesign() {
|
async function startDesign() {
|
||||||
const clone = agentsState.designer.currentClone;
|
const selectEl = document.getElementById('designerCloneSelect');
|
||||||
if (!clone) {
|
const urlEl = document.getElementById('designUrl');
|
||||||
// Try to get from URL input
|
|
||||||
const url = document.getElementById('designUrl')?.value?.trim();
|
// Se escolheu na droplist
|
||||||
|
if (selectEl && selectEl.value) {
|
||||||
|
agentsState.designer.currentClone = {
|
||||||
|
directory: 'cloned-sites/' + selectEl.value,
|
||||||
|
name: selectEl.value.split('_')[0],
|
||||||
|
url: 'https://' + selectEl.value.split('_')[0]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const url = urlEl?.value?.trim();
|
||||||
if (!url) {
|
if (!url) {
|
||||||
showAgentError('Designer', 'Nenhum site selecionado. Use o Scout ou insira uma URL.');
|
showAgentError('Designer', 'Selecione um site já clonado na lista ou insira uma URL válida.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
agentsState.designer.currentClone = { url, name: 'Site selecionado' };
|
agentsState.designer.currentClone = { url, name: 'Site selecionado' };
|
||||||
@@ -194,7 +251,10 @@ async function startDesign() {
|
|||||||
updateDesignerStatus('🚀 Iniciando redesign ultra-moderno...');
|
updateDesignerStatus('🚀 Iniciando redesign ultra-moderno...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 1: Clone the site
|
let directory = agentsState.designer.currentClone.directory;
|
||||||
|
|
||||||
|
// Se NÃO escolheu na droplist (ou seja, se passou URL nova), faz o clone do zero!
|
||||||
|
if (!directory) {
|
||||||
updateDesignerStatus('📥 Clonando site original...');
|
updateDesignerStatus('📥 Clonando site original...');
|
||||||
const cloneResult = await cloneSite(agentsState.designer.currentClone.url);
|
const cloneResult = await cloneSite(agentsState.designer.currentClone.url);
|
||||||
|
|
||||||
@@ -202,15 +262,18 @@ async function startDesign() {
|
|||||||
throw new Error(cloneResult.error || 'Falha ao clonar');
|
throw new Error(cloneResult.error || 'Falha ao clonar');
|
||||||
}
|
}
|
||||||
|
|
||||||
const directory = cloneResult.data?.directory || cloneResult.data?.path || cloneResult.directory;
|
directory = cloneResult.data?.directory || cloneResult.data?.path || cloneResult.directory;
|
||||||
agentsState.designer.currentClone.directory = directory;
|
agentsState.designer.currentClone.directory = directory;
|
||||||
updateDesignerStatus('✅ Site clonado com sucesso');
|
updateDesignerStatus('✅ Site clonado com sucesso');
|
||||||
|
} else {
|
||||||
|
updateDesignerStatus('📂 Usando site já clonado do storage...');
|
||||||
|
}
|
||||||
|
|
||||||
// Step 2: Apply ultra-modern redesign
|
// Step 2: Apply ultra-modern redesign
|
||||||
updateDesignerStatus('🎨 Aplicando redesign ultra-moderno...');
|
updateDesignerStatus('🎨 Aplicando redesign ultra-moderno com IA...');
|
||||||
const redesignResult = await applyUltraModernRedesign(directory);
|
const redesignResult = await applyUltraModernRedesign(directory);
|
||||||
|
|
||||||
updateDesignerStatus('✨ Redesign concluído!');
|
updateDesignerStatus('✨ Redesign concluído com sucesso!');
|
||||||
showDesignerPreview(redesignResult.previewUrl);
|
showDesignerPreview(redesignResult.previewUrl);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -240,7 +303,7 @@ async function applyUltraModernRedesign(cloneDir) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const rawResponse = await askAI(prompt, `Planeje o redesign do site no diretório: ${cloneDir}`);
|
const rawResponse = await askAI(prompt, `Planeje o redesign do site no diretório: ${cloneDir}`);
|
||||||
const jsonStr = rawResponse.replace(/```json/gi, '').replace(/```/g, '').trim();
|
let jsonStr = rawResponse.match(/\{[\s\S]*\}/)?.[0] || '{}';
|
||||||
const parsed = JSON.parse(jsonStr);
|
const parsed = JSON.parse(jsonStr);
|
||||||
if (parsed.appliedStyles) appliedStyles = parsed.appliedStyles;
|
if (parsed.appliedStyles) appliedStyles = parsed.appliedStyles;
|
||||||
if (parsed.elementsRedesigned) elementsRedesigned = parsed.elementsRedesigned;
|
if (parsed.elementsRedesigned) elementsRedesigned = parsed.elementsRedesigned;
|
||||||
@@ -248,11 +311,35 @@ async function applyUltraModernRedesign(cloneDir) {
|
|||||||
console.error("Erro na IA do Designer:", e);
|
console.error("Erro na IA do Designer:", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
const previewUrl = `http://localhost:${window.location.port || 3000}/${cloneDir.split('/').pop()}/index.html`;
|
// Remover barra no final se houver
|
||||||
|
let cleanDir = cloneDir.endsWith('/') ? cloneDir.slice(0, -1) : cloneDir;
|
||||||
|
let newPreviewUrl = `/api/preview/${cleanDir.split('/').pop()}`;
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/ai/inject-redesign', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
cloneDir,
|
||||||
|
appliedStyles,
|
||||||
|
elementsRedesigned,
|
||||||
|
outputDir: settings.outputDir,
|
||||||
|
agentName: 'designer'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.newFolderName) {
|
||||||
|
newPreviewUrl = `/api/preview/${data.newFolderName}`;
|
||||||
|
if (agentsState.designer.currentClone) {
|
||||||
|
agentsState.designer.currentClone.directory = 'cloned-sites/' + data.newFolderName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Erro ao injetar CSS de redesign:", e);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
previewUrl,
|
previewUrl: newPreviewUrl,
|
||||||
appliedStyles,
|
appliedStyles,
|
||||||
elementsRedesigned
|
elementsRedesigned
|
||||||
};
|
};
|
||||||
@@ -516,5 +603,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
btn.addEventListener('click', () => switchAgentTab(btn.dataset.tab));
|
btn.addEventListener('click', () => switchAgentTab(btn.dataset.tab));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Carregar a droplist de clones do Designer
|
||||||
|
loadDesignerClonesSelect();
|
||||||
|
|
||||||
console.log('✅ BrainSteel Web Agents initialized');
|
console.log('✅ BrainSteel Web Agents initialized');
|
||||||
});
|
});
|
||||||
|
|||||||
+102
-23
@@ -59,7 +59,8 @@ function navigateToPage(page) {
|
|||||||
'dashboard': 'Dashboard',
|
'dashboard': 'Dashboard',
|
||||||
'new-clone': 'Nova Clonagem',
|
'new-clone': 'Nova Clonagem',
|
||||||
'history': 'Histórico',
|
'history': 'Histórico',
|
||||||
'settings': 'Configurações'
|
'settings': 'Configurações',
|
||||||
|
'optimized-pages': 'Páginas Otimizadas (AI)'
|
||||||
};
|
};
|
||||||
document.getElementById('pageTitle').textContent = titles[page] || page;
|
document.getElementById('pageTitle').textContent = titles[page] || page;
|
||||||
|
|
||||||
@@ -70,6 +71,8 @@ function navigateToPage(page) {
|
|||||||
loadDashboard();
|
loadDashboard();
|
||||||
} else if (page === 'history') {
|
} else if (page === 'history') {
|
||||||
loadHistory();
|
loadHistory();
|
||||||
|
} else if (page === 'optimized-pages') {
|
||||||
|
loadOptimizedPages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +209,7 @@ async function handleCloneSubmit(e) {
|
|||||||
const includeCSSEl = document.getElementById('includeCSS');
|
const includeCSSEl = document.getElementById('includeCSS');
|
||||||
const includeJSEl = document.getElementById('includeJS');
|
const includeJSEl = document.getElementById('includeJS');
|
||||||
const convertLinksEl = document.getElementById('convertLinks');
|
const convertLinksEl = document.getElementById('convertLinks');
|
||||||
|
const customFolderEl = document.getElementById('customFolder');
|
||||||
|
|
||||||
if (!cloneUrlEl || !depthLevelEl || !includeImagesEl || !includeCSSEl || !includeJSEl || !convertLinksEl) {
|
if (!cloneUrlEl || !depthLevelEl || !includeImagesEl || !includeCSSEl || !includeJSEl || !convertLinksEl) {
|
||||||
console.error('Form elements not found');
|
console.error('Form elements not found');
|
||||||
@@ -219,6 +223,14 @@ async function handleCloneSubmit(e) {
|
|||||||
const includeCSS = includeCSSEl.checked;
|
const includeCSS = includeCSSEl.checked;
|
||||||
const includeJS = includeJSEl.checked;
|
const includeJS = includeJSEl.checked;
|
||||||
const convertLinks = convertLinksEl.checked;
|
const convertLinks = convertLinksEl.checked;
|
||||||
|
let folderName = customFolderEl ? customFolderEl.value.trim() : '';
|
||||||
|
if (folderName.includes('/root/Desktop/CLONE_SITE/')) {
|
||||||
|
folderName = folderName.replace('/root/Desktop/CLONE_SITE/', '').trim();
|
||||||
|
} else if (folderName.includes('/root/Desktop/CLONE_SITE')) {
|
||||||
|
folderName = folderName.replace('/root/Desktop/CLONE_SITE', '').trim();
|
||||||
|
}
|
||||||
|
// Caso tenha digitado caminhos absolutos, extrair apenas o final
|
||||||
|
folderName = folderName.replace(/[\/\\]/g, '').trim();
|
||||||
const cloneMethod = 'wget';
|
const cloneMethod = 'wget';
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
@@ -240,6 +252,7 @@ async function handleCloneSubmit(e) {
|
|||||||
includeCSS,
|
includeCSS,
|
||||||
includeJS,
|
includeJS,
|
||||||
convertLinks,
|
convertLinks,
|
||||||
|
folderName,
|
||||||
method: cloneMethod
|
method: cloneMethod
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -304,7 +317,11 @@ async function startCloning(url, options) {
|
|||||||
response = await fetch('/api/smart-clone', {
|
response = await fetch('/api/smart-clone', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ url })
|
body: JSON.stringify({
|
||||||
|
url,
|
||||||
|
outputDir: settings.outputDir,
|
||||||
|
folderName: options.folderName
|
||||||
|
})
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// WGET logic
|
// WGET logic
|
||||||
@@ -313,7 +330,9 @@ async function startCloning(url, options) {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
url,
|
url,
|
||||||
depth: options.depth
|
depth: options.depth,
|
||||||
|
outputDir: settings.outputDir,
|
||||||
|
folderName: options.folderName
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -329,9 +348,8 @@ async function startCloning(url, options) {
|
|||||||
progressMessage.textContent = '✅ Clonagem concluída com sucesso!';
|
progressMessage.textContent = '✅ Clonagem concluída com sucesso!';
|
||||||
|
|
||||||
// Update stats
|
// Update stats
|
||||||
// Update stats
|
const files = data.data?.files || data.data?.cloneInfo?.fileCount || data.data?.resources || data.files || 0;
|
||||||
const files = data.data.resources || data.data.files || 0;
|
const size = data.data?.size || data.data?.cloneInfo?.totalSize || data.size || 0;
|
||||||
const size = data.data.size || 0; // Smart clone might not return size yet
|
|
||||||
|
|
||||||
filesDownloaded.textContent = files;
|
filesDownloaded.textContent = files;
|
||||||
sizeDownloaded.textContent = formatBytes(size);
|
sizeDownloaded.textContent = formatBytes(size);
|
||||||
@@ -585,35 +603,38 @@ function loadSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Populate settings form (if needed)
|
// Populate settings form (if needed)
|
||||||
|
const outDirInput = document.getElementById('settingsOutputDir');
|
||||||
|
if (outDirInput) outDirInput.value = settings.outputDir || '/root/Desktop/CLONE_SITE';
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
|
const outDirInput = document.getElementById('settingsOutputDir');
|
||||||
|
if (outDirInput) settings.outputDir = outDirInput.value;
|
||||||
localStorage.setItem('cloneSettings', JSON.stringify(settings));
|
localStorage.setItem('cloneSettings', JSON.stringify(settings));
|
||||||
showToast('Configurações salvas!', 'success');
|
showToast('Configurações salvas!', 'success');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility Functions
|
// Utility Functions
|
||||||
function openClonedSite(directory) {
|
function openClonedSite(directory) {
|
||||||
// Try to open via server endpoint
|
const siteName = directory.replace(/\\/g, '/').split('/').pop();
|
||||||
fetch('/api/health', {
|
window.open(`/api/preview/${siteName}`, '_blank');
|
||||||
method: 'GET'
|
|
||||||
}).then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
// Server is running, open the site via same origin
|
|
||||||
const siteName = directory.split('/').pop();
|
|
||||||
window.open(`/${siteName}/index.html`, '_blank');
|
|
||||||
} else {
|
|
||||||
showToast('Servidor não está respondendo.', 'error');
|
|
||||||
}
|
|
||||||
}).catch(error => {
|
|
||||||
showToast('Servidor não está respondendo.', 'error');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openCloneFolder(directory) {
|
function openCloneFolder(directory) {
|
||||||
showToast('Abrindo pasta: ' + directory, 'info');
|
showToast('Abrindo gerenciador de arquivos web...', 'info');
|
||||||
// In a real app, this would use an API endpoint to open the folder
|
fetch('/api/open-folder', {
|
||||||
console.log('Open folder:', directory);
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ path: directory })
|
||||||
|
}).then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (!data.success) {
|
||||||
|
showToast('Erro ao abrir pasta: ' + (data.error || ''), 'error');
|
||||||
|
} else if (data.url) {
|
||||||
|
window.open(data.url, '_blank');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.error('Erro ao chamar open-folder:', err));
|
||||||
}
|
}
|
||||||
|
|
||||||
function showToast(message, type = 'info') {
|
function showToast(message, type = 'info') {
|
||||||
@@ -703,3 +724,61 @@ function formatRelativeTime(dateString) {
|
|||||||
if (minutes > 0) return minutes === 1 ? 'Há 1 minuto' : `Há ${minutes} minutos`;
|
if (minutes > 0) return minutes === 1 ? 'Há 1 minuto' : `Há ${minutes} minutos`;
|
||||||
return 'Agora mesmo';
|
return 'Agora mesmo';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optimized Pages
|
||||||
|
async function loadOptimizedPages() {
|
||||||
|
const listEl = document.getElementById('optimizedList');
|
||||||
|
if (!listEl) return;
|
||||||
|
|
||||||
|
listEl.innerHTML = `
|
||||||
|
<div class="empty-state">
|
||||||
|
<i class="fas fa-spinner fa-spin"></i>
|
||||||
|
<h3>Carregando...</h3>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/optimized-pages');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.success && data.pages.length > 0) {
|
||||||
|
listEl.innerHTML = data.pages.map(page => `
|
||||||
|
<div class="clone-item">
|
||||||
|
<div class="clone-info">
|
||||||
|
<div class="clone-icon" style="background: linear-gradient(135deg, #ec4899 0%, #8b5cf6 100%);">
|
||||||
|
<i class="fas fa-magic" style="color: white;"></i>
|
||||||
|
</div>
|
||||||
|
<div class="clone-details">
|
||||||
|
<h4>${page.name}</h4>
|
||||||
|
<p>Otimizada pela IA • ${page.directory}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="clone-actions">
|
||||||
|
<button class="btn btn-primary btn-sm" onclick="openClonedSite('${page.directory}')">
|
||||||
|
<i class="fas fa-external-link-alt"></i> Visualizar
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-secondary btn-sm" onclick="openCloneFolder('${page.directory}')">
|
||||||
|
<i class="fas fa-folder-open"></i> Pasta
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
} else {
|
||||||
|
listEl.innerHTML = `
|
||||||
|
<div class="empty-state">
|
||||||
|
<i class="fas fa-paint-brush"></i>
|
||||||
|
<h3>Nenhuma página otimizada encontrada</h3>
|
||||||
|
<p>Use o Agente Designer para otimizar suas clonagens.</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
listEl.innerHTML = `
|
||||||
|
<div class="empty-state">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i>
|
||||||
|
<h3>Erro ao carregar</h3>
|
||||||
|
<p>${e.message}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,12 +15,8 @@ urlInput.addEventListener('keypress', (e) => {
|
|||||||
|
|
||||||
document.getElementById('btnOpenSite').addEventListener('click', () => {
|
document.getElementById('btnOpenSite').addEventListener('click', () => {
|
||||||
if (clonedData && clonedData.data && clonedData.data.path) {
|
if (clonedData && clonedData.data && clonedData.data.path) {
|
||||||
// Construct local URL. Server serves /<folderName>/index.html
|
|
||||||
// We know server serves static files from cloned-sites directly if configured?
|
|
||||||
// Wait, server.js serves ../cloned-sites as static.
|
|
||||||
// so path is just /FolderName/index.html
|
|
||||||
const dirName = clonedData.data.path.split('\\').pop().split('/').pop();
|
const dirName = clonedData.data.path.split('\\').pop().split('/').pop();
|
||||||
window.open(`/${dirName}/index.html`, '_blank');
|
window.open(`/api/preview/${dirName}`, '_blank');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -30,6 +26,11 @@ document.getElementById('btnOpenFolder').addEventListener('click', () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ path: clonedData.data.path })
|
body: JSON.stringify({ path: clonedData.data.path })
|
||||||
|
}).then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success && data.url) {
|
||||||
|
window.open(data.url, '_blank');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -418,25 +418,25 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// Funções para gerenciar sites clonados
|
// Funções para gerenciar sites clonados
|
||||||
function openCloneFolder(directory) {
|
function openCloneFolder(directory) {
|
||||||
// Tentar abrir a pasta no explorador do Windows
|
|
||||||
fetch('/api/open-folder', {
|
fetch('/api/open-folder', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ path: directory })
|
body: JSON.stringify({ path: directory })
|
||||||
}).then(response => {
|
}).then(response => response.json())
|
||||||
if (!response.ok) {
|
.then(data => {
|
||||||
alert('Não foi possível abrir a pasta automaticamente.\nLocalização: ' + directory);
|
if (data.success && data.url) {
|
||||||
|
window.open(data.url, '_blank');
|
||||||
|
} else {
|
||||||
|
alert('Não foi possível abrir a pasta.\nLocalização: ' + directory);
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
alert('Não foi possível abrir a pasta automaticamente.\nLocalização: ' + directory);
|
alert('Não foi possível abrir a pasta.\nLocalização: ' + directory);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function openClonedSite(directory) {
|
function openClonedSite(directory) {
|
||||||
// Extract folder name and open site in browser via window.open
|
|
||||||
const folderName = directory.split('/').pop();
|
const folderName = directory.split('/').pop();
|
||||||
const siteUrl = window.location.protocol + '//' + window.location.host + '/' + folderName + '/index.html';
|
window.open('/api/preview/' + folderName, '_blank');
|
||||||
window.open(siteUrl, '_blank');
|
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,11 @@
|
|||||||
<span>Storage</span>
|
<span>Storage</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<a href="#" class="nav-item" data-page="optimized-pages">
|
||||||
|
<i class="fas fa-paint-brush"></i>
|
||||||
|
<span>Otimizados (AI)</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
<a href="#" class="nav-item" data-page="settings">
|
<a href="#" class="nav-item" data-page="settings">
|
||||||
<i class="fas fa-cog"></i>
|
<i class="fas fa-cog"></i>
|
||||||
<span>Configurações</span>
|
<span>Configurações</span>
|
||||||
@@ -150,6 +155,17 @@
|
|||||||
required
|
required
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="customFolder">
|
||||||
|
<i class="fas fa-folder"></i> Nome Específico da Pasta (Opcional)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="customFolder"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="ex: meu_projeto"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>
|
<label>
|
||||||
@@ -238,6 +254,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Optimized Pages Page -->
|
||||||
|
<div class="page" id="optimized-pages">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3><i class="fas fa-paint-brush"></i> Gestão de Páginas Otimizadas pela IA</h3>
|
||||||
|
<div class="header-actions">
|
||||||
|
<button class="btn btn-secondary btn-sm" onclick="loadOptimizedPages()">
|
||||||
|
<i class="fas fa-sync-alt"></i> Atualizar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clones-list" id="optimizedList">
|
||||||
|
<div class="empty-state">
|
||||||
|
<i class="fas fa-spinner fa-spin"></i>
|
||||||
|
<h3>Carregando...</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Settings Page -->
|
<!-- Settings Page -->
|
||||||
<div class="page" id="settings">
|
<div class="page" id="settings">
|
||||||
<div class="settings-container">
|
<div class="settings-container">
|
||||||
@@ -250,8 +285,8 @@
|
|||||||
<p>Local onde os sites clonados serão salvos</p>
|
<p>Local onde os sites clonados serão salvos</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-control">
|
<div class="setting-control">
|
||||||
<input type="text" class="form-control" value="M:\CLONEWEB\cloned-sites" readonly>
|
<input type="text" id="settingsOutputDir" class="form-control" value="/root/Desktop/Clonados">
|
||||||
<button class="btn btn-secondary btn-sm">
|
<button class="btn btn-secondary btn-sm" onclick="openCloneFolder(document.getElementById('settingsOutputDir').value)">
|
||||||
<i class="fas fa-folder-open"></i> Abrir
|
<i class="fas fa-folder-open"></i> Abrir
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -293,7 +328,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-actions">
|
<div class="settings-actions">
|
||||||
<button class="btn btn-primary">
|
<button class="btn btn-primary" onclick="saveSettings()">
|
||||||
<i class="fas fa-save"></i> Salvar Configurações
|
<i class="fas fa-save"></i> Salvar Configurações
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary">
|
<button class="btn btn-secondary">
|
||||||
@@ -386,7 +421,8 @@
|
|||||||
|
|
||||||
<div class="agent-inputs">
|
<div class="agent-inputs">
|
||||||
<input type="text" id="designUrl" class="form-control" placeholder="URL do site para redesign...">
|
<input type="text" id="designUrl" class="form-control" placeholder="URL do site para redesign...">
|
||||||
<button id="startDesignBtn" class="btn btn-primary">
|
|
||||||
|
<button id="startDesignBtn" class="btn btn-primary mt-3">
|
||||||
<i class="fas fa-rocket"></i> Iniciar Redesign
|
<i class="fas fa-rocket"></i> Iniciar Redesign
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ function confirmDeleteClone(cloneId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openClone(cloneId) {
|
function openClone(cloneId) {
|
||||||
window.open(`/${cloneId}/index.html`, '_blank');
|
window.open(`/api/preview/${cloneId}`, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneSiteAgain(baseUrl) {
|
function cloneSiteAgain(baseUrl) {
|
||||||
|
|||||||
+550
-29
@@ -3,10 +3,18 @@ const path = require('path');
|
|||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const { exec, spawn } = require('child_process');
|
const { exec, spawn } = require('child_process');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
// Security / Iframe Fix
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||||
|
res.removeHeader('X-Frame-Options'); // Try to remove it completely first, if proxy allows
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// Storage manager routes
|
// Storage manager routes
|
||||||
const storageManager = require('./storage-manager');
|
const storageManager = require('./storage-manager');
|
||||||
app.use('/api/clones', storageManager);
|
app.use('/api/clones', storageManager);
|
||||||
@@ -24,6 +32,93 @@ app.use((req, res, next) => {
|
|||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Helper para parsear cookies
|
||||||
|
function parseCookies(cookieHeader) {
|
||||||
|
const list = {};
|
||||||
|
if (!cookieHeader) return list;
|
||||||
|
cookieHeader.split(';').forEach(cookie => {
|
||||||
|
let [name, ...rest] = cookie.split('=');
|
||||||
|
name = name?.trim();
|
||||||
|
if (!name) return;
|
||||||
|
const value = rest.join('=').trim();
|
||||||
|
if (!value) return;
|
||||||
|
list[name] = decodeURIComponent(value);
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rota para ativar o Virtual Root Preview (define o cookie e redireciona para a raiz)
|
||||||
|
app.get('/api/preview/:folder', (req, res) => {
|
||||||
|
const folderName = req.params.folder;
|
||||||
|
res.setHeader('Set-Cookie', `clone_preview_target=${encodeURIComponent(folderName)}; Path=/; HttpOnly; SameSite=Lax`);
|
||||||
|
res.redirect('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rota para sair do Virtual Root Preview (limpa o cookie e volta ao dashboard)
|
||||||
|
app.get('/api/exit-preview', (req, res) => {
|
||||||
|
res.setHeader('Set-Cookie', 'clone_preview_target=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT');
|
||||||
|
res.redirect('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Middleware de Virtual Root Proxy (serve o site clonado diretamente na raiz / quando o cookie está ativo)
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const cookies = parseCookies(req.headers.cookie);
|
||||||
|
if (cookies.clone_preview_target && !req.path.startsWith('/api') && req.path !== '/old') {
|
||||||
|
const folderName = cookies.clone_preview_target;
|
||||||
|
const folderPath = path.join(__dirname, '..', 'cloned-sites', folderName);
|
||||||
|
|
||||||
|
if (fs.existsSync(folderPath)) {
|
||||||
|
let targetFile = req.path;
|
||||||
|
if (targetFile === '/') targetFile = '/index.html';
|
||||||
|
|
||||||
|
// Se o arquivo solicitado existir dentro da pasta do clone
|
||||||
|
const fullPath = path.join(folderPath, targetFile);
|
||||||
|
|
||||||
|
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
|
||||||
|
// Se for HTML, injeta a barra de preview flutuante
|
||||||
|
if (targetFile.endsWith('.html')) {
|
||||||
|
let html = fs.readFileSync(fullPath, 'utf8');
|
||||||
|
const previewBar = `
|
||||||
|
<div id="__cloneweb_preview_bar" style="position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #1f2937; color: white; padding: 12px 24px; border-radius: 50px; box-shadow: 0 10px 25px rgba(0,0,0,0.3); display: flex; align-items: center; gap: 16px; z-index: 2147483647; font-family: 'Inter', sans-serif; font-size: 14px;">
|
||||||
|
<span style="display: flex; align-items: center; gap: 8px;"><i class="fas fa-eye" style="color: #10b981;"></i> Live Preview: <strong style="color: #60a5fa;">${folderName.split('_')[0]}</strong></span>
|
||||||
|
<a href="/api/exit-preview" style="background: #ef4444; color: white; padding: 6px 16px; border-radius: 30px; text-decoration: none; font-weight: 600; transition: all 0.2s; box-shadow: 0 4px 12px rgba(239,68,68,0.3); font-size: 13px;">Sair do Preview</a>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
if (html.includes('</body>')) {
|
||||||
|
html = html.replace('</body>', previewBar + '</body>');
|
||||||
|
} else {
|
||||||
|
html += previewBar;
|
||||||
|
}
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
return res.send(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Para outros arquivos (CSS, JS, imagens), serve diretamente com o MIME type correto
|
||||||
|
if (targetFile.endsWith('.css')) res.setHeader('Content-Type', 'text/css');
|
||||||
|
if (targetFile.endsWith('.js')) res.setHeader('Content-Type', 'application/javascript');
|
||||||
|
return res.sendFile(fullPath);
|
||||||
|
} else {
|
||||||
|
// Fallback de SPA: se a rota virtual não existir como arquivo no disco, serve o index.html do clone!!!
|
||||||
|
const indexPath = path.join(folderPath, 'index.html');
|
||||||
|
if (fs.existsSync(indexPath)) {
|
||||||
|
let html = fs.readFileSync(indexPath, 'utf8');
|
||||||
|
const previewBar = `
|
||||||
|
<div id="__cloneweb_preview_bar" style="position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #1f2937; color: white; padding: 12px 24px; border-radius: 50px; box-shadow: 0 10px 25px rgba(0,0,0,0.3); display: flex; align-items: center; gap: 16px; z-index: 2147483647; font-family: 'Inter', sans-serif; font-size: 14px;">
|
||||||
|
<span style="display: flex; align-items: center; gap: 8px;"><i class="fas fa-eye" style="color: #10b981;"></i> Live Preview: <strong style="color: #60a5fa;">${folderName.split('_')[0]}</strong></span>
|
||||||
|
<a href="/api/exit-preview" style="background: #ef4444; color: white; padding: 6px 16px; border-radius: 30px; text-decoration: none; font-weight: 600; transition: all 0.2s; box-shadow: 0 4px 12px rgba(239,68,68,0.3); font-size: 13px;">Sair do Preview</a>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
if (html.includes('</body>')) html = html.replace('</body>', previewBar + '</body>');
|
||||||
|
else html += previewBar;
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
return res.send(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// Serve static files with proper MIME types
|
// Serve static files with proper MIME types
|
||||||
app.use(express.static(path.join(__dirname, 'public'), {
|
app.use(express.static(path.join(__dirname, 'public'), {
|
||||||
setHeaders: (res, path) => {
|
setHeaders: (res, path) => {
|
||||||
@@ -33,6 +128,137 @@ app.use(express.static(path.join(__dirname, 'public'), {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Middleware para injetar fix de roteador em sites clonados (SPAs como React, Vue, Angular, Vite) e reescrever JS
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
if (!req.path.startsWith('/api') && req.path !== '/' && req.path !== '/old') {
|
||||||
|
let urlPath = req.path;
|
||||||
|
// Remover prefixo /cloned-sites se existir para buscar corretamente no disco
|
||||||
|
if (urlPath.startsWith('/cloned-sites/')) {
|
||||||
|
urlPath = urlPath.replace('/cloned-sites/', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!urlPath.match(/\.[a-zA-Z0-9]+$/)) {
|
||||||
|
if (!urlPath.endsWith('/')) urlPath += '/';
|
||||||
|
urlPath += 'index.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interceptação de arquivos HTML (Camada 1 - DOM Mock Universal)
|
||||||
|
if (urlPath.endsWith('.html')) {
|
||||||
|
const filePath = path.join(__dirname, '..', 'cloned-sites', urlPath);
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
try {
|
||||||
|
let html = fs.readFileSync(filePath, 'utf8');
|
||||||
|
if (!html.includes('__CLONEWEB_ROUTER_FIX__')) {
|
||||||
|
const injectScript = `
|
||||||
|
<script id="__CLONEWEB_ROUTER_FIX__">
|
||||||
|
(function() {
|
||||||
|
try {
|
||||||
|
window.__mockLocationPathname = '/';
|
||||||
|
window.__mockLocationHref = window.location.protocol + '//' + window.location.host + '/';
|
||||||
|
|
||||||
|
let targetObj = window.location;
|
||||||
|
let proto = Object.getPrototypeOf(targetObj);
|
||||||
|
let pathDesc = null;
|
||||||
|
let hrefDesc = null;
|
||||||
|
|
||||||
|
while (proto && (!pathDesc || !hrefDesc)) {
|
||||||
|
if (!pathDesc) pathDesc = Object.getOwnPropertyDescriptor(proto, 'pathname');
|
||||||
|
if (!hrefDesc) hrefDesc = Object.getOwnPropertyDescriptor(proto, 'href');
|
||||||
|
proto = Object.getPrototypeOf(proto);
|
||||||
|
}
|
||||||
|
if (!pathDesc) pathDesc = Object.getOwnPropertyDescriptor(targetObj, 'pathname');
|
||||||
|
if (!hrefDesc) hrefDesc = Object.getOwnPropertyDescriptor(targetObj, 'href');
|
||||||
|
|
||||||
|
if (pathDesc && pathDesc.configurable) {
|
||||||
|
const origGet = pathDesc.get;
|
||||||
|
Object.defineProperty(proto || targetObj, 'pathname', {
|
||||||
|
get: function() {
|
||||||
|
const p = origGet ? origGet.call(this) : this.pathname;
|
||||||
|
if (p !== '/' && p !== '/index.html' && (p.includes('_202') || p.includes('/cloned-sites/'))) {
|
||||||
|
return '/';
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
},
|
||||||
|
set: pathDesc.set || function(v) { window.location.assign(v); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hrefDesc && hrefDesc.configurable) {
|
||||||
|
const origHrefGet = hrefDesc.get;
|
||||||
|
Object.defineProperty(proto || targetObj, 'href', {
|
||||||
|
get: function() {
|
||||||
|
const h = origHrefGet ? origHrefGet.call(this) : this.href;
|
||||||
|
if (h.includes('_202') || h.includes('/cloned-sites/')) {
|
||||||
|
const u = new URL(h);
|
||||||
|
return u.protocol + '//' + u.host + '/';
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
},
|
||||||
|
set: hrefDesc.set || function(v) { window.location.assign(v); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const OriginalURL = window.URL;
|
||||||
|
window.URL = function(url, base) {
|
||||||
|
if (typeof url === 'string' && (url.includes('_202') || url.includes('/cloned-sites/'))) {
|
||||||
|
url = url.replace(/\\/cloned-sites\\/[^/]+/gi, '').replace(/\\/[^/]+_202[0-9-_T:.]+(\\/index\\.html)?/gi, '/');
|
||||||
|
}
|
||||||
|
return new OriginalURL(url, base);
|
||||||
|
};
|
||||||
|
window.URL.prototype = OriginalURL.prototype;
|
||||||
|
Object.assign(window.URL, OriginalURL);
|
||||||
|
|
||||||
|
console.log('🚀 [CloneWeb] Ultimate SPA Router fix initialized successfully (Cross-browser Gecko/Blink support).');
|
||||||
|
} catch(e) {
|
||||||
|
console.error('⚠️ [CloneWeb] DOM mock fallback active. Using __mockLocationPathname. Error:', e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
`;
|
||||||
|
if (html.includes('<head>')) {
|
||||||
|
html = html.replace('<head>', '<head>' + injectScript);
|
||||||
|
} else {
|
||||||
|
html = injectScript + html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
return res.send(html);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Erro ao injetar fix no HTML do clone:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interceptação de arquivos JS de sites clonados (Camada 2 - JS Rewriter Supremo)
|
||||||
|
if (urlPath.endsWith('.js') && (urlPath.includes('_202') || urlPath.includes('/cloned-sites/'))) {
|
||||||
|
const filePath = path.join(__dirname, '..', 'cloned-sites', urlPath);
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
try {
|
||||||
|
let jsContent = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|
||||||
|
// Substitui window.location.pathname de forma segura
|
||||||
|
jsContent = jsContent.replace(/\bwindow\.location\.pathname\b/g, '(window.__mockLocationPathname || window.location.pathname)');
|
||||||
|
|
||||||
|
// Substitui location.pathname isolado (evita quebrar e.location.pathname ou history.location.pathname)
|
||||||
|
jsContent = jsContent.replace(/(?<!\w\.)\blocation\.pathname\b/g, '(window.__mockLocationPathname || window.location.pathname)');
|
||||||
|
|
||||||
|
// Substitui window.location.href de forma segura
|
||||||
|
jsContent = jsContent.replace(/\bwindow\.location\.href\b/g, '(window.__mockLocationHref || window.location.href)');
|
||||||
|
|
||||||
|
// Substitui location.href isolado (evita quebrar e.location.href ou history.location.href)
|
||||||
|
jsContent = jsContent.replace(/(?<!\w\.)\blocation\.href\b/g, '(window.__mockLocationHref || window.location.href)');
|
||||||
|
|
||||||
|
res.setHeader('Content-Type', 'application/javascript');
|
||||||
|
return res.send(jsContent);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Erro ao reescrever JS do clone:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// Serve cloned sites directory
|
// Serve cloned sites directory
|
||||||
app.use(express.static(path.join(__dirname, '..', 'cloned-sites'), {
|
app.use(express.static(path.join(__dirname, '..', 'cloned-sites'), {
|
||||||
setHeaders: (res, filePath) => {
|
setHeaders: (res, filePath) => {
|
||||||
@@ -82,10 +308,10 @@ app.post('/api/wget-clone', async (req, res) => {
|
|||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
const containerId = require('os').hostname();
|
const containerId = require('os').hostname();
|
||||||
const cloneDir = directory.split('/').pop();
|
const cloneDir = directory.split('/').pop();
|
||||||
const hostDir = '/root/Desktop/Clonados';
|
const hostDir = req.body.outputDir || '/root/Desktop/CLONE_SITE';
|
||||||
exec(`docker cp ${containerId}:${directory} ${hostDir}/ 2>/dev/null`, (err) => {
|
exec(`mkdir -p "${hostDir}" && cp -r "${directory}" "${hostDir}/" 2>/dev/null || docker cp ${containerId}:"${directory}" "${hostDir}/" 2>/dev/null`, (err) => {
|
||||||
if (err) console.log('⚠️ Sync to host failed:', err.message);
|
if (err) console.log('⚠️ Sync to host failed:', err.message);
|
||||||
else console.log('✅ Clone synced to host:', cloneDir);
|
else console.log('✅ Clone synced to host Desktop:', cloneDir);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +327,7 @@ app.post('/api/wget-clone', async (req, res) => {
|
|||||||
|
|
||||||
// Smart Clone Endpoint (Local Spawn)
|
// Smart Clone Endpoint (Local Spawn)
|
||||||
app.post('/api/smart-clone', (req, res) => {
|
app.post('/api/smart-clone', (req, res) => {
|
||||||
const { url } = req.body;
|
const { url, folderName } = req.body;
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return res.status(400).json({ error: 'URL is required' });
|
return res.status(400).json({ error: 'URL is required' });
|
||||||
@@ -112,9 +338,12 @@ app.post('/api/smart-clone', (req, res) => {
|
|||||||
|
|
||||||
// Spawn the smart cloner process
|
// Spawn the smart cloner process
|
||||||
const scriptPath = path.join(__dirname, '..', 'simple-crawler', 'smart-cloner.js');
|
const scriptPath = path.join(__dirname, '..', 'simple-crawler', 'smart-cloner.js');
|
||||||
console.log(`[SmartClone] Executing: node "${scriptPath}" --url="${url}"`);
|
let spawnArgs = [scriptPath, `--url=${url}`];
|
||||||
|
if (folderName) spawnArgs.push(`--folderName=${folderName}`);
|
||||||
|
|
||||||
const child = spawn('node', [scriptPath, `--url=${url}`], {
|
console.log(`[SmartClone] Executing: node "${scriptPath}" --url="${url}" ${folderName ? `--folderName="${folderName}"` : ''}`);
|
||||||
|
|
||||||
|
const child = spawn('node', spawnArgs, {
|
||||||
cwd: path.join(__dirname, '..'),
|
cwd: path.join(__dirname, '..'),
|
||||||
shell: true
|
shell: true
|
||||||
});
|
});
|
||||||
@@ -152,6 +381,20 @@ app.post('/api/smart-clone', (req, res) => {
|
|||||||
if (matches && matches.length > 0) {
|
if (matches && matches.length > 0) {
|
||||||
const lastMatch = matches[matches.length - 1];
|
const lastMatch = matches[matches.length - 1];
|
||||||
const result = JSON.parse(lastMatch);
|
const result = JSON.parse(lastMatch);
|
||||||
|
|
||||||
|
// Sync to host /root/Desktop/Clonados
|
||||||
|
const directory = result.data?.directory || result.directory || result.path;
|
||||||
|
if (result.success && directory) {
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
const containerId = require('os').hostname();
|
||||||
|
const cloneDir = directory.split('/').pop();
|
||||||
|
const hostDir = req.body.outputDir || '/root/Desktop/CLONE_SITE';
|
||||||
|
exec(`mkdir -p "${hostDir}" && cp -r "${directory}" "${hostDir}/" 2>/dev/null || docker cp ${containerId}:"${directory}" "${hostDir}/" 2>/dev/null`, (err) => {
|
||||||
|
if (err) console.log('⚠️ SmartClone sync to host failed:', err.message);
|
||||||
|
else console.log('✅ SmartClone synced to host Desktop:', cloneDir);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: result.success,
|
success: result.success,
|
||||||
data: result,
|
data: result,
|
||||||
@@ -186,7 +429,102 @@ app.get('/api/health', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Abrir pasta do clone
|
// Rota de visualização de arquivos da pasta clonada (Gerenciador de Arquivos Web Embutido)
|
||||||
|
app.get('/api/browse/:folder', (req, res) => {
|
||||||
|
try {
|
||||||
|
const folderName = req.params.folder;
|
||||||
|
const folderPath = path.join(__dirname, '..', 'cloned-sites', folderName);
|
||||||
|
|
||||||
|
if (!fs.existsSync(folderPath)) {
|
||||||
|
return res.status(404).send('<h1>Pasta não encontrada</h1><p>A pasta solicitada não existe no servidor.</p>');
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = fs.readdirSync(folderPath);
|
||||||
|
let filesHtml = '';
|
||||||
|
|
||||||
|
items.forEach(item => {
|
||||||
|
const itemPath = path.join(folderPath, item);
|
||||||
|
const stat = fs.statSync(itemPath);
|
||||||
|
const isDir = stat.isDirectory();
|
||||||
|
const size = isDir ? '-' : (stat.size / 1024).toFixed(2) + ' KB';
|
||||||
|
const date = new Date(stat.mtime).toLocaleString('pt-BR');
|
||||||
|
const icon = isDir ? 'fa-folder' : (item.endsWith('.html') ? 'fa-file-code' : (item.endsWith('.json') ? 'fa-file-alt' : 'fa-file'));
|
||||||
|
const link = isDir ? `#` : `/${folderName}/${item}`;
|
||||||
|
|
||||||
|
filesHtml += `
|
||||||
|
<tr>
|
||||||
|
<td><i class="fas ${icon}" style="color: #4f46e5; margin-right: 10px;"></i> <a href="${link}" target="_blank" style="color: #1f2937; text-decoration: none; font-weight: 500;">${item}</a></td>
|
||||||
|
<td style="color: #6b7280;">${size}</td>
|
||||||
|
<td style="color: #6b7280;">${date}</td>
|
||||||
|
<td>
|
||||||
|
${!isDir ? `<a href="${link}" target="_blank" class="btn btn-secondary btn-sm" style="background: #e0e7ff; color: #4f46e5; padding: 5px 10px; border-radius: 6px; text-decoration: none; font-size: 14px;">Visualizar</a>` : ''}
|
||||||
|
${!isDir ? `<a href="${link}" download="${item}" class="btn btn-secondary btn-sm" style="background: #fee2e2; color: #ef4444; padding: 5px 10px; border-radius: 6px; text-decoration: none; font-size: 14px; margin-left: 5px;">Baixar</a>` : ''}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pt-BR">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Arquivos Clonados - ${folderName}</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Inter', sans-serif; background: #f3f4f6; margin: 0; padding: 40px 20px; color: #1f2937; }
|
||||||
|
.container { max-width: 1000px; margin: 0 auto; background: white; border-radius: 16px; box-shadow: 0 10px 25px rgba(0,0,0,0.05); overflow: hidden; padding: 30px; }
|
||||||
|
.header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e5e7eb; padding-bottom: 20px; margin-bottom: 25px; }
|
||||||
|
.header h1 { font-size: 24px; margin: 0; color: #111827; display: flex; align-items: center; gap: 12px; }
|
||||||
|
.actions { display: flex; gap: 12px; }
|
||||||
|
.btn { padding: 10px 20px; border-radius: 8px; font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; font-size: 14px; transition: all 0.2s; }
|
||||||
|
.btn-primary { background: #4f46e5; color: white; }
|
||||||
|
.btn-primary:hover { background: #4338ca; }
|
||||||
|
.btn-secondary { background: #f3f4f6; color: #374151; }
|
||||||
|
.btn-secondary:hover { background: #e5e7eb; }
|
||||||
|
table { width: 100%; border-collapse: collapse; text-align: left; }
|
||||||
|
th { padding: 16px; background: #f9fafb; font-weight: 600; color: #374151; border-bottom: 1px solid #e5e7eb; font-size: 14px; }
|
||||||
|
td { padding: 16px; border-bottom: 1px solid #e5e7eb; font-size: 15px; }
|
||||||
|
tr:hover { background: #f9fafb; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1><i class="fas fa-folder-open" style="color: #4f46e5;"></i> ${folderName}</h1>
|
||||||
|
<div class="actions">
|
||||||
|
<a href="/${folderName}/index.html" target="_blank" class="btn btn-primary"><i class="fas fa-external-link-alt"></i> Abrir Site Clonado</a>
|
||||||
|
<a href="/" class="btn btn-secondary"><i class="fas fa-arrow-left"></i> Voltar ao Dashboard</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nome do Ficheiro</th>
|
||||||
|
<th>Tamanho</th>
|
||||||
|
<th>Modificado em</th>
|
||||||
|
<th>Ações</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${filesHtml}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
res.send(html);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao listar pasta:', error);
|
||||||
|
res.status(500).send('<h1>Erro interno do servidor</h1>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Abrir pasta do clone (mantém compatibilidade legada e retorna a URL do Web Browse)
|
||||||
app.post('/api/open-folder', (req, res) => {
|
app.post('/api/open-folder', (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { path: folderPath } = req.body;
|
const { path: folderPath } = req.body;
|
||||||
@@ -194,14 +532,10 @@ app.post('/api/open-folder', (req, res) => {
|
|||||||
return res.status(400).json({ error: 'Caminho da pasta é obrigatório' });
|
return res.status(400).json({ error: 'Caminho da pasta é obrigatório' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abrir pasta no gerenciador de ficheiros
|
const folderName = path.basename(folderPath);
|
||||||
exec(`xdg-open "${folderPath}"`, (error) => {
|
const browseUrl = `/api/browse/${folderName}`;
|
||||||
if (error) {
|
|
||||||
console.error('Erro ao abrir pasta:', error);
|
res.json({ success: true, message: 'Pasta acessível via Web', url: browseUrl });
|
||||||
return res.status(500).json({ error: 'Não foi possível abrir a pasta' });
|
|
||||||
}
|
|
||||||
res.json({ success: true, message: 'Pasta aberta com sucesso' });
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao abrir pasta:', error);
|
console.error('Erro ao abrir pasta:', error);
|
||||||
res.status(500).json({ error: 'Erro interno do servidor' });
|
res.status(500).json({ error: 'Erro interno do servidor' });
|
||||||
@@ -216,20 +550,10 @@ app.post('/api/open-site', (req, res) => {
|
|||||||
return res.status(400).json({ error: 'Caminho do site é obrigatório' });
|
return res.status(400).json({ error: 'Caminho do site é obrigatório' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extrair apenas o nome da pasta (último segmento do caminho)
|
|
||||||
const folderName = path.basename(sitePath);
|
const folderName = path.basename(sitePath);
|
||||||
const siteUrl = `http://localhost:${PORT}/${folderName}/index.html`;
|
const siteUrl = `/${folderName}/index.html`;
|
||||||
|
|
||||||
console.log(`🌍 Opening site via HTTP: ${siteUrl}`);
|
res.json({ success: true, message: 'Site aberto com sucesso', url: siteUrl });
|
||||||
|
|
||||||
// Abrir URL no navegador padrão (Linux)
|
|
||||||
exec(`xdg-open "${siteUrl}"`, (error) => {
|
|
||||||
if (error) {
|
|
||||||
console.error('Erro ao abrir site:', error);
|
|
||||||
return res.status(500).json({ error: 'Não foi possível abrir o site via HTTP' });
|
|
||||||
}
|
|
||||||
res.json({ success: true, message: 'Site aberto via HTTP com sucesso', url: siteUrl });
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao abrir site:', error);
|
console.error('Erro ao abrir site:', error);
|
||||||
res.status(500).json({ error: 'Erro interno do servidor' });
|
res.status(500).json({ error: 'Erro interno do servidor' });
|
||||||
@@ -282,13 +606,39 @@ app.get('/index', (req, res) => {
|
|||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// List optimized pages
|
||||||
|
app.get('/api/optimized-pages', (req, res) => {
|
||||||
|
try {
|
||||||
|
const clonesDir = path.join(__dirname, '..', 'cloned-sites');
|
||||||
|
if (!fs.existsSync(clonesDir)) {
|
||||||
|
return res.json({ success: true, pages: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = fs.readdirSync(clonesDir);
|
||||||
|
const optimized = items
|
||||||
|
.filter(item => {
|
||||||
|
const fullPath = path.join(clonesDir, item);
|
||||||
|
return fs.statSync(fullPath).isDirectory() && item.endsWith('_designer');
|
||||||
|
})
|
||||||
|
.map(item => ({
|
||||||
|
name: item,
|
||||||
|
directory: item
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json({ success: true, pages: optimized });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error listing optimized pages:', error);
|
||||||
|
res.status(500).json({ success: false, error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// AI Agent Route (MiniMax)
|
// AI Agent Route (MiniMax)
|
||||||
app.post('/api/ai/agent', async (req, res) => {
|
app.post('/api/ai/agent', async (req, res) => {
|
||||||
const { systemPrompt, userMessage } = req.body;
|
const { systemPrompt, userMessage } = req.body;
|
||||||
const apiKey = process.env.MINIMAX_API_KEY;
|
const apiKey = process.env.MINIMAX_API_KEY || 'sk-cp-iWzSsdzjVy0tT5dnvv_sGrAlv3Nw7kkrZ8hPK0KjbNeSRQxIY1O6AhkQAq_yrYV1XPJY1TH6ZQeOlJZd-Zi_elkJhef9PcTSzn2m9bcKIxezarM19BREcVM';
|
||||||
|
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
return res.status(500).json({ error: 'MINIMAX_API_KEY is missing in .env' });
|
return res.status(500).json({ error: 'MINIMAX_API_KEY is missing' });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -318,6 +668,177 @@ app.post('/api/ai/agent', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// AI Inject Redesign Route (Pilar 1 - Agente Designer Real)
|
||||||
|
app.post('/api/ai/inject-redesign', (req, res) => {
|
||||||
|
const { cloneDir, appliedStyles, elementsRedesigned, outputDir, agentName } = req.body;
|
||||||
|
if (!cloneDir) return res.status(400).json({ error: 'cloneDir is required' });
|
||||||
|
|
||||||
|
let originalFolderName = '';
|
||||||
|
let folderPath = '';
|
||||||
|
let newFolderPath = '';
|
||||||
|
|
||||||
|
// Sempre usar o diretório interno (cloned-sites)
|
||||||
|
const cleanDir = cloneDir.endsWith('/') ? cloneDir.slice(0, -1) : cloneDir;
|
||||||
|
originalFolderName = cleanDir.split('/').pop();
|
||||||
|
folderPath = path.join(__dirname, '..', 'cloned-sites', originalFolderName);
|
||||||
|
newFolderPath = path.join(__dirname, '..', 'cloned-sites', `${originalFolderName}_${agentName || 'designer'}`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(folderPath)) {
|
||||||
|
return res.status(404).json({ error: 'Cloned site folder not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Criar o arquivo CSS de Redesign Ultra-Moderno (__ai_redesign.css)
|
||||||
|
const cssContent = `
|
||||||
|
/* ==========================================================================
|
||||||
|
BRAINSTEEL WEB - AI ULTRA-MODERN REDESIGN (AGENTE DESIGNER)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;600;800&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--ai-bg-dark: #0b0f19;
|
||||||
|
--ai-bg-card: rgba(18, 24, 38, 0.7);
|
||||||
|
--ai-border-glass: rgba(255, 255, 255, 0.08);
|
||||||
|
--ai-accent-glow: #3b82f6;
|
||||||
|
--ai-accent-gradient: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%);
|
||||||
|
--ai-text-main: #f3f4f6;
|
||||||
|
--ai-text-muted: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Força Dark Mode elegante e tipografia moderna no body e containers principais */
|
||||||
|
body, main, #root, #app, .app, .main, .container, .wrapper, header, footer, section {
|
||||||
|
background-color: var(--ai-bg-dark) !important;
|
||||||
|
color: var(--ai-text-main) !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Glassmorphism e Glow em Cards, Painéis, Cabeçalhos e Rodapés */
|
||||||
|
div[class*="card"], div[class*="panel"], div[class*="box"], div[class*="container"], div[class*="item"], header, footer, nav, .navbar, .header, .footer {
|
||||||
|
background: var(--ai-bg-card) !important;
|
||||||
|
backdrop-filter: blur(16px) !important;
|
||||||
|
-webkit-backdrop-filter: blur(16px) !important;
|
||||||
|
border: 1px solid var(--ai-border-glass) !important;
|
||||||
|
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.5) !important;
|
||||||
|
border-radius: 16px !important;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[class*="card"]:hover, div[class*="item"]:hover {
|
||||||
|
transform: translateY(-5px) !important;
|
||||||
|
border-color: rgba(59, 130, 246, 0.4) !important;
|
||||||
|
box-shadow: 0 20px 40px -15px rgba(59, 130, 246, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Títulos com Gradiente Vibrante (Outfit Font) */
|
||||||
|
h1, h2, h3, h4, h5, .title, .heading, .header-title {
|
||||||
|
font-family: 'Outfit', sans-serif !important;
|
||||||
|
background: var(--ai-accent-gradient) !important;
|
||||||
|
-webkit-background-clip: text !important;
|
||||||
|
-webkit-text-fill-color: transparent !important;
|
||||||
|
background-clip: text !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
letter-spacing: -0.03em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Botões Ultra-Modernos com Gradiente e Animação de Pulso */
|
||||||
|
button, .btn, a[class*="btn"], input[type="submit"], input[type="button"] {
|
||||||
|
background: var(--ai-accent-gradient) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 50px !important;
|
||||||
|
padding: 12px 28px !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.02em !important;
|
||||||
|
box-shadow: 0 10px 25px -5px rgba(139, 92, 246, 0.5) !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
text-transform: none !important;
|
||||||
|
-webkit-text-fill-color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover, .btn:hover, a[class*="btn"]:hover {
|
||||||
|
transform: scale(1.05) translateY(-2px) !important;
|
||||||
|
box-shadow: 0 15px 35px -5px rgba(236, 72, 153, 0.6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inputs e Textareas com Efeito Glass */
|
||||||
|
input, select, textarea, .input, .form-control {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
border: 1px solid var(--ai-border-glass) !important;
|
||||||
|
color: var(--ai-text-main) !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
padding: 12px 16px !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus, select:focus, textarea:focus {
|
||||||
|
outline: none !important;
|
||||||
|
border-color: var(--ai-accent-glow) !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links e Textos Secundários */
|
||||||
|
a {
|
||||||
|
color: var(--ai-accent-glow) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
transition: color 0.2s !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #8b5cf6 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, span, li, label, td, th {
|
||||||
|
color: var(--ai-text-muted) !important;
|
||||||
|
line-height: 1.6 !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Copy the original folder to the new folder
|
||||||
|
exec(`cp -r "${folderPath}" "${newFolderPath}"`, (copyErr) => {
|
||||||
|
if (copyErr) {
|
||||||
|
console.error('Error copying folder for agent redesign:', copyErr);
|
||||||
|
return res.status(500).json({ error: 'Failed to create new agent folder' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Criar o arquivo CSS de Redesign Ultra-Moderno (__ai_redesign.css) no novo diretório
|
||||||
|
const cssPath = path.join(newFolderPath, '__ai_redesign.css');
|
||||||
|
fs.writeFileSync(cssPath, cssContent, 'utf8');
|
||||||
|
|
||||||
|
// 2. Injetar a tag <link> no index.html do novo clone
|
||||||
|
const indexPath = path.join(newFolderPath, 'index.html');
|
||||||
|
if (fs.existsSync(indexPath)) {
|
||||||
|
let html = fs.readFileSync(indexPath, 'utf8');
|
||||||
|
const linkTag = `\n<link rel="stylesheet" href="/__ai_redesign.css" id="__AI_REDESIGN_LINK__">\n`;
|
||||||
|
|
||||||
|
if (!html.includes('__ai_redesign.css')) {
|
||||||
|
if (html.includes('</head>')) {
|
||||||
|
html = html.replace('</head>', linkTag + '</head>');
|
||||||
|
} else {
|
||||||
|
html = linkTag + html;
|
||||||
|
}
|
||||||
|
fs.writeFileSync(indexPath, html, 'utf8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Sincronizar o novo diretório com o host
|
||||||
|
const hostDir = outputDir || '/root/Desktop/CLONE_SITE';
|
||||||
|
const containerId = require('os').hostname();
|
||||||
|
exec(`mkdir -p "${hostDir}" && cp -r "${newFolderPath}" "${hostDir}/" 2>/dev/null || docker cp ${containerId}:"${newFolderPath}" "${hostDir}/" 2>/dev/null`, (syncErr) => {
|
||||||
|
if (syncErr) console.log('⚠️ Redesign sync to host failed:', syncErr.message);
|
||||||
|
else console.log('✅ Redesign synced to host output dir:', path.basename(newFolderPath));
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({ success: true, message: 'AI Redesign CSS injected successfully', newFolderName: path.basename(newFolderPath) });
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error injecting AI redesign:', err);
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Handle 404s
|
// Handle 404s
|
||||||
app.use((req, res) => {
|
app.use((req, res) => {
|
||||||
res.status(404).json({
|
res.status(404).json({
|
||||||
|
|||||||
Reference in New Issue
Block a user