Repository navigation
Releases: jolynstudios/freehop
Release list
0.1.0-alpha.6 — Your TURN relay stays the last resort
Your own TURN relay (turn, opt-in since alpha.5) now stays the last resort after it connects a call. A pair it carries keeps checking for a cheaper route, moves to a direct route or a gateway as soon as one works, and then releases the relay. Only the browser client changed: gates, Freehop's TURN server and the ticket format are as in alpha.5, and integrations that don't configure turn behave exactly as before.
What's new
- Leaving the relay: while the application's TURN relay carries a pair, the side that restarts ICE (the impolite one, as for every restart) checks for a cheaper route with the relay still configured, so the call keeps its route when nothing better works. It checks after
timing.turnUpgradeMs(60 s by default), then at doubling intervals up tomaxRetryMs(5 minutes), and within seconds when a gateway the pair could use appears. - Release: once another route has held for two media checks, the relay leaves the pair's ICE servers on both sides and one more ICE restart ends its allocations. If that route fails later, the ladder runs again with TURN last.
timing.turnUpgradeMs: the first check, in milliseconds (default 60000).stats().countersreportsturnProbesandturnReleases.- Tests:
test/turn-upgrade.test.mjs, four newladdergatescenarios, andtest/browser/turn-upgrade.mjsinnpm run test:browsers(--browser=picks the engine).
Cost
Less relay traffic for the same calls: a pair moves off your relay as soon as a cheaper route works and gives its allocations back. A check costs one ICE restart with fresh TURN allocations, after a minute and then at most every 5 minutes. If the cheaper route breaks later, that pair has no media until the ladder reaches TURN again, about 7 to 20 seconds; keeping the relay on standby would avoid that gap but keep its allocations open.
Install this release
npm install freehop@alphaPublished on npm under the alpha tag; pin it with npm install freehop@0.1.0-alpha.6. The attached archive is the published package; its SHA-256 is in SHA256SUMS.
The wire format is unchanged, so alpha.5 and alpha.6 clients share calls. A pair moves off the relay when its impolite side runs alpha.6; the relay's allocations are released completely when both sides do.
Validation
- Full
npm run ship: 208 unit tests; export, type, documentation, contract and ladder gates; Chromium/Firefox/WebKit calls, multi-gate outage recovery, ticket rotation, the example app, the TURN rung, and leaving the relay again. laddergate: the 19 scenarios stamped for alpha.5 are byte-identical. Four new ones cover a pair that stays on the relay, one that moves to a direct route and back to TURN when that route breaks, one that moves to a gateway appearing mid-call, and the polite side.- Two Chromium peers on one machine, first limited to relayed candidates: a check with nothing better kept the call on the relay with no gap in the audio. Once every candidate was allowed, both moved to a direct route by themselves, again with no audio gap; the relay forwarded 0 bytes afterwards and its allocations ended about 70 s later. A variant without the final restart left one allocation open.
- Packed archive installed into an isolated consumer: browser Bundler/NodeNext and Node-only strict compilation, every entry point imported, a ticket round trip with
turn, and gate and TURN startup/close.
Work in progress
Firefox through the application TURN relay. In the relay-only browser setup, Firefox gets no audio in one direction through the application relay (the TURN server drops it for a missing permission), also with alpha.5. Chromium connects through it, and Firefox through desktop gateways and host nodes passed the home-lab tests.
Not yet verified
Leaving the relay was tested with Chromium on one machine, not on real networks or in WebKit. Port prediction's success case is still unverified, as in alpha.5.
0.1.0-alpha.5 — Opt-in last resorts before unreachable
Calls that would end unreachable can now try two opt-in last resorts first: your own TURN relay and port prediction. A new NAT check tells your app which kind of NAT each user is behind. All three are off by default, so integrations that don't opt in behave exactly as in alpha.4.
What's new
turn: your own TURN relay, tried last. A call it carries reportsrelaywithvia: 'turn'. Tickets can carry it:createAuthority({ turn })takes the servers, or a function that mints short-lived credentials per ticket.session.refresh()andsession.setTurn()rotate them. Gates and peers can never supply the application's TURN servers.portPrediction(off by default): when a peer's NAT hands out ports in order, try its next ports once (at most 16 candidates per ICE generation) before reportingunreachable. Random NATs are never predicted.classifyNat: learns from the browser's own STUN results whether this endpoint's NAT keeps one port (eim), hands them out in order (sequential) or picks them at random, shares that with peers and reports it asstats().nat.- Release gates:
laddergatereplays 19 path-ladder scenarios against traces recorded from the unmodified ladder;contractgatefreezes the public API, wire constants, ticket format and the client markers downstream apps check. Both run innpm run shipand CI. - NAT lab in Docker:
lab/docker.sh <scenario|qualify>runs the Linux NAT lab in a disposable container, including on macOS. - Example app:
FREEHOP_TURN_URLS,FREEHOP_TURN_USERNAMEandFREEHOP_TURN_CREDENTIALturn on the TURN last resort.
Cost
Nothing changes unless you opt in. classifyNat and portPrediction need no server. A turn relay carries only calls that would otherwise fail: about 50 MB per hour of two-way audio, or about 330 MB per hour with video at Freehop's caps. Its bandwidth is yours; a provider's free tier, or Freehop's own TURN server on a machine you already run, can keep that at zero.
Install this release
npm install freehop@alphaPublished on npm under the alpha tag; pin it with npm install freehop@0.1.0-alpha.5. The attached archive is the published package; its SHA-256 is in SHA256SUMS.
Validation
- Full
npm run ship: 201 unit tests; export, type, documentation, contract and ladder gates; Chromium/Firefox/WebKit calls, multi-gate outage recovery, ticket rotation, the example app, and a two-Chromium call that can only connect through the app's TURN relay. CI passed on Node 22. - NAT lab (Docker, Chromium, one run each): all 12 existing scenarios took the same routes as before. Two strict NATs (over UDP) and two UDP-blocked peers (over TCP) connect as relay via
turn. Random NATs are never predicted. Two newly documented limits, home router ↔ strict NAT and UDP-blocked ↔ home router, stayunreachableby default. - coturn's
turnutils_uclientagainst Freehop's TURN server: UDP 800/800 and TCP 800/800, 0 lost. - Packed archive installed into an isolated consumer: browser Bundler/NodeNext and Node-only compilation with the new option types, runtime imports, a ticket round trip with
turn, and gate and TURN startup/close.
Not yet verified
Port prediction's success case, a NAT that hands out ports in order, cannot be simulated with Linux NAT and has not been tested on real carrier networks, so portPrediction stays off by default.
0.1.0-alpha.4 — Typed SDK and refreshed docs
Freehop now includes TypeScript declarations across all 15 public package entry points. Browser and Node consumers get typed options, tickets, sessions, event payloads, stats and backend APIs. The runtime remains JavaScript and existing runtime imports stay compatible.
The website and documentation have also been refreshed around small meeting rooms, calls inside apps, shared workspaces, desktop collaboration and community rooms. Hopper and the live call demo remain the working examples. The site now follows your system theme, offers manual light/dark selection, fixes the results/calculator contrast issues, and uses consistent sans-serif typography informed by Refero research.
Install this release
npm install freehop@alphaDistribution: published on npm under the alpha tag. Pin this version with npm install freehop@0.1.0-alpha.4.
The original GitHub archive remains attached. The npm package updates its README and SDK installation instructions; runtime and declaration files are byte-identical.
Validation
- Full
npm run ship: 173 unit tests, export checks, strict type consumers, documentation checks, Chromium/Firefox/WebKit calls, multi-gate outage recovery, ticket rotation and the example app. - TypeScript 6 and 7 consumer checks; actual Electron 44.6.0 declarations accepted by the helper.
- Packed archive installed into an isolated consumer; browser Bundler/NodeNext and Node-only compilation, runtime imports, ticket round trip, gate and TURN startup/close passed.
- Root package audit: no reported vulnerabilities. Website audit gate passed with its existing reviewed, unpatched build-tool advisory allowance.
- Production site build, light/dark responsive layouts, automated WCAG AA checks, system preference changes and saved manual overrides passed.
Website · TypeScript guide · Use cases
The previous site is retained in the archive/pre-rebrand-2026-10-07 tag.
Freehop 0.1.0-alpha.3
What's new
- Added
session.setPeerMuted(peerId, muted)for local, per-member audio mute. It applies to audio tracks already playing and to tracks that arrive later, while leaving video unaffected. - Muting stays local to the listener: the sender is not notified. A temporary disconnect preserves the mute; a final departure clears it.
- Updated the SDK documentation and examples for the new API.
Install
npm install freehop@alphaThe alpha npm tag points to 0.1.0-alpha.3; the default latest tag remains on 0.1.0-alpha.1.
Verification
- The full ship pipeline passed: 173 unit tests, export and documentation checks, plus Chromium, Firefox, and WebKit browser suites.
- The npm-published tarball was downloaded and checked: it contains
setPeerMutedand matches the release candidate checksum.
Freehop remains alpha software. The home-lab network matrix is described in RESULTS.md; it has not been rerun for this revision.