summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common/src/meshbay_common
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-16 11:17:46 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-16 11:17:46 +0200
commitcde57423e04812fe2c939fdf983e3b45a77fd82d (patch)
tree7fe44bc9d83cf72382394ebf9b5177c207618be2 /packages/meshbay-common/src/meshbay_common
parent20706fb9a4ec646816b44a10842aa8f58ea0fd75 (diff)
downloadmeshbay-cde57423e04812fe2c939fdf983e3b45a77fd82d.tar.gz
mnp 3.1: per-account blobs the node cannot read
One row per playlist plus a manifest, so starring a track rewrites that playlist rather than the whole collection. blob_enc is a BLOB, not base64 TEXT: these run to hundreds of kilobytes. user_id comes from the session and never from the message; kind is validated against a pattern; every cap refuses with a stated reason rather than truncating. Additive, so MNP_MIN_SUPPORTED does not move — a 3.0 node answers "unknown message type" and the client writes to the next one it reaches. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-common/src/meshbay_common')
-rw-r--r--packages/meshbay-common/src/meshbay_common/__init__.py18
-rw-r--r--packages/meshbay-common/src/meshbay_common/protocol.py10
2 files changed, 27 insertions, 1 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/__init__.py b/packages/meshbay-common/src/meshbay_common/__init__.py
index 027c38a..80e6d92 100644
--- a/packages/meshbay-common/src/meshbay_common/__init__.py
+++ b/packages/meshbay-common/src/meshbay_common/__init__.py
@@ -165,5 +165,21 @@ __version__ = "0.14.0"
# `client.minimum` and the client checks it *before* connecting, and says "this
# version can no longer connect" rather than showing a handshake refusal nobody
# can act on.
-MNP_VERSION = "3.0"
+#
+# **3.1 (2026-09-16): per-account blobs the node holds and cannot read.**
+#
+# `user_blob_store` / `_fetch` / `_list` / `_delete`, modelled on
+# `keypair_bundle_*` in every respect including that the node stores and returns
+# an opaque byte string. Playlists are the first payload (docs/playlists.md
+# §8.1); `kind` is validated against a pattern rather than an enum, so the table
+# does not become an arbitrary key/value store for whatever a client feels like
+# writing.
+#
+# **Additive, and MINOR because nothing is required.** A 3.0 peer never sends
+# any of these and loses nothing it had; a 3.0 *node* answers `unknown message
+# type`, and a client that cannot store a playlist on one node stores it on the
+# next one it reaches and keeps its own copy meanwhile (§6.4). `MNP_MIN_SUPPORTED`
+# does not move. That is the difference from 3.0, where the requirement — not the
+# messages — is what made it MAJOR.
+MNP_VERSION = "3.1"
MHP_VERSION = "0.1"
diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py
index f4cd497..8ad36e6 100644
--- a/packages/meshbay-common/src/meshbay_common/protocol.py
+++ b/packages/meshbay-common/src/meshbay_common/protocol.py
@@ -141,6 +141,16 @@ class MNP:
KEYPAIR_BUNDLE_RESP = "keypair_bundle_resp" # node → client: encrypted keypair bundle
# carries `bundle_enc_recovery` too when the node has one stored
KEYPAIR_BUNDLE_DELETE = "keypair_bundle_delete" # client → node: withdraw own backup
+ # Per-account blobs the node holds and cannot read — playlists (MNP 3.1,
+ # docs/playlists.md §8.1). `kind` is "playlists" (the manifest) or
+ # "playlist:<uuid>" (one playlist's tracks); `blob_enc` is msgpack `bin`,
+ # not base64, because these run to hundreds of kilobytes.
+ USER_BLOB_STORE = "user_blob_store" # client → node: write one blob
+ USER_BLOB_FETCH = "user_blob_fetch" # client → node: read one blob
+ USER_BLOB_LIST = "user_blob_list" # client → node: which kinds, at what rev
+ USER_BLOB_DELETE = "user_blob_delete" # client → node: drop one blob
+ USER_BLOB_RESP = "user_blob_resp" # node → client: one blob, or null
+ USER_BLOB_LIST_RESP = "user_blob_list_resp" # node → client: kinds and revs only
JOIN_REQUEST = "join_request" # client → node: pair/recognise this identity
JOIN_RESULT = "join_result" # node → client: outcome + wrapped GEK
INVITE_CREATE = "invite_create" # operator → node: issue a pairing code