@atproto/bsky 0.0.233 → 0.0.235

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/api/app/bsky/embed/getEmbedExternalView.js +5 -3
  3. package/dist/api/app/bsky/embed/getEmbedExternalView.js.map +1 -1
  4. package/dist/hydration/external.d.ts.map +1 -1
  5. package/dist/hydration/external.js +8 -0
  6. package/dist/hydration/external.js.map +1 -1
  7. package/dist/hydration/hydrator.d.ts.map +1 -1
  8. package/dist/hydration/hydrator.js +48 -5
  9. package/dist/hydration/hydrator.js.map +1 -1
  10. package/dist/lexicons/app/bsky/embed/external.defs.d.ts +5 -0
  11. package/dist/lexicons/app/bsky/embed/external.defs.d.ts.map +1 -1
  12. package/dist/lexicons/app/bsky/embed/external.defs.js +4 -0
  13. package/dist/lexicons/app/bsky/embed/external.defs.js.map +1 -1
  14. package/dist/lexicons/chat/bsky/actor/getStatus.defs.d.ts +2 -0
  15. package/dist/lexicons/chat/bsky/actor/getStatus.defs.d.ts.map +1 -1
  16. package/dist/lexicons/chat/bsky/actor/getStatus.defs.js +1 -0
  17. package/dist/lexicons/chat/bsky/actor/getStatus.defs.js.map +1 -1
  18. package/dist/lexicons/chat/bsky/authFullChatClient.defs.js +1 -1
  19. package/dist/lexicons/chat/bsky/authFullChatClient.defs.js.map +1 -1
  20. package/dist/lexicons/chat/bsky/convo/defs.defs.d.ts +8 -0
  21. package/dist/lexicons/chat/bsky/convo/defs.defs.d.ts.map +1 -1
  22. package/dist/lexicons/chat/bsky/convo/defs.defs.js +2 -0
  23. package/dist/lexicons/chat/bsky/convo/defs.defs.js.map +1 -1
  24. package/dist/lexicons/chat/bsky/convo/listConvoRequests.defs.d.ts +3 -3
  25. package/dist/lexicons/chat/bsky/convo/listConvoRequests.defs.d.ts.map +1 -1
  26. package/dist/lexicons/chat/bsky/convo/listConvoRequests.defs.js +2 -2
  27. package/dist/lexicons/chat/bsky/convo/listConvoRequests.defs.js.map +1 -1
  28. package/dist/lexicons/chat/bsky/group/defs.defs.d.ts +26 -0
  29. package/dist/lexicons/chat/bsky/group/defs.defs.d.ts.map +1 -1
  30. package/dist/lexicons/chat/bsky/group/defs.defs.js +23 -0
  31. package/dist/lexicons/chat/bsky/group/defs.defs.js.map +1 -1
  32. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.d.ts +3 -0
  33. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.d.ts.map +1 -0
  34. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.d.ts +22 -0
  35. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.d.ts.map +1 -0
  36. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.js +22 -0
  37. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.js.map +1 -0
  38. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.js +6 -0
  39. package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.js.map +1 -0
  40. package/dist/lexicons/chat/bsky/group.d.ts +1 -1
  41. package/dist/lexicons/chat/bsky/group.d.ts.map +1 -1
  42. package/dist/lexicons/chat/bsky/group.js +1 -1
  43. package/dist/lexicons/chat/bsky/group.js.map +1 -1
  44. package/dist/lexicons/com/atproto/server/getServiceAuth.defs.d.ts +2 -2
  45. package/dist/lexicons/com/atproto/server/getServiceAuth.defs.js +1 -1
  46. package/dist/lexicons/com/atproto/server/getServiceAuth.defs.js.map +1 -1
  47. package/dist/logger.d.ts +1 -0
  48. package/dist/logger.d.ts.map +1 -1
  49. package/dist/logger.js +1 -0
  50. package/dist/logger.js.map +1 -1
  51. package/dist/util/standard-site.d.ts +12 -5
  52. package/dist/util/standard-site.d.ts.map +1 -1
  53. package/dist/util/standard-site.js +30 -9
  54. package/dist/util/standard-site.js.map +1 -1
  55. package/dist/views/index.d.ts.map +1 -1
  56. package/dist/views/index.js +14 -1
  57. package/dist/views/index.js.map +1 -1
  58. package/package.json +5 -5
  59. package/src/api/app/bsky/embed/getEmbedExternalView.ts +5 -3
  60. package/src/hydration/external.ts +17 -0
  61. package/src/hydration/hydrator.ts +53 -5
  62. package/src/logger.ts +2 -0
  63. package/src/util/standard-site.test.ts +116 -24
  64. package/src/util/standard-site.ts +30 -11
  65. package/src/views/index.ts +24 -1
  66. package/tests/views/profile.test.ts +3 -10
  67. package/tsconfig.build.tsbuildinfo +1 -1
  68. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.d.ts +0 -3
  69. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.d.ts.map +0 -1
  70. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.defs.d.ts +0 -22
  71. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.defs.d.ts.map +0 -1
  72. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.defs.js +0 -18
  73. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.defs.js.map +0 -1
  74. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.js +0 -6
  75. package/dist/lexicons/chat/bsky/group/getJoinLinkPreview.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @atproto/bsky
2
2
 
