github Leadaxe/singbox-launcher v1.2.6
release v1.2.6

3 hours ago

Release v1.2.6

Downloads

macOS (Universal) - Supports both Apple Silicon and Intel

Option 1: Installation Script (Recommended)

Install with a single command (version v1.2.6):

curl -fsSL https://raw.githubusercontent.com/Leadaxe/singbox-launcher/develop/scripts/install-macos.sh | bash -s -- v1.2.6

The script will:

  • Download the release archive
  • Extract and install to /Applications/
  • Fix macOS quarantine attributes and permissions
  • Launch the application automatically

Option 2: Manual Installation

  1. Download: singbox-launcher-v1.2.6-macos.zip
  2. Extract the ZIP file
  3. Remove quarantine attribute (required):
    xattr -cr "singbox-launcher.app" && chmod +x "singbox-launcher.app/Contents/MacOS/singbox-launcher"
  4. Double-click singbox-launcher.app to run
    • If macOS blocks the app, go to System Settings → Privacy & Security and click "Open Anyway"
    • Alternatively, right-click the app and select "Open" (first time only)

Windows (amd64)

  1. Download: singbox-launcher-v1.2.6-win64.zip
  2. Extract the ZIP file to a folder, for example: C:\Program Files\singbox-launcher\
  3. Run singbox-launcher.exe from that folder
    • You may need administrator rights to install to Program Files
    • The launcher will automatically download sing-box and wintun.dll on first launch

Windows 7 (x86, legacy)

  1. Download: singbox-launcher-v1.2.6-win7-32.zip
  2. Extract the ZIP file to a folder and run singbox-launcher-win7-32.exe
    • For Windows 7 / 32-bit or legacy compatibility only

Linux Support

⚠️ Linux build temporarily unavailable - мы ищем тестировщика для ручного тестирования перед включением автоматической сборки.

Checksums

See checksums.txt for SHA256 checksums of all files.

v1.2.6 — подписки с WebSocket Early Data (?ed=) наконец подключаются

Core pinned: sing-box-lx 1.14.0-lx.5 (unchanged from v1.2.5). No config migration needed.

A one-bug release. If your provider ships WebSocket nodes whose path carries Xray's ?ed=N tail, those nodes imported fine, looked correct in the UI, and then failed to connect with unexpected HTTP response status: 404. They work now.

EN

