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

mtproto-checker

v0.6.0

Published

Check Telegram MTProto proxies via a real TDLib handshake (testProxy), like tdesktop does

Downloads

393

Readme

🔍 mtproto-checker

Telegram MTProto proxy health checker powered by TDLib. Runs a real testProxy handshake through each proxy — the same path tdesktop uses — so a ✅ means the proxy actually works in Telegram, not just that a port is open.

⚡ Features

  • 🤝 Real MTProto handshake — not a port scan
  • 📡 Sources: remote URLs, local files, direct links, or any mix (auto-deduped)
  • 🖥 Three modes: one-shot CLI, on-demand HTTP API, always-on pool + web dashboard
  • 🎯 Accurate latency via a low-concurrency measurement pass
  • 🔐 Fake-TLS SNI extraction · adaptive result sorting

📦 Install

npm install -g mtproto-checker      # global → `mtproto-checker` command
# or from source:
git clone https://github.com/Tar4s/mtproto-checker.git && cd mtproto-checker && npm install

Requirements: Node.js ≥ 18 · TG_API_ID + TG_API_HASH from my.telegram.org (no phone login — they only initialize TDLib).

🔑 Environment

| Variable | Required | Description | |----------|:--------:|-------------| | TG_API_ID / TG_API_HASH | ✅ | Telegram API credentials | | CHECK_AUTH_USER / CHECK_AUTH_PASSWORD | server | Basic auth for POST /check (unset → /check returns 503) | | PORT | ❌ | HTTP port (default 8080) |

Examples below use node check.js; with the global install swap in mtproto-checker.

🖥 CLI (one-shot)

TG_API_ID=… TG_API_HASH=… node check.js [sources] [options]

node check.js --proxy "tg://proxy?server=1.2.3.4&port=443&secret=ee…"   # one link
node check.js https://example.com/proxies.txt                            # remote list
node check.js --sources urls.txt                                         # file of source URLs
node check.js ./my-proxies.txt                                           # local file
cat proxies.txt | node check.js                                          # stdin

| Flag | Default | Description | |------|:-------:|-------------| | --proxy <link> | — | Check one proxy link directly | | --url <url> | — | Add a source URL (repeatable) | | --sources <file> | — | File of source URLs | | --dc <1-5> | 2 | Data center for testProxy | | --timeout <sec> | 10 | Per-proxy timeout | | --concurrency <n> | 30 | Parallel checks (lower = more accurate ms) | | --iterations <n> | 1 | Re-check rounds; only working proxies advance | | --out <prefix> | result | Output prefix → <prefix>.json (full report) + .txt (working links) |

🛰 Service (serve / pool)

One HTTP server, one port. Always serves on-demand POST /check; optionally runs a background pool that keeps a live, always-ready set of working proxies plus a web dashboard at /.

node check.js serve   # POST /check; pool auto-on if sources.txt exists
node check.js pool    # POST /check + background pool (forced on)

Endpoints

| Endpoint | Auth | Response | |----------|:----:|----------| | POST /check | 🔐 | On-demand check of link(s)/list URL(s) → full report | | GET / | — | Web dashboard (served when pool is on) | | GET /proxies | — | Whole container; each entry has ok/ms/error | | GET /proxies?working=1 | — | Verified-working entries only (JSON) | | GET /proxies.txt | — | Verified-working links, plain text | | GET /status | — | Cycle/phase metadata (workingCount, containerCount, …) | | GET /health | — | Liveness probe |

curl "http://localhost:8080/proxies.txt"
curl -u admin:secret http://localhost:8080/check \
  -H 'Content-Type: application/json' -d '{"url":"https://example.com/list.txt"}'

