Tab Domain Executor Documentação
v 1.0
Introdução
O que é o TDE e por que ele existe

O Tab Domain Executor (TDE) é uma extensão para Google Chrome que oferece uma forma deliberada, segura e reversível de fechar abas agrupadas por domínio. Não é um gerenciador automático — é uma ferramenta de execução controlada, projetada para quando o usuário sabe exatamente o que quer fazer.

O Problema

Navegadores modernos acumulam dezenas (ou centenas) de abas espalhadas em múltiplas janelas. Fechar abas manualmente é tedioso, propenso a erros e, na maioria das vezes, irreversível. As extensões existentes ou automatizam demais (tirando o controle do usuário) ou são complexas demais para uma tarefa simples.

😩 Fechamento manual Clicar no X de cada aba individualmente, uma por uma
⚠️ Sem contexto de escopo Não há visão de quantas abas de um domínio existem nem onde estão
🔥 Ações irreversíveis Uma vez fechadas por engano, as abas desaparecem sem recuperação
🤖 Automação excessiva Ferramentas que decidem por você, sem a confirmação do que será afetado
A Filosofia do TDE

O TDE foi construído sobre três pilares que guiam cada decisão de design:

Controle Total do Usuário Nenhuma ação sem intenção explícita. Cada etapa exige uma decisão consciente e o processo pode ser abandonado a qualquer momento.
Segurança por Design Ações destrutivas só são possíveis após múltiplas etapas de confirmação. Um mecanismo de recuperação de 15 minutos serve como rede de segurança.
Transparência Absoluta O usuário sempre sabe o que vai acontecer: quantas abas serão fechadas, em quais janelas e com possibilidade de reverter.
Sobre esta documentação
Este documento cobre a especificação completa do TDE v1 — desde a motivação e casos de uso até a arquitetura técnica e guia de desenvolvimento. Use a barra lateral para navegar entre as seções.
Overview
Visão geral do sistema e fluxo principal

O TDE é uma extensão Chrome (Manifest V3) construída com TypeScript e Webpack. Seu design segue uma arquitetura modular em camadas onde a UI nunca executa ações diretamente — ela apenas solicita ao background, que orquestra os módulos especializados.

Fluxo Principal

Toda interação no TDE segue sempre o mesmo caminho de 5 etapas:

1
Analisar O usuário clica em "Analisar Abas". O sistema lê todas as abas abertas via Chrome Tabs API.
2
Agrupar As URLs são normalizadas e as abas agrupadas por domínio base (ex: youtube.com).
3
Selecionar O usuário escolhe um domínio e define o escopo: todas as janelas ou janelas específicas.
4
Executar As abas selecionadas são listadas para confirmação e então fechadas em lote.
5
Recuperar Caso necessário, a ação pode ser desfeita em até 15 minutos via mecanismo de recuperação.
Módulos do Sistema

O backend é composto por 5 módulos independentes, cada um com uma responsabilidade única:

Tab Reader
Abstrai o acesso à Chrome Tabs API. Retorna abas e janelas brutas sem qualquer transformação.
Normalizer
Extrai o domínio base de uma URL. Trata erros silenciosamente retornando null para URLs inválidas.
Grouper
Agrupa abas por domínio e por janela para compor os DomainGroup[] e WindowGroup[].
Executor
Executa o fechamento de abas (simples ou em lote) e a restauração via chrome.tabs.create().
Recovery
Mantém o log da última ação em memória com TTL de 15 minutos para permitir reversão.
Transformação de Dados
chrome.tabs.Tab Objeto nativo do Chrome
Tab Reader
chrome.tabs.Tab[] Dados brutos, sem transformação
Normalizer
Tab[] + campo domain adicionado
Grouper
DomainGroup[] Agregado por domínio
Popup UI
Cards de Domínio Renderizados para o usuário
Quick Start
Como instalar e usar em minutos

Instale o TDE em menos de 5 minutos. São apenas três passos: instalar dependências, buildar e carregar no Chrome.

