about summary refs log tree commit diff
path: root/src/state/queries/postgate/util.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/queries/postgate/util.ts')
-rw-r--r--src/state/queries/postgate/util.ts196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/state/queries/postgate/util.ts b/src/state/queries/postgate/util.ts
new file mode 100644
index 000000000..21509c3ac
--- /dev/null
+++ b/src/state/queries/postgate/util.ts
@@ -0,0 +1,196 @@
+import {
+  AppBskyEmbedRecord,
+  AppBskyEmbedRecordWithMedia,
+  AppBskyFeedDefs,
+  AppBskyFeedPostgate,
+  AtUri,
+} from '@atproto/api'
+
+export const POSTGATE_COLLECTION = 'app.bsky.feed.postgate'
+
+export function createPostgateRecord(
+  postgate: Partial<AppBskyFeedPostgate.Record> & {
+    post: AppBskyFeedPostgate.Record['post']
+  },
+): AppBskyFeedPostgate.Record {
+  return {
+    $type: POSTGATE_COLLECTION,
+    createdAt: new Date().toISOString(),
+    post: postgate.post,
+    detachedEmbeddingUris: postgate.detachedEmbeddingUris || [],
+    embeddingRules: postgate.embeddingRules || [],
+  }
+}
+
+export function mergePostgateRecords(
+  prev: AppBskyFeedPostgate.Record,
+  next: Partial<AppBskyFeedPostgate.Record>,
+) {
+  const detachedEmbeddingUris = Array.from(
+    new Set([
+      ...(prev.detachedEmbeddingUris || []),
+      ...(next.detachedEmbeddingUris || []),
+    ]),
+  )
+  const embeddingRules = [
+    ...(prev.embeddingRules || []),
+    ...(next.embeddingRules || []),
+  ].filter(
+    (rule, i, all) => all.findIndex(_rule => _rule.$type === rule.$type) === i,
+  )
+  return createPostgateRecord({
+    post: prev.post,
+    detachedEmbeddingUris,
+    embeddingRules,
+  })
+}
+
+export function createEmbedViewDetachedRecord({uri}: {uri: string}) {
+  const record: AppBskyEmbedRecord.ViewDetached = {
+    $type: 'app.bsky.embed.record#viewDetached',
+    uri,
+    detached: true,
+  }
+  return {
+    $type: 'app.bsky.embed.record#view',
+    record,
+  }
+}
+
+export function createMaybeDetachedQuoteEmbed({
+  post,
+  quote,
+  quoteUri,
+  detached,
+}:
+  | {
+      post: AppBskyFeedDefs.PostView
+      quote: AppBskyFeedDefs.PostView
+      quoteUri: undefined
+      detached: false
+    }
+  | {
+      post: AppBskyFeedDefs.PostView
+      quote: undefined
+      quoteUri: string
+      detached: true
+    }): AppBskyEmbedRecord.View | AppBskyEmbedRecordWithMedia.View | undefined {
+  if (AppBskyEmbedRecord.isView(post.embed)) {
+    if (detached) {
+      return createEmbedViewDetachedRecord({uri: quoteUri})
+    } else {
+      return createEmbedRecordView({post: quote})
+    }
+  } else if (AppBskyEmbedRecordWithMedia.isView(post.embed)) {
+    if (detached) {
+      return {
+        ...post.embed,
+        record: createEmbedViewDetachedRecord({uri: quoteUri}),
+      }
+    } else {
+      return createEmbedRecordWithMediaView({post, quote})
+    }
+  }
+}
+
+export function createEmbedViewRecordFromPost(
+  post: AppBskyFeedDefs.PostView,
+): AppBskyEmbedRecord.ViewRecord {
+  return {
+    $type: 'app.bsky.embed.record#viewRecord',
+    uri: post.uri,
+    cid: post.cid,
+    author: post.author,
+    value: post.record,
+    labels: post.labels,
+    replyCount: post.replyCount,
+    repostCount: post.repostCount,
+    likeCount: post.likeCount,
+    indexedAt: post.indexedAt,
+  }
+}
+
+export function createEmbedRecordView({
+  post,
+}: {
+  post: AppBskyFeedDefs.PostView
+}): AppBskyEmbedRecord.View {
+  return {
+    $type: 'app.bsky.embed.record#view',
+    record: createEmbedViewRecordFromPost(post),
+  }
+}
+
+export function createEmbedRecordWithMediaView({
+  post,
+  quote,
+}: {
+  post: AppBskyFeedDefs.PostView
+  quote: AppBskyFeedDefs.PostView
+}): AppBskyEmbedRecordWithMedia.View | undefined {
+  if (!AppBskyEmbedRecordWithMedia.isView(post.embed)) return
+  return {
+    ...(post.embed || {}),
+    record: {
+      record: createEmbedViewRecordFromPost(quote),
+    },
+  }
+}
+
+export function getMaybeDetachedQuoteEmbed({
+  viewerDid,
+  post,
+}: {
+  viewerDid: string
+  post: AppBskyFeedDefs.PostView
+}) {
+  if (AppBskyEmbedRecord.isView(post.embed)) {
+    // detached
+    if (AppBskyEmbedRecord.isViewDetached(post.embed.record)) {
+      const urip = new AtUri(post.embed.record.uri)
+      return {
+        embed: post.embed,
+        uri: urip.toString(),
+        isOwnedByViewer: urip.host === viewerDid,
+        isDetached: true,
+      }
+    }
+
+    // post
+    if (AppBskyEmbedRecord.isViewRecord(post.embed.record)) {
+      const urip = new AtUri(post.embed.record.uri)
+      return {
+        embed: post.embed,
+        uri: urip.toString(),
+        isOwnedByViewer: urip.host === viewerDid,
+        isDetached: false,
+      }
+    }
+  } else if (AppBskyEmbedRecordWithMedia.isView(post.embed)) {
+    // detached
+    if (AppBskyEmbedRecord.isViewDetached(post.embed.record.record)) {
+      const urip = new AtUri(post.embed.record.record.uri)
+      return {
+        embed: post.embed,
+        uri: urip.toString(),
+        isOwnedByViewer: urip.host === viewerDid,
+        isDetached: true,
+      }
+    }
+
+    // post
+    if (AppBskyEmbedRecord.isViewRecord(post.embed.record.record)) {
+      const urip = new AtUri(post.embed.record.record.uri)
+      return {
+        embed: post.embed,
+        uri: urip.toString(),
+        isOwnedByViewer: urip.host === viewerDid,
+        isDetached: false,
+      }
+    }
+  }
+}
+
+export const embeddingRules = {
+  disableRule: {$type: 'app.bsky.feed.postgate#disableRule'},
+}