OverviewFilesCommitsIssuesDocsReleasesPeers

favela-gateway / test / bsky-ingest.test.js

95 lines · javascript ref:
// 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)
})