Node.js 18+
npm 9+
Google Chrome 88+
Git (opcional)
1
Obter o projeto
Certifique-se de ter os arquivos do projeto na sua máquina e navegue até a pasta raiz.
bash
cd tab-domain-executor
2
Instalar dependências e buildar
Instala TypeScript, Webpack e todas as dependências, depois gera a pasta dist/ pronta para uso.
bash
npm install
npm run build
💡 Desenvolvimento? Use npm run dev para modo watch — a extensão é recompilada automaticamente a cada alteração.
3
Carregar no Chrome
Abra o gerenciador de extensões e aponte para a pasta dist/ gerada no passo anterior.
a Acesse chrome://extensions na barra de endereços
b Ative o toggle "Modo do desenvolvedor" (canto superior direito)
c Clique em "Carregar sem compactação" e selecione a pasta dist/
d Fixe a extensão na barra clicando em 🧩 → alfinete ao lado de "Tab Domain Executor"
Estrutura gerada em dist/
📁 dist/
📄 background.js
📄 popup.js
📄 popup.html
📄 manifest.json
📁 styles/
📄 main.css
📁 assets/icons/
🖼️ icon16.png · icon32.png · icon48.png · icon128.png
Funcionalidades
Tudo que o TDE é capaz de fazer

O TDE é uma ferramenta focada. Cada funcionalidade foi desenhada para aumentar o controle do usuário sem adicionar complexidade desnecessária.

Análise de Abas
  • todas as abas abertas em todas as janelas via getAllTabs()chrome.tabs.query({})
  • Normaliza URLs via normalizeUrl() extraindo o domínio base (ex: youtube.com)
  • Agrupa abas por domínio via groupByDomain() e por janela via groupByWindow()
  • Exibe quantidade de abas e janelas por domínio
  • Busca por nome de domínio na lista
  • Ordenação: mais abas, menos abas, A→Z, Z→A, mais recente, mais antigo
Seleção de Escopo
  • Escolha entre "Todas as janelas" ou "Escolher janelas"
  • Cards de janelas com contagem de abas por janela
  • Seleção múltipla de janelas por checkbox
  • Botão "Continuar" exibe o total de abas que serão afetadas
  • Navegação de volta sem perda de contexto
Fechamento de Abas
  • Lista todas as abas do escopo definido com título, URL e favicon
  • Fechamento individual por aba via closeSingleTab()chrome.tabs.remove(tabId)
  • Fechamento em lote de todas as abas do escopo via closeBulkTabs()chrome.tabs.remove([...ids])
  • Fechamento em lote armazena log via storeRecoveryLog(), válido por 15 min
  • Feedback visual claro após a execução
Recuperação de Ações
  • Log RecoveryLog em memória da última ação em lote, TTL via RECOVERY_TTL_MS (15 minutos)
  • Exibe botão "Recuperar" na tela inicial com tempo restante via hasRecoverableAction()
  • Recria as abas nas janelas originais via restoreTabs()chrome.tabs.create()
  • Log apagado via clearRecoveryLog() após recuperação ou expiração do setTimeout
  • Não disponível para fechamentos individuais (closeSingleTab não chama storeRecoveryLog)
Fora do Escopo — Intencionalmente

O TDE é deliberadamente simples. As seguintes funcionalidades foram excluídas por design:

🤖 Gerenciamento automático de abas
📊 Análise ou histórico de navegação
💾 Persistência de dados entre sessões
🔔 Notificações ou background monitoring
⚙️ Configurações ou preferências de usuário
↩️ Desfazer fechamentos individuais
Requisitos Funcionais
O que o sistema deve fazer

Os requisitos funcionais definem o comportamento esperado do sistema. Estão organizados em 4 grupos alinhados ao fluxo de uso.

