nolanlawson / pinafore

Alternative web client for Mastodon (UNMAINTAINED)
https://pinafore.social
GNU Affero General Public License v3.0
1.02k stars 172 forks source link

[Idea] Optionally fetch status context in its entirety from originating instance #2166

Closed kkkrist closed 1 year ago

kkkrist commented 1 year ago

I've started experimenting with running my own personal GoToSocial instance. It doesn't include a real frontend, so I use Pinafore and it works great.

One big downside of running your own little instance is that it's very likely a thread view is going to be incomplete. Clients fetch context from the user's instance and if a reply was sent from an instance it is not federating with, the reply just never reaches the user's instance (https://github.com/mastodon/mastodon/issues/14017). So in order to see all context (and be able to to properly engage with the discussion), you have to open another tab with the parent status original url first and that's kind of distracting. It gets harder if you want to reply to one of the statuses your instance has missed.

While poking around I discovered that context endpoints can be accessed w/out authorization and thought: Wouldn't it be possible to (optionally) fetch the context of a status from the instance it originated from (and that gets notified of every reply)? So I hacked this quick patch together and lo and behold, all replies started to appear:

export async function getStatusContext (instanceName, accessToken, statusId) {
  const status = await getStatus(instanceName, accessToken, statusId)
  const isRemote = !status.url.includes(instanceName)

  let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/context`

  if (isRemote) {
    const [, , remoteInstanceName, ...localParts] = status.url.split('/')
    const [remoteStatusId] = localParts.slice(-1)
    url = `${basename(remoteInstanceName)}/api/v1/statuses/${remoteStatusId}/context`
  }

  const context = await get(url, isRemote ? undefined : auth(accessToken), { timeout: DEFAULT_TIMEOUT })

  if (isRemote) {
    return {
      ...context,
      descendants: context.descendants.map(d => ({ ...d, in_reply_to_id: statusId }))
    }
  }

  return context
}

One obvious problem is mapping between the local and remote id of a status and its ancestors and descendants. Are there others? What needs to be done to make this work properly? Is this something worth looking into at all? Have I missed or misunderstood anything?

kkkrist commented 1 year ago

I poked around some more and it seems to me this is actually supposed to be done by the instance and might sometimes just fail due to GoToSocial still being alpha and ActivityPub implementations not being 100% compatible with each other. So adding this band-aid to a client is probably really a bad idea.