OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer commits / 4d0064c

0.3.108: serve list-blobs on both device surfaces (org #32 slice 2)
The blob INVENTORY, so an orphan can be seen at all. Referenced blobs are derivable by walking records; a blob uploaded and referenced by nothing is not, and that is what was permanently lost on 2026-07-03. Read-only and ungated, exactly like get-blob: it returns content addresses the peer already serves by CID, so it grants no access get-blob does not. Served on the swarm RPC and the UDS alike, delegating to DualBlobStore.list -> BlobPointerStore.list. The LEGACY store is excluded — it predates pointers, so it has no published set, and including it would advertise blobs the network cannot fetch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4d0064caa05071f0e8eefa414885a1e396bf5451
by plankatron <fleeky@gmail.com> · 2026-08-07T02:18:04.000Z

Changed files (4) +21 -1

lib/dual-blob-store.js +8 -0
……@@ -34,6 +34,14 @@ export class DualBlobStore {
3434 // ── operator repair (pass-through to the overlay side; the legacy bee needs neither) ──────────────
3535 // Re-register the blob FILES so peers can fetch them by oid. The legacy Hyperbee store keeps its bytes
3636 // as bee values, which replicate as core blocks — it has no oid index to repair.
37 // Inventory for listBlobs. Delegates to the overlay/pointer store only: the LEGACY store predates
38 // pointers entirely, so it has no published set to enumerate and including it would report blobs the
39 // rest of the network cannot fetch.
40 async list (opts) {
41 if (typeof this._new.list !== 'function') return { cids: [], cursor: null, skipped: 'not-supported' }
42 return this._new.list(opts)
43 }
44
3745 async reindexOverlay () {
3846 if (typeof this._new.reindexOverlay !== 'function') return { skipped: 'not-supported' }
3947 return this._new.reindexOverlay()
lib/serve-device-uds.js +4 -0
……@@ -140,6 +140,10 @@ export async function serveDeviceUds (device, { uds, blobs = null, onRelease = n
140140 // get-blob: local read counterpart to upload-blob — the co-located client (favela-web) renders images it
141141 // uploaded. The UDS had upload-blob but no read path, so locally-stored blobs were unreadable. Public (a
142142 // UDS connection is already filesystem-owner-gated). Returns { mimeType, size, bytes(hex) } or null.
143 svc.handle('list-blobs', async (ctx, { limit, cursor } = {}) => {
144 if (!blobs || typeof blobs.list !== 'function') return { cids: [], cursor: null, skipped: 'not-supported' }
145 return blobs.list({ limit, cursor })
146 })
143147 svc.handle('get-blob', async (ctx, { cid } = {}) => {
144148 if (!cid) throw new Error('get-blob: cid required')
145149 const blob = await blobs.get(String(cid))
lib/serve-device.js +8 -0
……@@ -50,6 +50,14 @@ export function serveDevice (device, swarm, { canWrite = null, blobs = null, ses
5050 // bsky; server-bare.js expects { mimeType, bytes(hex) } or null (→ 404). This responder was MISSING:
5151 // blobs could be uploaded but never read back, so every getBlob 404'd regardless of who held the bytes.
5252 if (blobs) {
53 // list-blobs: the DID's published blob inventory. READ-ONLY and ungated like get-blob — it returns
54 // content addresses the peer already serves by CID, so it grants no access that get-blob does not.
55 // This is what makes ORPHAN detection possible: a blob referenced by no record cannot be found by
56 // walking records, only by asking the authority what it has (spec/convergence.md §6).
57 rpc.respond('list-blobs', async ({ limit, cursor } = {}) => {
58 if (typeof blobs.list !== 'function') return { cids: [], cursor: null, skipped: 'not-supported' }
59 return blobs.list({ limit, cursor })
60 })
5361 rpc.respond('get-blob', async ({ cid } = {}) => {
5462 if (!cid) throw new Error('get-blob: cid required')
5563 const blob = await blobs.get(String(cid))
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "hyper-proto-peer",
3 "version": "0.3.107",
3 "version": "0.3.108",
44 "description": "Self-custody, P2P-native atproto peer — holds the user's key + content as Hypercores and authors+signs its own repo. The source of truth in the peer/bridge split (Model B); atproto-bridge projects it to bsky.",
55 "type": "module",
66 "main": "lib/peer.js",