How the pool works

  1. Load all sources into one deduped set and expose it immediately (ok: null = unchecked).
  2. Filter--iterations fast rounds prune the container live; dead links drop, survivors flip to ok: true the moment they pass.
  3. Measure — survivors re-checked once at low concurrency (--measure-concurrency) for accurate latency (concurrent-round ms is inflated by TDLib queueing and discarded).
  4. Sleep --interval hours, re-measuring every --keepalive minutes to drop proxies that died and refresh latency (console-only). Then repeat from sources.

Reads never block — a GET always returns a consistent snapshot, even mid-check.

Pool options

| Flag | Default | Description | |------|:-------:|-------------| | --sources <file> | sources.txt | Source list (URLs / links / files; # comments ok) | | --iterations <n> | 3 | Filtering rounds | | --interval <hours> | 6 | Pause between full cycles | | --keepalive <min> | 15 | Re-measure interval during the pause | | --concurrency <n> | 30 | Parallel checks in filtering rounds | | --measure-concurrency <n> | 1 | Parallel checks in the latency pass (keep low) | | --dc <1-5> · --timeout <sec> · --port <n> | 2 · 10 · 8080 | Same as CLI | | --clear-on-cycle | off | Empty the container at the start of each cycle | | --pool / --no-pool | auto | Force the pool on/off |

Quick local run

cp .env.example .env                 # fill TG_API_ID / TG_API_HASH (+ CHECK_AUTH_* for /check)
cp sources.example.txt sources.txt   # or edit the bundled example
npm run dev:pool                     # loads .env, fast params → http://localhost:8080/

POST /check contract

Body accepts url/urls/uri/uris (string or array of proxy links and/or list URLs), plus optional iterations (1) and concurrency (30).

// response
{ "uris": ["…"], "iterations": 2, "concurrency": 20, "count": 150, "working": 42,
  "results": [ { "proxy": { "raw": "tg://proxy?…", "server": "1.2.3.4", "port": 443, "secret": "ee…", "sni": "example.com" }, "ok": true, "ms": 312, "error": null } ] }

Errors: 400 bad request · 401 unauthorized · 405 wrong method · 502 upstream fetch failed · 503 /check disabled (no auth set).

📚 Library API

const { checkProxyLink, checkProxiesFromURIs, startServer } = require('mtproto-checker')

await checkProxyLink('tg://proxy?server=1.2.3.4&port=443&secret=ee…', { apiId, apiHash })

await checkProxiesFromURIs([
  'tg://proxy?server=1.2.3.4&port=443&secret=ee…',
  'https://example.com/list.txt',
  './local-list.txt'
], { apiId, apiHash, iterations: 2, concurrency: 20 })

await startServer({ apiId, apiHash, user: 'admin', password: 'secret', port: 8080 })

opts: apiId, apiHash, dc (2), timeout (10), concurrency (30), iterations (1), onProgress(proxy, res, index, total). Missing fields fall back to env vars.

🧩 Proxy link formats

tg://proxy?server=1.2.3.4&port=443&secret=ee…
https://t.me/proxy?server=1.2.3.4&port=443&secret=ee…

Secrets: hex, plain hex, or base64url (auto-detected). tg://socks links are ignored.

🐳 Deployment

The app runs in Docker as the unified service, published on 127.0.0.1:${HOST_PORT} only; host nginx terminates TLS and is the single public entry point.

  • Containerdocker/docker-compose.yml. Prepare .env (secrets) next to it; the image bakes sources.txt in, override it via the sources.txt volume.
  • nginx — copy nginx/mtproto-checker.conf into sites-available, point server_name + certs at your domain. TLS setup (acme.sh, standalone on port 80) in nginx/README.md.
  • CI/CD — GitHub Actions builds the image and deploys over SSH (git pulldocker compose up -d). APP_ENV / APP_SOURCES repo variables become the server's .env / sources.txt; SERVER_HOST / SERVER_USER / SSH_PRIVATE_KEY are secrets.
# on the server, manually:
cd /opt/mtproto-checker && docker compose up -d && docker compose logs -f app

📜 License

Unlicense — free to use, no restrictions.