3
+ ## 0.0.235
4
+
5
+ ### Patch Changes
6
+
7
+ - [#5001](https://github.com/bluesky-social/atproto/pull/5001) [`92ed125`](https://github.com/bluesky-social/atproto/commit/92ed125c27178bec1cb737ec15307334170768b7) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Ensure `associatedProfiles` is returned for Standard Site external embed views
8
+
9
+ - [#5004](https://github.com/bluesky-social/atproto/pull/5004) [`1a74fa5`](https://github.com/bluesky-social/atproto/commit/1a74fa559778392683f803e1bed71cd25e672114) Thanks [@blackmichael](https://github.com/blackmichael)! - Fix app.bsky.embed.getEmbedExternalView associatedProfiles duplicate data
10
+
11
+ - Updated dependencies [[`126ac1e`](https://github.com/bluesky-social/atproto/commit/126ac1ead8c44065e3fa7c02efba7bd20551ee99), [`60721e6`](https://github.com/bluesky-social/atproto/commit/60721e69c8db193eb817c4238ac447505ac855bc), [`60721e6`](https://github.com/bluesky-social/atproto/commit/60721e69c8db193eb817c4238ac447505ac855bc), [`622d365`](https://github.com/bluesky-social/atproto/commit/622d365aeb240133f40763a3b1c43981112837fc)]:
12
+ - @atproto/api@0.20.6
13
+ - @atproto/lex@0.1.3
14
+ - @atproto/did@0.5.0
15
+
16
+ ## 0.0.234
17
+
18
+ ### Patch Changes
19
+
20
+ - [#4993](https://github.com/bluesky-social/atproto/pull/4993) [`9378a82`](https://github.com/bluesky-social/atproto/commit/9378a82740529a7004e280fe71e91c611acc3905) Thanks [@blackmichael](https://github.com/blackmichael)! - Add associatedProfiles to app.bsky.embed.getEmbedExternalView output
21
+
22
+ - [#4995](https://github.com/bluesky-social/atproto/pull/4995) [`753ac51`](https://github.com/bluesky-social/atproto/commit/753ac51fde9d1feea8128745c049584a995855f7) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Update Standard Site validation to fix path resolution
23
+
24
+ - Updated dependencies [[`4984994`](https://github.com/bluesky-social/atproto/commit/4984994f7d3f0773b03c61dccd68286e42e0c6af)]:
25
+ - @atproto/api@0.20.5
26
+
3
27
  ## 0.0.233
4
28
 
5
29
  ### Patch Changes
@@ -27,8 +27,9 @@ const hydration = async (inputs) => {
27
27
  return ctx.hydrator.hydrateEmbedExternalViewFromUris(skeleton.uris, params.hydrateCtx);
28
28
  };
29
29
  const presentation = (inputs) => {
30
- const documents = inputs.hydration.siteStandardDocuments;
31
- const publications = inputs.hydration.siteStandardPublications;
30
+ const { hydration } = inputs;
31
+ const documents = hydration.siteStandardDocuments;
32
+ const publications = hydration.siteStandardPublications;
32
33
  // Dispatch by record type. Today site.standard is the only kind we know
33
34
  // how to render; future record types get their own branch.
34
35
  if ((documents && documents.size > 0) ||
@@ -46,7 +47,8 @@ const standardSitePresentation = (inputs, documents, publications) => {
46
47
  // Emit response refs/records only for the records we actually selected.
47
48
  // Anything else (e.g. extra publications the dataplane returned) is
48
49
  // intentionally excluded so the strongRefs Cardy writes onto the post
49
- // match the view we built.
50
+ // match the view we built. Profiles are emitted in the same order as
51
+ // refs (one per slot) so consumers can match by index.
50
52
  const associatedRefs = [];
51
53
  const associatedRecords = [];
52
54
  for (const slot of [document, publication]) {
@@ -1 +1 @@
1
- {"version":3,"file":"getEmbedExternalView.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/embed/getEmbedExternalView.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,oDAAoD,GACrD,MAAM,mCAAmC,CAAA;AAE1C,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACxD,OAAO,EAIL,cAAc,EACd,OAAO,GACR,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,oBAAoB,GAAG,cAAc,CACzC,QAAQ,EACR,SAAS,EACT,OAAO,EACP,YAAY,CACb,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE;QAC9C,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB;QACvC,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;YACzE,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAA;YACzE,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,UAAU,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;aACvD,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,KAAK,EACpB,MAAwC,EACrB,EAAE;IACrB,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAqB,EAAE,CAAA;AACtD,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,KAAK,EACrB,MAAmD,EACnD,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;IACxC,OAAO,GAAG,CAAC,QAAQ,CAAC,gCAAgC,CAClD,QAAQ,CAAC,IAAI,EACb,MAAM,CAAC,UAAU,CAClB,CAAA;AACH,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,CACnB,MAAsD,EAC9C,EAAE;IACV,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,qBAAqB,CAAA;IACxD,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,wBAAwB,CAAA;IAC9D,wEAAwE;IACxE,2DAA2D;IAC3D,IACE,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,CAAC;QACjC,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,EACvC,CAAC;QACD,OAAO,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAED,MAAM,wBAAwB,GAAG,CAC/B,MAAsD,EACtD,SAA4C,EAC5C,YAAkD,EAC1C,EAAE;IACV,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAA;IAEzC,qEAAqE;IACrE,sEAAsE;IACtE,oEAAoE;IACpE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAC7B,oDAAoD,CAClD,SAAS,EACT,YAAY,CACb,CAAA;IAEH,wEAAwE;IACxE,oEAAoE;IACpE,sEAAsE;IACtE,2BAA2B;IAC3B,MAAM,cAAc,GAAgB,EAAE,CAAA;IACtC,MAAM,iBAAiB,GAAa,EAAE,CAAA;IACtC,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,IAAI;YAAE,SAAQ;QACnB,cAAc,CAAC,IAAI,CACjB,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;YAChC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG;YACjB,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG;SACnB,CAAC,CACH,CAAA;QACD,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAgB,CAAC,CAAA;IACpD,CAAC;IAED,IAAI,CAAC,cAAc,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IAErC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,oCAAoC,CAAC;QAC7D,QAAQ;QACR,WAAW;QACX,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,MAAM,CAAC,GAAG;KACvB,CAAC,CAAA;IACF,wEAAwE;IACxE,0EAA0E;IAC1E,wEAAwE;IACxE,QAAQ;IACR,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAA;IAEvB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;QAC/C,QAAQ,EAAE;YACR,GAAG,OAAO;YACV,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,cAAc;SACf;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAA;AACpD,CAAC,CAAA","sourcesContent":["import { AtUriString, LexMap } from '@atproto/lex'\nimport { Server } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport {\n SiteStandardDocuments,\n SiteStandardPublications,\n getSiteStandardRecordsFromHydrationMapsByDocumentUri,\n} from '../../../../hydration/external.js'\nimport { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app, com } from '../../../../lexicons/index.js'\nimport {\n HydrationFnInput,\n PresentationFnInput,\n SkeletonFnInput,\n createPipeline,\n noRules,\n} from '../../../../pipeline.js'\nimport { Views } from '../../../../views/index.js'\nimport { ExternalEmbedView, StrongRef } from '../../../../views/types.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getEmbedExternalView = createPipeline(\n skeleton,\n hydration,\n noRules,\n presentation,\n )\n server.add(app.bsky.embed.getEmbedExternalView, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })\n const result = await getEmbedExternalView({ ...params, hydrateCtx }, ctx)\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n return { uris: inputs.params.uris as AtUriString[] }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n return ctx.hydrator.hydrateEmbedExternalViewFromUris(\n skeleton.uris,\n params.hydrateCtx,\n )\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n): Output => {\n const documents = inputs.hydration.siteStandardDocuments\n const publications = inputs.hydration.siteStandardPublications\n // Dispatch by record type. Today site.standard is the only kind we know\n // how to render; future record types get their own branch.\n if (\n (documents && documents.size > 0) ||\n (publications && publications.size > 0)\n ) {\n return standardSitePresentation(inputs, documents, publications)\n }\n return {}\n}\n\nconst standardSitePresentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n documents: SiteStandardDocuments | undefined,\n publications: SiteStandardPublications | undefined,\n): Output => {\n const { ctx, params, hydration } = inputs\n\n // Pick the first hydrated doc, then pair it with the publication its\n // `site` field points at (if any). Docs the dataplane auto-resolved a\n // publication for end up matched; unrelated publications fall away.\n const { document, publication } =\n getSiteStandardRecordsFromHydrationMapsByDocumentUri(\n documents,\n publications,\n )\n\n // Emit response refs/records only for the records we actually selected.\n // Anything else (e.g. extra publications the dataplane returned) is\n // intentionally excluded so the strongRefs Cardy writes onto the post\n // match the view we built.\n const associatedRefs: StrongRef[] = []\n const associatedRecords: LexMap[] = []\n for (const slot of [document, publication]) {\n if (!slot) continue\n associatedRefs.push(\n com.atproto.repo.strongRef.$build({\n uri: slot.ref.uri,\n cid: slot.info.cid,\n }),\n )\n associatedRecords.push(slot.info.record as LexMap)\n }\n\n if (!associatedRefs.length) return {}\n\n const overlay = ctx.views.externalEmbedFromStandardSiteRecords({\n document,\n publication,\n state: hydration,\n assumedUrl: params.url,\n })\n // The view builder rejected the records (validation failed, or the pair\n // didn't produce the title viewExternal requires). Return nothing — Cardy\n // falls back to its own card render and doesn't write strongRefs to the\n // post.\n if (!overlay) return {}\n\n const view = app.bsky.embed.external.view.$build({\n external: {\n ...overlay,\n uri: params.url,\n associatedRefs,\n },\n })\n\n return { view, associatedRefs, associatedRecords }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.embed.getEmbedExternalView.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n uris: AtUriString[]\n}\n\ntype Output = {\n view?: ExternalEmbedView\n associatedRefs?: StrongRef[]\n associatedRecords?: LexMap[]\n}\n"]}
1
+ {"version":3,"file":"getEmbedExternalView.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/embed/getEmbedExternalView.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtUriString, LexMap } from '@atproto/lex'\nimport { Server } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport {\n SiteStandardDocuments,\n SiteStandardPublications,\n getSiteStandardRecordsFromHydrationMapsByDocumentUri,\n} from '../../../../hydration/external.js'\nimport { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app, com } from '../../../../lexicons/index.js'\nimport {\n HydrationFnInput,\n PresentationFnInput,\n SkeletonFnInput,\n createPipeline,\n noRules,\n} from '../../../../pipeline.js'\nimport { Views } from '../../../../views/index.js'\nimport { ExternalEmbedView, StrongRef } from '../../../../views/types.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getEmbedExternalView = createPipeline(\n skeleton,\n hydration,\n noRules,\n presentation,\n )\n server.add(app.bsky.embed.getEmbedExternalView, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })\n const result = await getEmbedExternalView({ ...params, hydrateCtx }, ctx)\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n return { uris: inputs.params.uris as AtUriString[] }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n return ctx.hydrator.hydrateEmbedExternalViewFromUris(\n skeleton.uris,\n params.hydrateCtx,\n )\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n): Output => {\n const { hydration } = inputs\n const documents = hydration.siteStandardDocuments\n const publications = hydration.siteStandardPublications\n // Dispatch by record type. Today site.standard is the only kind we know\n // how to render; future record types get their own branch.\n if (\n (documents && documents.size > 0) ||\n (publications && publications.size > 0)\n ) {\n return standardSitePresentation(inputs, documents, publications)\n }\n return {}\n}\n\nconst standardSitePresentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n documents: SiteStandardDocuments | undefined,\n publications: SiteStandardPublications | undefined,\n): Output => {\n const { ctx, params, hydration } = inputs\n\n // Pick the first hydrated doc, then pair it with the publication its\n // `site` field points at (if any). Docs the dataplane auto-resolved a\n // publication for end up matched; unrelated publications fall away.\n const { document, publication } =\n getSiteStandardRecordsFromHydrationMapsByDocumentUri(\n documents,\n publications,\n )\n\n // Emit response refs/records only for the records we actually selected.\n // Anything else (e.g. extra publications the dataplane returned) is\n // intentionally excluded so the strongRefs Cardy writes onto the post\n // match the view we built. Profiles are emitted in the same order as\n // refs (one per slot) so consumers can match by index.\n const associatedRefs: StrongRef[] = []\n const associatedRecords: LexMap[] = []\n for (const slot of [document, publication]) {\n if (!slot) continue\n associatedRefs.push(\n com.atproto.repo.strongRef.$build({\n uri: slot.ref.uri,\n cid: slot.info.cid,\n }),\n )\n associatedRecords.push(slot.info.record as LexMap)\n }\n\n if (!associatedRefs.length) return {}\n\n const overlay = ctx.views.externalEmbedFromStandardSiteRecords({\n document,\n publication,\n state: hydration,\n assumedUrl: params.url,\n })\n // The view builder rejected the records (validation failed, or the pair\n // didn't produce the title viewExternal requires). Return nothing — Cardy\n // falls back to its own card render and doesn't write strongRefs to the\n // post.\n if (!overlay) return {}\n\n const view = app.bsky.embed.external.view.$build({\n external: {\n ...overlay,\n uri: params.url,\n associatedRefs,\n },\n })\n\n return { view, associatedRefs, associatedRecords }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.embed.getEmbedExternalView.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n uris: AtUriString[]\n}\n\ntype Output = {\n view?: ExternalEmbedView\n associatedRefs?: StrongRef[]\n associatedRecords?: LexMap[]\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"external.d.ts","sourceRoot":"","sources":["../../src/hydration/external.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAU/D,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAe,MAAM,WAAW,CAAA;AAE1E,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,0BAA0B,CAAC,CAAA;AACzE,MAAM,MAAM,uBAAuB,GAAG,UAAU,CAAC,6BAA6B,CAAC,CAAA;AAE/E;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,YAAY,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;AAC9E;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,YAAY,CACjD,MAAM,EACN,uBAAuB,CACxB,CAAA;AACD,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,qBAAqB,CAAA;IAChC,YAAY,EAAE,wBAAwB,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,4BAA4B,CAAC,CAAC,IAAI;IAC5C,GAAG,EAAE;QAAE,GAAG,EAAE,WAAW,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,IAAI,EAAE,CAAC,CAAA;CACR,CAAA;AAED,qBAAa,gBAAgB;IACR,SAAS,EAAE,eAAe;gBAA1B,SAAS,EAAE,eAAe;IAEvC,2BAA2B,CAC/B,IAAI,EAAE,OAAO,EAAE,EACf,gBAAgB,UAAQ,GACvB,OAAO,CAAC,mBAAmB,CAAC;IASzB,2BAA2B,CAC/B,IAAI,EAAE,WAAW,EAAE,EACnB,gBAAgB,UAAQ,GACvB,OAAO,CAAC,mBAAmB,CAAC;CAMhC;AAkCD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,6CAA6C,GACxD,gBAAgB,SAAS;IAAE,GAAG,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAS,EACxE,WAAW,qBAAqB,GAAG,SAAS,EAC5C,cAAc,wBAAwB,GAAG,SAAS,KACjD;IACD,QAAQ,EAAE,4BAA4B,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAA;IACxE,WAAW,EAAE,4BAA4B,CAAC,uBAAuB,CAAC,GAAG,SAAS,CAAA;CA6C/E,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,oDAAoD,GAC/D,WAAW,qBAAqB,GAAG,SAAS,EAC5C,cAAc,wBAAwB,GAAG,SAAS,KACjD;IACD,QAAQ,EAAE,4BAA4B,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAA;IACxE,WAAW,EAAE,4BAA4B,CAAC,uBAAuB,CAAC,GAAG,SAAS,CAAA;CAwC/E,CAAA"}
1
+ {"version":3,"file":"external.d.ts","sourceRoot":"","sources":["../../src/hydration/external.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAW/D,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAe,MAAM,WAAW,CAAA;AAE1E,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,0BAA0B,CAAC,CAAA;AACzE,MAAM,MAAM,uBAAuB,GAAG,UAAU,CAAC,6BAA6B,CAAC,CAAA;AAE/E;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,YAAY,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;AAC9E;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,YAAY,CACjD,MAAM,EACN,uBAAuB,CACxB,CAAA;AACD,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,qBAAqB,CAAA;IAChC,YAAY,EAAE,wBAAwB,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,4BAA4B,CAAC,CAAC,IAAI;IAC5C,GAAG,EAAE;QAAE,GAAG,EAAE,WAAW,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,IAAI,EAAE,CAAC,CAAA;CACR,CAAA;AAED,qBAAa,gBAAgB;IACR,SAAS,EAAE,eAAe;gBAA1B,SAAS,EAAE,eAAe;IAEvC,2BAA2B,CAC/B,IAAI,EAAE,OAAO,EAAE,EACf,gBAAgB,UAAQ,GACvB,OAAO,CAAC,mBAAmB,CAAC;IASzB,2BAA2B,CAC/B,IAAI,EAAE,WAAW,EAAE,EACnB,gBAAgB,UAAQ,GACvB,OAAO,CAAC,mBAAmB,CAAC;CAMhC;AAkCD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,6CAA6C,GACxD,gBAAgB,SAAS;IAAE,GAAG,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAS,EACxE,WAAW,qBAAqB,GAAG,SAAS,EAC5C,cAAc,wBAAwB,GAAG,SAAS,KACjD;IACD,QAAQ,EAAE,4BAA4B,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAA;IACxE,WAAW,EAAE,4BAA4B,CAAC,uBAAuB,CAAC,GAAG,SAAS,CAAA;CAyD/E,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,oDAAoD,GAC/D,WAAW,qBAAqB,GAAG,SAAS,EAC5C,cAAc,wBAAwB,GAAG,SAAS,KACjD;IACD,QAAQ,EAAE,4BAA4B,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAA;IACxE,WAAW,EAAE,4BAA4B,CAAC,uBAAuB,CAAC,GAAG,SAAS,CAAA;CA4C/E,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { site } from '../lexicons/index.js';
2
+ import { hydrationLogger } from '../logger.js';
2
3
  import { parseSiteStandardRecordKey, siteStandardRecordKey, } from '../util/standard-site.js';
3
4
  import { HydrationMap, parseRecord } from './util.js';
4
5
  export class ExternalHydrator {
@@ -95,6 +96,11 @@ export const getSiteStandardRecordsFromHydrationMapsByRefs = (associatedRefs, do
95
96
  // (or tampered with), so reject the whole pairing.
96
97
  if (document && publication) {
97
98
  if (document.info.record.site !== publication.ref.uri) {
99
+ hydrationLogger.warn({
100
+ documentUri: document.ref.uri,
101
+ documentSite: document.info.record.site,
102
+ publicationUri: publication.ref.uri,
103
+ }, 'site.standard byRefs lookup failed: doc.site does not match hydrated publication.uri');
98
104
  return { document: undefined, publication: undefined };
99
105
  }
100
106
  }
@@ -104,6 +110,7 @@ export const getSiteStandardRecordsFromHydrationMapsByRefs = (associatedRefs, do
104
110
  if (document && !publication) {
105
111
  const site = document.info.record.site;
106
112
  if (site && site.startsWith('at://')) {
113
+ hydrationLogger.warn({ documentUri: document.ref.uri, documentSite: site }, 'site.standard byRefs lookup failed: document.site is AT URI but no matching publication was hydrated');
107
114
  return { document: undefined, publication: undefined };
108
115
  }
109
116
  }
@@ -157,6 +164,7 @@ export const getSiteStandardRecordsFromHydrationMapsByDocumentUri = (documents,
157
164
  }
158
165
  }
159
166
  if (!publication) {
167
+ hydrationLogger.warn({ documentUri: document.ref.uri, documentSite: site }, 'site.standard byDocumentUri lookup failed: document.site is AT URI but no matching publication was hydrated');
160
168
  return { document: undefined, publication: undefined };
161
169
  }
162
170
  }
@@ -1 +1 @@
1
- {"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/hydration/external.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtUriString } from '@atproto/syntax'\nimport { DataPlaneClient } from '../data-plane/client/index.js'\nimport { site } from '../lexicons/index.js'\nimport {\n GetSiteStandardRecordsByRefResponse,\n GetSiteStandardRecordsByURIResponse,\n} from '../proto/bsky_pb.js'\nimport {\n parseSiteStandardRecordKey,\n siteStandardRecordKey,\n} from '../util/standard-site.js'\nimport {\n SiteStandardDocumentRecord,\n SiteStandardPublicationRecord,\n} from '../views/types.js'\nimport { HydrationMap, ItemRef, RecordInfo, parseRecord } from './util.js'\n\nexport type SiteStandardDocument = RecordInfo<SiteStandardDocumentRecord>\nexport type SiteStandardPublication = RecordInfo<SiteStandardPublicationRecord>\n\n/**\n * Keyed by `${uri}@${cid}` — see `siteStandardRecordKey`. A single hydration\n * batch can pull more than one version of the same URI (different posts\n * pinning different cids), so the composite key is needed for O(1)\n * version-exact lookups.\n */\nexport type SiteStandardDocuments = HydrationMap<string, SiteStandardDocument>\n/**\n * Keyed by `${uri}@${cid}`. See `SiteStandardDocuments` for the rationale.\n */\nexport type SiteStandardPublications = HydrationMap<\n string,\n SiteStandardPublication\n>\nexport type SiteStandardRecords = {\n documents: SiteStandardDocuments\n publications: SiteStandardPublications\n}\n\nexport type AssociatedSiteStandardRecord<T> = {\n ref: { uri: AtUriString; cid: string }\n info: T\n}\n\nexport class ExternalHydrator {\n constructor(public dataplane: DataPlaneClient) {}\n\n async getSiteStandardRecordsByRef(\n refs: ItemRef[],\n includeTakedowns = false,\n ): Promise<SiteStandardRecords> {\n if (!refs.length) return emptySiteStandardRecords()\n\n const res = await this.dataplane.getSiteStandardRecordsByRef({\n refs: refs.map(({ uri, cid }) => ({ uri, cid: cid ?? '' })),\n })\n return buildSiteStandardRecordsHydrationMaps(res, includeTakedowns)\n }\n\n async getSiteStandardRecordsByURI(\n uris: AtUriString[],\n includeTakedowns = false,\n ): Promise<SiteStandardRecords> {\n if (!uris.length) return emptySiteStandardRecords()\n\n const res = await this.dataplane.getSiteStandardRecordsByURI({ uris })\n return buildSiteStandardRecordsHydrationMaps(res, includeTakedowns)\n }\n}\n\nconst emptySiteStandardRecords = (): SiteStandardRecords => ({\n documents: new HydrationMap(),\n publications: new HydrationMap(),\n})\n\nconst buildSiteStandardRecordsHydrationMaps = (\n res:\n | GetSiteStandardRecordsByURIResponse\n | GetSiteStandardRecordsByRefResponse,\n includeTakedowns: boolean,\n): SiteStandardRecords => {\n const documents: SiteStandardDocuments = new HydrationMap()\n for (const { ref, record } of res.documents) {\n if (!ref?.uri || !ref.cid || !record) continue\n documents.set(\n siteStandardRecordKey(ref.uri, ref.cid),\n parseRecord(site.standard.document.main, record, includeTakedowns) ??\n null,\n )\n }\n const publications: SiteStandardPublications = new HydrationMap()\n for (const { ref, record } of res.publications) {\n if (!ref?.uri || !ref.cid || !record) continue\n publications.set(\n siteStandardRecordKey(ref.uri, ref.cid),\n parseRecord(site.standard.publication.main, record, includeTakedowns) ??\n null,\n )\n }\n return { documents, publications }\n}\n\n/**\n * Read-path resolution: caller pinned a set of `(uri, cid)` strongRefs in\n * the post at write time, and we honor those exact versions. Any pair\n * that doesn't structurally agree is rejected, so downstream callers can\n * trust the returned shape.\n *\n * Same observable contract as\n * `getSiteStandardRecordsFromHydrationMapsByDocumentUri` (the compose-path\n * sister) — both functions guarantee that a returned `(doc, pub)` pair\n * has matching site/uri, and reject orphan docs that claim a\n * non-hydrated publication. They differ only in how upstream availability\n * is asserted: this one trusts caller-supplied refs; the sister derives\n * everything from the dataplane response.\n *\n * Pairing rules:\n * - Both slots referenced: `doc.site` must equal `publication.ref.uri`,\n * else both come back `undefined`.\n * - Doc with at-uri `site` referenced but no matching publication ref:\n * reject the whole pairing (doc claims a publication that should have\n * been pinned, but wasn't).\n * - Loose doc (web-URL `site`) referenced: publication stays `undefined`.\n * - Only a publication referenced: document stays `undefined`.\n *\n * Each returned slot carries the matching `ref` so callers can recover\n * the owner DID for blob-cdn URL building, etc.\n */\nexport const getSiteStandardRecordsFromHydrationMapsByRefs = (\n associatedRefs: readonly { uri: AtUriString; cid: string }[] | undefined,\n documents: SiteStandardDocuments | undefined,\n publications: SiteStandardPublications | undefined,\n): {\n document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n publication: AssociatedSiteStandardRecord<SiteStandardPublication> | undefined\n} => {\n if (!associatedRefs?.length) {\n return { document: undefined, publication: undefined }\n }\n\n // Resolve each ref against the hydration maps, taking the first hit on\n // each side.\n let document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n let publication:\n | AssociatedSiteStandardRecord<SiteStandardPublication>\n | undefined\n for (const ref of associatedRefs) {\n const key = siteStandardRecordKey(ref.uri, ref.cid)\n if (!document) {\n const hit = documents?.get(key)\n if (hit) document = { ref, info: hit }\n }\n if (!publication) {\n const hit = publications?.get(key)\n if (hit) publication = { ref, info: hit }\n }\n if (document && publication) break\n }\n\n // Both refs resolved: enforce that the doc's `site` actually points at\n // the supplied publication. Mismatch means the post was misconstructed\n // (or tampered with), so reject the whole pairing.\n if (document && publication) {\n if (document.info.record.site !== publication.ref.uri) {\n return { document: undefined, publication: undefined }\n }\n }\n\n // Doc with at-uri `site` but no publication: the post should have\n // pinned the publication too. Treat as misconstructed — same contract\n // as the compose-path lookup.\n if (document && !publication) {\n const site = document.info.record.site\n if (site && site.startsWith('at://')) {\n return { document: undefined, publication: undefined }\n }\n }\n\n return { document, publication }\n}\n\n/**\n * Compose-path resolution: no caller-supplied refs — the dataplane\n * returned the latest version of each record (including any\n * publications it auto-resolved from a document's `site` field). Take\n * the first hydrated document and pair it with the publication its\n * `site` field points at.\n *\n * Same observable contract as\n * `getSiteStandardRecordsFromHydrationMapsByRefs` (the read-path\n * sister) — both functions guarantee that a returned `(doc, pub)` pair\n * has matching site/uri, and reject orphan docs that claim a\n * non-hydrated publication. They differ only in how upstream\n * availability is asserted: this one walks whatever was returned by the\n * dataplane; the sister checks against caller-supplied refs.\n *\n * Pairing rules:\n * - Doc with at-uri `site`: must find a hydrated publication at that\n * URI. If none was hydrated, the doc/publication chain is incomplete\n * and the function returns `undefined` for both slots; the doc alone\n * isn't useful without its source (can't verify the pub)\n * - Doc with web-URL `site` (loose): no publication.\n * - No doc hydrated: fall through to the first hydrated publication for\n * the publication-only resolution flow.\n */\nexport const getSiteStandardRecordsFromHydrationMapsByDocumentUri = (\n documents: SiteStandardDocuments | undefined,\n publications: SiteStandardPublications | undefined,\n): {\n document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n publication: AssociatedSiteStandardRecord<SiteStandardPublication> | undefined\n} => {\n // First hydrated doc.\n let document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n for (const [key, info] of documents ?? []) {\n if (!info) continue\n document = { ref: parseSiteStandardRecordKey(key), info }\n break\n }\n\n let publication:\n | AssociatedSiteStandardRecord<SiteStandardPublication>\n | undefined\n if (document) {\n const site = document.info.record.site\n if (site && site.startsWith('at://')) {\n // Doc declared an at-uri publication; we need it.\n for (const [key, info] of publications ?? []) {\n if (!info) continue\n const ref = parseSiteStandardRecordKey(key)\n if (ref.uri === site) {\n publication = { ref, info }\n break\n }\n }\n if (!publication) {\n return { document: undefined, publication: undefined }\n }\n }\n // else: loose doc (web-URL site), no publication needed.\n } else {\n // Publication-only flow: no doc, take the first hydrated publication.\n for (const [key, info] of publications ?? []) {\n if (!info) continue\n publication = { ref: parseSiteStandardRecordKey(key), info }\n break\n }\n }\n\n return { document, publication }\n}\n"]}
1
+ {"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/hydration/external.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtUriString } from '@atproto/syntax'\nimport { DataPlaneClient } from '../data-plane/client/index.js'\nimport { site } from '../lexicons/index.js'\nimport { hydrationLogger } from '../logger.js'\nimport {\n GetSiteStandardRecordsByRefResponse,\n GetSiteStandardRecordsByURIResponse,\n} from '../proto/bsky_pb.js'\nimport {\n parseSiteStandardRecordKey,\n siteStandardRecordKey,\n} from '../util/standard-site.js'\nimport {\n SiteStandardDocumentRecord,\n SiteStandardPublicationRecord,\n} from '../views/types.js'\nimport { HydrationMap, ItemRef, RecordInfo, parseRecord } from './util.js'\n\nexport type SiteStandardDocument = RecordInfo<SiteStandardDocumentRecord>\nexport type SiteStandardPublication = RecordInfo<SiteStandardPublicationRecord>\n\n/**\n * Keyed by `${uri}@${cid}` — see `siteStandardRecordKey`. A single hydration\n * batch can pull more than one version of the same URI (different posts\n * pinning different cids), so the composite key is needed for O(1)\n * version-exact lookups.\n */\nexport type SiteStandardDocuments = HydrationMap<string, SiteStandardDocument>\n/**\n * Keyed by `${uri}@${cid}`. See `SiteStandardDocuments` for the rationale.\n */\nexport type SiteStandardPublications = HydrationMap<\n string,\n SiteStandardPublication\n>\nexport type SiteStandardRecords = {\n documents: SiteStandardDocuments\n publications: SiteStandardPublications\n}\n\nexport type AssociatedSiteStandardRecord<T> = {\n ref: { uri: AtUriString; cid: string }\n info: T\n}\n\nexport class ExternalHydrator {\n constructor(public dataplane: DataPlaneClient) {}\n\n async getSiteStandardRecordsByRef(\n refs: ItemRef[],\n includeTakedowns = false,\n ): Promise<SiteStandardRecords> {\n if (!refs.length) return emptySiteStandardRecords()\n\n const res = await this.dataplane.getSiteStandardRecordsByRef({\n refs: refs.map(({ uri, cid }) => ({ uri, cid: cid ?? '' })),\n })\n return buildSiteStandardRecordsHydrationMaps(res, includeTakedowns)\n }\n\n async getSiteStandardRecordsByURI(\n uris: AtUriString[],\n includeTakedowns = false,\n ): Promise<SiteStandardRecords> {\n if (!uris.length) return emptySiteStandardRecords()\n\n const res = await this.dataplane.getSiteStandardRecordsByURI({ uris })\n return buildSiteStandardRecordsHydrationMaps(res, includeTakedowns)\n }\n}\n\nconst emptySiteStandardRecords = (): SiteStandardRecords => ({\n documents: new HydrationMap(),\n publications: new HydrationMap(),\n})\n\nconst buildSiteStandardRecordsHydrationMaps = (\n res:\n | GetSiteStandardRecordsByURIResponse\n | GetSiteStandardRecordsByRefResponse,\n includeTakedowns: boolean,\n): SiteStandardRecords => {\n const documents: SiteStandardDocuments = new HydrationMap()\n for (const { ref, record } of res.documents) {\n if (!ref?.uri || !ref.cid || !record) continue\n documents.set(\n siteStandardRecordKey(ref.uri, ref.cid),\n parseRecord(site.standard.document.main, record, includeTakedowns) ??\n null,\n )\n }\n const publications: SiteStandardPublications = new HydrationMap()\n for (const { ref, record } of res.publications) {\n if (!ref?.uri || !ref.cid || !record) continue\n publications.set(\n siteStandardRecordKey(ref.uri, ref.cid),\n parseRecord(site.standard.publication.main, record, includeTakedowns) ??\n null,\n )\n }\n return { documents, publications }\n}\n\n/**\n * Read-path resolution: caller pinned a set of `(uri, cid)` strongRefs in\n * the post at write time, and we honor those exact versions. Any pair\n * that doesn't structurally agree is rejected, so downstream callers can\n * trust the returned shape.\n *\n * Same observable contract as\n * `getSiteStandardRecordsFromHydrationMapsByDocumentUri` (the compose-path\n * sister) — both functions guarantee that a returned `(doc, pub)` pair\n * has matching site/uri, and reject orphan docs that claim a\n * non-hydrated publication. They differ only in how upstream availability\n * is asserted: this one trusts caller-supplied refs; the sister derives\n * everything from the dataplane response.\n *\n * Pairing rules:\n * - Both slots referenced: `doc.site` must equal `publication.ref.uri`,\n * else both come back `undefined`.\n * - Doc with at-uri `site` referenced but no matching publication ref:\n * reject the whole pairing (doc claims a publication that should have\n * been pinned, but wasn't).\n * - Loose doc (web-URL `site`) referenced: publication stays `undefined`.\n * - Only a publication referenced: document stays `undefined`.\n *\n * Each returned slot carries the matching `ref` so callers can recover\n * the owner DID for blob-cdn URL building, etc.\n */\nexport const getSiteStandardRecordsFromHydrationMapsByRefs = (\n associatedRefs: readonly { uri: AtUriString; cid: string }[] | undefined,\n documents: SiteStandardDocuments | undefined,\n publications: SiteStandardPublications | undefined,\n): {\n document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n publication: AssociatedSiteStandardRecord<SiteStandardPublication> | undefined\n} => {\n if (!associatedRefs?.length) {\n return { document: undefined, publication: undefined }\n }\n\n // Resolve each ref against the hydration maps, taking the first hit on\n // each side.\n let document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n let publication:\n | AssociatedSiteStandardRecord<SiteStandardPublication>\n | undefined\n for (const ref of associatedRefs) {\n const key = siteStandardRecordKey(ref.uri, ref.cid)\n if (!document) {\n const hit = documents?.get(key)\n if (hit) document = { ref, info: hit }\n }\n if (!publication) {\n const hit = publications?.get(key)\n if (hit) publication = { ref, info: hit }\n }\n if (document && publication) break\n }\n\n // Both refs resolved: enforce that the doc's `site` actually points at\n // the supplied publication. Mismatch means the post was misconstructed\n // (or tampered with), so reject the whole pairing.\n if (document && publication) {\n if (document.info.record.site !== publication.ref.uri) {\n hydrationLogger.warn(\n {\n documentUri: document.ref.uri,\n documentSite: document.info.record.site,\n publicationUri: publication.ref.uri,\n },\n 'site.standard byRefs lookup failed: doc.site does not match hydrated publication.uri',\n )\n return { document: undefined, publication: undefined }\n }\n }\n\n // Doc with at-uri `site` but no publication: the post should have\n // pinned the publication too. Treat as misconstructed — same contract\n // as the compose-path lookup.\n if (document && !publication) {\n const site = document.info.record.site\n if (site && site.startsWith('at://')) {\n hydrationLogger.warn(\n { documentUri: document.ref.uri, documentSite: site },\n 'site.standard byRefs lookup failed: document.site is AT URI but no matching publication was hydrated',\n )\n return { document: undefined, publication: undefined }\n }\n }\n\n return { document, publication }\n}\n\n/**\n * Compose-path resolution: no caller-supplied refs — the dataplane\n * returned the latest version of each record (including any\n * publications it auto-resolved from a document's `site` field). Take\n * the first hydrated document and pair it with the publication its\n * `site` field points at.\n *\n * Same observable contract as\n * `getSiteStandardRecordsFromHydrationMapsByRefs` (the read-path\n * sister) — both functions guarantee that a returned `(doc, pub)` pair\n * has matching site/uri, and reject orphan docs that claim a\n * non-hydrated publication. They differ only in how upstream\n * availability is asserted: this one walks whatever was returned by the\n * dataplane; the sister checks against caller-supplied refs.\n *\n * Pairing rules:\n * - Doc with at-uri `site`: must find a hydrated publication at that\n * URI. If none was hydrated, the doc/publication chain is incomplete\n * and the function returns `undefined` for both slots; the doc alone\n * isn't useful without its source (can't verify the pub)\n * - Doc with web-URL `site` (loose): no publication.\n * - No doc hydrated: fall through to the first hydrated publication for\n * the publication-only resolution flow.\n */\nexport const getSiteStandardRecordsFromHydrationMapsByDocumentUri = (\n documents: SiteStandardDocuments | undefined,\n publications: SiteStandardPublications | undefined,\n): {\n document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n publication: AssociatedSiteStandardRecord<SiteStandardPublication> | undefined\n} => {\n // First hydrated doc.\n let document: AssociatedSiteStandardRecord<SiteStandardDocument> | undefined\n for (const [key, info] of documents ?? []) {\n if (!info) continue\n document = { ref: parseSiteStandardRecordKey(key), info }\n break\n }\n\n let publication:\n | AssociatedSiteStandardRecord<SiteStandardPublication>\n | undefined\n if (document) {\n const site = document.info.record.site\n if (site && site.startsWith('at://')) {\n // Doc declared an at-uri publication; we need it.\n for (const [key, info] of publications ?? []) {\n if (!info) continue\n const ref = parseSiteStandardRecordKey(key)\n if (ref.uri === site) {\n publication = { ref, info }\n break\n }\n }\n if (!publication) {\n hydrationLogger.warn(\n { documentUri: document.ref.uri, documentSite: site },\n 'site.standard byDocumentUri lookup failed: document.site is AT URI but no matching publication was hydrated',\n )\n return { document: undefined, publication: undefined }\n }\n }\n // else: loose doc (web-URL site), no publication needed.\n } else {\n // Publication-only flow: no doc, take the first hydrated publication.\n for (const [key, info] of publications ?? []) {\n if (!info) continue\n publication = { ref: parseSiteStandardRecordKey(key), info }\n break\n }\n }\n\n return { document, publication }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"hydrator.d.ts","sourceRoot":"","sources":["../../src/hydration/hydrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hydrator.d.ts","sourceRoot":"","sources":["../../src/hydration/hydrator.ts"],"names":[],"mappings":"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"}
@@ -328,6 +328,15 @@ export class Hydrator {
328
328
  }
329
329
  const siteStandardRefs = siteStandardRefsFromPosts(postsLayer0, postsLayer1, postsLayer2);
330
330
  const siteStandardLabelSubjects = dedupeStrs(siteStandardRefs.map((ref) => ref.uri));
331
+ // Site-standard record owners need profile basics so we can populate
332
+ // `associatedProfiles` on the external embed view. Include them in the
333
+ // post-author profile fetch below; any DIDs surfaced later by the
334
+ // dataplane are picked up by the top-up after the parallel batch.
335
+ const ssRefDids = siteStandardRefs.map((ref) => uriToDid(ref.uri));
336
+ const knownProfileDids = dedupeStrs([
337
+ ...allPostUris.map(didFromUri),
338
+ ...ssRefDids,
339
+ ]);
331
340
  const [postAggs, postViewers, labels, postBlocks, profileState, listState, feedGenState, labelerState, starterPackState, postgates, { documents: siteStandardDocuments, publications: siteStandardPublications, },] = await Promise.all([
332
341
  this.feed.getPostAggregates(allRefs, ctx.viewer),
333
342
  ctx.viewer
@@ -335,7 +344,7 @@ export class Hydrator {
335
344
  : undefined,
336
345
  this.label.getLabelsForSubjects([...allPostUris, ...siteStandardLabelSubjects], ctx.labelers),
337
346
  this.hydratePostBlocks(posts, ctx),
338
- this.hydrateProfiles(allPostUris.map(didFromUri), ctx),
347
+ this.hydrateProfiles(knownProfileDids, ctx),
339
348
  this.hydrateLists([...nestedListUris, ...threadgateListUris], ctx),
340
349
  this.hydrateFeedGens(nestedFeedGenUris, ctx),
341
350
  this.hydrateLabelers(nestedLabelerDids, ctx),
@@ -347,8 +356,23 @@ export class Hydrator {
347
356
  actionTakedownLabels(allPostUris, posts, labels);
348
357
  actionSiteStandardTakedownLabels(siteStandardDocuments, siteStandardPublications, labels);
349
358
  }
359
+ // Defensive top-up: in the unlikely case the dataplane returned a
360
+ // publication owned by a DID not present in the post-author or
361
+ // pinned-ref sets, fetch its profile serially and fold it in.
362
+ const knownProfileDidsSet = new Set(knownProfileDids);
363
+ const extraSsDids = [];
364
+ for (const key of siteStandardPublications.keys()) {
365
+ const did = uriToDid(parseSiteStandardRecordKey(key).uri);
366
+ if (!knownProfileDidsSet.has(did)) {
367
+ knownProfileDidsSet.add(did);
368
+ extraSsDids.push(did);
369
+ }
370
+ }
371
+ const mergedProfileState = extraSsDids.length
372
+ ? mergeStates(profileState, await this.hydrateProfilesBasic(extraSsDids, ctx))
373
+ : profileState;
350
374
  // combine all hydration state
351
- return mergeManyStates(profileState, listState, feedGenState, labelerState, starterPackState, {
375
+ return mergeManyStates(mergedProfileState, listState, feedGenState, labelerState, starterPackState, {
352
376
  posts,
353
377
  postAggs,
354
378
  postViewers,
@@ -469,19 +493,38 @@ export class Hydrator {
469
493
  const ssUris = dedupeStrs(uris.filter((u) => new AtUri(u).collection.startsWith(SITE_STANDARD_NSID_PREFIX)));
470
494
  if (!ssUris.length)
471
495
  return { ctx };
472
- const [{ documents, publications }, labels] = await Promise.all([
496
+ const dids = dedupeStrs(ssUris.map((uri) => uriToDid(uri)));
497
+ const [{ documents, publications }, labels, profiles] = await Promise.all([
473
498
  this.external.getSiteStandardRecordsByURI(ssUris, ctx.includeTakedowns),
474
499
  this.label.getLabelsForSubjects(ssUris, ctx.labelers),
500
+ this.hydrateProfilesBasic(dids, ctx),
475
501
  ]);
476
502
  if (!ctx.includeTakedowns) {
477
503
  actionSiteStandardTakedownLabels(documents, publications, labels);
478
504
  }
479
- return {
505
+ // Edge case: a document's `site` may resolve to a publication owned by a
506
+ // different repo than any of the input URIs (the dataplane returns it
507
+ // even though it wasn't requested directly). Top up profile coverage for
508
+ // any such DIDs with a serial second hydration so `associatedProfiles`
509
+ // is complete.
510
+ const knownDids = new Set(dids);
511
+ const extraDids = [];
512
+ for (const key of publications.keys()) {
513
+ const did = uriToDid(parseSiteStandardRecordKey(key).uri);
514
+ if (!knownDids.has(did)) {
515
+ knownDids.add(did);
516
+ extraDids.push(did);
517
+ }
518
+ }
519
+ const profilesState = extraDids.length
520
+ ? mergeStates(profiles, await this.hydrateProfilesBasic(extraDids, ctx))
521
+ : profiles;
522
+ return mergeStates(profilesState, {
480
523
  ctx,
481
524
  labels,
482
525
  siteStandardDocuments: documents,
483
526
  siteStandardPublications: publications,
484
- };
527
+ });
485
528
  }
486
529
  // app.bsky.feed.defs#threadViewPost
487
530
  // - post