Highlights

  • WebSocket nodes with an ?ed=N path now connect (issue #96). Xray encodes WebSocket Early Data into the path itself — "path": "/api/v2/channel?ed=2560" — rather than using a dedicated field. The launcher copied that string straight through, and sing-box has no ?ed= convention: it treated the whole thing as a literal WebSocket path, so the server matched no route and answered 404. The tail is now split off into the two fields sing-box actually expects:

    "transport": {
      "type": "ws",
      "path": "/api/v2/channel",
      "max_early_data": 2560,
      "early_data_header_name": "Sec-WebSocket-Protocol"
    }

    early_data_header_name has to be exactly Sec-WebSocket-Protocol: left empty, sing-box appends early data to the path instead (the V2Ray convention), which an Xray server does not understand. Reported with a full diagnosis — including the working manual fix — by @Septdir.

Technical / Internal

  • The ?ed= tail arrived through four layers, and all four needed the fix. A single helper (splitWSEarlyData / applyWSEarlyData in node_parser_transport.go) is now applied at every one:
    • uriTransportFromQuery — share-URI type=ws, which covers both VLESS and Trojan;
    • buildOutbound — the VMess net=ws branch;
    • xrayTransportFromStreamSettings — Xray JSON wsSettings.path, the path the issue was filed against;
    • appendOutboundTransportParts — the emitter.
  • The emitter was the non-obvious one. appendOutboundTransportParts is an allow-list of transport keys, not a passthrough copy. Without an explicit branch there, max_early_data and early_data_header_name would have been silently dropped every time config.json was rebuilt from state.json — the fix would have survived the initial subscription import and then quietly disappeared on the next rebuild. max_early_data is read type-tolerantly, because it is an int coming out of the parser and a float64 coming back through a state round-trip.
  • Share-URI exporters re-encode ?ed=N. transportToQuery (VLESS/Trojan) and shareURIFromVMess put the tail back, so a node → share-link → node round-trip no longer loses early data.
  • Malformed ed degrades instead of failing. A non-numeric, empty, or zero ed drops the early-data fields but still strips the ?-tail from the path — the node runs as plain WebSocket rather than poisoning the whole config.json. This follows the same policy as the REALITY pbk validation added in v1.1.7.
  • Tests: 12 new cases across two files — the helper's edge cases, all three parser layers, the emitter, the float64 state round-trip, and the share-URI round-trip.

Notes

  • sing-box check never caught this. The broken config was syntactically valid — /api/v2/channel?ed=2560 is a perfectly legal string for a path field. The failure only ever showed up at runtime, as a 404 during the WebSocket handshake. Worth remembering when a node validates but will not connect.
  • Nothing else changed. If none of your nodes use ?ed= WebSocket paths, this release is a no-op for you.

RU

Основное

  • WebSocket-ноды с ?ed=N в пути наконец подключаются (issue #96). Xray кодирует WebSocket Early Data прямо в путь — "path": "/api/v2/channel?ed=2560" — вместо отдельного поля. Лаунчер копировал эту строку как есть, а в sing-box никакого соглашения ?ed= нет: он считал её буквальным путём WebSocket, сервер не находил такого маршрута и отвечал 404. Теперь хвост отделяется в те два поля, которых sing-box и ждёт:

    "transport": {
      "type": "ws",
      "path": "/api/v2/channel",
      "max_early_data": 2560,
      "early_data_header_name": "Sec-WebSocket-Protocol"
    }

    early_data_header_name обязан быть именно Sec-WebSocket-Protocol: с пустым значением sing-box отправляет early data в путь (соглашение V2Ray), и Xray-сервер этого не понимает. Issue с полным разбором — включая рабочий обходной путь — прислал @Septdir.

Техническое / Внутреннее

  • Хвост ?ed= приходил через четыре слоя, и чинить пришлось все четыре. Общий хелпер (splitWSEarlyData / applyWSEarlyData в node_parser_transport.go) теперь применяется в каждом:
    • uriTransportFromQuery — share-URI type=ws, покрывает и VLESS, и Trojan;
    • buildOutbound — ветка VMess net=ws;
    • xrayTransportFromStreamSettings — Xray JSON wsSettings.path, то самое место из issue;
    • appendOutboundTransportParts — эмиттер.
  • Эмиттер — неочевидная часть. appendOutboundTransportParts это allowlist ключей транспорта, а не сквозное копирование. Без явной ветки там max_early_data и early_data_header_name молча вырезались бы при каждой пересборке config.json из state.json — фикс пережил бы первый импорт подписки и тихо исчез на следующей пересборке. max_early_data читается устойчиво к типу: из парсера это int, а после round-trip через state — уже float64.
  • Share-экспортёры восстанавливают ?ed=N. transportToQuery (VLESS/Trojan) и shareURIFromVMess дописывают хвост обратно, поэтому round-trip «нода → ссылка → нода» больше не теряет early data.
  • Битый ed деградирует, а не роняет конфиг. Нечисловой, пустой или нулевой ed убирает поля early data, но ?-хвост из пути всё равно срезается — нода работает как обычный WebSocket вместо того, чтобы испортить весь config.json. Та же политика, что и при валидации REALITY pbk в v1.1.7.
  • Тесты: 12 новых кейсов в двух файлах — краевые случаи хелпера, все три слоя парсинга, эмиттер, round-trip через state с float64 и round-trip через share-URI.

Примечания

  • sing-box check эту проблему не ловил. Сломанный конфиг синтаксически валиден — /api/v2/channel?ed=2560 совершенно законная строка для поля пути. Отказ проявлялся только в рантайме, как 404 при WebSocket-хендшейке. Стоит помнить, когда нода проходит проверку, но не подключается.
  • Больше ничего не изменилось. Если у вас нет нод с ?ed= в пути WebSocket, этот релиз для вас пустой.

Don't miss a new singbox-launcher release

NewReleases is sending notifications on new releases.