RF-01 a RF-06 — Análise de Abas
IDDescriçãoPrioridade
RF-01O sistema deve ler todas as abas abertas em todas as janelas via chrome.tabs.query({}) somente quando solicitado pelo usuário.Alta
RF-02O sistema deve normalizar a URL de cada aba via normalizeUrl() (url-normalizer.ts) extraindo o domínio base (ex: youtube.com), retornando null para URLs inválidas.Alta
RF-03O sistema deve agrupar as abas por domínio via groupByDomain(), retornando DomainGroup[] com tabCount, windowCount e windowIds. Os campos minTabId e maxTabId são calculados no dispatcher a partir dos IDs das abas para suportar ordenação por recência (RF-05).Alta
RF-04O sistema deve exibir os domínios como cards ordenáveis com busca por texto.Alta
RF-05O sistema deve suportar ordenação por: mais abas, menos abas, A→Z, Z→A, mais recente, mais antigo.Média
RF-06O sistema deve ignorar abas sem domínio válido. URLs com prefixo chrome://, about: ou chrome-extension:// retornam null do normalizador e são excluídas do agrupamento.Alta
RF-07 a RF-10 — Seleção de Escopo
IDDescriçãoPrioridade
RF-07Após selecionar um domínio, o sistema deve oferecer duas opções: "Todas as janelas" ou "Escolher janelas".Alta
RF-08Se "Todas as janelas" (TabScope = 'all'), o sistema deve avançar diretamente para a listagem via filterTabsByScope(tabs, domain, 'all') sem etapa adicional.Alta
RF-09Se "Escolher janelas" (TabScope = 'windows'), o sistema deve exibir cards gerados por groupByWindow() retornando WindowGroup[], com seleção múltipla por checkbox (campo selected).Alta
RF-10O botão "Continuar" deve exibir o total de abas que serão afetadas e estar desabilitado se nenhuma janela for selecionada.Alta
RF-11 a RF-14 — Fechamento de Abas
IDDescriçãoPrioridade
RF-11O sistema deve listar as abas do escopo definido com título, URL completa e favicon.Alta
RF-12O sistema deve permitir fechar uma aba individualmente via closeSingleTab(tabId)chrome.tabs.remove(tabId). Esta ação não chama storeRecoveryLog e é irreversível.Alta
RF-13O sistema deve fechar todas as abas do escopo em lote via closeBulkTabs(tabIds)chrome.tabs.remove([...ids]), seguido de storeRecoveryLog(tabs) em memória.Alta
RF-14Após o fechamento, o sistema deve exibir feedback visual confirmando a ação e informando a disponibilidade de recuperação.Alta
RF-15 a RF-18 — Recuperação
IDDescriçãoPrioridade
RF-15O sistema deve armazenar em memória um RecoveryLog com tabs: TabMinimal[] (url + windowId), timestamp e ttl das abas fechadas em lote.Alta
RF-16O log de recuperação deve expirar automaticamente após RECOVERY_TTL_MS (15 × 60 × 1000 ms) via setTimeout em recovery-manager.ts.Alta
RF-17Na tela inicial, se houver log válido, deve ser exibido botão "Recuperar" com tempo restante.Alta
RF-18Ao recuperar, o sistema deve recriar todas as abas via restoreTabs(tabs)chrome.tabs.create() nas janelas originais e apagar o log via clearRecoveryLog() imediatamente.Alta
Requisitos Não Funcionais
Restrições de qualidade e desempenho

Os requisitos não funcionais definem as restrições de qualidade que o sistema deve atender independentemente do comportamento funcional.

Desempenho
  • RNF-01 A análise de abas deve completar em menos de 2 segundos para até 200 abas abertas.
  • RNF-02 A resposta a ações do usuário (cliques, digitação) não deve apresentar latência perceptível (< 100ms).
  • RNF-03 O fechamento em lote não deve bloquear a UI durante a execução.
Segurança
  • RNF-04 Nenhum dado de navegação deve ser transmitido para servidores externos.
  • RNF-05 O log de recuperação deve existir exclusivamente em memória — variável let recoveryLog: RecoveryLog | null em recovery-manager.ts (sem localStorage ou chrome.storage).
  • RNF-06 A extensão deve operar com as permissões mínimas necessárias: "permissions": ["tabs"] em manifest.json.
