// bsky-ingest.test.js — the wiring: bound DIDs → a Spacedust subscription → the identity's observation feed
// (hyper-social #82, I2b).
//
// ⛔ ONLY BOUND DIDs ARE SUBSCRIBED. A fronted DID that does not name a held favela feed whose reach names it back
// is not anyone's here (bsky-bind.js); subscribing for it would collect interactions nobody may see.
// ⛔ AND NEVER AN EMPTY FILTER — that is a subscription to the whole network (spacedust.js refuses it too).
import test from 'brittle'
import { BskyIngest } from '../lib/bsky-ingest.js'
import { tidFor } from 'favela-bridge/lib/tid.js'
const DID = 'did:plc:fleekyfleekyfleeky'
const LC = 'did:plc:loserclubloserclub'
const FEED = 'd2'.repeat(32)
const ALICE = 'did:plc:alicealicealice'
const NAME = '01k4qspvquliq9js01m6c5658b'
const POST = `at://${DID}/app.bsky.feed.post/${tidFor(NAME)}`
function harness () {
const notes = []
const removes = []
const sockets = []
const fetched = []
const membrane = {
metrics: () => ({ dids: [{ did: DID }, { did: LC }] }),
peers: {
front: async (did) => ({ getRecord: async () => (did === DID ? { value: { $type: 'net.favela.feed', feed: FEED } } : null) })
}
}
const fediverse = {
heldFeed: (feed) => (feed === FEED
? { reach: async () => ({ networks: ['bsky'], credential: DID }), ownPosts: async () => ({ feed: FEED, rows: [{ name: NAME }] }) }
: null),
observationsForFeed: (feed) => (feed === FEED
? { note: async (obs) => { notes.push(obs) }, remove: async (activity) => { removes.push(activity) } }
: null)
}
const createSocket = (url) => {
const handlers = {}
const s = { on: (ev, fn) => { (handlers[ev] = handlers[ev] || []).push(fn); return s }, emit: (ev, ...a) => { for (const fn of handlers[ev] || []) fn(...a) } }
s.url = url; s.write = () => {}; s.destroy = () => {}; sockets.push(s); return s }
const fetch = async (url) => {
fetched.push(url)
return { ok: true, json: async () => ({ posts: [{ uri: `at://${ALICE}/app.bsky.feed.post/3rep`, record: { text: 'megusta from bsky' } }] }) }
}
return { membrane, fediverse, createSocket, fetch, notes, removes, sockets, fetched }
}
const frame = (operation, source, subject, collection, rkey) => Buffer.from(JSON.stringify({
kind: 'link', origin: 'live', link: { operation, source, subject, source_record: `at://${ALICE}/${collection}/${rkey}`, source_rev: '3x' }
}))
const settle = () => new Promise((resolve) => setTimeout(resolve, 30))
test('★★ only BOUND DIDs are subscribed, and a like lands as an observation aimed at the favela post', async (t) => {
const h = harness()
const ingest = new BskyIngest({ membrane: h.membrane, fediverse: h.fediverse, fetch: h.fetch, createSocket: h.createSocket, log: () => {} })
await ingest.start()
t.teardown(() => ingest.stop())
t.is(h.sockets.length, 1, 'one subscription')
t.ok(h.sockets[0].url.includes(encodeURIComponent(DID)) || h.sockets[0].url.includes(DID), 'for the bound DID')
t.absent(h.sockets[0].url.includes(LC), 'never for an unbound one')
t.alike(ingest.metrics().bound, [{ did: DID, feed: FEED }])
h.sockets[0].emit('data', frame('create', 'app.bsky.feed.like:subject.uri', POST, 'app.bsky.feed.like', '3lk'))
await settle()
t.is(h.notes.length, 1)
t.alike({ kind: h.notes[0].kind, actor: h.notes[0].actor, target: h.notes[0].target, activity: h.notes[0].activity },
{ kind: 'like', actor: ALICE, target: { feed: FEED, collection: 'post', name: NAME }, activity: `at://${ALICE}/app.bsky.feed.like/3lk` })
})
test('★ a reply carries its text, fetched for display; a delete removes', async (t) => {
const h = harness()
const ingest = new BskyIngest({ membrane: h.membrane, fediverse: h.fediverse, fetch: h.fetch, createSocket: h.createSocket, log: () => {} })
await ingest.start()
t.teardown(() => ingest.stop())
h.sockets[0].emit('data', frame('create', 'app.bsky.feed.post:reply.parent.uri', POST, 'app.bsky.feed.post', '3rep'))
await settle()
t.is(h.notes.length, 1)
t.is(h.notes[0].kind, 'reply')
t.is(h.notes[0].body, 'megusta from bsky', 'the reply text')
t.ok(h.fetched.some((u) => u.includes('app.bsky.feed.getPosts')), 'from the public AppView')
h.sockets[0].emit('data', frame('delete', 'app.bsky.feed.like:subject.uri', POST, 'app.bsky.feed.like', '3lk'))
await settle()
t.alike(h.removes, [`at://${ALICE}/app.bsky.feed.like/3lk`])
})
test('⛔ nothing bound → no subscription at all (an empty filter would be the whole network)', async (t) => {
const h = harness()
h.membrane.metrics = () => ({ dids: [{ did: LC }] })
const ingest = new BskyIngest({ membrane: h.membrane, fediverse: h.fediverse, fetch: h.fetch, createSocket: h.createSocket, log: () => {} })
await ingest.start()
t.teardown(() => ingest.stop())
t.is(h.sockets.length, 0)
})