summaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md24
1 files changed, 14 insertions, 10 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 9f63595..ece3828 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -72,10 +72,13 @@ dans le bon `pyproject.toml`.
- All three packages share the same version number (released together)
### Protocol versions (independent)
-- MNP: `0.2` → bumped independently of package version
+- MNP: `0.4` → bumped independently of package version
- 0.2 added `PING`/`PONG` and backward chat paging (`before` / `has_more`).
Additive, so an 0.1 peer still works: it sends no `before` and is answered
with the newest page, which is what it wanted
+ - 0.4 added `apps_enabled`/`apps_enabled_ack` and `enabled_apps` on the
+ handshake ack, for the group-applications registry (`docs/apps.md`).
+ Additive, same reasoning
- MHP: `0.1` → bumped independently of package version
- Every wire message carries a `v` field
- Breaking change → MAJOR bump; backward-compatible → MINOR bump
@@ -699,8 +702,9 @@ SFR residential Fedora 44 → meshbay.org OVH VPS:
| WebRTC transport (browser) | `meshbay_node.transport.webrtc_server` | Phase 9.3 — `aiortc` DataChannel |
| WebRTC signaling (hub) | `meshbay_hub.api.signaling` | Phase 9.2 — SDP/ICE relay |
| Browser transport client | `static/transport.js` | Phase 9.4 — WebRTC DataChannel |
-| Web SPA | `static/app.js` | Phase 9.6 — Preact + preact-router |
-| File download (large) | `static/app.js` | File System Access API (`showSaveFilePicker`) — stream to disk |
+| Web SPA | `static/app.js` | Phase 9.6 — Preact + preact-router. Routing and every page except a group's — see `docs/apps.md` for the group UI's file layout (2026-08-23 split) |
+| Group applications (adding one) | `docs/apps.md` | Chat/Files today, Videos/Music/Photos planned. Props contract, enablement mechanism, checklist |
+| File download (large) | `static/file-utils.js` | `downloadEntry`/`_openDownloadTarget`, File System Access API (`showSaveFilePicker`) — stream to disk |
| Background tasks (node) | `meshbay_node.transport.webrtc_server` | `_spawn()` — the only way to start one; a bare `ensure_future` can be collected |
| Stream handover (node) | `meshbay_node.transport.webrtc_server` | `_replace_stream` + `shutdown_tasks` — one viewer, one film, and the slot comes back when they leave |
| Download backpressure (node) | `meshbay_node.transport.webrtc_server` | `DOWNLOAD_BUFFER_HIGH` — 8 × 1 MB answered blind queues 8 MB on the channel |
@@ -730,10 +734,10 @@ SFR residential Fedora 44 → meshbay.org OVH VPS:
| Ed25519 sign (browser) | `static/keyderive.js` | `signChallenge()` — admin challenge-response |
| Auth key derivation (browser) | `static/keyderive.js` | `deriveAuthKey()` — password split, hub never sees raw password |
| GEK wrap AES (Python) | `meshbay_common.crypto` | Phase 10b.2 — `wrap_gek_aes()` / `unwrap_gek_aes()` |
-| IndexedDB cache (browser) | `static/app.js` | Phase 10b.5 — group index caching |
+| IndexedDB cache (browser) | `static/hub-client.js` | Phase 10b.5 — group index caching, moved out of app.js in the 2026-08-23 split |
| Cross-group search (browser) | `static/app.js` | Phase 10b.6 — SearchPage, client-side |
| MSE video streaming (node) | `meshbay_node.transport.webrtc_server` | Phase 10c — ffmpeg fMP4 remux + encrypted segments |
-| MSE video streaming (browser) | `static/app.js` | Phase 10c — MediaSource + SourceBuffer progressive playback |
+| MSE video streaming (browser) | `static/video-player.js` | Phase 10c — MediaSource + SourceBuffer progressive playback, moved out of app.js in the 2026-08-23 split |
| Video codec detection | `meshbay_node.transport.webrtc_server` | Phase 10c — `_probe_video()` ffprobe + MSE codec strings |
| Node daemon (production) | `meshbay_node.daemon` | Phase 11 — WebRTC + WS + chat + HTTP + audit all wired |
| Node config | `meshbay_node.config` | `node.toml` loader, `data_dir` for chat/audit DBs |
@@ -743,24 +747,24 @@ SFR residential Fedora 44 → meshbay.org OVH VPS:
| Bundle store (node) | `meshbay_node.bundle_store` | SQLite P2P GEK + keypair bundles, `data_dir/bundles.db` — hub never stores crypto |
| P2P bundle exchange (MNP) | `meshbay_common.protocol` | GEK + keypair bundle STORE/FETCH/RESP message types |
| Bundle via DataChannel | `static/transport.js` | GEK + keypair bundle fetch during handshake, store after connect |
-| Key persistence (browser) | `static/app.js` | `_bundleKey` in IndexedDB, `_sessionKeys` in sessionStorage |
+| Key persistence (browser) | `static/hub-client.js` | `session.bundleKey` (renamed from the bare `_bundleKey` in the 2026-08-23 split) in IndexedDB, `_sessionKeys` in sessionStorage |
| pkX from private key | `static/transport.js` | `_pkFromSk()` — JWK export to derive X25519 public key |
| Group delete (hub) | `meshbay_hub.api.groups` | `DELETE /v1/groups/{group_id}` — admin only |
| JWT scope enforcement | `meshbay_hub.api.deps` | `require_user_scope` — blocks node-scoped tokens from mutations |
| Operator operations | `meshbay_node.ops` | **One implementation, several front doors.** The loopback API, the CLI and the signed MNP handlers all call these; they take the daemon `state`, raise `OpError`, and know nothing about HTTP. Two implementations of one operation with two authorization checks is C1/C6 one size down |
| Node local admin UI | `meshbay_node.ui.app` | Dashboard, peers, groups, audit log (localhost:18000). Each operation endpoint is one `_op(...)` line — logic there is a rule the MNP path does not have |
| Demo scripts | — | `QE/demo-v1/*.py`, `QE/demo-v2/*.py`, `QE/demo-v3/*.py` (not versioned) |
-| Video flow control (browser) | `static/app.js` | `pump()` — the only place credit is granted. Read-ahead bounded by `BUFFER_AHEAD_S` of film, `STREAM_WINDOW` segments in flight, driven by a clock and by playback, never by arriving data |
+| Video flow control (browser) | `static/video-player.js` | `pump()` — the only place credit is granted. Read-ahead bounded by `BUFFER_AHEAD_S` of film, `STREAM_WINDOW` segments in flight, driven by a clock and by playback, never by arriving data |
| Player under test | `tests/harness/mse_harness.mjs` | Runs the real `pump`/`flushQueue`/`evictBehind` against a fake SourceBuffer with a ceiling. Do not write a second model of them |
| Asset versioning (hub) | `meshbay_hub.api.webapp` | `_asset_version()` — content hash; whole module graph served under `/a/<hash>/` so a cache cannot mix two builds |
| Stream capacity (node) | `meshbay_node.config` | `[node] max_concurrent_streams` (default 8) — a slot is held for the length of a film, so it counts simultaneous viewers |
| Stream diagnosis (node) | `webrtc_server.py` | `client_diag` at DEBUG — the player's own view (`ready`, `quota`, `ranges`, `err`) in the node's log. The only window into a phone |
| Stream probe (no browser) | — | `QE/deploy/stream_probe.py` — pulls a real film over real MNP, `--start` to seek. Answers "is it the node or the browser" in one run (not versioned) |
-| Seeking (browser) | `static/app.js` | `requestSeek` → node restarts ffmpeg with `-ss`; `reinitAt` clears the buffer and sets `timestampOffset`. `-copyts` does *not* preserve position — measured — so the offset comes from the client |
+| Seeking (browser) | `static/video-player.js` | `requestSeek` → node restarts ffmpeg with `-ss`; `reinitAt` clears the buffer and sets `timestampOffset`. `-copyts` does *not* preserve position — measured — so the offset comes from the client |
| Seeking (node) | `webrtc_server.py` | `start` on `stream_req`; `-ss` **before** `-i` (index seek, not decode-and-discard), clamped away from the end, echoed in `stream_init` |
-| Resume position | `static/app.js` | `readResumePosition` / `writeResumePosition` — localStorage, per file, per browser. No protocol, and nothing new learns what you watch |
+| Resume position | `static/video-player.js` | `readResumePosition` / `writeResumePosition` — localStorage, per file, per browser. No protocol, and nothing new learns what you watch |
| Layout, measured | `tests/harness/layout_probe.py` | Renders `style.css` in Chrome at any width and returns bounding boxes. Use it for layout, not `test_layout_responsive.py`, which only pins CSS values |
-| Session renewal (browser) | `static/app.js` | `refreshAccessToken` / `ensureFreshToken` — one writer (`setAuth`), one in-flight renewal, rotated refresh token stored. `hubFetch` renews on 401 and replays |
+| Session renewal (browser) | `static/hub-client.js` | `refreshAccessToken` / `ensureFreshToken` — one writer (`setAuth`), one in-flight renewal, rotated refresh token stored. `hubFetch` renews on 401 and replays. Moved out of app.js in the 2026-08-23 split |
| Token lifetimes (hub) | `meshbay_hub.config` | `[jwt] access_token_ttl` 4 h, `refresh_token_ttl` 30 days. **Production sets both in `~/.config/meshbay/hub.toml`** — changing the code default alone does nothing there |
## meshbay.org server (état cible)