Usabilidade
  • RNF-07 O fluxo completo (análise → fechamento) deve ser executável em menos de 5 interações.
  • RNF-08 O usuário deve conseguir entender o estado atual da interface sem nenhuma instrução prévia.
  • RNF-09 O popup deve ter largura fixa de 400px — definida por width: 400px em main.css.
Manutenibilidade
  • RNF-10 Cada módulo deve ter responsabilidade única e ser testável de forma isolada. A suíte de testes deve cobrir todos os módulos de negócio individualmente (unit) e o fluxo de mensagens completo (integration).
  • RNF-11 Todo o código deve ser escrito em TypeScript com tipagem estrita — "strict": true configurado em tsconfig.json.
  • RNF-12 A UI não deve chamar a Chrome API diretamente — toda comunicação passa pelo background via chrome.runtime.sendMessage.
  • RNF-19 A cobertura de testes deve respeitar os thresholds mínimos configurados em jest.config.js: 80% linhas, 80% statements, 75% funções e 70% branches.
Compatibilidade
  • RNF-13 A extensão deve seguir a especificação Manifest V3 do Chrome.
  • RNF-14 Deve ser compatível com Google Chrome versão 88 ou superior.
  • RNF-15 Sem dependências externas de runtime — apenas APIs nativas do Chrome e do navegador.
Confiabilidade
  • RNF-16 Erros em qualquer módulo devem ser capturados e retornados como ActionResult.success = false (tipo ActionResult em common.types.ts), sem propagar exceções para a UI.
  • RNF-17 O log de recuperação deve expirar graciosamente após 15 minutos sem intervenção do usuário.
  • RNF-18 A ausência de favicon não deve impedir a renderização de uma aba na lista.
Casos de Uso
Cenários de interação entre usuários e o sistema

Os casos de uso descrevem as interações entre o Usuário (único ator do sistema) e o TDE. Há 4 casos de uso principais.

Ator: Usuário Pessoa que opera a extensão diretamente. Sem perfis ou níveis de permissão — o sistema tem um único tipo de usuário.
UC-01 Fechar abas de um domínio em todas as janelas
Pré-condiçãoO Chrome possui ao menos 2 abas de um mesmo domínio abertas em qualquer janela.
AtorUsuário
Fluxo Principal
  1. Usuário clica em "Analisar Abas".
  2. Sistema exibe a lista de domínios agrupados.
  3. Usuário seleciona o domínio desejado.
  4. Sistema exibe opções de escopo.
  5. Usuário escolhe "Todas as janelas".
  6. Sistema lista todas as abas do domínio.
  7. Usuário clica em "Fechar todas as abas".
  8. Sistema fecha as abas e exibe confirmação com opção de recuperação.
Pós-condiçãoAs abas do domínio são fechadas em todas as janelas. Log de recuperação criado por 15 min.
UC-02 Fechar abas de um domínio em janelas específicas
Pré-condiçãoO domínio possui abas em ao menos 2 janelas diferentes.
AtorUsuário
Fluxo Principal
  1. Usuário seleciona o domínio e escolhe "Escolher janelas".
  2. Sistema exibe cards de janelas com a contagem de abas de cada uma.
  3. Usuário marca as janelas desejadas via checkbox.
  4. Botão "Continuar" exibe o total de abas que serão afetadas.
  5. Usuário clica em "Continuar".
  6. Sistema lista as abas das janelas selecionadas.
  7. Usuário clica em "Fechar todas as abas".
  8. Sistema fecha apenas as abas das janelas escolhidas.
Fluxo Alternativo — Nenhuma janela selecionada
  1. Usuário não marca nenhuma janela.
  2. Botão "Continuar" permanece desativado.
  3. Usuário deve selecionar ao menos uma janela para prosseguir.
Pós-condiçãoApenas as abas das janelas selecionadas são fechadas. Abas de outras janelas permanecem intactas.
UC-03 Fechar uma aba individualmente
Pré-condiçãoO usuário está na lista de abas (após selecionar domínio e escopo).
AtorUsuário
Fluxo Principal
  1. Usuário localiza a aba desejada na lista.
  2. Usuário clica no botão × ao lado da aba.
  3. Sistema remove a aba imediatamente da lista e fecha no Chrome.
