From cc5147946c8bd23c436d2a70e2784e6b24a43e7e Mon Sep 17 00:00:00 2001 From: Evandro Fonseca Junior Date: Mon, 14 Sep 2026 06:08:51 -0300 Subject: [PATCH] docs: reescreve o README para o estado real do projeto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O README descrevia um proxy de streaming com `GET /stream?url=&offset=` que não existe mais (a rota responde 410 desde a reescrita do backend), falava em "retomar downloads" e não mencionava sessão, storage temporário, polling de tasks nem o endpoint de entrega do arquivo. O novo texto segue o padrão da auditoria: one-liner, badges reais (sem licença e sem CI, que não existem no repo), Sobre, Como funciona com diagrama, Stack, Requisitos, Início rápido testado, Uso, API, Produção, Estrutura do projeto, Verificação, Estado atual e limitações, Documentação e Licença. O que está escrito corresponde ao que foi executado nesta auditoria: install, build, lint, 13 checagens de API, download de 10 MB com sha256 idêntico ao da origem e a interface rodando em Chrome headless. --- README.md | 215 +++++++++++++++++++++++++++--------------------------- 1 file changed, 106 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 46e3a52..efbf2a2 100644 --- a/README.md +++ b/README.md @@ -1,153 +1,150 @@ -## Ephemeral Downloader +# Ephemeral Downloader -Um proxy de download efêmero para você usar a **sua VPS como ponte de alta velocidade** entre servidores lentos e a sua máquina local. +**Proxy de download efêmero: a sua VPS baixa o arquivo por uma rota melhor e entrega para o seu navegador, com os arquivos apagados automaticamente depois.** -Em vez de baixar direto de um host congestionado, você aponta o link para o Ephemeral Downloader, que: +![Node](https://img.shields.io/badge/Node-%3E%3D20.19-5FA04E?logo=nodedotjs&logoColor=white) +![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?logo=typescript&logoColor=white) +![Fastify](https://img.shields.io/badge/Fastify-5-000000?logo=fastify&logoColor=white) +![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=black) +![Vite](https://img.shields.io/badge/Vite-7-646CFF?logo=vite&logoColor=white) +![pnpm](https://img.shields.io/badge/pnpm-9%2B-F69220?logo=pnpm&logoColor=white) -- Faz o download via VPS (geralmente com rota/peering melhor). -- Transmite o arquivo por **streaming** para o seu navegador. -- Libera os recursos assim que o download termina. +## Sobre -Simples, focado e pensado para quem vive baixando ISOs, ROMs e arquivos grandes. +Baixar um arquivo grande direto de um host congestionado costuma ser lento, e muitas vezes o gargalo não é a sua internet nem o servidor de origem, e sim o caminho entre eles. O Ephemeral Downloader coloca a sua VPS no meio: o servidor faz o download (normalmente com peering melhor), mostra o progresso em tempo real e entrega o arquivo para você pelo navegador. ---- +O projeto é focado em uso efêmero. O arquivo fica em um diretório temporário da sessão no servidor e é apagado quando a sessão expira (1 hora sem interação). Não é um proxy de streaming puro: o download passa pelo disco do servidor antes de chegar até você. -## Como funciona (visão rápida) +## Como funciona -- **Frontend (React + Vite)** +``` +navegador (React + Vite) + │ POST /api/queue {url} GET /api/tasks (polling de 2 s) + ▼ ▲ +Fastify (server/) ──undici GET──▶ host de origem │ + │ │ + ▼ │ +server/storage//_ ────────┘ + ▲ + │ GET /api/download/:taskId (arquivo concluído) +navegador +``` - - Interface SPA com campo de texto para múltiplos links (um por linha). - - Lista de downloads recentes com: - - Progresso em tempo real. - - Tamanho total e já baixado. - - Velocidade em **MB/s** e **Mbps**. - - Botão para **retomar downloads** que falharam dentro da mesma sessão. +- `POST /api/queue` enfileira a URL e o backend baixa com `undici`, gravando em `server/storage//` por um pipeline (respeita backpressure e só marca a task como concluída depois do arquivo em disco). +- O frontend faz polling de `GET /api/tasks` a cada 2 segundos e mostra status, progresso, bytes recebidos, total e velocidade em MB/s e Mbps. +- Quando a task conclui, o botão "Save to Disk" busca `GET /api/download/:taskId` e salva o arquivo. +- Em produção o próprio Fastify serve o build do Vite na raiz, com fallback da SPA. +- `GET /stream` é o proxy antigo, mantido apenas respondendo 410 (descontinuado). -- **Backend (Fastify + Streams)** - - Rota `GET /stream?url=...&offset=...` que: - - Faz `HEAD` na origem para validar o link e obter `Content-Length`. - - Faz `GET` (ou `Range: bytes=offset-` para retomada). - - Faz o **streaming direto** para o cliente, sem guardar arquivo em disco. - - Em produção, também serve o build do frontend (Vite) na própria porta do servidor. +## Stack ---- +| Camada | Escolha | +|---|---| +| Runtime | Node.js 20.19 ou superior | +| Backend | Fastify 5, undici 7 (cliente HTTP), zod (validação) | +| Frontend | React 19, Vite 7, Tailwind CSS 4, lucide-react | +| Linguagem | TypeScript 5.9 | +| Monorepo | pnpm workspaces (`server` e `web`) | +| Deploy | nixpacks (`nixpacks.toml`) | ## Requisitos -- Node.js **>= 20** -- `pnpm` **>= 8** +- Node.js 20.19 ou superior (exigência do Vite 7 e do undici 7; verificado no Node 24.20.0) +- pnpm 9 ou superior (verificado no pnpm 12.4.1; o lockfile é o formato 9.0) +- Portas livres: backend (padrão 3000) e Vite (5173) em desenvolvimento ---- +Observação sobre pnpm: a seção `overrides` do `pnpm-workspace.yaml` (fastify e undici com versão mínima de segurança) só é aplicada pelo pnpm 10 ou superior. Com pnpm 9 ela é ignorada. -## Instalação - -Clone o repositório e instale as dependências: +## Início rápido ```bash -git clone Downloader -cd Downloader pnpm install -``` ---- - -## Scripts principais - -Na raiz do projeto: - -- **Desenvolvimento (backend + frontend juntos)**: - -```bash +# desenvolvimento: Fastify (3000) + Vite (5173) juntos pnpm dev +# abra http://localhost:5173 ``` -Isso sobe: - -- Fastify em `http://localhost:3000` -- Vite em `http://localhost:5173` - -- **Build de produção (server + web)**: +Em desenvolvimento o Vite encaminha `/api` para o backend (proxy configurado em `web/vite.config.ts`), então não é preciso arquivo `.env`. Se a porta 3000 estiver ocupada: ```bash -pnpm build +PORT=3100 VITE_API_PROXY=http://localhost:3100 pnpm dev ``` -- **Start de produção (tudo pela porta 3000)**: +## Uso + +1. Cole a URL direta (http ou https) de um arquivo e clique em **Download**. +2. A lista de downloads mostra status, progresso, tamanho e velocidade, atualizada a cada 2 segundos. +3. Quando o download conclui, use **Save to Disk** para salvar o arquivo na sua máquina. +4. A sessão dura 1 hora de inatividade (o contador reinicia a cada interação) e depois os arquivos são apagados do servidor. + +## API + +| Método | Rota | O que faz | +|---|---|---| +| GET | `/health` | Devolve `{"status":"ok"}`. | +| GET | `/` | Serve a SPA (build do Vite). | +| GET | `/api/session` | Cria ou recupera a sessão e devolve `sessionId`, `expiresAt` e `remainingMs`. O id também vem no header `x-session-id`. | +| POST | `/api/queue` | Corpo `{"url":"https://..."}`. Enfileira e inicia o download, devolvendo a task criada. | +| GET | `/api/tasks` | Lista as tasks da sessão (usado no polling da interface). | +| GET | `/api/download/:taskId` | Entrega o arquivo concluído da task. | +| GET | `/stream` | Descontinuado: responde 410. | + +A sessão é identificada pelo header `x-session-id` (a interface guarda o id em `localStorage`). Erros observados: 400 para URL inválida (`{"error":"Invalid URL"}`) ou download não pronto, 403 para task de outra sessão e 404 para task inexistente. Se a origem falhar (por exemplo, 404 no host de origem), a task fica com `status: "error"` e a mensagem em `error`. + +## Produção ```bash -pnpm start +pnpm build # server: tsc | web: tsc -b && vite build +PORT=3000 pnpm start # node server/dist/index.js: API + build do front na mesma porta ``` -O servidor Fastify: +O `nixpacks.toml` descreve esse fluxo: build em `pnpm install --frozen-lockfile && pnpm build` e start em `pnpm start`. -- Servirá o build do Vite na raiz (`/`). -- Continuará expondo `GET /stream` para o proxy de download. +Variáveis de ambiente: `PORT` (padrão 3000) e `STORAGE_ROOT` (padrão `server/storage`) no backend; `VITE_API_URL` (host da API no frontend) e `VITE_API_PROXY` (alvo do proxy em dev). ---- +## Estrutura do projeto -## Configuração de ambiente - -### Desenvolvimento - -Por padrão o frontend conversa com o backend em: - -```ts -const API_URL = import.meta.env.VITE_API_URL ?? "http://localhost:3000"; +``` +server/ backend Fastify +├── src/index.ts rotas (/health, /api/*), CORS e static do front +└── src/lib/ + ├── DownloadManager.ts download da origem com undici e gravação na sessão + └── SessionManager.ts sessões, expiração (1 h) e limpeza dos arquivos +web/ frontend React + Vite +├── src/context/ SessionContext (sessão e polling das tasks) +├── src/components/ ui/ (Input, Button, Card, Alert...) e feature/ (form, item, timer) +└── vite.config.ts proxy de /api em desenvolvimento +.agent/ scaffolding de agentes de IA (não faz parte do runtime) +docs/PLAN.md vazio (placeholder nunca preenchido) +nixpacks.toml comandos de build e start do deploy +pnpm-workspace.yaml workspaces, allowBuilds e overrides ``` -Se você mudar a porta ou rodar o backend em outro host, basta criar um arquivo `.env` dentro de `web/`: +## Verificação -```bash -VITE_API_URL=http://seu-backend:3000 -``` +Não há testes automatizados neste repositório. O que existe de fato: -### Produção (Nixpacks ou similar) +- `pnpm build` roda o `tsc` do server e `tsc -b && vite build` do web, e é o gate atual; +- `pnpm --filter web lint` roda o eslint (passa com 1 warning de `exhaustive-deps` em `SessionContext.tsx`); +- verificação manual executada em 14/09/2026 (Linux, Node 24.20.0, pnpm 12.4.1): `pnpm install` e `pnpm build` com exit 0; 13 checagens de API passando (`/health`, `/`, `/api/session`, `/api/queue` com URL inválida e válida, `/api/tasks`, `/api/download/:id`, 400/403/404 e `/stream` respondendo 410); download de 10 MB conferido por sha256 idêntico ao da origem; interface verificada em Chrome headless (sessão inicializada, task concluída e "Save to Disk" baixando o arquivo com o mesmo sha256). -- Defina a variável `PORT` (a maioria das plataformas faz isso automaticamente). -- O servidor Fastify faz fallback para `3000` se `PORT` não estiver definida. -- O arquivo `nixpacks.toml` já descreve: - - Comando de build: `pnpm build` - - Comando de start: `pnpm start` +Adicionar testes automatizados é o próximo passo natural do projeto. ---- +## Estado atual e limitações -## Fluxo de uso típico +- Sessões e tasks ficam em memória: reiniciar o servidor perde a lista de tasks (os arquivos em disco são removidos pelo coletor depois de 1 hora). +- Sem autenticação: qualquer um que alcance o servidor pode enfileirar downloads. Coloque atrás de VPN, autenticação reversa ou firewall. +- Não há retomada de download nem uso de `Range` no fluxo atual (o parâmetro `offset` do antigo `/stream` não existe mais). +- Não há limite de tamanho, banda ou cota: um link muito grande ocupa o disco do servidor até a sessão expirar. +- URLs que não sejam http/https são aceitas na fila e falham depois com `status: "error"`. +- Sem CI configurada e sem arquivo de licença. +- O diretório `.agent/` é scaffolding de ferramentas de IA e não é usado pela aplicação. -1. Você tem uma **VPS bem localizada** (por exemplo, no mesmo continente do servidor de origem). -2. No seu desktop/notebook, abre o Ephemeral Downloader. -3. Cola um ou mais links HTTP/HTTPS diretos (por exemplo, ROMs no SourceForge). -4. Clica em **“Iniciar download”**. -5. A VPS baixa em alta velocidade e o app: - - Mostra o progresso. - - Indica tamanho total / baixado. - - Mostra velocidade agregada em MB/s e Mbps. -6. Se a conexão cair, você pode **retomar** dentro da mesma sessão. +## Documentação ---- +Não há documentação interna além deste README: `docs/PLAN.md` está vazio e `web/README.md` é o texto padrão do template do Vite. -## Limitações intencionais +## Licença -- **Retomada entre sessões** (fechar aba / desligar máquina) **não é suportada**. - - O projeto é focado em uso efêmero, sem manter arquivos em disco no servidor. -- O servidor realiza apenas: - - Validação básica de URL (somente `http`/`https`). - - Proxy por streaming com **backpressure** nativo do Node.js. - - Nenhuma autenticação ou controle de cota por usuário (idealmente coloque atrás de VPN, auth reverso ou firewall). - ---- - -## Ideias futuras - -- Autenticação simples para restringir o painel. -- Limite de banda por IP/usuário. -- Modo “linha de comando” usando a mesma API do servidor. - ---- - -## Por que esse projeto existe? - -Porque às vezes o problema não é a sua internet nem o servidor de origem, e sim o **caminho entre eles**. - -Colocando uma VPS no meio do caminho, você “puxa” o arquivo por uma rota melhor até a VPS e, de lá, faz o streaming até você com muito mais previsibilidade. - -O Ephemeral Downloader encapsula essa ideia em uma interface simples, focada em quem só quer **colar o link, apertar um botão e acompanhar o progresso**. +Sem licença definida no repositório: não existe arquivo `LICENSE` e o `package.json` está marcado como `private`. Defina uma licença antes de reutilizar ou publicar o código.