@atproto/bsky 0.0.194 → 0.0.195
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.
- package/CHANGELOG.md +10 -0
- package/dist/api/app/bsky/feed/searchPosts.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/searchPosts.js +43 -12
- package/dist/api/app/bsky/feed/searchPosts.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getPostThreadOtherV2.js +1 -2
- package/dist/api/app/bsky/unspecced/getPostThreadOtherV2.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getPostThreadV2.js +0 -1
- package/dist/api/app/bsky/unspecced/getPostThreadV2.js.map +1 -1
- package/dist/auth-verifier.d.ts +1 -0
- package/dist/auth-verifier.d.ts.map +1 -1
- package/dist/auth-verifier.js +4 -0
- package/dist/auth-verifier.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/data-plane/server/routes/search.d.ts.map +1 -1
- package/dist/data-plane/server/routes/search.js +15 -1
- package/dist/data-plane/server/routes/search.js.map +1 -1
- package/dist/data-plane/server/util.d.ts +7 -0
- package/dist/data-plane/server/util.d.ts.map +1 -1
- package/dist/data-plane/server/util.js +38 -1
- package/dist/data-plane/server/util.js.map +1 -1
- package/dist/lexicon/index.d.ts +2 -0
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +4 -0
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +98 -28
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +52 -14
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts +0 -2
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/actor/defs.js.map +1 -1
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.d.ts +0 -2
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.js.map +1 -1
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.d.ts +0 -2
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.js.map +1 -1
- package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.d.ts +28 -0
- package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.d.ts.map +1 -0
- package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.js +7 -0
- package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.js.map +1 -0
- package/dist/views/index.d.ts +2 -4
- package/dist/views/index.d.ts.map +1 -1
- package/dist/views/index.js +8 -14
- package/dist/views/index.js.map +1 -1
- package/dist/views/threads-v2.d.ts +0 -1
- package/dist/views/threads-v2.d.ts.map +1 -1
- package/dist/views/threads-v2.js +2 -4
- package/dist/views/threads-v2.js.map +1 -1
- package/package.json +5 -5
- package/src/api/app/bsky/feed/searchPosts.ts +51 -10
- package/src/api/app/bsky/unspecced/getPostThreadOtherV2.ts +1 -2
- package/src/api/app/bsky/unspecced/getPostThreadV2.ts +0 -1
- package/src/auth-verifier.ts +5 -0
- package/src/config.ts +8 -0
- package/src/data-plane/server/routes/search.ts +18 -1
- package/src/data-plane/server/util.ts +51 -0
- package/src/lexicon/index.ts +13 -0
- package/src/lexicon/lexicons.ts +52 -16
- package/src/lexicon/types/app/bsky/actor/defs.ts +0 -2
- package/src/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.ts +0 -2
- package/src/lexicon/types/app/bsky/unspecced/getPostThreadV2.ts +0 -2
- package/src/lexicon/types/com/atproto/lexicon/resolveLexicon.ts +46 -0
- package/src/views/index.ts +3 -23
- package/src/views/threads-v2.ts +2 -12
- package/tests/utils.test.ts +45 -0
- package/tests/views/post-search.test.ts +221 -0
- package/tests/views/thread-v2.test.ts +2 -109
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.tests.tsbuildinfo +1 -1
|
@@ -56,7 +56,6 @@ export declare function sortTrimFlattenThreadTree(anchorTree: ThreadTree, option
|
|
|
56
56
|
type SortTrimFlattenOptions = {
|
|
57
57
|
branchingFactor: GetPostThreadV2QueryParams['branchingFactor'];
|
|
58
58
|
opDid: string;
|
|
59
|
-
prioritizeFollowedUsers: boolean;
|
|
60
59
|
sort?: GetPostThreadV2QueryParams['sort'];
|
|
61
60
|
viewer: HydrateCtx['viewer'];
|
|
62
61
|
threadTagsBumpDown: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threads-v2.d.ts","sourceRoot":"","sources":["../../src/views/threads-v2.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"threads-v2.d.ts","sourceRoot":"","sources":["../../src/views/threads-v2.ts"],"names":[],"mappings":"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"}
|
package/dist/views/threads-v2.js
CHANGED
|
@@ -50,7 +50,7 @@ function applyBumping(aNode, bNode, opts) {
|
|
|
50
50
|
if (!isPostNode(bNode)) {
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
|
-
const { opDid,
|
|
53
|
+
const { opDid, viewer, threadTagsBumpDown, threadTagsHide } = opts;
|
|
54
54
|
const maybeBump = (bump, predicateFn) => {
|
|
55
55
|
const aPredicate = predicateFn(aNode);
|
|
56
56
|
const bPredicate = predicateFn(bNode);
|
|
@@ -82,9 +82,7 @@ function applyBumping(aNode, bNode, opts) {
|
|
|
82
82
|
// Followers posts.
|
|
83
83
|
[
|
|
84
84
|
'up',
|
|
85
|
-
(i) => i.type === 'post' &&
|
|
86
|
-
prioritizeFollowedUsers &&
|
|
87
|
-
!!i.item.value.post.author.viewer?.following,
|
|
85
|
+
(i) => i.type === 'post' && !!i.item.value.post.author.viewer?.following,
|
|
88
86
|
],
|
|
89
87
|
// Bump-down tags.
|
|
90
88
|
[
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threads-v2.js","sourceRoot":"","sources":["../../src/views/threads-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import { asPredicate } from '@atproto/api'\nimport { HydrateCtx } from '../hydration/hydrator'\nimport { validateRecord as validatePostRecord } from '../lexicon/types/app/bsky/feed/post'\nimport {\n ThreadItemBlocked,\n ThreadItemNoUnauthenticated,\n ThreadItemNotFound,\n ThreadItemPost,\n} from '../lexicon/types/app/bsky/unspecced/defs'\nimport { ThreadItem as ThreadOtherItem } from '../lexicon/types/app/bsky/unspecced/getPostThreadOtherV2'\nimport {\n QueryParams as GetPostThreadV2QueryParams,\n ThreadItem,\n} from '../lexicon/types/app/bsky/unspecced/getPostThreadV2'\nimport { $Typed } from '../lexicon/util'\n\ntype ThreadMaybeOtherPostNode = ThreadPostNode | ThreadOtherPostNode\ntype ThreadNodeWithReplies =\n | ThreadPostNode\n | ThreadOtherPostNode\n | ThreadOtherAnchorPostNode\n\ntype ThreadItemValue<T extends ThreadItem['value']> = Omit<\n ThreadItem,\n 'value'\n> & {\n value: T\n}\n\nexport type ThreadItemValueBlocked = ThreadItemValue<$Typed<ThreadItemBlocked>>\n\nexport type ThreadItemValueNoUnauthenticated = ThreadItemValue<\n $Typed<ThreadItemNoUnauthenticated>\n>\n\nexport type ThreadItemValueNotFound = ThreadItemValue<\n $Typed<ThreadItemNotFound>\n>\n\nexport type ThreadItemValuePost = ThreadItemValue<$Typed<ThreadItemPost>>\n\ntype ThreadBlockedNode = {\n type: 'blocked'\n item: ThreadItemValueBlocked\n}\ntype ThreadNoUnauthenticatedNode = {\n type: 'noUnauthenticated'\n parent: ThreadTree | undefined\n item: ThreadItemValueNoUnauthenticated\n}\n\ntype ThreadNotFoundNode = {\n type: 'notFound'\n item: ThreadItemValueNotFound\n}\n\ntype ThreadPostNode = {\n type: 'post'\n item: ThreadItemValuePost\n tags: Set<string>\n hasOPLike: boolean\n parent: ThreadTree | undefined\n replies: ThreadTree[] | undefined\n}\n\ntype ThreadOtherItemValue<T extends ThreadOtherItem['value']> = Omit<\n ThreadOtherItem,\n 'value'\n> & {\n value: T\n}\n\nexport type ThreadOtherItemValuePost = ThreadOtherItemValue<\n $Typed<ThreadItemPost>\n>\n\n// This is an intermediary type that doesn't map to the views.\n// It is useful to differentiate between the anchor post and the replies for the hidden case,\n// while also differentiating between hidden and visible cases.\nexport type ThreadOtherAnchorPostNode = {\n type: 'hiddenAnchor'\n item: Omit<ThreadOtherItem, 'value'> & { value: undefined }\n replies: ThreadOtherPostNode[] | undefined\n}\n\nexport type ThreadOtherPostNode = {\n type: 'hiddenPost'\n item: ThreadOtherItemValuePost\n tags: Set<string>\n replies: ThreadOtherPostNode[] | undefined\n}\n\nconst isNodeWithReplies = (node: ThreadTree): node is ThreadNodeWithReplies =>\n 'replies' in node && node.replies !== undefined\n\nconst isPostNode = (node: ThreadTree): node is ThreadMaybeOtherPostNode =>\n node.type === 'post' || node.type === 'hiddenPost'\n\nexport type ThreadTreeVisible =\n | ThreadBlockedNode\n | ThreadNoUnauthenticatedNode\n | ThreadNotFoundNode\n | ThreadPostNode\n\nexport type ThreadTreeOther = ThreadOtherAnchorPostNode | ThreadOtherPostNode\n\nexport type ThreadTree = ThreadTreeVisible | ThreadTreeOther\n\n/** This function mutates the tree parameter. */\nexport function sortTrimFlattenThreadTree(\n anchorTree: ThreadTree,\n options: SortTrimFlattenOptions,\n) {\n const sortedAnchorTree = sortTrimThreadTree(anchorTree, options)\n\n return flattenTree(sortedAnchorTree)\n}\n\ntype SortTrimFlattenOptions = {\n branchingFactor: GetPostThreadV2QueryParams['branchingFactor']\n opDid: string\n prioritizeFollowedUsers: boolean\n sort?: GetPostThreadV2QueryParams['sort']\n viewer: HydrateCtx['viewer']\n threadTagsBumpDown: readonly string[]\n threadTagsHide: readonly string[]\n}\n\nconst isPostRecord = asPredicate(validatePostRecord)\n\n/** This function mutates the tree parameter. */\nfunction sortTrimThreadTree(\n n: ThreadTree,\n opts: SortTrimFlattenOptions,\n): ThreadTree {\n if (!isNodeWithReplies(n)) {\n return n\n }\n const node: ThreadNodeWithReplies = n\n\n if (node.replies) {\n node.replies.sort((an: ThreadTree, bn: ThreadTree) => {\n if (!isPostNode(an)) {\n return 1\n }\n if (!isPostNode(bn)) {\n return -1\n }\n const aNode: ThreadMaybeOtherPostNode = an\n const bNode: ThreadMaybeOtherPostNode = bn\n\n // First applies bumping.\n const bump = applyBumping(aNode, bNode, opts)\n if (bump !== null) {\n return bump\n }\n\n // Then applies sorting.\n return applySorting(aNode, bNode, opts)\n })\n\n // Trimming: after sorting, apply branching factor to all levels of replies except the anchor direct replies.\n if (node.item.depth !== 0) {\n node.replies = node.replies.slice(0, opts.branchingFactor)\n }\n\n node.replies.forEach((reply) => sortTrimThreadTree(reply, opts))\n }\n\n return node\n}\n\nfunction applyBumping(\n aNode: ThreadMaybeOtherPostNode,\n bNode: ThreadMaybeOtherPostNode,\n opts: SortTrimFlattenOptions,\n): number | null {\n if (!isPostNode(aNode)) {\n return null\n }\n if (!isPostNode(bNode)) {\n return null\n }\n\n const {\n opDid,\n prioritizeFollowedUsers,\n viewer,\n threadTagsBumpDown,\n threadTagsHide,\n } = opts\n\n type BumpDirection = 'up' | 'down'\n type BumpPredicateFn = (i: ThreadMaybeOtherPostNode) => boolean\n\n const maybeBump = (\n bump: BumpDirection,\n predicateFn: BumpPredicateFn,\n ): number | null => {\n const aPredicate = predicateFn(aNode)\n const bPredicate = predicateFn(bNode)\n if (aPredicate && bPredicate) {\n return applySorting(aNode, bNode, opts)\n } else if (aPredicate) {\n return bump === 'up' ? -1 : 1\n } else if (bPredicate) {\n return bump === 'up' ? 1 : -1\n }\n return null\n }\n\n // The order of the bumps determines the priority with which they are applied.\n // Bumps-up applied first make the item appear higher in the list than later bumps-up.\n // Bumps-down applied first make the item appear lower in the list than later bumps-down.\n const bumps: [BumpDirection, BumpPredicateFn][] = [\n /*\n General bumps.\n */\n // OP replies.\n ['up', (i) => i.item.value.post.author.did === opDid],\n // Viewer replies.\n ['up', (i) => i.item.value.post.author.did === viewer],\n\n /*\n Bumps within visible replies.\n */\n // Followers posts.\n [\n 'up',\n (i) =>\n i.type === 'post' &&\n prioritizeFollowedUsers &&\n !!i.item.value.post.author.viewer?.following,\n ],\n // Bump-down tags.\n [\n 'down',\n (i) => i.type === 'post' && threadTagsBumpDown.some((t) => i.tags.has(t)),\n ],\n // Pushpin-only.\n [\n 'down',\n (i) =>\n i.type === 'post' &&\n isPostRecord(i.item.value.post.record) &&\n i.item.value.post.record.text.trim() === '📌',\n ],\n\n /*\n Bumps within hidden replies.\n This determines the order of hidden replies:\n 1. hidden by threadgate.\n 2. hidden by tags.\n 3. muted by viewer.\n */\n // Muted account by the viewer.\n ['down', (i) => i.type === 'hiddenPost' && i.item.value.mutedByViewer],\n // Hidden by tags.\n [\n 'down',\n (i) =>\n i.type === 'hiddenPost' && threadTagsHide.some((t) => i.tags.has(t)),\n ],\n // Hidden by threadgate.\n ['down', (i) => i.type === 'hiddenPost' && i.item.value.hiddenByThreadgate],\n ]\n\n for (const [bump, predicateFn] of bumps) {\n const bumpResult = maybeBump(bump, predicateFn)\n if (bumpResult !== null) {\n return bumpResult\n }\n }\n\n return null\n}\n\nfunction applySorting(\n aNode: ThreadMaybeOtherPostNode,\n bNode: ThreadMaybeOtherPostNode,\n opts: SortTrimFlattenOptions,\n): number {\n const a = aNode.item.value\n const b = bNode.item.value\n\n // Only customize sort for visible posts.\n if (aNode.type === 'post' && bNode.type === 'post') {\n const { sort } = opts\n\n if (sort === 'oldest') {\n return a.post.indexedAt.localeCompare(b.post.indexedAt)\n }\n if (sort === 'top') {\n const aLikes = a.post.likeCount ?? 0\n const bLikes = b.post.likeCount ?? 0\n const aTop = topSortValue(aLikes, aNode.hasOPLike)\n const bTop = topSortValue(bLikes, bNode.hasOPLike)\n if (aTop !== bTop) {\n return bTop - aTop\n }\n }\n }\n\n // Fallback to newest.\n return b.post.indexedAt.localeCompare(a.post.indexedAt)\n}\n\nfunction topSortValue(likeCount: number, hasOPLike: boolean): number {\n return Math.log(3 + likeCount) * (hasOPLike ? 1.45 : 1.0)\n}\n\nfunction flattenTree(tree: ThreadTree) {\n return [\n // All parents above.\n ...Array.from(\n flattenInDirection({\n tree,\n direction: 'up',\n }),\n ),\n\n // The anchor.\n // In the case of hidden replies, the anchor item itself is undefined.\n ...(tree.item.value ? [tree.item] : []),\n\n // All replies below.\n ...Array.from(\n flattenInDirection({\n tree,\n direction: 'down',\n }),\n ),\n ]\n}\n\nfunction* flattenInDirection({\n tree,\n direction,\n}: {\n tree: ThreadTree\n direction: 'up' | 'down'\n}) {\n if (tree.type === 'noUnauthenticated') {\n if (direction === 'up') {\n if (tree.parent) {\n // Unfold all parents above.\n yield* flattenTree(tree.parent)\n }\n }\n }\n\n if (tree.type === 'post') {\n if (direction === 'up') {\n if (tree.parent) {\n // Unfold all parents above.\n yield* flattenTree(tree.parent)\n }\n } else {\n // Unfold all replies below.\n if (tree.replies?.length) {\n for (const reply of tree.replies) {\n yield* flattenTree(reply)\n }\n }\n }\n }\n\n // For the first level of hidden replies, the items are undefined.\n if (tree.type === 'hiddenAnchor' || tree.type === 'hiddenPost') {\n if (direction === 'down') {\n // Unfold all replies below.\n if (tree.replies?.length) {\n for (const reply of tree.replies) {\n yield* flattenTree(reply)\n }\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"threads-v2.js","sourceRoot":"","sources":["../../src/views/threads-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import { asPredicate } from '@atproto/api'\nimport { HydrateCtx } from '../hydration/hydrator'\nimport { validateRecord as validatePostRecord } from '../lexicon/types/app/bsky/feed/post'\nimport {\n ThreadItemBlocked,\n ThreadItemNoUnauthenticated,\n ThreadItemNotFound,\n ThreadItemPost,\n} from '../lexicon/types/app/bsky/unspecced/defs'\nimport { ThreadItem as ThreadOtherItem } from '../lexicon/types/app/bsky/unspecced/getPostThreadOtherV2'\nimport {\n QueryParams as GetPostThreadV2QueryParams,\n ThreadItem,\n} from '../lexicon/types/app/bsky/unspecced/getPostThreadV2'\nimport { $Typed } from '../lexicon/util'\n\ntype ThreadMaybeOtherPostNode = ThreadPostNode | ThreadOtherPostNode\ntype ThreadNodeWithReplies =\n | ThreadPostNode\n | ThreadOtherPostNode\n | ThreadOtherAnchorPostNode\n\ntype ThreadItemValue<T extends ThreadItem['value']> = Omit<\n ThreadItem,\n 'value'\n> & {\n value: T\n}\n\nexport type ThreadItemValueBlocked = ThreadItemValue<$Typed<ThreadItemBlocked>>\n\nexport type ThreadItemValueNoUnauthenticated = ThreadItemValue<\n $Typed<ThreadItemNoUnauthenticated>\n>\n\nexport type ThreadItemValueNotFound = ThreadItemValue<\n $Typed<ThreadItemNotFound>\n>\n\nexport type ThreadItemValuePost = ThreadItemValue<$Typed<ThreadItemPost>>\n\ntype ThreadBlockedNode = {\n type: 'blocked'\n item: ThreadItemValueBlocked\n}\ntype ThreadNoUnauthenticatedNode = {\n type: 'noUnauthenticated'\n parent: ThreadTree | undefined\n item: ThreadItemValueNoUnauthenticated\n}\n\ntype ThreadNotFoundNode = {\n type: 'notFound'\n item: ThreadItemValueNotFound\n}\n\ntype ThreadPostNode = {\n type: 'post'\n item: ThreadItemValuePost\n tags: Set<string>\n hasOPLike: boolean\n parent: ThreadTree | undefined\n replies: ThreadTree[] | undefined\n}\n\ntype ThreadOtherItemValue<T extends ThreadOtherItem['value']> = Omit<\n ThreadOtherItem,\n 'value'\n> & {\n value: T\n}\n\nexport type ThreadOtherItemValuePost = ThreadOtherItemValue<\n $Typed<ThreadItemPost>\n>\n\n// This is an intermediary type that doesn't map to the views.\n// It is useful to differentiate between the anchor post and the replies for the hidden case,\n// while also differentiating between hidden and visible cases.\nexport type ThreadOtherAnchorPostNode = {\n type: 'hiddenAnchor'\n item: Omit<ThreadOtherItem, 'value'> & { value: undefined }\n replies: ThreadOtherPostNode[] | undefined\n}\n\nexport type ThreadOtherPostNode = {\n type: 'hiddenPost'\n item: ThreadOtherItemValuePost\n tags: Set<string>\n replies: ThreadOtherPostNode[] | undefined\n}\n\nconst isNodeWithReplies = (node: ThreadTree): node is ThreadNodeWithReplies =>\n 'replies' in node && node.replies !== undefined\n\nconst isPostNode = (node: ThreadTree): node is ThreadMaybeOtherPostNode =>\n node.type === 'post' || node.type === 'hiddenPost'\n\nexport type ThreadTreeVisible =\n | ThreadBlockedNode\n | ThreadNoUnauthenticatedNode\n | ThreadNotFoundNode\n | ThreadPostNode\n\nexport type ThreadTreeOther = ThreadOtherAnchorPostNode | ThreadOtherPostNode\n\nexport type ThreadTree = ThreadTreeVisible | ThreadTreeOther\n\n/** This function mutates the tree parameter. */\nexport function sortTrimFlattenThreadTree(\n anchorTree: ThreadTree,\n options: SortTrimFlattenOptions,\n) {\n const sortedAnchorTree = sortTrimThreadTree(anchorTree, options)\n\n return flattenTree(sortedAnchorTree)\n}\n\ntype SortTrimFlattenOptions = {\n branchingFactor: GetPostThreadV2QueryParams['branchingFactor']\n opDid: string\n sort?: GetPostThreadV2QueryParams['sort']\n viewer: HydrateCtx['viewer']\n threadTagsBumpDown: readonly string[]\n threadTagsHide: readonly string[]\n}\n\nconst isPostRecord = asPredicate(validatePostRecord)\n\n/** This function mutates the tree parameter. */\nfunction sortTrimThreadTree(\n n: ThreadTree,\n opts: SortTrimFlattenOptions,\n): ThreadTree {\n if (!isNodeWithReplies(n)) {\n return n\n }\n const node: ThreadNodeWithReplies = n\n\n if (node.replies) {\n node.replies.sort((an: ThreadTree, bn: ThreadTree) => {\n if (!isPostNode(an)) {\n return 1\n }\n if (!isPostNode(bn)) {\n return -1\n }\n const aNode: ThreadMaybeOtherPostNode = an\n const bNode: ThreadMaybeOtherPostNode = bn\n\n // First applies bumping.\n const bump = applyBumping(aNode, bNode, opts)\n if (bump !== null) {\n return bump\n }\n\n // Then applies sorting.\n return applySorting(aNode, bNode, opts)\n })\n\n // Trimming: after sorting, apply branching factor to all levels of replies except the anchor direct replies.\n if (node.item.depth !== 0) {\n node.replies = node.replies.slice(0, opts.branchingFactor)\n }\n\n node.replies.forEach((reply) => sortTrimThreadTree(reply, opts))\n }\n\n return node\n}\n\nfunction applyBumping(\n aNode: ThreadMaybeOtherPostNode,\n bNode: ThreadMaybeOtherPostNode,\n opts: SortTrimFlattenOptions,\n): number | null {\n if (!isPostNode(aNode)) {\n return null\n }\n if (!isPostNode(bNode)) {\n return null\n }\n\n const { opDid, viewer, threadTagsBumpDown, threadTagsHide } = opts\n\n type BumpDirection = 'up' | 'down'\n type BumpPredicateFn = (i: ThreadMaybeOtherPostNode) => boolean\n\n const maybeBump = (\n bump: BumpDirection,\n predicateFn: BumpPredicateFn,\n ): number | null => {\n const aPredicate = predicateFn(aNode)\n const bPredicate = predicateFn(bNode)\n if (aPredicate && bPredicate) {\n return applySorting(aNode, bNode, opts)\n } else if (aPredicate) {\n return bump === 'up' ? -1 : 1\n } else if (bPredicate) {\n return bump === 'up' ? 1 : -1\n }\n return null\n }\n\n // The order of the bumps determines the priority with which they are applied.\n // Bumps-up applied first make the item appear higher in the list than later bumps-up.\n // Bumps-down applied first make the item appear lower in the list than later bumps-down.\n const bumps: [BumpDirection, BumpPredicateFn][] = [\n /*\n General bumps.\n */\n // OP replies.\n ['up', (i) => i.item.value.post.author.did === opDid],\n // Viewer replies.\n ['up', (i) => i.item.value.post.author.did === viewer],\n\n /*\n Bumps within visible replies.\n */\n // Followers posts.\n [\n 'up',\n (i) => i.type === 'post' && !!i.item.value.post.author.viewer?.following,\n ],\n // Bump-down tags.\n [\n 'down',\n (i) => i.type === 'post' && threadTagsBumpDown.some((t) => i.tags.has(t)),\n ],\n // Pushpin-only.\n [\n 'down',\n (i) =>\n i.type === 'post' &&\n isPostRecord(i.item.value.post.record) &&\n i.item.value.post.record.text.trim() === '📌',\n ],\n\n /*\n Bumps within hidden replies.\n This determines the order of hidden replies:\n 1. hidden by threadgate.\n 2. hidden by tags.\n 3. muted by viewer.\n */\n // Muted account by the viewer.\n ['down', (i) => i.type === 'hiddenPost' && i.item.value.mutedByViewer],\n // Hidden by tags.\n [\n 'down',\n (i) =>\n i.type === 'hiddenPost' && threadTagsHide.some((t) => i.tags.has(t)),\n ],\n // Hidden by threadgate.\n ['down', (i) => i.type === 'hiddenPost' && i.item.value.hiddenByThreadgate],\n ]\n\n for (const [bump, predicateFn] of bumps) {\n const bumpResult = maybeBump(bump, predicateFn)\n if (bumpResult !== null) {\n return bumpResult\n }\n }\n\n return null\n}\n\nfunction applySorting(\n aNode: ThreadMaybeOtherPostNode,\n bNode: ThreadMaybeOtherPostNode,\n opts: SortTrimFlattenOptions,\n): number {\n const a = aNode.item.value\n const b = bNode.item.value\n\n // Only customize sort for visible posts.\n if (aNode.type === 'post' && bNode.type === 'post') {\n const { sort } = opts\n\n if (sort === 'oldest') {\n return a.post.indexedAt.localeCompare(b.post.indexedAt)\n }\n if (sort === 'top') {\n const aLikes = a.post.likeCount ?? 0\n const bLikes = b.post.likeCount ?? 0\n const aTop = topSortValue(aLikes, aNode.hasOPLike)\n const bTop = topSortValue(bLikes, bNode.hasOPLike)\n if (aTop !== bTop) {\n return bTop - aTop\n }\n }\n }\n\n // Fallback to newest.\n return b.post.indexedAt.localeCompare(a.post.indexedAt)\n}\n\nfunction topSortValue(likeCount: number, hasOPLike: boolean): number {\n return Math.log(3 + likeCount) * (hasOPLike ? 1.45 : 1.0)\n}\n\nfunction flattenTree(tree: ThreadTree) {\n return [\n // All parents above.\n ...Array.from(\n flattenInDirection({\n tree,\n direction: 'up',\n }),\n ),\n\n // The anchor.\n // In the case of hidden replies, the anchor item itself is undefined.\n ...(tree.item.value ? [tree.item] : []),\n\n // All replies below.\n ...Array.from(\n flattenInDirection({\n tree,\n direction: 'down',\n }),\n ),\n ]\n}\n\nfunction* flattenInDirection({\n tree,\n direction,\n}: {\n tree: ThreadTree\n direction: 'up' | 'down'\n}) {\n if (tree.type === 'noUnauthenticated') {\n if (direction === 'up') {\n if (tree.parent) {\n // Unfold all parents above.\n yield* flattenTree(tree.parent)\n }\n }\n }\n\n if (tree.type === 'post') {\n if (direction === 'up') {\n if (tree.parent) {\n // Unfold all parents above.\n yield* flattenTree(tree.parent)\n }\n } else {\n // Unfold all replies below.\n if (tree.replies?.length) {\n for (const reply of tree.replies) {\n yield* flattenTree(reply)\n }\n }\n }\n }\n\n // For the first level of hidden replies, the items are undefined.\n if (tree.type === 'hiddenAnchor' || tree.type === 'hiddenPost') {\n if (direction === 'down') {\n // Unfold all replies below.\n if (tree.replies?.length) {\n for (const reply of tree.replies) {\n yield* flattenTree(reply)\n }\n }\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/bsky",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.195",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Reference implementation of app.bsky App View (Bluesky API)",
|
|
6
6
|
"keywords": [
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
"zod": "3.23.8",
|
|
54
54
|
"@atproto-labs/fetch-node": "0.2.0",
|
|
55
55
|
"@atproto-labs/xrpc-utils": "0.0.22",
|
|
56
|
-
"@atproto/api": "^0.
|
|
56
|
+
"@atproto/api": "^0.18.0",
|
|
57
57
|
"@atproto/common": "^0.4.12",
|
|
58
58
|
"@atproto/crypto": "^0.4.4",
|
|
59
59
|
"@atproto/did": "^0.2.1",
|
|
60
60
|
"@atproto/identity": "^0.4.9",
|
|
61
61
|
"@atproto/lexicon": "^0.5.1",
|
|
62
62
|
"@atproto/repo": "^0.8.10",
|
|
63
|
-
"@atproto/sync": "^0.1.
|
|
63
|
+
"@atproto/sync": "^0.1.36",
|
|
64
64
|
"@atproto/syntax": "^0.4.1",
|
|
65
65
|
"@atproto/xrpc-server": "^0.9.5"
|
|
66
66
|
},
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
"jest": "^28.1.2",
|
|
78
78
|
"ts-node": "^10.8.2",
|
|
79
79
|
"typescript": "^5.6.3",
|
|
80
|
-
"@atproto/api": "^0.
|
|
80
|
+
"@atproto/api": "^0.18.0",
|
|
81
81
|
"@atproto/lex-cli": "^0.9.6",
|
|
82
|
-
"@atproto/pds": "^0.4.
|
|
82
|
+
"@atproto/pds": "^0.4.192",
|
|
83
83
|
"@atproto/xrpc": "^0.7.5"
|
|
84
84
|
},
|
|
85
85
|
"scripts": {
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { AtpAgent } from '@atproto/api'
|
|
2
2
|
import { mapDefined } from '@atproto/common'
|
|
3
|
+
import { ServerConfig } from '../../../../config'
|
|
3
4
|
import { AppContext } from '../../../../context'
|
|
4
5
|
import { DataPlaneClient } from '../../../../data-plane'
|
|
6
|
+
import {
|
|
7
|
+
PostSearchQuery,
|
|
8
|
+
parsePostSearchQuery,
|
|
9
|
+
} from '../../../../data-plane/server/util'
|
|
5
10
|
import { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'
|
|
6
11
|
import { parseString } from '../../../../hydration/util'
|
|
7
12
|
import { Server } from '../../../../lexicon'
|
|
@@ -21,16 +26,20 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
21
26
|
const searchPosts = createPipeline(
|
|
22
27
|
skeleton,
|
|
23
28
|
hydration,
|
|
24
|
-
|
|
29
|
+
noBlocksOrTagged,
|
|
25
30
|
presentation,
|
|
26
31
|
)
|
|
27
32
|
server.app.bsky.feed.searchPosts({
|
|
28
33
|
auth: ctx.authVerifier.standardOptional,
|
|
29
34
|
handler: async ({ auth, params, req }) => {
|
|
30
|
-
const viewer =
|
|
35
|
+
const { viewer, isModService } = ctx.authVerifier.parseCreds(auth)
|
|
36
|
+
|
|
31
37
|
const labelers = ctx.reqLabelers(req)
|
|
32
38
|
const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })
|
|
33
|
-
const results = await searchPosts(
|
|
39
|
+
const results = await searchPosts(
|
|
40
|
+
{ ...params, hydrateCtx, isModService },
|
|
41
|
+
ctx,
|
|
42
|
+
)
|
|
34
43
|
return {
|
|
35
44
|
encoding: 'application/json',
|
|
36
45
|
body: results,
|
|
@@ -42,6 +51,9 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
42
51
|
|
|
43
52
|
const skeleton = async (inputs: SkeletonFnInput<Context, Params>) => {
|
|
44
53
|
const { ctx, params } = inputs
|
|
54
|
+
const parsedQuery = parsePostSearchQuery(params.q, {
|
|
55
|
+
author: params.author,
|
|
56
|
+
})
|
|
45
57
|
|
|
46
58
|
if (ctx.searchAgent) {
|
|
47
59
|
// @NOTE cursors won't change on appview swap
|
|
@@ -64,6 +76,7 @@ const skeleton = async (inputs: SkeletonFnInput<Context, Params>) => {
|
|
|
64
76
|
return {
|
|
65
77
|
posts: res.posts.map(({ uri }) => uri),
|
|
66
78
|
cursor: parseString(res.cursor),
|
|
79
|
+
parsedQuery,
|
|
67
80
|
}
|
|
68
81
|
}
|
|
69
82
|
|
|
@@ -75,6 +88,7 @@ const skeleton = async (inputs: SkeletonFnInput<Context, Params>) => {
|
|
|
75
88
|
return {
|
|
76
89
|
posts: res.uris,
|
|
77
90
|
cursor: parseString(res.cursor),
|
|
91
|
+
parsedQuery,
|
|
78
92
|
}
|
|
79
93
|
}
|
|
80
94
|
|
|
@@ -88,11 +102,30 @@ const hydration = async (
|
|
|
88
102
|
)
|
|
89
103
|
}
|
|
90
104
|
|
|
91
|
-
const
|
|
92
|
-
const { ctx, skeleton, hydration } = inputs
|
|
105
|
+
const noBlocksOrTagged = (inputs: RulesFnInput<Context, Params, Skeleton>) => {
|
|
106
|
+
const { ctx, params, skeleton, hydration } = inputs
|
|
107
|
+
const { parsedQuery } = skeleton
|
|
108
|
+
|
|
93
109
|
skeleton.posts = skeleton.posts.filter((uri) => {
|
|
110
|
+
const post = hydration.posts?.get(uri)
|
|
111
|
+
if (!post) return
|
|
112
|
+
|
|
94
113
|
const creator = creatorFromUri(uri)
|
|
95
|
-
|
|
114
|
+
const isCuratedSearch = params.sort === 'top'
|
|
115
|
+
const isPostByViewer = creator === params.hydrateCtx.viewer
|
|
116
|
+
|
|
117
|
+
// Cases to always show.
|
|
118
|
+
if (isPostByViewer) return true
|
|
119
|
+
if (params.isModService) return true
|
|
120
|
+
|
|
121
|
+
// Cases to never show.
|
|
122
|
+
if (ctx.views.viewerBlockExists(creator, hydration)) return false
|
|
123
|
+
|
|
124
|
+
// Cases to conditionally show based on tagging.
|
|
125
|
+
const tagged = [...ctx.cfg.searchTagsHide].some((t) => post.tags.has(t))
|
|
126
|
+
if (isCuratedSearch && tagged) return false
|
|
127
|
+
if (!parsedQuery.author && tagged) return false
|
|
128
|
+
return true
|
|
96
129
|
})
|
|
97
130
|
return skeleton
|
|
98
131
|
}
|
|
@@ -101,9 +134,12 @@ const presentation = (
|
|
|
101
134
|
inputs: PresentationFnInput<Context, Params, Skeleton>,
|
|
102
135
|
) => {
|
|
103
136
|
const { ctx, skeleton, hydration } = inputs
|
|
104
|
-
const posts = mapDefined(skeleton.posts, (uri) =>
|
|
105
|
-
|
|
106
|
-
|
|
137
|
+
const posts = mapDefined(skeleton.posts, (uri) => {
|
|
138
|
+
const post = hydration.posts?.get(uri)
|
|
139
|
+
if (!post) return
|
|
140
|
+
|
|
141
|
+
return ctx.views.post(uri, hydration)
|
|
142
|
+
})
|
|
107
143
|
return {
|
|
108
144
|
posts,
|
|
109
145
|
cursor: skeleton.cursor,
|
|
@@ -112,16 +148,21 @@ const presentation = (
|
|
|
112
148
|
}
|
|
113
149
|
|
|
114
150
|
type Context = {
|
|
151
|
+
cfg: ServerConfig
|
|
115
152
|
dataplane: DataPlaneClient
|
|
116
153
|
hydrator: Hydrator
|
|
117
154
|
views: Views
|
|
118
155
|
searchAgent?: AtpAgent
|
|
119
156
|
}
|
|
120
157
|
|
|
121
|
-
type Params = QueryParams & {
|
|
158
|
+
type Params = QueryParams & {
|
|
159
|
+
hydrateCtx: HydrateCtx
|
|
160
|
+
isModService: boolean
|
|
161
|
+
}
|
|
122
162
|
|
|
123
163
|
type Skeleton = {
|
|
124
164
|
posts: string[]
|
|
125
165
|
hitsTotal?: number
|
|
126
166
|
cursor?: string
|
|
167
|
+
parsedQuery: PostSearchQuery
|
|
127
168
|
}
|
|
@@ -93,11 +93,10 @@ const hydration = async (
|
|
|
93
93
|
const presentation = (
|
|
94
94
|
inputs: PresentationFnInput<Context, Params, Skeleton>,
|
|
95
95
|
) => {
|
|
96
|
-
const { ctx,
|
|
96
|
+
const { ctx, skeleton, hydration } = inputs
|
|
97
97
|
const thread = ctx.views.threadOtherV2(skeleton, hydration, {
|
|
98
98
|
below: BELOW,
|
|
99
99
|
branchingFactor: BRANCHING_FACTOR,
|
|
100
|
-
prioritizeFollowedUsers: params.prioritizeFollowedUsers,
|
|
101
100
|
})
|
|
102
101
|
return { thread }
|
|
103
102
|
}
|
package/src/auth-verifier.ts
CHANGED
|
@@ -388,12 +388,17 @@ export class AuthVerifier {
|
|
|
388
388
|
const canPerformTakedown =
|
|
389
389
|
(creds.credentials.type === 'role' && creds.credentials.admin) ||
|
|
390
390
|
creds.credentials.type === 'mod_service'
|
|
391
|
+
const isModService =
|
|
392
|
+
creds.credentials.type === 'mod_service' ||
|
|
393
|
+
(creds.credentials.type === 'standard' &&
|
|
394
|
+
this.isModService(creds.credentials.iss))
|
|
391
395
|
|
|
392
396
|
return {
|
|
393
397
|
viewer,
|
|
394
398
|
includeTakedowns: includeTakedownsAnd3pBlocks,
|
|
395
399
|
include3pBlocks: includeTakedownsAnd3pBlocks,
|
|
396
400
|
canPerformTakedown,
|
|
401
|
+
isModService,
|
|
397
402
|
}
|
|
398
403
|
}
|
|
399
404
|
}
|
package/src/config.ts
CHANGED
|
@@ -42,6 +42,7 @@ export interface ServerConfigValues {
|
|
|
42
42
|
courierHttpVersion?: '1.1' | '2'
|
|
43
43
|
courierIgnoreBadTls?: boolean
|
|
44
44
|
searchUrl?: string
|
|
45
|
+
searchTagsHide: Set<string>
|
|
45
46
|
suggestionsUrl?: string
|
|
46
47
|
suggestionsApiKey?: string
|
|
47
48
|
topicsUrl?: string
|
|
@@ -133,6 +134,7 @@ export class ServerConfig {
|
|
|
133
134
|
process.env.BSKY_SEARCH_URL ||
|
|
134
135
|
process.env.BSKY_SEARCH_ENDPOINT ||
|
|
135
136
|
undefined
|
|
137
|
+
const searchTagsHide = new Set(envList(process.env.BSKY_SEARCH_TAGS_HIDE))
|
|
136
138
|
const suggestionsUrl = process.env.BSKY_SUGGESTIONS_URL || undefined
|
|
137
139
|
const suggestionsApiKey = process.env.BSKY_SUGGESTIONS_API_KEY || undefined
|
|
138
140
|
const topicsUrl = process.env.BSKY_TOPICS_URL || undefined
|
|
@@ -296,6 +298,7 @@ export class ServerConfig {
|
|
|
296
298
|
dataplaneHttpVersion,
|
|
297
299
|
dataplaneIgnoreBadTls,
|
|
298
300
|
searchUrl,
|
|
301
|
+
searchTagsHide,
|
|
299
302
|
suggestionsUrl,
|
|
300
303
|
suggestionsApiKey,
|
|
301
304
|
topicsUrl,
|
|
@@ -440,6 +443,10 @@ export class ServerConfig {
|
|
|
440
443
|
return this.cfg.searchUrl
|
|
441
444
|
}
|
|
442
445
|
|
|
446
|
+
get searchTagsHide() {
|
|
447
|
+
return this.cfg.searchTagsHide
|
|
448
|
+
}
|
|
449
|
+
|
|
443
450
|
get suggestionsUrl() {
|
|
444
451
|
return this.cfg.suggestionsUrl
|
|
445
452
|
}
|
|
@@ -539,6 +546,7 @@ export class ServerConfig {
|
|
|
539
546
|
get threadTagsHide() {
|
|
540
547
|
return this.cfg.threadTagsHide
|
|
541
548
|
}
|
|
549
|
+
|
|
542
550
|
get threadTagsBumpDown() {
|
|
543
551
|
return this.cfg.threadTagsBumpDown
|
|
544
552
|
}
|
|
@@ -2,6 +2,7 @@ import { ServiceImpl } from '@connectrpc/connect'
|
|
|
2
2
|
import { Service } from '../../../proto/bsky_connect'
|
|
3
3
|
import { Database } from '../db'
|
|
4
4
|
import { IndexedAtDidKeyset, TimeCidKeyset, paginate } from '../db/pagination'
|
|
5
|
+
import { parsePostSearchQuery } from '../util'
|
|
5
6
|
|
|
6
7
|
export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
|
7
8
|
// @TODO actor search endpoints still fall back to search service
|
|
@@ -35,12 +36,28 @@ export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
|
|
35
36
|
// @TODO post search endpoint still falls back to search service
|
|
36
37
|
async searchPosts(req) {
|
|
37
38
|
const { term, limit, cursor } = req
|
|
39
|
+
const { q, author } = parsePostSearchQuery(term)
|
|
40
|
+
|
|
41
|
+
let authorDid = author
|
|
42
|
+
if (author && !author?.startsWith('did:')) {
|
|
43
|
+
const res = await db.db
|
|
44
|
+
.selectFrom('actor')
|
|
45
|
+
.where('handle', '=', author)
|
|
46
|
+
.selectAll()
|
|
47
|
+
.executeTakeFirst()
|
|
48
|
+
authorDid = res?.did
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
const { ref } = db.db.dynamic
|
|
39
52
|
let builder = db.db
|
|
40
53
|
.selectFrom('post')
|
|
41
|
-
.where('post.text', 'like', `%${
|
|
54
|
+
.where('post.text', 'like', `%${q}%`)
|
|
42
55
|
.selectAll()
|
|
43
56
|
|
|
57
|
+
if (authorDid) {
|
|
58
|
+
builder = builder.where('post.creator', '=', authorDid)
|
|
59
|
+
}
|
|
60
|
+
|
|
44
61
|
const keyset = new TimeCidKeyset(ref('post.sortAt'), ref('post.cid'))
|
|
45
62
|
builder = paginate(builder, {
|
|
46
63
|
limit,
|
|
@@ -153,3 +153,54 @@ export const violatesThreadGate = async (
|
|
|
153
153
|
|
|
154
154
|
return true
|
|
155
155
|
}
|
|
156
|
+
|
|
157
|
+
// @NOTE: This type is not complete with all supported options.
|
|
158
|
+
// Only the ones that we needed to apply custom logic on are currently present.
|
|
159
|
+
export type PostSearchQuery = {
|
|
160
|
+
q: string
|
|
161
|
+
author: string | undefined
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const parsePostSearchQuery = (
|
|
165
|
+
qParam: string,
|
|
166
|
+
params?: {
|
|
167
|
+
author?: string
|
|
168
|
+
},
|
|
169
|
+
): PostSearchQuery => {
|
|
170
|
+
// Accept individual params, but give preference to options embedded in `q`.
|
|
171
|
+
let author = params?.author
|
|
172
|
+
|
|
173
|
+
const parts: string[] = []
|
|
174
|
+
let curr = ''
|
|
175
|
+
let quoted = false
|
|
176
|
+
for (const c of qParam) {
|
|
177
|
+
if (c === ' ' && !quoted) {
|
|
178
|
+
curr.trim() && parts.push(curr)
|
|
179
|
+
curr = ''
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (c === '"') {
|
|
184
|
+
quoted = !quoted
|
|
185
|
+
}
|
|
186
|
+
curr += c
|
|
187
|
+
}
|
|
188
|
+
curr.trim() && parts.push(curr)
|
|
189
|
+
|
|
190
|
+
const qParts: string[] = []
|
|
191
|
+
for (const p of parts) {
|
|
192
|
+
const tokens = p.split(':')
|
|
193
|
+
if (tokens[0] === 'did') {
|
|
194
|
+
author = p
|
|
195
|
+
} else if (tokens[0] === 'author' || tokens[0] === 'from') {
|
|
196
|
+
author = tokens[1]
|
|
197
|
+
} else {
|
|
198
|
+
qParts.push(p)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
q: qParts.join(' '),
|
|
204
|
+
author,
|
|
205
|
+
}
|
|
206
|
+
}
|
package/src/lexicon/index.ts
CHANGED
|
@@ -145,6 +145,7 @@ import * as ComAtprotoIdentitySubmitPlcOperation from './types/com/atproto/ident
|
|
|
145
145
|
import * as ComAtprotoIdentityUpdateHandle from './types/com/atproto/identity/updateHandle.js'
|
|
146
146
|
import * as ComAtprotoLabelQueryLabels from './types/com/atproto/label/queryLabels.js'
|
|
147
147
|
import * as ComAtprotoLabelSubscribeLabels from './types/com/atproto/label/subscribeLabels.js'
|
|
148
|
+
import * as ComAtprotoLexiconResolveLexicon from './types/com/atproto/lexicon/resolveLexicon.js'
|
|
148
149
|
import * as ComAtprotoModerationCreateReport from './types/com/atproto/moderation/createReport.js'
|
|
149
150
|
import * as ComAtprotoRepoApplyWrites from './types/com/atproto/repo/applyWrites.js'
|
|
150
151
|
import * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createRecord.js'
|
|
@@ -2108,6 +2109,18 @@ export class ComAtprotoLexiconNS {
|
|
|
2108
2109
|
constructor(server: Server) {
|
|
2109
2110
|
this._server = server
|
|
2110
2111
|
}
|
|
2112
|
+
|
|
2113
|
+
resolveLexicon<A extends Auth = void>(
|
|
2114
|
+
cfg: MethodConfigOrHandler<
|
|
2115
|
+
A,
|
|
2116
|
+
ComAtprotoLexiconResolveLexicon.QueryParams,
|
|
2117
|
+
ComAtprotoLexiconResolveLexicon.HandlerInput,
|
|
2118
|
+
ComAtprotoLexiconResolveLexicon.HandlerOutput
|
|
2119
|
+
>,
|
|
2120
|
+
) {
|
|
2121
|
+
const nsid = 'com.atproto.lexicon.resolveLexicon' // @ts-ignore
|
|
2122
|
+
return this._server.xrpc.method(nsid, cfg)
|
|
2123
|
+
}
|
|
2111
2124
|
}
|
|
2112
2125
|
|
|
2113
2126
|
export class ComAtprotoModerationNS {
|
package/src/lexicon/lexicons.ts
CHANGED
|
@@ -555,10 +555,6 @@ export const schemaDict = {
|
|
|
555
555
|
'hotness',
|
|
556
556
|
],
|
|
557
557
|
},
|
|
558
|
-
prioritizeFollowedUsers: {
|
|
559
|
-
type: 'boolean',
|
|
560
|
-
description: 'Show followed users at the top of all replies.',
|
|
561
|
-
},
|
|
562
558
|
},
|
|
563
559
|
},
|
|
564
560
|
interestsPref: {
|
|
@@ -6799,12 +6795,6 @@ export const schemaDict = {
|
|
|
6799
6795
|
description:
|
|
6800
6796
|
'Reference (AT-URI) to post record. This is the anchor post.',
|
|
6801
6797
|
},
|
|
6802
|
-
prioritizeFollowedUsers: {
|
|
6803
|
-
type: 'boolean',
|
|
6804
|
-
description:
|
|
6805
|
-
'Whether to prioritize posts from followed users. It only has effect when the user is authenticated.',
|
|
6806
|
-
default: false,
|
|
6807
|
-
},
|
|
6808
6798
|
},
|
|
6809
6799
|
},
|
|
6810
6800
|
output: {
|
|
@@ -6886,12 +6876,6 @@ export const schemaDict = {
|
|
|
6886
6876
|
minimum: 0,
|
|
6887
6877
|
maximum: 100,
|
|
6888
6878
|
},
|
|
6889
|
-
prioritizeFollowedUsers: {
|
|
6890
|
-
type: 'boolean',
|
|
6891
|
-
description:
|
|
6892
|
-
'Whether to prioritize posts from followed users. It only has effect when the user is authenticated.',
|
|
6893
|
-
default: false,
|
|
6894
|
-
},
|
|
6895
6879
|
sort: {
|
|
6896
6880
|
type: 'string',
|
|
6897
6881
|
description: 'Sorting for the thread replies.',
|
|
@@ -10531,6 +10515,57 @@ export const schemaDict = {
|
|
|
10531
10515
|
},
|
|
10532
10516
|
},
|
|
10533
10517
|
},
|
|
10518
|
+
ComAtprotoLexiconResolveLexicon: {
|
|
10519
|
+
lexicon: 1,
|
|
10520
|
+
id: 'com.atproto.lexicon.resolveLexicon',
|
|
10521
|
+
defs: {
|
|
10522
|
+
main: {
|
|
10523
|
+
type: 'query',
|
|
10524
|
+
description: 'Resolves an atproto lexicon (NSID) to a schema.',
|
|
10525
|
+
parameters: {
|
|
10526
|
+
type: 'params',
|
|
10527
|
+
properties: {
|
|
10528
|
+
nsid: {
|
|
10529
|
+
format: 'nsid',
|
|
10530
|
+
type: 'string',
|
|
10531
|
+
description: 'The lexicon NSID to resolve.',
|
|
10532
|
+
},
|
|
10533
|
+
},
|
|
10534
|
+
required: ['nsid'],
|
|
10535
|
+
},
|
|
10536
|
+
output: {
|
|
10537
|
+
encoding: 'application/json',
|
|
10538
|
+
schema: {
|
|
10539
|
+
type: 'object',
|
|
10540
|
+
properties: {
|
|
10541
|
+
cid: {
|
|
10542
|
+
type: 'string',
|
|
10543
|
+
format: 'cid',
|
|
10544
|
+
description: 'The CID of the lexicon schema record.',
|
|
10545
|
+
},
|
|
10546
|
+
schema: {
|
|
10547
|
+
type: 'ref',
|
|
10548
|
+
ref: 'lex:com.atproto.lexicon.schema#main',
|
|
10549
|
+
description: 'The resolved lexicon schema record.',
|
|
10550
|
+
},
|
|
10551
|
+
uri: {
|
|
10552
|
+
type: 'string',
|
|
10553
|
+
format: 'at-uri',
|
|
10554
|
+
description: 'The AT-URI of the lexicon schema record.',
|
|
10555
|
+
},
|
|
10556
|
+
},
|
|
10557
|
+
required: ['uri', 'cid', 'schema'],
|
|
10558
|
+
},
|
|
10559
|
+
},
|
|
10560
|
+
errors: [
|
|
10561
|
+
{
|
|
10562
|
+
description: 'No lexicon was resolved for the NSID.',
|
|
10563
|
+
name: 'LexiconNotFound',
|
|
10564
|
+
},
|
|
10565
|
+
],
|
|
10566
|
+
},
|
|
10567
|
+
},
|
|
10568
|
+
},
|
|
10534
10569
|
ComAtprotoLexiconSchema: {
|
|
10535
10570
|
lexicon: 1,
|
|
10536
10571
|
id: 'com.atproto.lexicon.schema',
|
|
@@ -14177,6 +14212,7 @@ export const ids = {
|
|
|
14177
14212
|
ComAtprotoLabelDefs: 'com.atproto.label.defs',
|
|
14178
14213
|
ComAtprotoLabelQueryLabels: 'com.atproto.label.queryLabels',
|
|
14179
14214
|
ComAtprotoLabelSubscribeLabels: 'com.atproto.label.subscribeLabels',
|
|
14215
|
+
ComAtprotoLexiconResolveLexicon: 'com.atproto.lexicon.resolveLexicon',
|
|
14180
14216
|
ComAtprotoLexiconSchema: 'com.atproto.lexicon.schema',
|
|
14181
14217
|
ComAtprotoModerationCreateReport: 'com.atproto.moderation.createReport',
|
|
14182
14218
|
ComAtprotoModerationDefs: 'com.atproto.moderation.defs',
|
|
@@ -18,8 +18,6 @@ const id = 'app.bsky.unspecced.getPostThreadOtherV2'
|
|
|
18
18
|
export type QueryParams = {
|
|
19
19
|
/** Reference (AT-URI) to post record. This is the anchor post. */
|
|
20
20
|
anchor: string
|
|
21
|
-
/** Whether to prioritize posts from followed users. It only has effect when the user is authenticated. */
|
|
22
|
-
prioritizeFollowedUsers: boolean
|
|
23
21
|
}
|
|
24
22
|
export type InputSchema = undefined
|
|
25
23
|
|
|
@@ -25,8 +25,6 @@ export type QueryParams = {
|
|
|
25
25
|
below: number
|
|
26
26
|
/** Maximum of replies to include at each level of the thread, except for the direct replies to the anchor, which are (NOTE: currently, during unspecced phase) all returned (NOTE: later they might be paginated). */
|
|
27
27
|
branchingFactor: number
|
|
28
|
-
/** Whether to prioritize posts from followed users. It only has effect when the user is authenticated. */
|
|
29
|
-
prioritizeFollowedUsers: boolean
|
|
30
28
|
/** Sorting for the thread replies. */
|
|
31
29
|
sort: 'newest' | 'oldest' | 'top' | (string & {})
|
|
32
30
|
}
|