AtençãoFechamento individual não gera log de recuperação. A ação é irreversível.
UC-04 Recuperar a última ação em lote
Pré-condiçãoUm fechamento em lote foi realizado há menos de 15 minutos.
AtorUsuário
Fluxo Principal
  1. Usuário abre a extensão. A tela inicial exibe o botão "Recuperar" com tempo restante.
  2. Usuário clica em "Recuperar".
  3. Sistema recria todas as abas fechadas nas janelas originais.
  4. Log de recuperação é apagado imediatamente.
  5. Sistema exibe confirmação do número de abas restauradas.
Fluxo Alternativo — TTL expirado
  1. 15 minutos se passaram desde o fechamento.
  2. O botão "Recuperar" não é exibido na tela inicial.
  3. A recuperação não está mais disponível.
Pós-condiçãoAs abas são restauradas nas janelas originais. Log apagado. Botão "Recuperar" desaparece da interface.
Diagramas de Casos de Uso
Representação visual dos fluxos de interação

Diagramas visuais dos casos de uso e do fluxo de estados da interface.

Diagrama de Casos de Uso — UML

Relacionamento entre o único ator (Usuário) e os 4 casos de uso do sistema.

« system » Tab Domain Executor Usuário Fechar abas em todas as janelas (UC-01) Fechar abas em janelas específicas (UC-02) Fechar aba individual (UC-03) Recuperar última ação em lote (UC-04)
Diagrama de Fluxo de Estados — Interface

Estados da UI e transições possíveis durante a interação do usuário.

INITIAL Tela inicial Analisar Abas DOMAIN_VIEW Lista de domínios Selecionar domínio SCOPE_SEL. Escopo: janelas Todas as jan. Escolher janelas WINDOW_SEL. Seleção de janelas Continuar TAB_ACTION Lista de abas Fechar tudo FEEDBACK Confirmação ← Voltar RECOVERY Recuperação se TTL válido
Transição principal
Navegação de retorno
Fluxo condicional (TTL)
Fluxos por Caso de Uso
UC-01 Lote v1.0 UC-01 — Fechar abas em todas as janelas
1
Analisar Abas
Usuário clica em "Analisar Abas". O sistema lê todas as abas abertas via chrome.tabs.query({}).
2
Selecionar domínio
Sistema exibe lista de domínios agrupados. Usuário clica no domínio desejado.
3
Definir escopo
Sistema exibe opções de escopo. Usuário escolhe "Todas as janelas".
4
Fechar em lote
Sistema lista as abas do domínio. Usuário clica em "Fechar todas as abas".
5
Feedback + Log
Sistema fecha as abas, exibe confirmação e cria log de recuperação válido por 15 min.
Pré-condições
Há ao menos 2 abas do mesmo domínio abertas em qualquer janela.
Pós-condições
Todas as abas do domínio são fechadas. Log de recuperação criado por 15 min.
Fluxo alternativo
Não há abas do domínio selecionado: a lista aparece vazia e o botão de fechar fica desabilitado.
Módulos envolvidos tab-reader.tsurl-normalizer.tstab-grouper.tsaction-executor.tsrecovery-manager.tsmessage-dispatcher.ts
UC-02 Lote v1.0 UC-02 — Fechar abas em janelas específicas
1
Analisar + Selecionar
Usuário analisa, visualiza a lista de domínios e seleciona o domínio desejado.
2
Escolher janelas
Sistema exibe opções de escopo. Usuário escolhe "Escolher janelas".
3
Marcar janelas
Sistema exibe cards de janelas com contagem de abas. Usuário marca as janelas via checkbox.
4
Confirmar + Fechar
Botão "Continuar" exibe total de abas afetadas. Usuário clica e confirma o fechamento em lote.
5
Feedback + Log
Apenas as abas das janelas selecionadas são fechadas. Log de recuperação criado por 15 min.
Pré-condições
O domínio possui abas em ao menos 2 janelas diferentes.
Pós-condições
Apenas as abas das janelas selecionadas são fechadas. Abas de outras janelas permanecem intactas.
Fluxo alternativo
Nenhuma janela selecionada: botão "Continuar" permanece desabilitado. Usuário deve marcar ao menos uma.
Módulos envolvidos tab-reader.tstab-grouper.tsaction-executor.tsrecovery-manager.tsmessage-dispatcher.ts
UC-03 Individual v1.0 UC-03 — Fechar uma aba individualmente
1
Analisar + Navegar
Usuário analisa abas, seleciona um domínio e define o escopo para chegar à lista de abas.
2
Localizar aba
Usuário visualiza a lista com título, URL e favicon de cada aba do escopo selecionado.
3
Fechar com ×
Usuário clica no botão × ao lado da aba desejada.
4
Remoção imediata
Sistema remove a aba da lista e a fecha no Chrome via chrome.tabs.remove(). Sem log de recuperação.
Pré-condições
O usuário está na tela de lista de abas (após selecionar domínio e escopo).
Pós-condições
A aba selecionada é fechada no Chrome e removida da lista. As demais abas permanecem.
⚠ Atenção
Fechamento individual não gera log de recuperação. A ação é irreversível.
Módulos envolvidos action-executor.tsmessage-dispatcher.ts
UC-04 Recuperação v1.0 UC-04 — Recuperar a última ação em lote
1
Log disponível
Um fechamento em lote foi realizado há menos de 15 min. Log válido em memória no background.
2
Abrir extensão
Usuário abre o popup. Tela inicial exibe botão "Recuperar" com tempo restante visível.
3
Acionar recuperação
Usuário clica em "Recuperar". Sistema solicita restauração ao background via chrome.runtime.sendMessage.
4
Abas restauradas
Sistema recria todas as abas nas janelas originais via chrome.tabs.create(). Log apagado imediatamente.
Pré-condições
Um fechamento em lote (UC-01 ou UC-02) foi realizado há menos de 15 minutos.
Pós-condições
As abas são restauradas nas janelas originais. Log apagado. Botão "Recuperar" desaparece da interface.
Fluxo alternativo — TTL expirado
15 minutos decorridos: log apagado automaticamente, botão "Recuperar" não aparece na tela inicial.
Módulos envolvidos recovery-manager.tsaction-executor.tsmessage-dispatcher.ts
Arquitetura e Estrutura do Projeto
Camadas, módulos e organização de arquivos
Layered Architecture v1.0

