@henrique-olivier/network-listener
v0.1.6
Published
Lightweight frontend network diagnostics for fetch and Axios.
Maintainers
Readme
@henrique-olivier/network-listener
Biblioteca leve para observar requisicoes HTTP reais no front-end e gerar diagnosticos provaveis sobre lentidao, erro ou instabilidade.
Funciona sem React, sem hooks e sem acoplamento com framework. O foco e ser simples de instalar em projetos legados e seguro por padrao: a lib nao le payloads, headers sensiveis, cookies ou body de resposta.
Compatibilidade
O pacote publicado foi configurado para:
- CommonJS;
- JavaScript ES5;
- declaracoes TypeScript;
- sem dependencia de React;
- sem dependencia obrigatoria de Axios;
- sem polyfills globais;
- sem leitura de body de request ou response.
Instalacao
npm install @henrique-olivier/network-listenerUso
import { createNetworkListener } from '@henrique-olivier/network-listener';
const listener = createNetworkListener({
slowRequestThresholdMs: 1500,
maxSamples: 20,
minimumSamplesToDiagnose: 5,
});
listener.installFetch();
listener.installAxios(axiosInstance);
const unsubscribe = listener.subscribe(function (diagnosis) {
console.log(diagnosis);
});
listener.start();
// Quando nao precisar mais observar:
listener.stop();
unsubscribe();Opcoes
createNetworkListener({
maxSamples: 20,
slowRequestThresholdMs: 1500,
minimumSamplesToDiagnose: 5,
timeoutThresholdMs: 30000,
crossTab: {
enabled: true,
collectionMode: 'active-tab-only',
channelName: 'network-listener',
storagePrefix: 'network-listener',
heartbeatIntervalMs: 2000,
leaseDurationMs: 7000,
claimSettleDelayMs: 100,
persistRecord: true,
persistSnapshot: true,
storageWriteDebounceMs: 300,
},
});maxSamples: tamanho da janela em memoria.slowRequestThresholdMs: tempo minimo para uma request ser considerada lenta.minimumSamplesToDiagnose: minimo de amostras antes de diagnosticar.timeoutThresholdMs: duracao usada para marcar uma request como timeout provavel.crossTab: coordenacao entre abas da mesma origem.
Coordenacao entre abas
Por padrao, somente a aba visivel, focada e dona do lease inicia novas coletas. A decisao de coletar e feita no inicio da request; se a request comecou na aba coletora, ela pode ser finalizada mesmo que a aba perca o foco antes da resposta.
Aba ativa e focada
|
tenta adquirir lease
|
confirma propriedade
|
coleta fetch/Axios
|
renova heartbeat
|
persiste record e snapshot
|
perde foco
|
libera lease
|
nova aba assume e continua o mesmo recordO lease e uma permissao temporaria persistida em localStorage. A aba dona renova o lease por heartbeat. Se a aba travar ou fechar sem liberar, o lease expira e outra aba ativa pode assumir.
Defaults:
enabled: truecollectionMode: 'active-tab-only'channelName: 'network-listener'storagePrefix: 'network-listener'heartbeatIntervalMs: 2000leaseDurationMs: 7000claimSettleDelayMs: 100persistRecord: truepersistSnapshot: truestorageWriteDebounceMs: 300
Use collectionMode: 'all-tabs' para manter o comportamento sem lideranca entre abas. Use enabled: false para desligar a coordenacao e a persistencia compartilhada.
Fallbacks
A lib usa BroadcastChannel quando disponivel. Se nao estiver disponivel, usa localStorage com evento storage. Se localStorage falhar ou estiver bloqueado, a lib continua em memoria, sem sincronizacao real entre abas.
A sincronizacao funciona somente entre contextos da mesma origem: mesmo protocolo, dominio e porta. Subdominios diferentes nao compartilham o mesmo estado.
Refresh e record compartilhado
O record ativo e salvo em {storagePrefix}:active-record; o snapshot agregado fica em {storagePrefix}:snapshot; o lease fica em {storagePrefix}:collector-lease.
Ao atualizar a pagina, a mesma aba preserva seu tabId via sessionStorage e restaura o record valido. Uma troca de aba nao cria novo recordId. Se o record ja tiver passado de endsAt, somente a aba dona confirmada do lease tenta finalizar.
API adicional
listener.getTabState();
listener.getCollectorState();
listener.isCollector();
listener.getSharedRecord();
listener.getSharedSnapshot();
listener.destroy();Callbacks opcionais:
createNetworkListener({
onCollectorChange: function (state) {},
onRecordRestored: function (record) {},
onCrossTabError: function (error) {},
});Privacidade no storage
O estado persistido e sanitizado. A lib nao deve gravar bodies, cookies, tokens, header Authorization, URL completa com query string ou mensagens brutas do backend. Eventos persistidos usam rota normalizada, status HTTP, tempos, tipos de erro e metricas agregadas.
Troubleshooting
- Duas abas coletando por poucos milissegundos durante disputa de lease podem ocorrer, mas a releitura apos
claimSettleDelayMsconverge para uma vencedora. - Se uma aba passiva nao exibe atualizacao, verifique se
localStorageesta liberado e se as abas estao na mesma origem. - Em testes automatizados, chame
listener.destroy()ou usecrossTab.enabled: falsequando o caso nao estiver testando coordenacao entre abas.
Diagnostico
O snapshot atual pode ser obtido a qualquer momento:
const diagnosis = listener.getSnapshot();Exemplo de retorno:
{
status: 'degraded',
probableCause: 'specific-endpoint',
confidenceLevel: 'medium',
reasons: ['Only one endpoint concentrates slow requests.'],
summary: {
requestCount: 20,
errorRate: 0,
clientErrorRate: 0,
serverErrorRate: 0,
networkErrorRate: 0,
timeoutRate: 0,
abortedRate: 0,
slowRequestRate: 0.35,
medianDurationMs: 700,
p95DurationMs: 2300,
affectedEndpointRatio: 0.2
},
affectedEndpoints: [
{
normalizedRoute: '/api/reports',
requestCount: 7,
errorRate: 0,
timeoutRate: 0,
slowRequestRate: 1,
medianDurationMs: 1800,
p95DurationMs: 2300,
statusCodes: [],
issueTypes: ['slow']
}
]
}Endpoints afetados
Quando o diagnostico encontra lentidao ou erro concentrado em rotas especificas, o payload inclui affectedEndpoints.
Esse campo pode ser usado pela aplicacao para mostrar alertas, logs de debug ou uma mensagem amigavel ao usuario sem expor URL completa, query string, payload ou headers.
Privacidade
A lib nao coleta por padrao:
- headers;
- cookies;
- payload;
- corpo de resposta;
- query strings completas;
- geolocalizacao;
- IP.
O principal identificador tecnico e normalizedRoute.
Exemplo:
/api/users/123/orders?token=abcvira:
/api/users/:id/ordersScripts
npm test
npm run buildEscopo fora da POC
- XHR;
- health-check automatico;
- teste de download;
- PerformanceObserver;
- Server-Timing;
- navigator.connection;
- dashboard;
- envio de telemetria para backend.
