Skip to content

Commit 391c883

Browse files
committed
feat: use constellation to fetch bluesky backlinks
This is a WIP. It only runs once on the client when you refresh the page.
1 parent 6774771 commit 391c883

File tree

3 files changed

+90
-8
lines changed

3 files changed

+90
-8
lines changed

app/components/BlogPostWrapper.vue

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ useSeoMeta({
1313
ogType: 'article',
1414
})
1515
16-
// TODO: Hardcoded for testing - waiting on constellation/slingshot work
17-
// Using Daniel Roe's post for testing: https://bsky.app/profile/danielroe.dev/post/3mcg6svsgsm2k
18-
const BSKY_DID = 'did:plc:jbeaa5kdaladzwq3r7f5xgwe'
19-
// const BSKY_DID = 'did:plc:5ixnpdbogli5f7fbbee5fmuq'
20-
const BSKY_POST_ID = '3mcg6svsgsm2k'
16+
// Hardcoded values for reference/testing
17+
// const BSKY_DID = 'did:plc:jbeaa5kdaladzwq3r7f5xgwe'
18+
// const BSKY_DID = 'did:plc:5ixnpdbogli5f7fbbee5fmuq' // Albie
19+
// const BSKY_POST_ID = '3mcg6svsgsm2k'
2120
// const BSKY_POST_ID = '3mdoijswyz22u'
2221
23-
const blueskyPostUri = computed(() =>
24-
BSKY_POST_ID ? `at://${BSKY_DID}/app.bsky.feed.post/${BSKY_POST_ID}` : null,
25-
)
22+
const slug = computed(() => props.frontmatter?.slug)
23+
24+
// Use Constellation to find the Bluesky post linking to this blog post
25+
const { data: blueskyLink } = useBlogPostBlueskyLink(slug)
26+
const blueskyPostUri = computed(() => blueskyLink.value?.postUri ?? null)
2627
</script>
2728

2829
<template>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { Constellation } from '#shared/utils/constellation'
2+
// import { NPMX_SITE } from '#shared/utils/constants'
3+
4+
const BLOG_BACKLINK_TTL_IN_SECONDS = 60 * 5
5+
6+
export interface BlogPostBlueskyLink {
7+
did: string
8+
rkey: string
9+
postUri: string
10+
}
11+
12+
export function useBlogPostBlueskyLink(slug: MaybeRefOrGetter<string | null | undefined>) {
13+
const cachedFetch = useCachedFetch()
14+
15+
const blogUrl = computed(() => {
16+
const s = toValue(slug)
17+
if (!s) return null
18+
// return `${NPMX_SITE}/blog/${s}`
19+
// TODO: Deploy Preview used for testing remove before merge
20+
return `https://npmxdev-git-fork-jonathanyeong-feat-atproto-blog-fe-poetry.vercel.app/blog/${s}`
21+
})
22+
23+
return useLazyAsyncData<BlogPostBlueskyLink | null>(
24+
() => (blogUrl.value ? `blog-bsky-link:${blogUrl.value}` : 'blog-bsky-link:none'),
25+
async () => {
26+
const url = blogUrl.value
27+
if (!url) return null
28+
29+
const constellation = new Constellation(cachedFetch)
30+
31+
try {
32+
// Try embed.external.uri first (link card embeds)
33+
const { data: embedBacklinks } = await constellation.getBackLinks(
34+
url,
35+
'app.bsky.feed.post',
36+
'embed.external.uri',
37+
1,
38+
undefined,
39+
false,
40+
[['did:plc:5ixnpdbogli5f7fbbee5fmuq']],
41+
BLOG_BACKLINK_TTL_IN_SECONDS,
42+
)
43+
44+
const embedRecord = embedBacklinks.records[0]
45+
if (embedRecord) {
46+
return {
47+
did: embedRecord.did,
48+
rkey: embedRecord.rkey,
49+
postUri: `at://${embedRecord.did}/app.bsky.feed.post/${embedRecord.rkey}`,
50+
}
51+
}
52+
53+
// Try facets.features.uri (URLs in post text)
54+
const { data: facetBacklinks } = await constellation.getBackLinks(
55+
url,
56+
'app.bsky.feed.post',
57+
'facets.features.uri',
58+
1,
59+
undefined,
60+
false,
61+
[],
62+
BLOG_BACKLINK_TTL_IN_SECONDS,
63+
)
64+
65+
const facetRecord = facetBacklinks.records[0]
66+
if (facetRecord) {
67+
return {
68+
did: facetRecord.did,
69+
rkey: facetRecord.rkey,
70+
postUri: `at://${facetRecord.did}/app.bsky.feed.post/${facetRecord.rkey}`,
71+
}
72+
}
73+
} catch {
74+
// Constellation unavailable or error - fail silently
75+
}
76+
77+
return null
78+
},
79+
)
80+
}

shared/schemas/blog.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const BlogPostSchema = object({
77
date: pipe(string(), isoDate()),
88
description: string(),
99
path: string(),
10+
slug: string(),
1011
excerpt: optional(string()),
1112
tags: optional(array(string())),
1213
draft: optional(boolean()),

0 commit comments

Comments
 (0)