Arquitetura em camadas com dependências unidirecionais — camadas externas dependem das internas. A UI nunca acessa a Chrome API diretamente; toda comunicação passa pelo Background Service Worker via chrome.runtime.sendMessage.

UI
Interface do usuário
popup/
Renderiza o fluxo, captura eventos e envia mensagens tipadas ao background. Não acessa Chrome APIs.
Orquestração
Background + Dispatcher
background/
Service Worker que recebe as mensagens da UI, coordena os módulos de negócio e retorna respostas tipadas.
Módulos
Lógica de negócio pura
modules/
5 módulos independentes com responsabilidade única. Apenas Executor e Tab Reader acessam Chrome APIs.
Compartilhado
Tipos & Constantes
shared/
Tipos TypeScript, interfaces, constantes e utils. Consumidos por todas as camadas sem dependências cruzadas.
Estrutura do Projeto
Arquivos essenciais para o funcionamento da extensão.
manifest.json
Manifest V3: define permissões (tabs), service worker, action/popup e ícones da extensão.
background/
Orquestração MV3: recebe mensagens do popup, coordena os módulos e mantém o log de recuperação em memória.
TS
background/background.ts
Entry do Service Worker. Registra o listener chrome.runtime.onMessage e inicializa o dispatcher.
TS
background/message-dispatcher.ts
Ponto central do runtime: roteia mensagens tipadas, coordena módulos e compõe respostas. 410 linhas
modules/
5 módulos de negócio independentes, cada um com responsabilidade única e testável isoladamente.
TS
modules/tab-reader/tab-reader.ts
Abstrai o acesso à chrome.tabs e chrome.windows. Retorna dados brutos sem transformação.
TS
modules/normalizer/url-normalizer.ts
Extrai domínio base de uma URL. Ignora chrome://, chrome-extension:// e about:; retorna null para URLs inválidas.
TS
modules/grouper/tab-grouper.ts
Agrupa abas em DomainGroup[] (por domínio) e WindowGroup[] (por janela dentro de cada domínio).
TS
modules/executor/action-executor.ts
Fecha abas individualmente ou em lote e restaura abas a partir do log de recuperação via chrome.tabs.
TS
modules/recovery/recovery-manager.ts
Log temporário em memória da última ação em lote. TTL de 15 minutos com limpeza automática via setTimeout.
popup/
Camada de UI: renderiza todos os estados do fluxo e se comunica com o background via mensagens.
HTM
popup/popup.html
Shell HTML da extensão. Apenas estrutura mínima — todo o conteúdo é gerado dinamicamente pelo popup.ts.
TS
popup/popup.ts
UI completa: gerencia todos os estados (inicial, domínios, janelas, abas, feedback, recuperação) e envia mensagens tipadas. 864 linhas
CSS
popup/styles/main.css
Estilos e tema visual do popup. Único arquivo CSS da extensão — usa variáveis CSS para consistência.
shared/
Contratos centrais: tipos TypeScript, constantes e utilitários consumidos por todas as camadas.
TS
shared/types/
8 arquivos de tipos: Tab, DomainGroup, WindowGroup, ActionResult, RecoveryLog, mensagens e estado da UI. Sem lógica.
TS
shared/constants/ · shared/utils/
Constantes de aplicação (TTL, mensagens de erro) e funções utilitárias de formatação e validação.
TS
30
Arquivos TypeScript
CSS
1
Arquivo CSS (popup)
<900
864
Maior arquivo (linhas) — popup.ts
MOD
5
Módulos de negócio independentes
0
Zero
Dependências de runtime
Responsabilidade por Módulo
MóduloArquivoResponsabilidadeChrome API
UI Layer popup.ts Renderiza fluxo, captura eventos, envia mensagens Não
Dispatcher message-dispatcher.ts Roteamento, validação e orquestração de mensagens Não diretamente
Tab Reader tab-reader.ts Leitura de abas e janelas — abstração da API Sim
Normalizer url-normalizer.ts Extrai domínio base de URLs (string | null) Não
Grouper tab-grouper.ts Agrupa abas em DomainGroup[] e WindowGroup[] Não
Executor action-executor.ts Fecha e restaura abas via chrome.tabs Sim
Recovery recovery-manager.ts Log temporário em memória (TTL 15 min) Não
Tecnologias
Stack, ferramentas e dependências

