aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-28 18:22:07 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-28 18:22:07 +0200
commitf63104b82da24ff3f406c53346300bd50788796f (patch)
tree1bd4466385e4298a2e2936d188b01047a4a7a8a6 /packages/meshbay-hub
parenta4b36e5fe31cb671a4cbbdaad75746cd68b601fe (diff)
downloadmeshbay-f63104b82da24ff3f406c53346300bd50788796f.tar.gz
refactor: remove dead code across packages
Unused modules, functions, constants and client helpers with no caller, the unreachable hub:probe IPC handler, and the CSAM hash matching. Behaviour unchanged; the dispatch golden loses only the two removed message types. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/groups.py4
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/signaling.py2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/app.py5
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/csam.py158
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js7
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/crypto.js57
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/downloads.js7
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/files-app.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/i18n.js4
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/keyderive.js20
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/transfers.js7
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/transport-chat.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/transport.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/video-player.js6
-rw-r--r--packages/meshbay-hub/tests/test_memory_ceiling.py1
15 files changed, 10 insertions, 281 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/groups.py b/packages/meshbay-hub/src/meshbay_hub/api/groups.py
index 3a11345..52d9f60 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/groups.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/groups.py
@@ -255,10 +255,6 @@ async def swarm_register(
Availability: the endpoint is a port, not an address, and the number of
hashes one account may claim is bounded. See the two constants above.
"""
- from meshbay_hub.csam import check_content_hash
- if check_content_hash(body.content_hash):
- raise HTTPException(status_code=451, detail="Content blocked")
-
m = _SWARM_ENDPOINT.match(body.endpoint or "")
if not m or not (0 < int(m.group(2)) < 65536):
raise HTTPException(
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/signaling.py b/packages/meshbay-hub/src/meshbay_hub/api/signaling.py
index fc40204..6c9699b 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/signaling.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/signaling.py
@@ -171,7 +171,7 @@ async def webrtc_offer(
Finding H4: it also ignored group status, so "suspend a group" did not stop new
connections from being brokered to nodes hosting it.
"""
- from meshbay_hub.api.revocation import _connected_nodes, _node_groups
+ from meshbay_hub.api.revocation import _connected_nodes
if len(body.sdp) > MAX_SDP_BYTES:
raise HTTPException(status_code=413, detail="SDP too large")
diff --git a/packages/meshbay-hub/src/meshbay_hub/app.py b/packages/meshbay-hub/src/meshbay_hub/app.py
index 7ccf598..cca1e6b 100644
--- a/packages/meshbay-hub/src/meshbay_hub/app.py
+++ b/packages/meshbay-hub/src/meshbay_hub/app.py
@@ -41,7 +41,6 @@ from meshbay_hub.api.webapp import configure as webapp_configure
from meshbay_hub.api.webapp import router as webapp_router
from meshbay_hub.auth import generate_hub_keypair, load_hub_keypair
from meshbay_hub.config import HubConfig
-from meshbay_hub.csam import csam_router
from meshbay_hub.db.engine import close_db, init_db
@@ -129,9 +128,6 @@ def create_app(cfg: HubConfig | None = None) -> FastAPI:
if cfg.identity.admin_usernames:
await _sync_admin_roles(cfg.identity.admin_usernames)
- from meshbay_hub.csam import get_csam_checker
- get_csam_checker().load()
-
from meshbay_hub.db.engine import get_session_factory
from meshbay_hub.tasks.cleanup import cleanup_loop
cleanup_task = asyncio.create_task(cleanup_loop(get_session_factory()))
@@ -207,7 +203,6 @@ def create_app(cfg: HubConfig | None = None) -> FastAPI:
app.include_router(revocation_router)
app.include_router(moderation_router)
app.include_router(federation_router)
- app.include_router(csam_router)
app.include_router(health_router)
app.include_router(relay_router)
app.include_router(signaling_router)
diff --git a/packages/meshbay-hub/src/meshbay_hub/csam.py b/packages/meshbay-hub/src/meshbay_hub/csam.py
deleted file mode 100644
index b8e8d04..0000000
--- a/packages/meshbay-hub/src/meshbay_hub/csam.py
+++ /dev/null
@@ -1,158 +0,0 @@
-"""
-MeshBay Hub — CSAM hash matching.
-
-Checks public content hashes against known CSAM (Child Sexual Abuse Material)
-hash databases before allowing content to be registered or served publicly.
-
-Production integration:
- - NCMEC (National Center for Missing & Exploited Children): PhotoDNA hash database
- Access requires formal application: https://www.missingkids.org/gethelpnow/cybertipline
- - IWF (Internet Watch Foundation): URL and hash list (UK-based)
- Access via IWF membership: https://www.iwf.org.uk/our-technology/our-products/hash-list/
-
-This module provides:
- 1. A local CSAM hash database (SQLite file, populated from official sources)
- 2. A check function used before content registration
- 3. An admin endpoint to update the hash list
-
-IMPORTANT: Never log matched hashes or file contents. CSAM detection
-must be reported to NCMEC (US law) or relevant authority immediately.
-"""
-
-import logging
-from pathlib import Path
-
-from fastapi import APIRouter, Depends, HTTPException
-
-from meshbay_hub.api.deps import require_admin
-from meshbay_hub.db.models import User
-
-log = logging.getLogger(__name__)
-
-# Default path for the CSAM hash database (blake3 hex hashes, one per line)
-DEFAULT_CSAM_DB_PATH = Path("/var/lib/meshbay/hub/csam_hashes.txt")
-
-
-class CSAMChecker:
- """
- Checks content hashes against a known CSAM hash database.
-
- Usage:
- checker = CSAMChecker()
- checker.load()
- if checker.is_known_csam(blake3_hex):
- # refuse to serve, report to authority
- pass
- """
-
- def __init__(self, db_path: Path = DEFAULT_CSAM_DB_PATH):
- self._db_path = db_path
- self._hashes: set[str] = set()
- self._loaded = False
-
- def load(self, db_path: Path | None = None) -> int:
- """
- Load CSAM hashes from the hash database file.
- Returns the number of hashes loaded.
-
- File format: one blake3 hex hash per line (64 chars), comments with #.
- """
- path = db_path or self._db_path
- if not path.exists():
- log.warning("CSAM hash database not found: %s. "
- "Contact NCMEC (US) or IWF (EU) for access.", path)
- self._loaded = True
- return 0
-
- count = 0
- with open(path) as f:
- for line in f:
- line = line.strip()
- if line and not line.startswith("#") and len(line) == 64:
- self._hashes.add(line.lower())
- count += 1
-
- self._loaded = True
- log.info("CSAM hash database loaded: %d hashes from %s", count, path)
- return count
-
- def is_known_csam(self, content_hash_hex: str) -> bool:
- """
- Return True if the hash matches a known CSAM hash.
- NEVER logs the hash or any file information.
- """
- if not self._loaded:
- self.load()
- return content_hash_hex.lower() in self._hashes
-
- @property
- def hash_count(self) -> int:
- return len(self._hashes)
-
- def add_hash(self, hash_hex: str) -> None:
- """Add a hash to the in-memory set (and optionally persist)."""
- self._hashes.add(hash_hex.lower())
-
- def update_from_file(self, new_db_path: Path) -> int:
- """Hot-reload from a new hash database file."""
- old_count = len(self._hashes)
- self._hashes.clear()
- count = self.load(new_db_path)
- log.info("CSAM database updated: %d → %d hashes", old_count, count)
- return count
-
-
-# Module-level singleton (initialised in hub lifespan)
-_checker = CSAMChecker()
-
-
-def get_csam_checker() -> CSAMChecker:
- return _checker
-
-
-def check_content_hash(blake3_hex: str) -> bool:
- """
- Check a content hash against the CSAM database.
- Returns True if the content is KNOWN CSAM — block immediately.
-
- Callers MUST:
- 1. Refuse to serve the content
- 2. Log the event (without the hash) for legal audit purposes
- 3. Report to NCMEC CyberTipline if operating in the US:
- https://www.missingkids.org/gethelpnow/cybertipline
- """
- return _checker.is_known_csam(blake3_hex)
-
-
-# ── Hub API integration ───────────────────────────────────────────────────────
-
-csam_router = APIRouter(prefix="/v1/admin/csam", tags=["csam"])
-
-
-@csam_router.get("/status")
-async def csam_status(current_user: User = Depends(require_admin)):
- """Return CSAM checker status (hash count, database path)."""
- return {
- "hash_count": _checker.hash_count,
- "db_path": str(_checker._db_path),
- "loaded": _checker._loaded,
- "note": "Contact NCMEC or IWF for hash database access.",
- }
-
-
-@csam_router.post("/check")
-async def check_hash(
- body: dict,
- current_user: User = Depends(require_admin),
-):
- """
- Check a single hash. Admin use only.
- Returns True/False WITHOUT logging the hash (legal requirement).
- """
- hash_hex = body.get("hash", "")
- if len(hash_hex) != 64:
- raise HTTPException(status_code=422, detail="hash must be 64 hex chars")
- matched = check_content_hash(hash_hex)
- # Do NOT log whether a match was found — only log the check attempt
- log.info("CSAM check performed by admin %s", current_user.username)
- return {"matched": matched}
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index 3101be7..bcd5999 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -3,7 +3,7 @@
import { clearPending, loadPending } from './invite-link.js';
import {
html, render, useState, useEffect, useLayoutEffect, useCallback, useRef,
- createContext, useContext,
+ createContext,
} from './vendor/htm-preact.js';
import { t, getLocale, setLocale, initLocale, LOCALES } from './i18n.js';
import { ZipStream, entriesUnder } from './zipstream.js';
@@ -72,7 +72,6 @@ function useRoute() {
// ── Context ──────────────────────────────────────────────────────────────────
const AuthContext = createContext(null);
-function useAuth() { return useContext(AuthContext); }
// The M of the wordmark is a picture; the rest is text. Resolved from this
// module's own URL so the hub's fingerprinted path and the application's
@@ -645,10 +644,6 @@ function LazyCreateGroupPage(props) {
return html`<${_CreateGroupPage} ...${props} />`;
}
-// ── Settings Page ───────────────────────────────────────────────────────────
-
-const THEME_OPTIONS = ['light', 'dark', 'system'];
-
// ── Profile Page ────────────────────────────────────────────────────────────
//
// ── Lazy-loaded Admin page (admin/moderator only) ─────────────────────────
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/crypto.js b/packages/meshbay-hub/src/meshbay_hub/static/crypto.js
index a3680ce..b74732c 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/crypto.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/crypto.js
@@ -1,20 +1,12 @@
/**
- * MeshBay Browser Crypto — AES-256-GCM private group decryption.
- * Uses WebCrypto SubtleCrypto API (available in all modern browsers).
- *
- * Handles groups with cipher="aes-256-gcm" (browser-accessible groups).
- * ChaCha20-Poly1305 groups (cipher="chacha20-poly1305") require the
- * native client (node) for decryption — not supported in browser.
+ * MeshBay Browser Crypto — AES-256-GCM, through WebCrypto's SubtleCrypto API.
+ * The one content cipher, for every client (meshbay_common/webcrypto.py).
*
* Usage:
* const gek = await importGEK(gekB64);
* const plaintext = await decryptChunkBin(gek, fileHashHex, chunkIndex, nonce, ct);
*/
-const CIPHER_INFO_PREFIX = new TextEncoder().encode('file:');
-const CIPHER_INFO_SUFFIX_AES = new TextEncoder().encode(':aes');
-
-
// ── Key derivation ────────────────────────────────────────────────────────────
/**
@@ -284,38 +276,7 @@ async function verifyChatSignature(deviceRaw, groupId, epoch, nonce, ct, sig) {
}
-// ── GEK generation + ECIES wrapping ──────────────────────────────────────────
-
-function generateGEK() {
- return crypto.getRandomValues(new Uint8Array(32));
-}
-
-async function wrapGEK(gek, pkXRaw) {
- const skEph = await crypto.subtle.generateKey({ name: 'X25519' }, true, ['deriveBits']);
- const pkEphRaw = new Uint8Array(await crypto.subtle.exportKey('raw', skEph.publicKey));
-
- const pkRecip = await crypto.subtle.importKey('raw', pkXRaw, { name: 'X25519' }, false, []);
- const sharedBits = await crypto.subtle.deriveBits(
- { name: 'X25519', public: pkRecip }, skEph.privateKey, 256);
-
- const sharedKey = await crypto.subtle.importKey(
- 'raw', sharedBits, 'HKDF', false, ['deriveKey']);
- const wrapKey = await crypto.subtle.deriveKey(
- { name: 'HKDF', hash: 'SHA-256', salt: pkEphRaw,
- info: new TextEncoder().encode('meshbay:gek_wrap:v1:aes') },
- sharedKey,
- { name: 'AES-GCM', length: 256 }, false, ['encrypt']);
-
- const nonce = crypto.getRandomValues(new Uint8Array(12));
- const ct = await crypto.subtle.encrypt(
- { name: 'AES-GCM', iv: nonce, additionalData: pkXRaw }, wrapKey, gek);
-
- return {
- pk_eph_b64: btoa(String.fromCharCode(...pkEphRaw)),
- nonce_b64: btoa(String.fromCharCode(...nonce)),
- wrapped_b64: btoa(String.fromCharCode(...new Uint8Array(ct))),
- };
-}
+// ── GEK unwrapping (ECIES) ─────────────────────────────────────────────────────
async function unwrapGEK(bundle, skXPkcs8, pkXRaw) {
const pkEphRaw = b64decode(bundle.pk_eph_b64);
@@ -342,16 +303,6 @@ async function unwrapGEK(bundle, skXPkcs8, pkXRaw) {
return new Uint8Array(plain);
}
-// ── Chunk encryption (for upload) ────────────────────────────────────────────
-
-async function encryptChunk(gek, fileHashHex, chunkIndex, plaintext) {
- const chunkKey = await deriveChunkKey(gek, fileHashHex, chunkIndex);
- const nonce = crypto.getRandomValues(new Uint8Array(12));
- const ct = await crypto.subtle.encrypt(
- { name: 'AES-GCM', iv: nonce }, chunkKey, plaintext);
- return { nonce, ct: new Uint8Array(ct) };
-}
-
function b64encode(bytes) {
return btoa(String.fromCharCode(...bytes));
}
@@ -583,7 +534,7 @@ async function verifyNodeSignature(nodePkB64, sigB64, transcript) {
window.MeshBayCrypto = {
importGEK, deriveChunkKey, decryptChunkBin,
openGroup, sealGroup,
- generateGEK, wrapGEK, unwrapGEK, encryptChunk, b64encode, b64decode,
+ unwrapGEK, b64encode, b64decode,
adminTranscript, handshakeTranscript, handshakeProof, webrtcBinding,
challengeTranscript, joinTranscript, verifyNodeSignature, constantTimeEqual,
deviceRequestTranscript, deviceAddTranscript, deviceHelloTranscript,
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/downloads.js b/packages/meshbay-hub/src/meshbay_hub/static/downloads.js
index 9c23d3c..50bca46 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/downloads.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/downloads.js
@@ -193,13 +193,6 @@ export async function openTarget(filename) {
};
}
-/**
- * Below this, a download with no granted folder and no service worker is
- * collected in memory and handed to the browser. Above it that would mean
- * holding gigabytes in a tab, so it is worth one Save As dialog instead.
- */
-export const BLOB_LIMIT = 512 * 1024 * 1024;
-
// ── Streaming to disk without the File System Access API ────────────────────
const SW_PATH = '/sw.js';
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
index ac978e2..775e2e3 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
@@ -893,7 +893,6 @@ function FilesPanel({
// ── File Preview (text, images) ─────────────────────────────────────────
-const TEXT_EXTS = /\.(txt|md|json|csv|log|xml|yaml|yml|ini|conf|py|js|html|css|sh|c|h|java|rs|go|rb|toml)$/i;
const IMAGE_EXTS = /\.(jpg|jpeg|png|gif|webp|svg|bmp|ico)$/i;
function FilePreview({ entry, transportRef, gekRef, onClose, onDownload }) {
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/i18n.js b/packages/meshbay-hub/src/meshbay_hub/static/i18n.js
index 56d35f7..bc78266 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/i18n.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/i18n.js
@@ -131,10 +131,6 @@ export function setLocale(code) {
return true;
}
-export function addLocale(code, strings) {
- _strings[code] = strings;
-}
-
function _pluralRules(locale) {
if (!_plurals[locale]) _plurals[locale] = new Intl.PluralRules(locale);
return _plurals[locale];
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js b/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
index 879f56f..33b1cf2 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
@@ -256,15 +256,9 @@ async function deriveRecoveryKey(R, username) {
// ── Bundle encryption ─────────────────────────────────────────────────────────
/**
- * Encrypt the keypair bundle with the password-derived AES key.
- * Bundle format: JSON { skEd: base64(pkcs8), skX: base64(pkcs8) }
+ * Encrypt the keypair bundle with a bundle key derived at sign-in. Always
+ * writes v2. Bundle format: JSON { skEd: base64(pkcs8), skX: base64(pkcs8) }
*/
-async function encryptBundle(skEdRaw, skXRaw, password, username) {
- const aesKey = await deriveEncryptionKey(password, username);
- return encryptBundleWithKey(skEdRaw, skXRaw, aesKey);
-}
-
-/** Same, when the key was already derived at sign-in. Always writes v2. */
async function encryptBundleWithKey(skEdRaw, skXRaw, aesKey) {
const nonce = crypto.getRandomValues(new Uint8Array(12));
const data = new TextEncoder().encode(JSON.stringify({
@@ -289,16 +283,6 @@ function bundleVersion(bundleB64) {
} catch { return 1; }
}
-/**
- * Decrypt a keypair bundle. Throws if password is wrong.
- */
-async function decryptBundle(bundleB64, password, username) {
- const key = bundleVersion(bundleB64) === 2
- ? await deriveEncryptionKey(password, username)
- : await deriveEncryptionKeyV1(password, username);
- return decryptBundleWithKey(bundleB64, key);
-}
-
// ── Registration ──────────────────────────────────────────────────────────────
/**
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transfers.js b/packages/meshbay-hub/src/meshbay_hub/static/transfers.js
index 9a1455a..bde382f 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/transfers.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/transfers.js
@@ -29,13 +29,6 @@ function _live(status) {
|| status === 'paused';
}
-/** Raised by `run` when it stopped because the transfer was paused. */
-function _pausedError() {
- const err = new Error('Paused');
- err.name = 'PausedError';
- return err;
-}
-
function _abortError() {
const err = new Error('Cancelled');
err.name = 'AbortError';
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport-chat.js b/packages/meshbay-hub/src/meshbay_hub/static/transport-chat.js
index d6d733f..270c76e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/transport-chat.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/transport-chat.js
@@ -212,7 +212,6 @@ extendTransport(class {
if (msg.epoch) this.chatEpoch = msg.epoch;
this._chatKeys = null;
this._chatKeysInFlight = null;
- if (this._onChatEpoch) this._onChatEpoch(this.chatEpoch);
}
/**
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport.js b/packages/meshbay-hub/src/meshbay_hub/static/transport.js
index 97b2293..0f3f3b8 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/transport.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/transport.js
@@ -571,9 +571,6 @@ class MeshBayTransport {
set onIndexDelta(fn) { this._onIndexDelta = fn; }
set onRootsChanged(fn) { this._onRootsChanged = fn; }
- /** The MNP version the connected node declared, or '' before a handshake. */
- get nodeVersion() { return this._nodeVersion || ''; }
-
/** This member's own caps in this group, or null when the node said nothing. */
get transferLimits() { return this._transferLimits; }
@@ -582,7 +579,6 @@ class MeshBayTransport {
set onChatDirectory(fn) { this._onChatDirectory = fn; }
set onChatLinkPreview(fn) { this._onChatLinkPreview = fn; }
set onSearchListed(fn) { this._onSearchListed = fn; }
- set onChatEpoch(fn) { this._onChatEpoch = fn; }
set onTmdbConfig(fn) { this._onTmdbConfig = fn; }
set onTmdbEnabled(fn) { this._onTmdbEnabled = fn; }
set onMusicbrainzEnabled(fn) { this._onMusicbrainzEnabled = fn; }
@@ -941,12 +937,9 @@ class MeshBayTransport {
if (reply.type === 'handshake_challenge') {
// The node's half of the range. Checked before anything else in this
// block, because everything below — the join, the proof, the sealed ack
- // — assumes both sides mean the same thing by each message.
+ // — assumes both sides mean the same thing by each message. Nothing else
+ // reads the node's version: a peer this admits speaks every message here.
_checkNodeVersion(reply);
- // 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');
}
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js
index 2b274b5..fa10d15 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js
@@ -270,12 +270,6 @@ function reconnectPlan(playhead, range, ended, castActive) {
return { mode: 'seek', at: playhead };
}
-function _mseSupported(codec) {
- if (!window.MediaSource) return false;
- const mime = `video/mp4; codecs="${codec}"`;
- return MediaSource.isTypeSupported(mime);
-}
-
/** Seconds as h:mm:ss, or m:ss under an hour. */
function formatClock(seconds) {
const s = Math.max(0, Math.floor(seconds || 0));
diff --git a/packages/meshbay-hub/tests/test_memory_ceiling.py b/packages/meshbay-hub/tests/test_memory_ceiling.py
index 9ea6ad3..48aac1a 100644
--- a/packages/meshbay-hub/tests/test_memory_ceiling.py
+++ b/packages/meshbay-hub/tests/test_memory_ceiling.py
@@ -84,7 +84,6 @@ const platform = {{
bridgeMessage: (e) => String(e),
}};
const downloads = {{
- BLOB_LIMIT: 512 * 1024 * 1024,
// Called by the refusal to name why the streamed path declined -- absent
// from this stub, the error constructor threw TypeError and the test saw the
// wrong failure entirely.