From 68f9978544663f50f5d99df631cc23bdabc28b50 Mon Sep 17 00:00:00 2001
From: Nerual Dreming
Date: Wed, 14 Oct 2026 11:13:56 +0300
Subject: [PATCH 1/6] Welcome tab: report a problem through the issue forms,
with the browser filled in
The about section links to GitHub's choice of forms and passes the browser and system to the bug form; the forms point to the Bulka Telegram community.
---
.github/ISSUE_TEMPLATE/config.yml | 6 ++---
website/src/data/changelog.json | 24 +++++++++++++++++
.../src/repl/components/panel/WelcomeTab.jsx | 26 +++++++++++++++++++
3 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 7aed5ff6..5c80e737 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -3,6 +3,6 @@ contact_links:
- name: Latest version / Последняя версия
url: https://github.com/timoncool/bulka/releases/latest
about: Many problems are already fixed in the newest release. · Многое уже исправлено в свежей версии.
- - name: News and announcements / Новости (Telegram)
- url: https://t.me/nerual_dreming
- about: Releases and plans of the author. · Выпуски и планы автора.
+ - name: Bulka community / Сообщество Bulka (Telegram)
+ url: https://t.me/bulka_app
+ about: Questions, patterns and news. · Вопросы, паттерны и новости.
diff --git a/website/src/data/changelog.json b/website/src/data/changelog.json
index 7b3f10f2..13687dfe 100644
--- a/website/src/data/changelog.json
+++ b/website/src/data/changelog.json
@@ -5,10 +5,34 @@
"dateFormatted": "⚠️ ГЕНЕРИРУЕТСЯ АВТОМАТИЧЕСКИ",
"changes": []
},
+ {
+ "date": "2026-10-14",
+ "dateFormatted": "14 октября 2026",
+ "changes": [
+ {
+ "type": "other",
+ "typeLabel": "Прочее",
+ "emoji": "📦",
+ "description": "Issue forms: bug, idea, question",
+ "scope": null,
+ "author": "Nerual Dreming",
+ "hash": "cd53c2308"
+ }
+ ]
+ },
{
"date": "2026-10-12",
"dateFormatted": "12 октября 2026",
"changes": [
+ {
+ "type": "fix",
+ "typeLabel": "Исправления",
+ "emoji": "🐛",
+ "description": "make-release.sh works from Git Bash (node for Windows got /d/... paths)",
+ "scope": "desktop",
+ "author": "Nerual Dreming",
+ "hash": "6ec511f59"
+ },
{
"type": "fix",
"typeLabel": "Исправления",
diff --git a/website/src/repl/components/panel/WelcomeTab.jsx b/website/src/repl/components/panel/WelcomeTab.jsx
index 7379c37d..d508c4f1 100644
--- a/website/src/repl/components/panel/WelcomeTab.jsx
+++ b/website/src/repl/components/panel/WelcomeTab.jsx
@@ -46,6 +46,11 @@ function WelcomeRu() {
Telegram-сообществу
!
+ {' '}Нашли ошибку?{' '}
+
+ Сообщите о проблеме
+
+ .
🌐 Официальный сайт:{' '}
@@ -110,6 +115,11 @@ function WelcomeEn() {
Telegram community
!
+ {' '}Found a bug?{' '}
+
+ Report a problem
+
+ .
🌐 Website:{' '}
@@ -136,6 +146,22 @@ function WelcomeEn() {
);
}
+/**
+ * GitHub's choice of forms (bug, idea, question) with the browser and system passed along: the key is the `id` of
+ * the text field in `.github/ISSUE_TEMPLATE/*.yml`, and the chosen form fills it from the query parameter.
+ */
+function issueReportUrl() {
+ const agent = navigator.userAgent;
+ const known = [['Edg', 'Edge'], ['OPR', 'Opera'], ['YaBrowser', 'Yandex'], ['Firefox', 'Firefox'], ['Chrome', 'Chrome'], ['Version', 'Safari']];
+ const found = known.map(([token, label]) => [label, agent.match(new RegExp(`${token}/(\\d+)`))]).find(([, m]) => m);
+ const name = found ? `${found[0]} ${found[1][1]}` : '';
+ const os = /Windows/.test(agent) ? 'Windows' : /Mac OS X|Macintosh/.test(agent) ? 'macOS' : /Android/.test(agent) ? 'Android' : /Linux/.test(agent) ? 'Linux' : '';
+ const query = new URLSearchParams();
+ const described = [name, os].filter(Boolean).join(', ');
+ if (described) query.set('browser', described);
+ return `https://github.com/timoncool/Bulka/issues/new/choose?${query.toString()}`;
+}
+
export function WelcomeTab() {
const { fontFamily } = useSettings();
return (
From c5303fe5482192a9d3b932f8225e679b9209c59a Mon Sep 17 00:00:00 2001
From: Nerual Dreming
Date: Wed, 14 Oct 2026 17:38:26 +0300
Subject: [PATCH 2/6] The desktop app sends the computer number the studios
send, so one person with Bulka and a studio counts once
---
desktop/src-tauri/Cargo.lock | 405 +++++++++++++++++-
desktop/src-tauri/Cargo.toml | 2 +
desktop/src-tauri/src/lib.rs | 2 +
test/hub-client.test.mjs | 18 +-
website/src/components/HeadCommon.astro | 4 +-
website/src/data/changelog.json | 9 +
website/src/hub/bulkaHub.mjs | 3 +-
website/src/hub/studioHub.mjs | 4 +-
website/src/i18n/en.mjs | 2 +-
website/src/i18n/ru.mjs | 2 +-
.../src/repl/components/TelemetryConsent.jsx | 1 +
11 files changed, 440 insertions(+), 12 deletions(-)
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index d3cac822..7b8977a2 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -222,6 +222,81 @@ version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
+[[package]]
+name = "aws-lc-rs"
+version = "1.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faac5829c2b74c28f830747e7818ccfb684261b5f48a1118b1e2a13d36dfab13"
+dependencies = [
+ "aws-lc-sys",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1622d8446a2d4b2ce0c7eefc73dd43a99779028d5ee5c2dd8073a658ba8a2bc"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+ "pkg-config",
+]
+
+[[package]]
+name = "axum"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90"
+dependencies = [
+ "axum-core",
+ "bytes",
+ "form_urlencoded",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde_core",
+ "serde_json",
+ "serde_path_to_error",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "axum-core"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "http-body-util",
+ "mime",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "base64"
version = "0.21.7"
@@ -279,6 +354,15 @@ dependencies = [
"generic-array",
]
+[[package]]
+name = "block-buffer"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
+dependencies = [
+ "hybrid-array",
+]
+
[[package]]
name = "block2"
version = "0.6.2"
@@ -337,6 +421,7 @@ version = "0.3.0"
dependencies = [
"serde",
"serde_json",
+ "studio-hub-client",
"tauri",
"tauri-build",
"tauri-plugin-dialog",
@@ -447,6 +532,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838"
dependencies = [
"find-msvc-tools",
+ "jobserver",
+ "libc",
"shlex",
]
@@ -483,6 +570,23 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
+[[package]]
+name = "cfg_aliases"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
+
+[[package]]
+name = "chacha20"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.3.1",
+ "rand_core",
+]
+
[[package]]
name = "chrono"
version = "0.4.45"
@@ -495,6 +599,21 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "cmake"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "cmov"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
+
[[package]]
name = "combine"
version = "4.6.8"
@@ -514,6 +633,12 @@ dependencies = [
"crossbeam-utils",
]
+[[package]]
+name = "const-oid"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
+
[[package]]
name = "cookie"
version = "0.18.2"
@@ -589,6 +714,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "cpufeatures"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "crc32fast"
version = "1.5.2"
@@ -623,6 +757,15 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "crypto-common"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
+dependencies = [
+ "hybrid-array",
+]
+
[[package]]
name = "cssparser"
version = "0.37.0"
@@ -652,6 +795,15 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d"
+[[package]]
+name = "ctutils"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574"
+dependencies = [
+ "cmov",
+]
+
[[package]]
name = "darling"
version = "0.24.1"
@@ -775,8 +927,20 @@ version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
- "block-buffer",
- "crypto-common",
+ "block-buffer 0.10.4",
+ "crypto-common 0.1.7",
+]
+
+[[package]]
+name = "digest"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
+dependencies = [
+ "block-buffer 0.12.1",
+ "const-oid",
+ "crypto-common 0.2.2",
+ "ctutils",
]
[[package]]
@@ -1105,6 +1269,12 @@ dependencies = [
"percent-encoding",
]
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
[[package]]
name = "futures-channel"
version = "0.3.34"
@@ -1305,8 +1475,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"wasi",
+ "wasm-bindgen",
]
[[package]]
@@ -1328,8 +1500,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"r-efi 6.0.0",
+ "rand_core",
+ "wasm-bindgen",
]
[[package]]
@@ -1516,6 +1691,15 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+[[package]]
+name = "hmac"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f"
+dependencies = [
+ "digest 0.11.3",
+]
+
[[package]]
name = "html5ever"
version = "0.39.0"
@@ -1565,6 +1749,21 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hybrid-array"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17"
+dependencies = [
+ "typenum",
+]
+
[[package]]
name = "hyper"
version = "1.12.0"
@@ -1577,6 +1776,7 @@ dependencies = [
"http",
"http-body",
"httparse",
+ "httpdate",
"itoa",
"pin-project-lite",
"smallvec",
@@ -1983,6 +2183,16 @@ dependencies = [
"syn 2.0.119",
]
+[[package]]
+name = "jobserver"
+version = "0.1.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
+dependencies = [
+ "getrandom 0.4.3",
+ "libc",
+]
+
[[package]]
name = "js-sys"
version = "0.3.106"
@@ -2111,6 +2321,23 @@ version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
+[[package]]
+name = "lru-slab"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f"
+
+[[package]]
+name = "machine-uid"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfe0d6336d341b10ae80e099b8f3c59f34bf8aef66ef25e83aa98bf2955c0ae7"
+dependencies = [
+ "libc",
+ "windows-registry",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "markup5ever"
version = "0.39.0"
@@ -2122,6 +2349,12 @@ dependencies = [
"web_atoms",
]
+[[package]]
+name = "matchit"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
+
[[package]]
name = "memchr"
version = "2.8.3"
@@ -2848,6 +3081,63 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "quinn"
+version = "0.11.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls",
+ "socket2",
+ "thiserror 2.0.21",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe"
+dependencies = [
+ "aws-lc-rs",
+ "bytes",
+ "getrandom 0.4.3",
+ "lru-slab",
+ "rand",
+ "rand_pcg",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.21",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.52.0",
+]
+
[[package]]
name = "quote"
version = "1.0.47"
@@ -2869,6 +3159,32 @@ version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+[[package]]
+name = "rand"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af"
+dependencies = [
+ "chacha20",
+ "getrandom 0.4.3",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+
+[[package]]
+name = "rand_pcg"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a"
+dependencies = [
+ "rand_core",
+]
+
[[package]]
name = "raw-window-handle"
version = "0.6.2"
@@ -2963,6 +3279,7 @@ dependencies = [
"log",
"percent-encoding",
"pin-project-lite",
+ "quinn",
"rustls",
"rustls-pki-types",
"rustls-platform-verifier",
@@ -3054,6 +3371,7 @@ version = "0.23.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634"
dependencies = [
+ "aws-lc-rs",
"once_cell",
"ring",
"rustls-pki-types",
@@ -3080,6 +3398,7 @@ version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
dependencies = [
+ "web-time",
"zeroize",
]
@@ -3116,6 +3435,7 @@ version = "0.103.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
dependencies = [
+ "aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@@ -3127,6 +3447,12 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
[[package]]
name = "same-file"
version = "1.0.6"
@@ -3320,6 +3646,17 @@ dependencies = [
"zmij",
]
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
+dependencies = [
+ "itoa",
+ "serde",
+ "serde_core",
+]
+
[[package]]
name = "serde_repr"
version = "0.1.21"
@@ -3349,6 +3686,18 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
[[package]]
name = "serde_with"
version = "3.24.0"
@@ -3420,8 +3769,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
- "cpufeatures",
- "digest",
+ "cpufeatures 0.2.17",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha2"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.3.1",
+ "digest 0.11.3",
]
[[package]]
@@ -3584,6 +3944,25 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+[[package]]
+name = "studio-hub-client"
+version = "0.1.0"
+source = "git+https://github.com/timoncool/studio-hub-client?rev=987e7bd3fadc6530cd6b2940592ed8a0b917ea39#987e7bd3fadc6530cd6b2940592ed8a0b917ea39"
+dependencies = [
+ "axum",
+ "chrono",
+ "hmac",
+ "machine-uid",
+ "regex",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "sha2 0.11.1",
+ "tokio",
+ "tracing",
+ "uuid",
+]
+
[[package]]
name = "subtle"
version = "2.6.1"
@@ -3844,7 +4223,7 @@ dependencies = [
"semver",
"serde",
"serde_json",
- "sha2",
+ "sha2 0.10.9",
"syn 2.0.119",
"tauri-utils",
"thiserror 2.0.21",
@@ -4224,9 +4603,21 @@ dependencies = [
"mio",
"pin-project-lite",
"socket2",
+ "tokio-macros",
"windows-sys 0.61.2",
]
+[[package]]
+name = "tokio-macros"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.8",
+]
+
[[package]]
name = "tokio-rustls"
version = "0.26.6"
@@ -4359,6 +4750,7 @@ dependencies = [
"tokio",
"tower-layer",
"tower-service",
+ "tracing",
]
[[package]]
@@ -4397,6 +4789,7 @@ version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
+ "log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@@ -5257,7 +5650,7 @@ dependencies = [
"once_cell",
"percent-encoding",
"raw-window-handle",
- "sha2",
+ "sha2 0.10.9",
"soup3",
"tao-macros",
"thiserror 2.0.21",
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 58930551..89081035 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -21,6 +21,8 @@ tauri-plugin-updater = "2"
tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
+# только machine::id — номер компьютера, общий со студиями
+studio-hub-client = { git = "https://github.com/timoncool/studio-hub-client", rev = "987e7bd3fadc6530cd6b2940592ed8a0b917ea39" }
[profile.release]
opt-level = "s"
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index b9ee7c2d..945ce4a1 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -160,6 +160,8 @@ fn spawn_server(app: &tauri::AppHandle, app_dir: &PathBuf, data: &PathBuf, port:
.env("BULKA_DESKTOP", "1")
// Куда сохранять записи/экспорт (сервер кладёт файлы в <данные>/recordings и открывает папку).
.env("BULKA_APP_DIR", data.to_string_lossy().into_owned())
+ // номер компьютера, общий со студиями: статистика считает одного человека один раз
+ .env("BULKA_MACHINE", studio_hub_client::machine::id().unwrap_or_default())
.current_dir(app_dir.clone());
let (mut rx, child) = cmd.spawn().map_err(|e| format!("node не запустился: {e}"))?;
diff --git a/test/hub-client.test.mjs b/test/hub-client.test.mjs
index 7c8141ec..442b238f 100644
--- a/test/hub-client.test.mjs
+++ b/test/hub-client.test.mjs
@@ -11,8 +11,9 @@ function memoryStorage() {
return { getItem: (k) => data.get(k) ?? null, setItem: (k, v) => data.set(k, String(v)), data };
}
-function hubWith(fetchImpl, storage = memoryStorage()) {
+function hubWith(fetchImpl, storage = memoryStorage(), extra = {}) {
return new StudioHub({
+ ...extra,
app: 'bulka',
version: '0.6.0',
os: 'web Windows Chrome',
@@ -152,3 +153,18 @@ describe('studio hub client', () => {
expect(() => hub.count('Bad-Name')).toThrow();
});
});
+
+describe('computer id', () => {
+ it('goes with the report of the desktop app and is absent on the web', async () => {
+ const machine = '041bb722-6c3b-4ebe-be3a-7ed023dab1b9';
+ const desktop = hubWith(vi.fn(ok), memoryStorage(), { machine });
+ desktop.acknowledge(true);
+ desktop.count('pattern_play_done');
+ const day = new Date().toISOString().slice(0, 10);
+ expect(desktop.reportFor(day).machine).toBe(machine);
+ const web = hubWith(vi.fn(ok));
+ web.acknowledge(true);
+ web.count('pattern_play_done');
+ expect('machine' in web.reportFor(day)).toBe(false);
+ });
+});
diff --git a/website/src/components/HeadCommon.astro b/website/src/components/HeadCommon.astro
index 9420c2b0..8fb9a598 100644
--- a/website/src/components/HeadCommon.astro
+++ b/website/src/components/HeadCommon.astro
@@ -15,7 +15,9 @@ const lang = langFromPath(Astro.url.pathname);
const desktop = process.env.BULKA_DESKTOP === '1';
const hubUrl = import.meta.env.PUBLIC_STUDIO_HUB_URL || process.env.STUDIO_HUB_URL || '';
const hubTest = import.meta.env.DEV || process.env.STUDIO_HUB_TEST === '1';
-const build = { desktop, version: desktop ? desktopConf.version : websitePackage.version, hubUrl };
+// the computer id the shell derives (studio-hub-client `machine::id`), so Bulka and the studios count one person once
+const machine = desktop && process.env.BULKA_MACHINE ? process.env.BULKA_MACHINE : undefined;
+const build = { desktop, version: desktop ? desktopConf.version : websitePackage.version, hubUrl, machine };
const notice = { app: 'bulka', lang, version: build.version, ...(hubTest ? { test: '1' } : {}) };
---
diff --git a/website/src/data/changelog.json b/website/src/data/changelog.json
index 13687dfe..860bf7d2 100644
--- a/website/src/data/changelog.json
+++ b/website/src/data/changelog.json
@@ -9,6 +9,15 @@
"date": "2026-10-14",
"dateFormatted": "14 октября 2026",
"changes": [
+ {
+ "type": "other",
+ "typeLabel": "Прочее",
+ "emoji": "📦",
+ "description": "Welcome tab: report a problem through the issue forms, with the browser filled in",
+ "scope": null,
+ "author": "Nerual Dreming",
+ "hash": "68f997854"
+ },
{
"type": "other",
"typeLabel": "Прочее",
diff --git a/website/src/hub/bulkaHub.mjs b/website/src/hub/bulkaHub.mjs
index 435b40fd..0948ec75 100644
--- a/website/src/hub/bulkaHub.mjs
+++ b/website/src/hub/bulkaHub.mjs
@@ -41,7 +41,7 @@ function noticeEvents(on) {
/** The hub of this page, or null where statistics are not wired (local dev without PUBLIC_STUDIO_HUB_URL). */
export function initBulkaHub() {
if (hub || typeof window === 'undefined') return hub;
- const { desktop, version, hubUrl } = build();
+ const { desktop, version, hubUrl, machine } = build();
if (import.meta.env.DEV && !hubUrl) {
console.info('[studio hub] dev: statistics are off; set PUBLIC_STUDIO_HUB_URL to send them to a local hub');
return null;
@@ -56,6 +56,7 @@ export function initBulkaHub() {
storage: window.localStorage,
fetch: window.fetch.bind(window),
onTelemetry: noticeEvents,
+ machine,
});
noticeEvents(hub.telemetryOn());
window.__bulkaHub = hub;
diff --git a/website/src/hub/studioHub.mjs b/website/src/hub/studioHub.mjs
index c343ee1a..1c1e7495 100644
--- a/website/src/hub/studioHub.mjs
+++ b/website/src/hub/studioHub.mjs
@@ -31,7 +31,8 @@ export function shortName(text) {
export class StudioHub {
/**
* @param {{ app: string, version: string, os: string, backend: string, lang: () => string,
- * urls: string[], storage: Storage, fetch: typeof fetch, now?: () => number }} config
+ * urls: string[], storage: Storage, fetch: typeof fetch, now?: () => number, machine?: string }} config
+ * `machine`: the computer id the desktop shell derives, the same in every program of timoncool's; none on the web.
*/
constructor(config) {
this.config = config;
@@ -129,6 +130,7 @@ export class StudioHub {
return {
schema: 1,
install: this.state.install,
+ ...(this.config.machine ? { machine: this.config.machine } : {}),
app: this.config.app,
version: this.config.version,
day: dayKey,
diff --git a/website/src/i18n/en.mjs b/website/src/i18n/en.mjs
index e7ebc6a2..6d53ae3b 100644
--- a/website/src/i18n/en.mjs
+++ b/website/src/i18n/en.mjs
@@ -365,7 +365,7 @@ export default {
'summary.toolError': 'Tool error',
'telemetry.title': 'Anonymous statistics',
'telemetry.about':
- 'Helps us see what is used and what breaks: how many pattern runs, recordings, exports and AI agent replies, which errors happened (without details), the interface language, OS and browser. Nothing personal: no code, no prompts, no keys, no file names. You can turn it off in the settings.',
+ 'Helps us see what is used and what breaks: how many pattern runs, recordings, exports and AI agent replies, which errors happened (without details), the interface language, OS and browser, and in the desktop app a computer number shared by our programs (a one-way hash, not the system number itself). Nothing personal: no code, no prompts, no keys, no file names. You can turn it off in the settings.',
'telemetry.checkbox': 'Send anonymous usage statistics',
'telemetry.what': 'What is sent',
'telemetry.done': 'Done',
diff --git a/website/src/i18n/ru.mjs b/website/src/i18n/ru.mjs
index 532324ea..e20cb500 100644
--- a/website/src/i18n/ru.mjs
+++ b/website/src/i18n/ru.mjs
@@ -364,7 +364,7 @@ export default {
'summary.toolError': 'Ошибка инструмента',
'telemetry.title': 'Анонимная статистика',
'telemetry.about':
- 'Помогает понять, чем пользуются и что ломается: сколько запусков паттернов, записей, экспортов и ответов ИИ-агента, какие ошибки случились (без подробностей), язык интерфейса, ОС и браузер. Ничего личного: ни кода, ни промптов, ни ключей, ни имён файлов. Выключить можно в настройках.',
+ 'Помогает понять, чем пользуются и что ломается: сколько запусков паттернов, записей, экспортов и ответов ИИ-агента, какие ошибки случились (без подробностей), язык интерфейса, ОС и браузер, а в приложении для компьютера ещё номер компьютера, общий для наших программ (необратимый хеш, не сам системный номер). Ничего личного: ни кода, ни промптов, ни ключей, ни имён файлов. Выключить можно в настройках.',
'telemetry.checkbox': 'Отправлять анонимную статистику',
'telemetry.what': 'Что отправляется',
'telemetry.done': 'Готово',
diff --git a/website/src/repl/components/TelemetryConsent.jsx b/website/src/repl/components/TelemetryConsent.jsx
index 887ed226..57764300 100644
--- a/website/src/repl/components/TelemetryConsent.jsx
+++ b/website/src/repl/components/TelemetryConsent.jsx
@@ -8,6 +8,7 @@ export function TelemetryPreview({ hub }) {
const report = hub.reportFor(day) ?? {
schema: 1,
install: t('telemetry.previewInstall'),
+ ...(hub.config.machine ? { machine: hub.config.machine } : {}),
app: hub.config.app,
version: hub.config.version,
day,
From 79fe8b8acccf36ffdac30048b0431e9373efa3a3 Mon Sep 17 00:00:00 2001
From: Nerual Dreming
Date: Wed, 14 Oct 2026 20:10:02 +0300
Subject: [PATCH 3/6] =?UTF-8?q?=D0=A0=D0=B5=D0=B2=D1=8C=D1=8E:=20=D0=BD?=
=?UTF-8?q?=D0=BE=D0=BC=D0=B5=D1=80=20=D0=BA=D0=BE=D0=BC=D0=BF=D1=8C=D1=8E?=
=?UTF-8?q?=D1=82=D0=B5=D1=80=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D0=BA?=
=?UTF-8?q?=D0=BD=D0=B0=20=E2=80=94=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE?=
=?UTF-8?q?=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC=D0=BD=D1=8B=D0=B9=20(ma?=
=?UTF-8?q?chine::system=5Fid),=20=D0=B1=D0=B5=D0=B7=20=D0=B7=D0=B0=D0=BF?=
=?UTF-8?q?=D0=B8=D1=81=D0=B8=20=D0=BE=D0=B1=D1=89=D0=B5=D0=B3=D0=BE=20?=
=?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20=D0=B4=D0=BE=20=D1=81=D0=BE?=
=?UTF-8?q?=D0=B3=D0=BB=D0=B0=D1=81=D0=B8=D1=8F;=20studio-hub-client=2068d?=
=?UTF-8?q?95f8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
desktop/src-tauri/Cargo.lock | 32 ++++++++++++++++----------------
desktop/src-tauri/Cargo.toml | 2 +-
desktop/src-tauri/src/lib.rs | 2 +-
website/src/data/changelog.json | 9 +++++++++
4 files changed, 27 insertions(+), 18 deletions(-)
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index 7b8977a2..7acbe3eb 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -961,7 +961,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -1146,7 +1146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -2431,7 +2431,7 @@ dependencies = [
"png 0.18.1",
"serde",
"thiserror 2.0.21",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -2768,7 +2768,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -3135,7 +3135,7 @@ dependencies = [
"once_cell",
"socket2",
"tracing",
- "windows-sys 0.52.0",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -3362,7 +3362,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -3420,7 +3420,7 @@ dependencies = [
"security-framework",
"security-framework-sys",
"webpki-root-certs",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -3857,7 +3857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -3947,7 +3947,7 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "studio-hub-client"
version = "0.1.0"
-source = "git+https://github.com/timoncool/studio-hub-client?rev=987e7bd3fadc6530cd6b2940592ed8a0b917ea39#987e7bd3fadc6530cd6b2940592ed8a0b917ea39"
+source = "git+https://github.com/timoncool/studio-hub-client?rev=68d95f8699ebc5dc919a842c4a5d55802c9ceb1b#68d95f8699ebc5dc919a842c4a5d55802c9ceb1b"
dependencies = [
"axum",
"chrono",
@@ -4491,10 +4491,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
- "getrandom 0.4.3",
+ "getrandom 0.3.4",
"once_cell",
"rustix",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -4834,7 +4834,7 @@ dependencies = [
"png 0.18.1",
"serde",
"thiserror 2.0.21",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -4863,7 +4863,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
dependencies = [
"memoffset",
"tempfile",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -5203,7 +5203,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -5224,7 +5224,7 @@ dependencies = [
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
"windows-version",
]
@@ -5605,7 +5605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10"
dependencies = [
"cfg-if",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 89081035..64b391e9 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -22,7 +22,7 @@ tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# только machine::id — номер компьютера, общий со студиями
-studio-hub-client = { git = "https://github.com/timoncool/studio-hub-client", rev = "987e7bd3fadc6530cd6b2940592ed8a0b917ea39" }
+studio-hub-client = { git = "https://github.com/timoncool/studio-hub-client", rev = "68d95f8699ebc5dc919a842c4a5d55802c9ceb1b" }
[profile.release]
opt-level = "s"
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 945ce4a1..581905c7 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -161,7 +161,7 @@ fn spawn_server(app: &tauri::AppHandle, app_dir: &PathBuf, data: &PathBuf, port:
// Куда сохранять записи/экспорт (сервер кладёт файлы в <данные>/recordings и открывает папку).
.env("BULKA_APP_DIR", data.to_string_lossy().into_owned())
// номер компьютера, общий со студиями: статистика считает одного человека один раз
- .env("BULKA_MACHINE", studio_hub_client::machine::id().unwrap_or_default())
+ .env("BULKA_MACHINE", studio_hub_client::machine::system_id().unwrap_or_default())
.current_dir(app_dir.clone());
let (mut rx, child) = cmd.spawn().map_err(|e| format!("node не запустился: {e}"))?;
diff --git a/website/src/data/changelog.json b/website/src/data/changelog.json
index 860bf7d2..cc43818a 100644
--- a/website/src/data/changelog.json
+++ b/website/src/data/changelog.json
@@ -9,6 +9,15 @@
"date": "2026-10-14",
"dateFormatted": "14 октября 2026",
"changes": [
+ {
+ "type": "other",
+ "typeLabel": "Прочее",
+ "emoji": "📦",
+ "description": "The desktop app sends the computer number the studios send, so one person with Bulka and a studio counts once",
+ "scope": null,
+ "author": "Nerual Dreming",
+ "hash": "c5303fe54"
+ },
{
"type": "other",
"typeLabel": "Прочее",
From 2b3d2778557deff84ec6ec11b26101ea9e4b7161 Mon Sep 17 00:00:00 2001
From: Nerual Dreming
Date: Wed, 14 Oct 2026 20:18:28 +0300
Subject: [PATCH 4/6] studio-hub-client 365c2b7
---
desktop/src-tauri/Cargo.lock | 28 ++++++++++++++--------------
desktop/src-tauri/Cargo.toml | 2 +-
website/src/data/changelog.json | 9 +++++++++
3 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index 7acbe3eb..c07cd6a0 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -961,7 +961,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -1146,7 +1146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -2431,7 +2431,7 @@ dependencies = [
"png 0.18.1",
"serde",
"thiserror 2.0.21",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -3135,7 +3135,7 @@ dependencies = [
"once_cell",
"socket2",
"tracing",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -3362,7 +3362,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -3420,7 +3420,7 @@ dependencies = [
"security-framework",
"security-framework-sys",
"webpki-root-certs",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -3857,7 +3857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
dependencies = [
"libc",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -3947,7 +3947,7 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "studio-hub-client"
version = "0.1.0"
-source = "git+https://github.com/timoncool/studio-hub-client?rev=68d95f8699ebc5dc919a842c4a5d55802c9ceb1b#68d95f8699ebc5dc919a842c4a5d55802c9ceb1b"
+source = "git+https://github.com/timoncool/studio-hub-client?rev=365c2b757bfddd45fff67e7264b41f4f961a0032#365c2b757bfddd45fff67e7264b41f4f961a0032"
dependencies = [
"axum",
"chrono",
@@ -4494,7 +4494,7 @@ dependencies = [
"getrandom 0.3.4",
"once_cell",
"rustix",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -4834,7 +4834,7 @@ dependencies = [
"png 0.18.1",
"serde",
"thiserror 2.0.21",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -4863,7 +4863,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
dependencies = [
"memoffset",
"tempfile",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -5203,7 +5203,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -5224,7 +5224,7 @@ dependencies = [
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
"windows-version",
]
@@ -5605,7 +5605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10"
dependencies = [
"cfg-if",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 64b391e9..1c7be754 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -22,7 +22,7 @@ tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# только machine::id — номер компьютера, общий со студиями
-studio-hub-client = { git = "https://github.com/timoncool/studio-hub-client", rev = "68d95f8699ebc5dc919a842c4a5d55802c9ceb1b" }
+studio-hub-client = { git = "https://github.com/timoncool/studio-hub-client", rev = "365c2b757bfddd45fff67e7264b41f4f961a0032" }
[profile.release]
opt-level = "s"
diff --git a/website/src/data/changelog.json b/website/src/data/changelog.json
index cc43818a..a1784524 100644
--- a/website/src/data/changelog.json
+++ b/website/src/data/changelog.json
@@ -9,6 +9,15 @@
"date": "2026-10-14",
"dateFormatted": "14 октября 2026",
"changes": [
+ {
+ "type": "other",
+ "typeLabel": "Прочее",
+ "emoji": "📦",
+ "description": "Ревью: номер компьютера для окна — только системный (machine::system_id), без записи общего файла до согласия; studio-hub-client 68d95f8",
+ "scope": null,
+ "author": "Nerual Dreming",
+ "hash": "79fe8b8ac"
+ },
{
"type": "other",
"typeLabel": "Прочее",
From 758013ac413a17040f14ce8a27a7bc383085bfb4 Mon Sep 17 00:00:00 2001
From: Nerual Dreming
Date: Thu, 15 Oct 2026 01:52:58 +0300
Subject: [PATCH 5/6] The window's own page gets the microphone WebView2 left
unanswered, so the sound outputs are listed
---
desktop/src-tauri/src/lib.rs | 10 ++++++++++
website/src/data/changelog.json | 9 +++++++++
2 files changed, 19 insertions(+)
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 581905c7..f3f74b89 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -339,6 +339,16 @@ pub fn run() {
.min_inner_size(1100.0, 700.0)
.resizable(true)
.disable_drag_drop_handler()
+ // WebView2 оставляет запрос микрофона без ответа и без окна согласия: getUserMedia своей страницы
+ // (названия звуковых выходов, запись) висел, и список устройств вывода оставался пустым
+ .on_permission_request(move |webview, kind| match kind {
+ tauri::webview::PermissionKind::Microphone
+ if webview.url().is_ok_and(|url| url.host_str() == Some("127.0.0.1") && url.port() == Some(port)) =>
+ {
+ tauri::webview::PermissionResponse::Allow
+ }
+ _ => tauri::webview::PermissionResponse::Default,
+ })
.build()?;
if let Some(ic) = icon {
win.set_icon(ic)?;
diff --git a/website/src/data/changelog.json b/website/src/data/changelog.json
index a1784524..dc0dd29f 100644
--- a/website/src/data/changelog.json
+++ b/website/src/data/changelog.json
@@ -9,6 +9,15 @@
"date": "2026-10-14",
"dateFormatted": "14 октября 2026",
"changes": [
+ {
+ "type": "other",
+ "typeLabel": "Прочее",
+ "emoji": "📦",
+ "description": "studio-hub-client 365c2b7",
+ "scope": null,
+ "author": "Nerual Dreming",
+ "hash": "2b3d27785"
+ },
{
"type": "other",
"typeLabel": "Прочее",
From 958d332f287ba38709566286d23fc3e76a9a8af5 Mon Sep 17 00:00:00 2001
From: Nerual Dreming
Date: Thu, 15 Oct 2026 02:39:36 +0300
Subject: [PATCH 6/6] The microphone asked for only to name the sound outputs
is released at once
---
packages/superdough/superdough.mjs | 10 ++++++++--
website/src/data/changelog.json | 15 +++++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs
index a4f17c98..bc0b7d58 100644
--- a/packages/superdough/superdough.mjs
+++ b/packages/superdough/superdough.mjs
@@ -171,8 +171,14 @@ export function getSound(s) {
}
export const getAudioDevices = async () => {
- await navigator.mediaDevices.getUserMedia({ audio: true });
- let mediaDevices = await navigator.mediaDevices.enumerateDevices();
+ // the microphone is asked for only so the outputs are named: it is released at once
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
+ let mediaDevices;
+ try {
+ mediaDevices = await navigator.mediaDevices.enumerateDevices();
+ } finally {
+ stream.getTracks().forEach((track) => track.stop());
+ }
mediaDevices = mediaDevices.filter((device) => device.kind === 'audiooutput' && device.deviceId !== 'default');
const devicesMap = new Map();
devicesMap.set(DEFAULT_AUDIO_DEVICE_NAME, '');
diff --git a/website/src/data/changelog.json b/website/src/data/changelog.json
index dc0dd29f..57559222 100644
--- a/website/src/data/changelog.json
+++ b/website/src/data/changelog.json
@@ -5,6 +5,21 @@
"dateFormatted": "⚠️ ГЕНЕРИРУЕТСЯ АВТОМАТИЧЕСКИ",
"changes": []
},
+ {
+ "date": "2026-10-15",
+ "dateFormatted": "15 октября 2026",
+ "changes": [
+ {
+ "type": "other",
+ "typeLabel": "Прочее",
+ "emoji": "📦",
+ "description": "The window's own page gets the microphone WebView2 left unanswered, so the sound outputs are listed",
+ "scope": null,
+ "author": "Nerual Dreming",
+ "hash": "758013ac4"
+ }
+ ]
+ },
{
"date": "2026-10-14",
"dateFormatted": "14 октября 2026",