O TDE não tem nenhuma dependência de runtime — apenas devDependencies. Tudo que chega ao usuário final é código puro bundlado pelo Webpack.

Plataforma
Chrome Extension Manifest V3 Especificação vigente do Chrome. Service Workers em vez de background pages persistentes.
Chrome API 88+ Apenas chrome.tabs, chrome.windows e chrome.runtime. Permissão "tabs" no manifest.
TypeScript
TypeScript 5.3.3 Compilado para ES2020 com strict: true. Todos os módulos totalmente tipados.
@types/chrome ^0.0.260 Definições de tipo para a Chrome Extension API.
Bundler
Webpack 5.104.1 2 entry points: background.ts e popup.ts. Output em dist/.
ts-loader 9.5.1 Transpila TypeScript diretamente no pipeline do Webpack.
copy-webpack-plugin 12.0.2 Copia manifest.json, HTML, CSS e assets para dist/ sem transformação.
Testes
Jest 29.7.0 Framework de testes. 62 testes em 6 suites (5 unit + 1 integration). Ambiente node. Configurado em config/jest.config.js.
ts-jest 29.1.1 Transforma TypeScript diretamente para o Jest sem etapa de compilação separada. Usa o mesmo tsconfig.json do projeto.
@types/jest 29.5.x Tipos globais de describe, it, expect, jest.fn() e afins.
Qualidade de Código
ESLint 8.56.0 Linting TypeScript com @typescript-eslint. Configurado em config/eslint.config.js.
Prettier 3.1.1 Formatação automática de código configurada em config/.prettierrc.
Zero dependências de runtime
O package.json contém apenas devDependencies. O bundle final entregue ao Chrome é composto apenas por código JavaScript puro gerado pelo Webpack — sem bibliotecas externas na extensão.
Desenvolvimento
Setup do ambiente, build e contribuição

