Add postgate queries, begin integration

This commit is contained in:
Eric Bailey
2024-08-05 17:04:02 -05:00
parent 926595493d
commit 15862a6f7f
3 changed files with 208 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
import {AppBskyFeedPostgate, AtUri, BskyAgent} from '@atproto/api'
import {useMutation} from '@tanstack/react-query'
import {networkRetry} from '#/lib/async/retry'
import {
createPostgateRecord,
mergePostgateRecords,
POSTGATE_COLLECTION,
} from '#/state/queries/postgate/util'
import {useAgent} from '#/state/session'
export async function getPostgateRecord({
agent,
postUri,
}: {
agent: BskyAgent
postUri: string
}): Promise<AppBskyFeedPostgate.Record | undefined> {
const urip = new AtUri(postUri)
if (!urip.host.startsWith('did:')) {
const res = await agent.resolveHandle({
handle: urip.host,
})
urip.host = res.data.did
}
try {
const {data} = await networkRetry(2, () =>
agent.api.com.atproto.repo.getRecord({
repo: urip.host,
collection: POSTGATE_COLLECTION,
rkey: urip.rkey,
}),
)
if (data.value && AppBskyFeedPostgate.isRecord(data.value)) {
return data.value
} else {
return undefined
}
} catch (e: any) {
if (e.message.includes(`Could not locate record:`)) {
return undefined
} else {
throw new Error(`Failed to get postgate record`, {cause: e})
}
}
}
export async function writePostgateRecord({
agent,
postUri,
postgate,
}: {
agent: BskyAgent
postUri: string
postgate: AppBskyFeedPostgate.Record
}) {
const postUrip = new AtUri(postUri)
const record = createPostgateRecord({
post: postUri,
detachedQuotes: postgate.detachedQuotes,
})
await networkRetry(2, () =>
agent.api.com.atproto.repo.putRecord({
repo: agent.session!.did,
collection: POSTGATE_COLLECTION,
rkey: postUrip.rkey,
record,
}),
)
}
export async function upsertPostgate(
{
agent,
postUri,
}: {
agent: BskyAgent
postUri: string
},
callback: (
postgate: AppBskyFeedPostgate.Record | undefined,
) => Promise<AppBskyFeedPostgate.Record | undefined>,
) {
const prev = await getPostgateRecord({
agent,
postUri,
})
const next = await callback(prev)
if (!next) return
await writePostgateRecord({
agent,
postUri,
postgate: next,
})
}
export function useToggleQuoteDetachmentMutation() {
const agent = useAgent()
return useMutation({
mutationFn: async ({
postUri,
quotedUri,
action,
}: {
postUri: string
quotedUri: string
action: 'detach' | 'reattach'
}) => {
await upsertPostgate({agent, postUri: quotedUri}, async prev => {
if (prev) {
if (action === 'detach') {
return mergePostgateRecords(prev, {
detachedQuotes: [postUri],
})
} else if (action === 'reattach') {
return {
...prev,
detachedQuotes:
prev.detachedQuotes?.filter(uri => uri !== postUri) || [],
}
}
} else {
if (action === 'detach') {
return createPostgateRecord({
post: quotedUri,
detachedQuotes: [postUri],
})
}
}
})
},
})
}
+44
View File
@@ -0,0 +1,44 @@
import {AppBskyFeedPostgate} from '@atproto/api'
import {ViewRemoved} from '@atproto/api/dist/client/types/app/bsky/embed/record'
export const POSTGATE_COLLECTION = 'app.bsky.feed.postgate'
export function createPostgateRecord(
postgate: Partial<AppBskyFeedPostgate.Record>,
): AppBskyFeedPostgate.Record {
if (!postgate.post) {
throw new Error(`Cannot create a postgate record without a post URI`)
}
return {
$type: POSTGATE_COLLECTION,
createdAt: new Date().toISOString(),
post: postgate.post,
detachedQuotes: postgate.detachedQuotes || [],
}
}
export function mergePostgateRecords(
prev: AppBskyFeedPostgate.Record,
next: Partial<AppBskyFeedPostgate.Record>,
) {
const detachedQuotes = Array.from(
new Set([...(prev.detachedQuotes || []), ...(next.detachedQuotes || [])]),
)
return createPostgateRecord({
post: prev.post,
detachedQuotes,
})
}
export function createEmbedViewRemovedRecord({uri}: {uri: string}) {
const record: ViewRemoved = {
$type: 'app.bsky.embed.record#viewRemoved',
uri,
removed: true,
}
return {
$type: 'app.bsky.embed.record#view',
record,
}
}