npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@henrique-olivier/network-listener

v0.1.6

Published

Lightweight frontend network diagnostics for fetch and Axios.

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

Uso

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 record

O 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: true
  • collectionMode: 'active-tab-only'
  • channelName: 'network-listener'
  • storagePrefix: 'network-listener'
  • heartbeatIntervalMs: 2000
  • leaseDurationMs: 7000
  • claimSettleDelayMs: 100
  • persistRecord: true
  • persistSnapshot: true
  • storageWriteDebounceMs: 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 claimSettleDelayMs converge para uma vencedora.
  • Se uma aba passiva nao exibe atualizacao, verifique se localStorage esta liberado e se as abas estao na mesma origem.
  • Em testes automatizados, chame listener.destroy() ou use crossTab.enabled: false quando 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=abc

vira:

/api/users/:id/orders

Scripts

npm test
npm run build

Escopo fora da POC

  • XHR;
  • health-check automatico;
  • teste de download;
  • PerformanceObserver;
  • Server-Timing;
  • navigator.connection;
  • dashboard;
  • envio de telemetria para backend.