a tool for shared writing and social publishing
0

Configure Feed

Select the types of activity you want to include in your feed.

add associated refs to embed in bsky publish flow

Jared Pereira (May 28, 2026, 3:35 PM EDT) 8e89d6d0 3212781d

+27 -10
+27 -10
app/(app)/[leaflet_id]/publish/publishBskyPost.ts
··· 1 1 "use server"; 2 2 3 3 import { 4 + AppBskyEmbedExternal, 4 5 AppBskyRichtextFacet, 5 6 Agent as BskyAgent, 6 7 UnicodeString, ··· 19 20 } from "src/utils/getMicroLinkOgImage"; 20 21 import { fetchAtprotoBlob } from "app/api/atproto_images/route"; 21 22 import { maybeOffloadPagesToBlob } from "src/utils/offloadPagesToBlob"; 23 + 24 + type StrongRef = { 25 + $type: "com.atproto.repo.strongRef"; 26 + uri: string; 27 + cid: string; 28 + }; 22 29 23 30 type PublishBskyResult = 24 31 | { success: true } ··· 107 114 .eq("document", documentUri) 108 115 .maybeSingle(); 109 116 110 - let associatedRefs: { uri: string; cid: string }[] = []; 117 + let associatedRefs: StrongRef[] = []; 111 118 for (let uri of [documentUri, docInPub?.publication]) { 112 119 if (!uri) continue; 113 120 let ref = await getRecordStrongRef(agent, uri); 114 121 if (ref) associatedRefs.push(ref); 115 122 } 116 123 124 + // associatedRefs hangs off the external embed card alongside uri/title/etc. 125 + // It isn't in the published @atproto/api types yet, so widen External here. 126 + let external: AppBskyEmbedExternal.External & { 127 + associatedRefs?: StrongRef[]; 128 + } = { 129 + uri: args.url, 130 + title: args.title, 131 + description: args.description, 132 + thumb: blob.data.blob, 133 + }; 134 + if (associatedRefs.length > 0) external.associatedRefs = associatedRefs; 135 + 117 136 let bsky = new BskyAgent(credentialSession); 118 137 let post = await bsky.app.bsky.feed.post.create( 119 138 { ··· 126 145 facets: args.facets, 127 146 embed: { 128 147 $type: "app.bsky.embed.external", 129 - external: { 130 - uri: args.url, 131 - title: args.title, 132 - description: args.description, 133 - thumb: blob.data.blob, 134 - }, 148 + external, 135 149 }, 136 - ...(associatedRefs.length > 0 && { associatedRefs }), 137 150 }, 138 151 ); 139 152 let record = args.document_record; ··· 166 179 async function getRecordStrongRef( 167 180 agent: AtpBaseClient, 168 181 uri: string, 169 - ): Promise<{ uri: string; cid: string } | null> { 182 + ): Promise<StrongRef | null> { 170 183 try { 171 184 let { host, collection, rkey } = new AtUri(uri); 172 185 let { data } = await agent.com.atproto.repo.getRecord({ ··· 175 188 rkey, 176 189 }); 177 190 if (!data.cid) return null; 178 - return { uri: data.uri, cid: data.cid }; 191 + return { 192 + $type: "com.atproto.repo.strongRef", 193 + uri: data.uri, 194 + cid: data.cid, 195 + }; 179 196 } catch { 180 197 return null; 181 198 }