// bsky-bind.js — is this fronted DID a favela identity's, by BOTH sides' word? (hyper-social #82, I2a / D4a)
//
// ⛔ TWO-SIDED, OR NOT AT ALL. The DID's repo, signed by the DID key, names a favela feed (`net.favela.feed/self`,
// written by favela-bridge's projection); AND that feed's reach/self, written by the identity's own devices, names
// the DID as its credential. Either half alone is a claim anyone can make. Only the pair binds, and only a binding
// lets bsky interactions on the DID reach that identity's observation feed.
//
// PURE + INJECTED: `front` is the membrane's front for the DID (getRecord), `feedOf(feedKey)` the held favela feed or
// null. A failed read is a refusal, never a throw — the caller re-evaluates on the next change.
export const FEED_CLAIM = 'net.favela.feed'
export async function bindDid (did, { front, feedOf } = {}) {
let rec = null
try { rec = front && typeof front.getRecord === 'function' ? await front.getRecord(FEED_CLAIM, 'self') : null } catch { return { refused: 'could not read the DID repo' } }
const feed = rec && rec.value && typeof rec.value.feed === 'string' ? rec.value.feed.toLowerCase() : null
if (!feed) return { refused: 'the DID names no favela feed' }
if (!/^[0-9a-f]{64}$/.test(feed)) return { refused: 'the DID names a malformed feed key' }
let held = null
try { held = feedOf ? await feedOf(feed) : null } catch { held = null }
if (!held || typeof held.reach !== 'function') return { refused: 'that feed is not held here' }
let reach = null
try { reach = await held.reach() } catch { return { refused: 'could not read that feed\'s reach' } }
if (!reach || reach.credential !== did) return { refused: 'that feed does not name this DID' }
return { did, feed }
}
export default { bindDid, FEED_CLAIM }