diff options
Diffstat (limited to 'packages/meshbay-hub/src')
14 files changed, 17 insertions, 222 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js index 0f442cf..341d37e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js @@ -145,10 +145,6 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, // destination rather than a set of folders it reads. const [chatDirectory, setChatDirectory] = useState(''); const [chatLinkPreview, setChatLinkPreview] = useState(true); - // Whether this node speaks the operations MNP 1.1 added. False for one that - // predates them, and the Settings page then offers what that node can - // actually do rather than controls whose messages it drops unanswered. - const [nodeSupportsAppOps, setNodeSupportsAppOps] = useState(false); // MusicBrainz on/off (per-group) — docs/musicbay.md §3.2. const [musicbrainzConfig, setMusicbrainzConfig] = useState(null); const onPlayQueue = useCallback((tracks, startIndex) => { @@ -365,7 +361,6 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, || (ack.audio_root ? [ack.audio_root] : []), photo: ack.photo_directories || ack.photo_roots || [], }); - setNodeSupportsAppOps(transport.supportsAppOps); setChatDirectory(ack.chat_directory || ''); setChatLinkPreview(ack.chat_link_preview !== false); setMusicbrainzConfig({ @@ -827,7 +822,6 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, onScanSettings=${(s) => setScanSettings(s)} entries=${entries} nodeDirs=${nodeDirs} appSettings=${appSettings} - nodeSupportsAppOps=${nodeSupportsAppOps} ${/* The saving pane already knows what it asked for; this is so the page's own copy moves at the same time, rather than waiting for the ack it will not be handed (transport.js diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js index dce5833..8e11088 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js @@ -40,7 +40,6 @@ import * as platform from './platform.js'; * transport — MeshBayTransport instance, or null when not connected * signFn — signing function for admin ops * nodeDetected — whether the loopback node API answers - * readOnly — suppress every edit control * onRootsChange — called after a change, to re-read the loopback list * onRefreshIndex — full index refresh. Not called after a root change: see * `run()` for why the node's own push is what settles it @@ -48,7 +47,7 @@ import * as platform from './platform.js'; * localRoots / onLocalRootsChange — the array, in "local" mode */ function SharedDirectoriesTable({ roots, groupId, transport, signFn, - nodeDetected: nodeAvail, readOnly, + nodeDetected: nodeAvail, onRootsChange, onRefreshIndex, mode = 'live', localRoots, onLocalRootsChange }) { @@ -116,7 +115,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, // API is not (it is authorized by being on localhost with the run token). const overMnp = !isLocal && transport && transport.connected; const overLoopback = !isLocal && !overMnp && nodeAvail; - const canEdit = !readOnly && (isLocal || overMnp || overLoopback); + const canEdit = isLocal || overMnp || overLoopback; const rootUrl = (name, suffix = '') => '/api/groups/' + groupId + '/roots/' + encodeURIComponent(name) + suffix; @@ -401,7 +400,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, enabledApps, onEnabledApps, scanSettings, onScanSettings, entries, nodeDirs, - appSettings, nodeSupportsAppOps, + appSettings, onAppDirectories, onRefreshIndex, onPaired, onLeft }) { const [members, setMembers] = useState([]); @@ -693,14 +692,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, if (!transport || !transport.connected) { throw new Error(t('node.root_no_route')); } - // A node too old for the generic op still answers the three per-app - // messages that came before it, so an operator on one keeps the ability - // they had rather than being handed a control that times out. - if (transport.supportsAppOps) { - await transport.setAppDirectories(appKey, paths, adminSignFn); - } else { - await transport.setAppDirectoriesLegacy(appKey, paths, adminSignFn); - } + await transport.setAppDirectories(appKey, paths, adminSignFn); if (onAppDirectories) onAppDirectories(appKey, paths); }, [transportRef, adminSignFn, onAppDirectories]); @@ -898,19 +890,11 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, <p class="settings-hint">${t('settings_node.shared_directories_hint')}</p> ${!connected && nodeDetected && html` <p class="settings-hint">${t('settings_node.roots_offline_hint')}</p>`} - ${/* Read-only against a node that predates the root operations: - writable, removable, eject and plug have no older equivalent - to fall back to, and an unknown message type is dropped - unanswered — a thirty-second wait ending in a timeout, with - nothing on screen to say the node simply cannot do it. */''} - ${connected && !nodeSupportsAppOps && !nodeDetected && html` - <p class="settings-hint">${t('settings_node.roots_node_too_old')}</p>`} <${SharedDirectoriesTable} roots=${effectiveRoots} groupId=${groupId} transport=${transportRef.current} signFn=${adminSignFn} - readOnly=${connected && !nodeSupportsAppOps && !nodeDetected} nodeDetected=${nodeDetected} onRootsChange=${loadNodeInfo} onRefreshIndex=${onRefreshIndex} /> @@ -937,9 +921,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, disabled=${appsBusy} onChange=${() => toggleApp(app.key)} /> `}> - ${!nodeSupportsAppOps && app.key === 'chat' - ? html`<p class="settings-hint">${t('settings_node.app_node_too_old')}</p>` - : activeApps.includes(app.key) + ${activeApps.includes(app.key) ? html`<${app.Settings} roots=${effectiveRoots} dirs=${folderOptions} settings=${appSettings} diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js index 0f632e3..9d4aef8 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js @@ -896,8 +896,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Registrieren Sie sich bei TMDB, um einen eigenen API-Schlüssel zu erzeugen.', 'settings_app.tmdb_token_link': 'Schlüssel holen', 'settings_node.roots_offline_hint': 'Nicht mit dem Node verbunden — Änderungen laufen über den lokalen Node und greifen beim nächsten Neuladen.', - 'settings_node.roots_node_too_old': 'Dieser Node ist älter als diese Seite: Er kann seine Verzeichnisse anzeigen, aber hier nicht ändern. Aktualisieren Sie ihn oder nutzen Sie die meshbay-node root-Befehle.', - 'settings_node.app_node_too_old': 'Dieser Node ist älter als diese Seite und hat für diese App noch keine Einstellung. Aktualisieren Sie ihn, um sie hier zu konfigurieren.', 'settings_node.directories_title': 'App-Verzeichnisse', 'settings_node.directories_hint': 'Freigegebene Ordner und welchen davon die Videos-, Musik- und Fotos-Apps als eigene(n) Einstiegspunkt(e) nutzen.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js index cb7f4a0..8385caf 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js @@ -650,8 +650,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Sign up on TMDB to generate your own API key.', 'settings_app.tmdb_token_link': 'Get a key', 'settings_node.roots_offline_hint': 'Not connected to the node — changes go through the local node instead, and take effect on its next reload.', - 'settings_node.roots_node_too_old': 'This node is older than this page: it can show its directories but not change them here. Update it, or use the meshbay-node root commands.', - 'settings_node.app_node_too_old': 'This node is older than this page and has no setting for this app yet. Update it to configure this here.', 'settings_node.directories_title': 'App directories', 'settings_node.directories_hint': 'Which shared folders the Videos, Music and Photos apps use as their entry point(s).', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js index fe1c13b..cb8f312 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js @@ -891,8 +891,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Regístrate en TMDB para generar tu propia clave de API.', 'settings_app.tmdb_token_link': 'Obtener una clave', 'settings_node.roots_offline_hint': 'Sin conexión con el nodo: los cambios pasan por el nodo local y se aplican en su próxima recarga.', - 'settings_node.roots_node_too_old': 'Este nodo es más antiguo que esta página: puede mostrar sus directorios pero no cambiarlos aquí. Actualízalo o usa los comandos meshbay-node root.', - 'settings_node.app_node_too_old': 'Este nodo es más antiguo que esta página y aún no tiene ajustes para esta aplicación. Actualízalo para configurarla aquí.', 'settings_node.directories_title': 'Directorios de apps', 'settings_node.directories_hint': 'Carpetas compartidas, y cuál de ellas usan las apps de Vídeos, Música y Fotos como su(s) propio(s) punto(s) de entrada.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js index ea3f60e..608da62 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js @@ -909,8 +909,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Créez un compte TMDB pour générer votre propre clé d\'API.', 'settings_app.tmdb_token_link': 'Obtenir une clé', 'settings_node.roots_offline_hint': 'Non connecté au nœud — les changements passent par le nœud local et prennent effet à son prochain rechargement.', - 'settings_node.roots_node_too_old': 'Ce nœud est plus ancien que cette page : il peut afficher ses répertoires mais pas les modifier ici. Mettez-le à jour, ou utilisez les commandes meshbay-node root.', - 'settings_node.app_node_too_old': 'Ce nœud est plus ancien que cette page et n\'a pas encore de réglage pour cette application. Mettez-le à jour pour la configurer ici.', 'settings_node.directories_title': 'Répertoires des applications', 'settings_node.directories_hint': 'Quel(s) dossier(s) partagés les applications Vidéos, Musique et Photos utilisent comme leur(s) propre(s) point(s) d\'entrée.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js index 0687b25..be5fe29 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js @@ -905,8 +905,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Registrati su TMDB per generare la tua chiave API.', 'settings_app.tmdb_token_link': 'Ottieni una chiave', 'settings_node.roots_offline_hint': 'Non connesso al nodo: le modifiche passano dal nodo locale e hanno effetto al successivo ricaricamento.', - 'settings_node.roots_node_too_old': 'Questo nodo è più vecchio di questa pagina: può mostrare le sue directory ma non modificarle qui. Aggiornalo, oppure usa i comandi meshbay-node root.', - 'settings_node.app_node_too_old': 'Questo nodo è più vecchio di questa pagina e non ha ancora impostazioni per questa applicazione. Aggiornalo per configurarla qui.', 'settings_node.directories_title': 'Directory delle app', 'settings_node.directories_hint': 'Cartelle condivise, e quale di esse le app Video, Musica e Foto usano come proprio/i punto/i di ingresso.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js index a02e058..f2d94d9 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js @@ -889,8 +889,6 @@ export default { 'settings_app.tmdb_token_prompt': 'TMDB に登録して、自分の API キーを発行してください。', 'settings_app.tmdb_token_link': 'キーを取得', 'settings_node.roots_offline_hint': 'ノードに接続していません — 変更はローカルノード経由で行われ、次回の再読み込みで反映されます。', - 'settings_node.roots_node_too_old': 'このノードはこのページより古く、ディレクトリの表示はできますがここでの変更はできません。更新するか、meshbay-node root コマンドを使ってください。', - 'settings_node.app_node_too_old': 'このノードはこのページより古く、このアプリの設定をまだ持っていません。ここで設定するには更新してください。', 'settings_node.directories_title': 'アプリのディレクトリ', 'settings_node.directories_hint': '共有フォルダと、動画・音楽・写真の各アプリがそれぞれの起点として使用するフォルダです。', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js index 0235d8a..f7f0775 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js @@ -907,8 +907,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Meld u aan bij TMDB om uw eigen API-sleutel te maken.', 'settings_app.tmdb_token_link': 'Sleutel ophalen', 'settings_node.roots_offline_hint': 'Niet verbonden met de node — wijzigingen gaan via de lokale node en worden bij de volgende herlaadbeurt actief.', - 'settings_node.roots_node_too_old': 'Deze node is ouder dan deze pagina: hij kan zijn mappen tonen maar hier niet wijzigen. Werk hem bij, of gebruik de meshbay-node root-opdrachten.', - 'settings_node.app_node_too_old': 'Deze node is ouder dan deze pagina en heeft nog geen instelling voor deze app. Werk hem bij om die hier in te stellen.', 'settings_node.directories_title': 'App-mappen', 'settings_node.directories_hint': 'Gedeelde mappen, en welke daarvan de Video\'s-, Muziek- en Foto\'s-apps als eigen startpunt(en) gebruiken.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js index af4a5bb..8c50790 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js @@ -933,8 +933,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Zarejestruj się w TMDB, aby wygenerować własny klucz API.', 'settings_app.tmdb_token_link': 'Pobierz klucz', 'settings_node.roots_offline_hint': 'Brak połączenia z węzłem — zmiany przechodzą przez węzeł lokalny i zaczną działać po jego następnym przeładowaniu.', - 'settings_node.roots_node_too_old': 'Ten węzeł jest starszy niż ta strona: może pokazać swoje katalogi, ale nie zmieni ich tutaj. Zaktualizuj go albo użyj poleceń meshbay-node root.', - 'settings_node.app_node_too_old': 'Ten węzeł jest starszy niż ta strona i nie ma jeszcze ustawień tej aplikacji. Zaktualizuj go, aby skonfigurować ją tutaj.', 'settings_node.directories_title': 'Katalogi aplikacji', 'settings_node.directories_hint': 'Katalogi udostępnione oraz to, który z nich aplikacje Wideo, Muzyka i Zdjęcia traktują jako własny punkt (punkty) wejścia.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js index f179c6f..8f903ba 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js @@ -892,8 +892,6 @@ export default { 'settings_app.tmdb_token_prompt': 'Cadastre-se no TMDB para gerar sua própria chave de API.', 'settings_app.tmdb_token_link': 'Obter uma chave', 'settings_node.roots_offline_hint': 'Sem conexão com o nó — as alterações passam pelo nó local e entram em vigor no próximo recarregamento.', - 'settings_node.roots_node_too_old': 'Este nó é mais antigo que esta página: ele pode mostrar seus diretórios, mas não alterá-los aqui. Atualize-o ou use os comandos meshbay-node root.', - 'settings_node.app_node_too_old': 'Este nó é mais antigo que esta página e ainda não tem configuração para este aplicativo. Atualize-o para configurá-lo aqui.', 'settings_node.directories_title': 'Diretórios de apps', 'settings_node.directories_hint': 'Pastas compartilhadas, e qual delas os apps Vídeos, Música e Fotos tratam como seu(s) próprio(s) ponto(s) de entrada.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js index c89bbdc..c836de3 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js @@ -876,8 +876,6 @@ export default { 'settings_app.tmdb_token_prompt': '在 TMDB 注册以生成你自己的 API 密钥。', 'settings_app.tmdb_token_link': '获取密钥', 'settings_node.roots_offline_hint': '未连接到节点 — 变更将通过本地节点进行,并在其下次重新加载时生效。', - 'settings_node.roots_node_too_old': '该节点比本页面旧:它能显示自己的目录,但无法在此更改。请更新节点,或使用 meshbay-node root 命令。', - 'settings_node.app_node_too_old': '该节点比本页面旧,尚不支持此应用的设置。请更新节点后在此配置。', 'settings_node.directories_title': '应用目录', 'settings_node.directories_hint': '共享文件夹,以及“视频”“音乐”和“照片”应用各自使用哪个(些)作为入口。', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport.js b/packages/meshbay-hub/src/meshbay_hub/static/transport.js index 99e3fb9..2e3712c 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/transport.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/transport.js @@ -115,8 +115,7 @@ function _replayBroadcast(transport, msg) { } const ADMIN_OP_TYPES = new Set([ - 'tmdb_override', 'tmdb_rematch', 'tmdb_config', 'tmdb_enabled', 'video_root', 'audio_root', - 'photo_roots', + 'tmdb_override', 'tmdb_rematch', 'tmdb_config', 'tmdb_enabled', 'musicbrainz_enabled', 'file_delete', 'dir_delete', 'apps_enabled', 'set_scan_settings', 'member_revoke', 'root_add', 'root_remove', 'root_update', 'root_eject', 'root_plug', @@ -339,12 +338,6 @@ class Lease { this._wait = new Promise((resolve) => { this._granted = resolve; }); } - /** No slots on this node: behave as though one was granted at once. */ - _skip() { - this.state = 'granted'; - this._granted(); - } - _request() { // A closed channel is not a failure here, and must not throw: the transport // reconnects on its own, `_reopenTransfers` re-asks for every live lease @@ -417,7 +410,6 @@ class Lease { this.closed = true; clearTimeout(this._watchdog); this.transport._leases.delete(this.tr); - if (!this.transport.supportsTransferSlots) return; try { this.transport._send({ type: 'transfer_close', v: '0.1', tr: this.tr, reason }); @@ -530,48 +522,9 @@ class MeshBayTransport { /** The MNP version the connected node declared, or '' before a handshake. */ get nodeVersion() { return this._nodeVersion || ''; } - /** - * Whether this node hands out transfer slots. - * - * Read from the handshake ack rather than from the MNP version: the caps - * shipped before the version bump that will make leases compulsory, so for - * now a node either answers with `transfer_limits` or it predates all of - * this. A node that does not is asked for nothing and enforces nothing — - * every download behaves exactly as it did. - */ - get supportsTransferSlots() { return this._transferLimits !== null; } - /** This member's own caps in this group, or null when the node said nothing. */ get transferLimits() { return this._transferLimits; } - /** - * Whether the node speaks the per-root and per-app operations MNP 1.1 added: - * `root_update`/`root_eject`/`root_plug`, `app_directories`, - * `chat_directory`, `chat_link_preview`. - * - * An older node has no equivalent for the root ones at all, and answers the - * app ones through their three predecessors (`video_root`, `audio_root`, - * `photo_roots`). The caller chooses which; what it must not do is send a - * 1.1 message and wait, because an unknown type is logged and dropped. - */ - get supportsAppOps() { - const m = /^(\d+)\.(\d+)$/.exec(this._nodeVersion || ''); - if (!m) return false; - return (Number(m[1]) > 1) || (Number(m[1]) === 1 && Number(m[2]) >= 1); - } - /** - * Whether the node opens a sealed upload (MNP 2.0). - * - * A 1.x node reads `filename` and `data` off the message itself, finds - * neither — they are inside the seal — and answers "Missing filename or - * data", an error about the wrong thing that names no upload_id and so fails - * every upload in flight. Asked before sending rather than discovered after, - * for the same reason `supportsAppOps` is. - */ - get supportsSealedUpload() { - const m = /^(\d+)\.(\d+)$/.exec(this._nodeVersion || ''); - return !!m && Number(m[1]) >= 2; - } set onAppsEnabled(fn) { this._onAppsEnabled = fn; } set onAppDirectories(fn) { this._onAppDirectories = fn; } set onChatDirectory(fn) { this._onChatDirectory = fn; } @@ -867,11 +820,9 @@ class MeshBayTransport { // block, because everything below — the join, the proof, the sealed ack // — assumes both sides mean the same thing by each message. _checkNodeVersion(reply); - // Kept, not just checked. Several controls exist only on a node new - // enough to have them, and the alternative to asking is offering a - // button whose message an older node logs as unknown and never answers - // — a 30-second wait ending in a timeout, with nothing on screen to say - // the node simply cannot do this. + // Kept for diagnostics only. Nothing branches on it: the range check + // above is what decides whether these two can talk at all, and a peer it + // admits speaks every message in this file. this._nodeVersion = String(reply.v || ''); if (!window.MeshBayCrypto) { throw new Error('Node requires GEK proof but no crypto available'); @@ -1075,15 +1026,6 @@ class MeshBayTransport { Object.assign(ack, config); this._transferLimits = ack.transfer_limits || null; - // Tell the node which of this account's devices is on this connection. - // Deliberately after the ack, and gated on the node's own version rather - // than sent hopefully: a node that does not know the message answers - // nothing at all, which would leave a `device_hello` sitting in - // `_pending` for the full 30s — and the arrival-order fallback hands an - // unrouted reply to the *oldest* pending request, which right after a - // handshake is exactly this one. That is the routed-by-luck bug the chat - // ack comment above was written for; not repeating it. - this._nodeMnp = String(ack.v || ''); // From the *sealed* part of the ack: a forged epoch would have this // client sealing under a key the group has retired. this.chatEpoch = ack.chat_epoch || 0; @@ -1093,9 +1035,10 @@ class MeshBayTransport { this._chatKeysInFlight = null; this._roster = null; this._rosterInFlight = null; - // Not gated on a version any more: a node that reached this point speaks - // MNP 2.0, where identifying the device is what makes chat possible at - // all. `check_version` refused anything older before we got here. + // Tell the node which of this account's devices is on this connection, + // after the ack and unconditionally: a peer `check_version` admitted + // speaks this message, and identifying the device is what makes chat + // possible at all. await this._announceDevice().catch((e) => { console.warn('[MeshBay] device_hello failed — chat will not work:', e); }); @@ -1349,10 +1292,6 @@ class MeshBayTransport { openTransfer({ kind = 'download', bytes = 0, chunks = 0, onState = null } = {}) { const tr = _hex(crypto.getRandomValues(new Uint8Array(16))); const lease = new Lease(this, tr, kind, bytes, chunks, onState); - if (!this.supportsTransferSlots) { - lease._skip(); - return lease; - } this._leases.set(tr, lease); lease._request(); return lease; @@ -1360,7 +1299,6 @@ class MeshBayTransport { /** Re-ask for every live lease. Called after a reconnect. */ _reopenTransfers() { - if (!this.supportsTransferSlots) return; for (const lease of this._leases.values()) { // The node lost the lease with the session, so this is a fresh request // for the same `tr` — which the node treats as the same transfer rather @@ -1450,7 +1388,7 @@ class MeshBayTransport { } /** - * Correct a wrong automatic TMDB match. Signed like setVideoRoot/ + * Correct a wrong automatic TMDB match. Signed like * setTmdbConfig: it replaces what every member sees for a show/movie, * node-wide (media_cache is shared, not per-viewer) — an unsigned * override would let any member vandalize another show's metadata. @@ -1520,7 +1458,7 @@ class MeshBayTransport { * Whether TMDB lookups run for this group at all — per-group (2026-08-24, * used to be node-wide): a real media-library group and a test/demo group * on the same node need not share the decision to spend TMDB quota and - * make outbound requests. Signed like setVideoRoot — it decides whether + * make outbound requests. Signed like the rest — it decides whether * this group's members' Videos tab ever makes outbound TMDB traffic. */ async setTmdbEnabled(enabled, signFn) { @@ -1538,100 +1476,6 @@ class MeshBayTransport { return msg; } - /** - * Which folder (possibly a subfolder of a shared root) the Videos app - * treats as its entry point for this group. `path: ''` means the whole - * group index. Signed like setAppsEnabled — it decides what every - * member's Videos tab shows. - */ - async setVideoRoot(path, signFn) { - const clean = (path || '').replace(/^\/+|\/+$/g, ''); - const msg = await this._sendAndWait({ type: 'video_root', v: '0.5', path: clean }); - if (msg.type === 'error') throw new Error(msg.detail); - if (msg.type === 'admin_challenge') { - return this._authorizeAdminOp(msg, 'video_root', clean, signFn); - } - return msg; - } - - /** - * Same shape as setVideoRoot above — the Music app's own entry point. - */ - async setAudioRoot(path, signFn) { - const clean = (path || '').replace(/^\/+|\/+$/g, ''); - console.log('[MeshBay] setAudioRoot: sending request, path=', JSON.stringify(clean)); - const msg = await this._sendAndWait({ type: 'audio_root', v: '0.10', path: clean }); - console.log('[MeshBay] setAudioRoot: first reply =', msg); - if (msg.type === 'error') throw new Error(msg.detail); - if (msg.type === 'admin_challenge') { - return this._authorizeAdminOp(msg, 'audio_root', clean, signFn); - } - return msg; - } - - /** - * Which folder(s) the Photos app treats as its entry points for this - * group (docs/photos.md §2.1). Unlike setVideoRoot/setAudioRoot, `roots` - * is a whole set, replaced in one signed op — same shape as - * setAppsEnabled. The client normalizes the same way the node does - * (webrtc_server.py's `_do_photo_roots`: trim slashes, drop empties, - * dedupe, sort) so the subject built here matches byte-for-byte what the - * node signs the challenge against. - */ - async setPhotoRoots(roots, signFn) { - const clean = [...new Set( - (roots || []).map((r) => (r || '').replace(/^\/+|\/+$/g, '')).filter(Boolean), - )].sort(); - const msg = await this._sendAndWait({ type: 'photo_roots', v: '0.11', roots: clean }); - if (msg.type === 'error') throw new Error(msg.detail); - if (msg.type === 'admin_challenge') { - return this._authorizeAdminOp(msg, 'photo_roots', clean.join(','), signFn); - } - return msg; - } - - /** - * Point an application at folder(s) inside the group's shared directories. - * - * One method for every app, keyed by the app's registry name — the same - * generic op the node grew for the same reason (docs/refactor-groups.md - * §1.6). `setVideoRoot`, `setAudioRoot` and `setPhotoRoots` are still here - * and still work; nothing new should call them. - * - * The subject names the app as well as the paths, because an operator shown - * "Media/Films" alone cannot tell which application is about to be pointed - * at it, and two apps' challenges would otherwise be indistinguishable. - * Cleaned and sorted the same way the node does, so both sides build the - * same bytes to sign. - */ - /** - * The same instruction a node too old for `app_directories` understands. - * - * Videos, Music and Photos each had their own message before this, and they - * still work — so an operator on an un-upgraded node keeps the ability they - * had, rather than being handed a control that silently times out. Chat has - * no predecessor, which is why its settings are hidden rather than routed. - */ - async setAppDirectoriesLegacy(appKey, directories, signFn) { - const clean = [...new Set( - (directories || []).map((d) => (d || '').replace(/^\/+|\/+$/g, '')).filter(Boolean), - )].sort(); - if (appKey === 'photo') return this.setPhotoRoots(clean, signFn); - // One folder was all these two could carry. Sending several would store - // the first and silently drop the rest, so it is refused instead. - if (clean.length > 1) { - throw new Error( - 'This node is older than this page and can hold one folder per app. ' - + 'Update it, or choose a single folder.'); - } - const one = clean[0] || ''; - if (appKey === 'video') return this.setVideoRoot(one, signFn); - if (appKey === 'music') return this.setAudioRoot(one, signFn); - throw new Error( - 'This node is older than this page and cannot store this app\'s ' - + 'folders. Its operator has to update it.'); - } - async setAppDirectories(appKey, directories, signFn) { const clean = [...new Set( (directories || []).map((d) => (d || '').replace(/^\/+|\/+$/g, '')).filter(Boolean), @@ -2471,11 +2315,6 @@ class MeshBayTransport { throw new Error(`${file.name} is already being uploaded`); } if (!this._gekRaw) throw new Error('This group has no key on this device'); - if (!this.supportsSealedUpload) { - throw new Error( - 'This node is running an older MeshBay and cannot accept an upload ' - + 'from this page. Its operator has to update it.'); - } const C = window.MeshBayCrypto; const groupId = (this._connectArgs && this._connectArgs.groupId) || ''; this._inFlightUploads.add(file.name); @@ -3143,7 +2982,7 @@ class MeshBayTransport { // generic "oldest pending" fallback further down. Returns as soon as a // match resolves: this transport instance is the one that submitted // the request, and its own caller already updates local state from - // what *it* sent (setAppsEnabled/setVideoRoot/... callers all do + // what *it* sent (setAppsEnabled/setAppDirectories/... callers all do // `onX(next)` with their own local value, never by reading the ack), // so the broadcast-oriented per-type handlers below — there for every // *other* connected client learning the change — have nothing left to diff --git a/packages/meshbay-hub/src/meshbay_hub/static/video-app.js b/packages/meshbay-hub/src/meshbay_hub/static/video-app.js index f590d20..18b99af 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/video-app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/video-app.js @@ -595,7 +595,7 @@ function SeasonMenu({ seasons, selected, selectedYear, onSelect }) { // ── operator: correct a wrong automatic TMDB match ────────────────────────── -// Same shape as group-settings.js's own signFn construction (setVideoRoot, +// Same shape as group-settings.js's own signFn construction (setAppDirectories, // setTmdbConfig, ...) — there is no group-wide "sign this" helper to share, // each caller builds one from the connection it already has. function buildSignFn(transportRef) { |