Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision fb30b5d0f27e2c88d8c14739a2d20267e7a655ed)
+++ src/services/ActivityPubService.js	(revision 4c70ecbe5990b354c76af6b01ef4b3d7e937a63a)
@@ -1965,4 +1965,14 @@
         return { status: 202, url: actorUri };
       }
+      // Shaer "in Orbit" = a real Block (FEP-c648 client side): lands in
+      // ap_blocks, shows in the Block tab, and purges the actor's cached
+      // content. Client-side filtering becomes a cache of this state.
+      case 'Block': {
+        const targetUri = c2sIdOf(object);
+        if (!targetUri) return { status: 400, error: 'missing_object' };
+        const r = await blockTarget(site, targetUri);
+        if (r && r.error) return { status: 400, error: r.error };
+        return { status: 202, url: targetUri };
+      }
       case 'Undo': {
         const inner = object && typeof object === 'object' ? object : null;
@@ -1971,4 +1981,9 @@
         const innerTarget = c2sIdOf(inner && inner.object);
         if (innerType === 'Follow') { await unfollowActor(site, innerTarget); return { status: 202, url: innerTarget }; }
+        if (innerType === 'Block') {
+          if (!innerTarget) return { status: 400, error: 'missing_object' };
+          unblock(site, innerTarget);   // release from Orbit
+          return { status: 202, url: innerTarget };
+        }
         if (innerType === 'Like' || innerType === 'Announce') {
           const kind = innerType === 'Announce' ? 'unboost' : 'unlike';