Guia para configurar o ambiente de desenvolvimento, entender a estrutura do projeto e contribuir com o código.

Estrutura do Projeto
📁 tab-domain-executor/
📄 package.json — scripts, devDependencies
📄 tsconfig.json — target ES2020, strict: true
📄 webpack.config.js — entry: background.ts + popup.ts
📁 config/
📄 eslint.config.js · jest.config.js
📁 src/
📁 background/ — Service Worker + dispatcher
📁 popup/ — UI: HTML, TS, CSS, state
📁 modules/ — executor, grouper, normalizer, recovery, tab-reader
📁 shared/ — types, constants, utils
📁 tests/
� setup.ts — mock global da Chrome API (runtime, tabs, windows)
📁 unit/modules/
📄 normalizer.test.ts · grouper.test.ts · tab-reader.test.ts · executor.test.ts · recovery.test.ts
📁 integration/
📄 dispatcher.test.ts — fluxo end-to-end via message-dispatcher
📁 mocks/
📄 chrome.mock.ts · tab.fixtures.ts
📁 dist/ — output do build (gerado)
Scripts disponíveis
ComandoDescrição
npm run devBuild em modo desenvolvimento com watch — recompila ao salvar
npm run buildBuild de produção em dist/ (minificado)
npm testExecuta todos os testes (unit + integration)
npm run test:watchTestes em modo watch
npm run test:coverageTestes com relatório de cobertura
npm run test:integrationExecuta apenas os testes de integração
npm run lintVerifica erros de lint no TypeScript
npm run lint:fixCorrige automaticamente erros de lint
npm run formatFormata o código com Prettier
npm run format:checkVerifica formatação sem modificar os arquivos
npm run cleanRemove dist/ e coverage/
Workflow de Desenvolvimento
1
Iniciar o watcher
bash
npm run dev
2
Editar arquivos em src/

O Webpack recompila automaticamente ao salvar. Os arquivos em dist/ são atualizados.

3
Recarregar a extensão no Chrome

Acesse chrome://extensions e clique no ícone 🔄 ao lado do TDE para recarregar.

4
Testar a mudança

Clique no ícone da extensão para abrir o popup e testar o comportamento esperado.

5
Rodar os testes
bash
npm test
Suites de Testes
SuiteTipoO que cobreTestes
normalizer.test.tsUnitnormalizeUrl, extractDomain — URLs válidas, www., chrome://4
tab-reader.test.tsUnitgetAllTabs, getAllWindows, getTabsByWindowId — mock de chrome.tabs e chrome.windows6
grouper.test.tsUnitgroupByDomain, groupByWindow, filterTabsByScope — agrupamento, ordenação, filtragem por escopo14
executor.test.tsUnitcloseSingleTab, closeBulkTabs, restoreTabs — sucesso, falha e sucesso parcial10
recovery.test.tsUnitstoreRecoveryLog, getRecoveryLog, hasRecoverableAction, clearRecoveryLog — TTL com fake timers12
dispatcher.test.tsIntegrationTodos os 7 MessageType via handle() — validação de payload, roteamento e respostas compostas16
Total62
Thresholds mínimos de cobertura (npm run test:coverage)
Branches70%
Functions75%
Lines80%
Statements80%
Configurações TypeScript relevantes
targetES2020Chrome 88+ suporta plenamente
stricttrueTipagem estrita obrigatória
moduleESNextBundled pelo Webpack
sourceMaptruePara debugging em dev
baseUrl./srcAlias @/ aponta para src/
types["chrome", "node", "jest"]Tipos globais disponíveis