Skip to content

Commit 92ed125

Browse files
Add more Standard Site logging, ensure associatedProfiles is returned on external view only for SS hydrations (bluesky-social#5001)
* Add some more logs * Build associatedProfiles inside externalEmbedFromStandardSiteRecords Hoists the doc/pub profile lookup into the shared SS overlay builder so both the read-path externalEmbed and the compose-path handler emit associatedProfiles from the same source of truth, derived from the selected document/publication refs rather than the post's full associatedRefs array. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Changeset * Format --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 126ac1e commit 92ed125

4 files changed

Lines changed: 41 additions & 12 deletions

File tree

.changeset/chatty-icons-agree.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@atproto/bsky': patch
3+
---
4+
5+
Ensure `associatedProfiles` is returned for Standard Site external embed views

packages/bsky/src/hydration/external.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AtUriString } from '@atproto/syntax'
22
import { DataPlaneClient } from '../data-plane/client/index.js'
33
import { site } from '../lexicons/index.js'
4+
import { hydrationLogger } from '../logger.js'
45
import {
56
GetSiteStandardRecordsByRefResponse,
67
GetSiteStandardRecordsByURIResponse,
@@ -162,6 +163,14 @@ export const getSiteStandardRecordsFromHydrationMapsByRefs = (
162163
// (or tampered with), so reject the whole pairing.
163164
if (document && publication) {
164165
if (document.info.record.site !== publication.ref.uri) {
166+
hydrationLogger.warn(
167+
{
168+
documentUri: document.ref.uri,
169+
documentSite: document.info.record.site,
170+
publicationUri: publication.ref.uri,
171+
},
172+
'site.standard byRefs lookup failed: doc.site does not match hydrated publication.uri',
173+
)
165174
return { document: undefined, publication: undefined }
166175
}
167176
}
@@ -172,6 +181,10 @@ export const getSiteStandardRecordsFromHydrationMapsByRefs = (
172181
if (document && !publication) {
173182
const site = document.info.record.site
174183
if (site && site.startsWith('at://')) {
184+
hydrationLogger.warn(
185+
{ documentUri: document.ref.uri, documentSite: site },
186+
'site.standard byRefs lookup failed: document.site is AT URI but no matching publication was hydrated',
187+
)
175188
return { document: undefined, publication: undefined }
176189
}
177190
}
@@ -234,6 +247,10 @@ export const getSiteStandardRecordsFromHydrationMapsByDocumentUri = (
234247
}
235248
}
236249
if (!publication) {
250+
hydrationLogger.warn(
251+
{ documentUri: document.ref.uri, documentSite: site },
252+
'site.standard byDocumentUri lookup failed: document.site is AT URI but no matching publication was hydrated',
253+
)
237254
return { document: undefined, publication: undefined }
238255
}
239256
}

packages/bsky/src/util/standard-site.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ describe(validateStandardSiteForUrl, () => {
101101
validateStandardSiteForUrl(undefined, pub, 'https://other.com'),
102102
).toBe(false)
103103
})
104+
105+
it('accepts when assumedUrl has a trailing slash and publication.url does not', () => {
106+
const pub = makePub({ url: 'https://atproto.com/blog' })
107+
expect(
108+
validateStandardSiteForUrl(undefined, pub, 'https://atproto.com/blog/'),
109+
).toBe(true)
110+
})
104111
})
105112

106113
describe('neither', () => {

packages/bsky/src/views/index.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,14 +2141,6 @@ export class Views {
21412141
state,
21422142
assumedUrl: embed.external.uri,
21432143
})
2144-
// Profiles of the owners of pinned `associatedRefs`. Hydrator covers
2145-
// these DIDs alongside post-author profiles, so misses here only
2146-
// happen when an actor is unavailable (suspended, deleted, etc.) —
2147-
// drop those rather than emit `undefined` slots.
2148-
const associatedProfiles = mapDefined(
2149-
embed.external.associatedRefs ?? [],
2150-
(ref) => this.profileBasic(uriToDid(ref.uri), state),
2151-
) as ProfileViewBasic[]
21522144
return app.bsky.embed.external.view.$build({
21532145
external: {
21542146
uri: embed.external.uri,
@@ -2163,9 +2155,6 @@ export class Views {
21632155
: undefined,
21642156
...ssView,
21652157
associatedRefs: embed.external.associatedRefs,
2166-
associatedProfiles: associatedProfiles.length
2167-
? associatedProfiles
2168-
: undefined,
21692158
},
21702159
})
21712160
}
@@ -2263,7 +2252,7 @@ export class Views {
22632252
documentUri: document?.ref.uri,
22642253
publicationUri: publication?.ref.uri,
22652254
},
2266-
'SS record(s) failed URL validation for external embed',
2255+
'site.standard URL validation failed',
22672256
)
22682257
return undefined
22692258
}
@@ -2333,6 +2322,17 @@ export class Views {
23332322
overlay.source = this.externalEmbedSource(publication)
23342323
}
23352324

2325+
// Profiles of the owners of the records backing this embed. Hydrator
2326+
// covers these DIDs alongside post-author profiles, so misses here
2327+
// only happen when an actor is unavailable (suspended, deleted, etc.)
2328+
// — drop those rather than emit `undefined` slots.
2329+
const associatedProfiles = mapDefined(
2330+
[document?.ref.uri, publication?.ref.uri],
2331+
(uri) => (uri ? this.profileBasic(uriToDid(uri), state) : undefined),
2332+
) as ProfileViewBasic[]
2333+
if (associatedProfiles.length)
2334+
overlay.associatedProfiles = associatedProfiles
2335+
23362336
return overlay
23372337
}
23382338

0 commit comments

Comments
 (0)