Evandro Fonseca Junior cc5147946c docs: reescreve o README para o estado real do projeto
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.
2026-09-14 06:08:51 -03:00
2025-11-21 23:32:19 -03:00
2025-11-21 23:32:19 -03:00

Ephemeral Downloader

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.

Node TypeScript Fastify React Vite pnpm

Sobre

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

navegador (React + Vite)
   │  POST /api/queue {url}                 GET /api/tasks (polling de 2 s)
   ▼                                                   ▲
Fastify (server/)  ──undici GET──▶  host de origem      │
   │                                                   │
   ▼                                                   │
server/storage/<id-da-sessao>/<task>_<arquivo> ────────┘
   ▲
   │  GET /api/download/:taskId (arquivo concluído)
navegador
  • POST /api/queue enfileira a URL e o backend baixa com undici, gravando em server/storage/<id-da-sessão>/ 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).

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.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.

Início rápido

pnpm install

# desenvolvimento: Fastify (3000) + Vite (5173) juntos
pnpm dev
# abra http://localhost:5173

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:

PORT=3100 VITE_API_PROXY=http://localhost:3100 pnpm dev

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

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 nixpacks.toml descreve esse fluxo: build em pnpm install --frozen-lockfile && pnpm build e start em pnpm start.

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

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

Verificação

Não há testes automatizados neste repositório. O que existe de fato:

  • 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).

Adicionar testes automatizados é o próximo passo natural do projeto.

Estado atual e limitações

  • 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.

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.

Licença

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.

S
Description
No description provided
Readme
658 KiB
0 Stars 1 Watchers 0 Forks
Languages
Python 80.1%
TypeScript 16.4%
CSS 2.5%
JavaScript 0.9%
HTML 0.1%