import { MastodonClient } from './mastodon-client.js'
import { KeetClient } from './keet-client.js'
import { Router } from './router.js'
import { statusToEnvelope, keetToMastodon, statusToKeetText, envelopeToStatusText } from './adapter.js'
class MastodonBridge {
constructor (opts = {}) {
this.mastodon = new MastodonClient({
instance: opts.instance,
token: opts.token
})
this.keet = new KeetClient({
host: opts.keetHost,
port: opts.keetPort
})
this.roomId = opts.roomId
this.visibility = opts.visibility || 'unlisted' // default post visibility
this.bridgeIdentity = opts.bridgeIdentity || null
this.tag = opts.tag || null // optional hashtag filter
this.onLog = opts.onLog || (() => {})
this.router = new Router({
onKeetMessage: (author, text) => {
this.keet.send(this.roomId, text).catch(err => {
this.onLog(`Keet send error: ${err.message}`)
})
},
onExternalMessage: (author, text) => {
this.mastodon.postStatus(text, { visibility: this.visibility }).catch(err => {
this.onLog(`Mastodon post error: ${err.message}`)
})
}
})
}
async start () {
// Get bridge identity from keet-daemon
if (!this.bridgeIdentity) {
try {
const identity = await this.keet.identity()
this.bridgeIdentity = identity.memberId || identity.id || ''
this.onLog(`Bridge identity: ${this.bridgeIdentity}`)
} catch (err) {
this.onLog(`Warning: Could not get identity: ${err.message}`)
}
}
// Verify Mastodon credentials
try {
const account = await this.mastodon.verifyCredentials()
this.onLog(`Mastodon: logged in as @${account.acct || account.username}`)
} catch (err) {
this.onLog(`Mastodon auth failed: ${err.message}`)
throw err
}
// Stream Mastodon → Keet
const streamType = this.tag ? `hashtag&tag=${this.tag}` : 'user'
this.mastodon.stream(streamType, (status) => {
const envelope = statusToEnvelope(status)
if (!envelope) return
const text = statusToKeetText(envelope)
this.router.routeToKeet(envelope.author, text)
})
// Watch Keet → Mastodon
this.keet.watch(this.roomId, (msg) => {
const result = keetToMastodon(msg, this.bridgeIdentity)
if (!result) return
const text = `${result.author}: ${result.text}`
this.router.routeToExternal(result.author, text)
})
this.onLog(`Bridge started: Mastodon (${this.mastodon.instance}) ↔ Keet`)
}
stop () {
this.mastodon.stopStream()
this.keet.stopWatch()
this.onLog('Bridge stopped')
}
}
export { MastodonBridge }