github DanielLavrushin/b4 v1.76.2rc2

latest release: v1.76.2rc3
pre-release5 hours ago

[1.76.2] - 2026-08-12

  • FIXED: Photos, videos and stickers stopped loading in 1.76.0 and 1.76.1 - data center 203, the one Telegram serves media from, was addressed as kws2 on the shared Cloudflare pool and on a custom WebSocket domain. Those names are separate records with separate origins: kws2 is data center 2 at 149.154.167.51, kws203 is 91.105.192.100. Every media session therefore established, in about 150 ms, against a data center that could not serve it, and because the connection succeeded the direct route behind it was never tried. kws203 was said to be a name that exists nowhere, which is true only of Telegram's own edge, and data center 203 was already kept away from that edge on other grounds.
  • CHANGED: A Cloudflare Worker of your own is now the last WebSocket route tried, not the first - Cloudflare reclaims a stateless worker part-way through a session, and it does so long after the handshake, so every connection test passed it and every video failed. Measured from a censored network against data center 1: a worker answered 8 rounds and went mute at 8.7 seconds, a domain from the shared pool answered 100 rounds over two minutes on the same machine. Ahead of the pool the worker won the dial and took the session with it, because the route list only moves on when a dial fails, and this one succeeds.
  • FIXED: A route that answered nothing at all was handed the next connection anyway - a relay was only ranked down when it went quiet mid-session with a request outstanding. A worker reclaimed by Cloudflare does not go quiet, it stops existing: the client gives up first, and the whole session shows as a dial that worked and carried nothing. A route that took a request and returned zero bytes is now ranked down like a mute one.
  • CHANGED: The Cloudflare Worker script in the documentation keeps its relay alive longer - the loop carrying data back from Telegram was a promise nobody awaited, which Cloudflare may cancel the moment the handler returns, and this handler returns as soon as the WebSocket is accepted. It is handed to ctx.waitUntil() now, and the three socket promises that nobody watches get a no-op handler so a reclaimed session stops filling the worker log with unhandled rejections. Set the worker's compatibility date to 2026-04-07 or later as well. This is not a full remedy - waitUntil is documented to extend a request by about thirty seconds - which is why the worker now sits behind the shared pool.
  • FIXED: tgprobe never tested the shared Cloudflare pool - it built its configuration from an empty struct and then applied defaults, and applying defaults deliberately leaves booleans alone, so every on/off setting read as off. It builds its configuration the way b4 itself does now.
  • CHANGED: The Cloudflare Worker is asked for a data center address only, never a port - a Worker that opens 443 whatever it was asked for is the right one: Telegram serves the same endpoint on 80, 443 and 5222, 443 is the port every data center listens on, and data center 203 does not answer on 5222 at all, so passing the port on turned a working media connection into a dead one. The script in the Telegram documentation is again the tg-ws-proxy script unchanged, and a Worker deployed from either page needs nothing done to it.

What's Changed

Full Changelog: v1.76.0...v1.76.2rc2

Don't miss a new b4 release

NewReleases is sending notifications on new releases.