From 2ce8a11b8daf5d39027488c5dde8c47b0eb937bf Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 25 Sep 2023 17:45:57 -0500 Subject: [PATCH 1/3] Add hashtag detection to richtext (#1651) * add tag detection to richtext * fix duplicate tag index error * add utils * fix leading space index failures, test for them * add changeset --- .changeset/moody-wombats-live.md | 5 + packages/api/src/rich-text/detection.ts | 27 +++++ packages/api/src/rich-text/rich-text.ts | 13 +++ .../api/tests/rich-text-detection.test.ts | 104 ++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 .changeset/moody-wombats-live.md diff --git a/.changeset/moody-wombats-live.md b/.changeset/moody-wombats-live.md new file mode 100644 index 00000000000..c146f008d5c --- /dev/null +++ b/.changeset/moody-wombats-live.md @@ -0,0 +1,5 @@ +--- +'@atproto/api': patch +--- + +Adds support for hashtags in the `RichText.detectFacets` method. diff --git a/packages/api/src/rich-text/detection.ts b/packages/api/src/rich-text/detection.ts index 910804ca0db..503866d7df8 100644 --- a/packages/api/src/rich-text/detection.ts +++ b/packages/api/src/rich-text/detection.ts @@ -69,6 +69,33 @@ export function detectFacets(text: UnicodeString): Facet[] | undefined { }) } } + { + const re = /(?:^|\s)(#[^\d\s]\S*)(?=\s)?/g + while ((match = re.exec(text.utf16))) { + let [tag] = match + const hasLeadingSpace = /^\s/.test(tag) + + tag = tag.trim().replace(/\p{P}+$/gu, '') // strip ending punctuation + + // inclusive of #, max of 64 chars + if (tag.length > 66) continue + + const index = match.index + (hasLeadingSpace ? 1 : 0) + + facets.push({ + index: { + byteStart: text.utf16IndexToUtf8Index(index), + byteEnd: text.utf16IndexToUtf8Index(index + tag.length), // inclusive of last char + }, + features: [ + { + $type: 'app.bsky.richtext.facet#tag', + tag, + }, + ], + }) + } + } return facets.length > 0 ? facets : undefined } diff --git a/packages/api/src/rich-text/rich-text.ts b/packages/api/src/rich-text/rich-text.ts index 46ccc7dfef1..4c041b8bb5f 100644 --- a/packages/api/src/rich-text/rich-text.ts +++ b/packages/api/src/rich-text/rich-text.ts @@ -100,6 +100,7 @@ import { detectFacets } from './detection' export type Facet = AppBskyRichtextFacet.Main export type FacetLink = AppBskyRichtextFacet.Link export type FacetMention = AppBskyRichtextFacet.Mention +export type FacetTag = AppBskyRichtextFacet.Tag export type Entity = AppBskyFeedPost.Entity export interface RichTextProps { @@ -141,6 +142,18 @@ export class RichTextSegment { isMention() { return !!this.mention } + + get tag(): FacetTag | undefined { + const tag = this.facet?.features.find(AppBskyRichtextFacet.isTag) + if (AppBskyRichtextFacet.isTag(tag)) { + return tag + } + return undefined + } + + isTag() { + return !!this.tag + } } export class RichText { diff --git a/packages/api/tests/rich-text-detection.test.ts b/packages/api/tests/rich-text-detection.test.ts index da81fe415b1..df2aed84889 100644 --- a/packages/api/tests/rich-text-detection.test.ts +++ b/packages/api/tests/rich-text-detection.test.ts @@ -1,4 +1,5 @@ import { AtpAgent, RichText, RichTextSegment } from '../src' +import { isTag } from '../src/client/types/app/bsky/richtext/facet' describe('detectFacets', () => { const agent = new AtpAgent({ service: 'http://localhost' }) @@ -208,6 +209,109 @@ describe('detectFacets', () => { expect(Array.from(rt.segments(), segmentToOutput)).toEqual(outputs[i]) } }) + + it('correctly detects tags inline', async () => { + const inputs: [ + string, + string[], + { byteStart: number; byteEnd: number }[], + ][] = [ + ['#a', ['#a'], [{ byteStart: 0, byteEnd: 2 }]], + [ + '#a #b', + ['#a', '#b'], + [ + { byteStart: 0, byteEnd: 2 }, + { byteStart: 3, byteEnd: 5 }, + ], + ], + ['#1', [], []], + ['#tag', ['#tag'], [{ byteStart: 0, byteEnd: 4 }]], + ['body #tag', ['#tag'], [{ byteStart: 5, byteEnd: 9 }]], + ['#tag body', ['#tag'], [{ byteStart: 0, byteEnd: 4 }]], + ['body #tag body', ['#tag'], [{ byteStart: 5, byteEnd: 9 }]], + ['body #1', [], []], + ['body #a1', ['#a1'], [{ byteStart: 5, byteEnd: 8 }]], + ['#', [], []], + ['text #', [], []], + ['text # text', [], []], + [ + 'body #thisisa64characterstring_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + ['#thisisa64characterstring_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], + [{ byteStart: 5, byteEnd: 71 }], + ], + [ + 'body #thisisa65characterstring_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab', + [], + [], + ], + [ + 'its a #double#rainbow', + ['#double#rainbow'], + [{ byteStart: 6, byteEnd: 21 }], + ], + ['##hashash', ['##hashash'], [{ byteStart: 0, byteEnd: 9 }]], + ['some #n0n3s@n5e!', ['#n0n3s@n5e'], [{ byteStart: 5, byteEnd: 15 }]], + [ + 'works #with,punctuation', + ['#with,punctuation'], + [{ byteStart: 6, byteEnd: 23 }], + ], + [ + 'strips trailing #punctuation, #like. #this!', + ['#punctuation', '#like', '#this'], + [ + { byteStart: 16, byteEnd: 28 }, + { byteStart: 30, byteEnd: 35 }, + { byteStart: 37, byteEnd: 42 }, + ], + ], + [ + 'strips #multi_trailing___...', + ['#multi_trailing'], + [{ byteStart: 7, byteEnd: 22 }], + ], + [ + 'works with #🦋 emoji, and #butter🦋fly', + ['#🦋', '#butter🦋fly'], + [ + { byteStart: 11, byteEnd: 16 }, + { byteStart: 28, byteEnd: 42 }, + ], + ], + [ + '#same #same #but #diff', + ['#same', '#same', '#but', '#diff'], + [ + { byteStart: 0, byteEnd: 5 }, + { byteStart: 6, byteEnd: 11 }, + { byteStart: 12, byteEnd: 16 }, + { byteStart: 17, byteEnd: 22 }, + ], + ], + ] + + for (const [input, tags, indices] of inputs) { + const rt = new RichText({ text: input }) + await rt.detectFacets(agent) + + let detectedTags: string[] = [] + let detectedIndices: { byteStart: number; byteEnd: number }[] = [] + + for (const { facet } of rt.segments()) { + if (!facet) continue + for (const feature of facet.features) { + if (isTag(feature)) { + detectedTags.push(feature.tag) + } + } + detectedIndices.push(facet.index) + } + + expect(detectedTags).toEqual(tags) + expect(detectedIndices).toEqual(indices) + } + }) }) function segmentToOutput(segment: RichTextSegment): string[] { From 4a64944783e9b2a530df2288833af520bc89412f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:48:05 -0500 Subject: [PATCH 2/3] Version packages (#1669) Co-authored-by: github-actions[bot] --- .changeset/moody-wombats-live.md | 5 ----- packages/api/CHANGELOG.md | 6 ++++++ packages/api/package.json | 2 +- packages/bsky/CHANGELOG.md | 7 +++++++ packages/bsky/package.json | 2 +- packages/dev-env/CHANGELOG.md | 9 +++++++++ packages/dev-env/package.json | 2 +- packages/pds/CHANGELOG.md | 7 +++++++ packages/pds/package.json | 2 +- 9 files changed, 33 insertions(+), 9 deletions(-) delete mode 100644 .changeset/moody-wombats-live.md diff --git a/.changeset/moody-wombats-live.md b/.changeset/moody-wombats-live.md deleted file mode 100644 index c146f008d5c..00000000000 --- a/.changeset/moody-wombats-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@atproto/api': patch ---- - -Adds support for hashtags in the `RichText.detectFacets` method. diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index f438c52525d..1d6d7788839 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -1,5 +1,11 @@ # @atproto/api +## 0.6.18 + +### Patch Changes + +- [#1651](https://github.com/bluesky-social/atproto/pull/1651) [`2ce8a11b`](https://github.com/bluesky-social/atproto/commit/2ce8a11b8daf5d39027488c5dde8c47b0eb937bf) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Adds support for hashtags in the `RichText.detectFacets` method. + ## 0.6.17 ### Patch Changes diff --git a/packages/api/package.json b/packages/api/package.json index 8165fa63dd2..13624588c0c 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/api", - "version": "0.6.17", + "version": "0.6.18", "license": "MIT", "description": "Client library for atproto and Bluesky", "keywords": [ diff --git a/packages/bsky/CHANGELOG.md b/packages/bsky/CHANGELOG.md index 0d973cc3d50..9d85cfa4a70 100644 --- a/packages/bsky/CHANGELOG.md +++ b/packages/bsky/CHANGELOG.md @@ -1,5 +1,12 @@ # @atproto/bsky +## 0.0.9 + +### Patch Changes + +- Updated dependencies [[`2ce8a11b`](https://github.com/bluesky-social/atproto/commit/2ce8a11b8daf5d39027488c5dde8c47b0eb937bf)]: + - @atproto/api@0.6.18 + ## 0.0.8 ### Patch Changes diff --git a/packages/bsky/package.json b/packages/bsky/package.json index ec203970552..33cafe53947 100644 --- a/packages/bsky/package.json +++ b/packages/bsky/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/bsky", - "version": "0.0.8", + "version": "0.0.9", "license": "MIT", "description": "Reference implementation of app.bsky App View (Bluesky API)", "keywords": [ diff --git a/packages/dev-env/CHANGELOG.md b/packages/dev-env/CHANGELOG.md index 130a330007b..67523be96e0 100644 --- a/packages/dev-env/CHANGELOG.md +++ b/packages/dev-env/CHANGELOG.md @@ -1,5 +1,14 @@ # @atproto/dev-env +## 0.2.9 + +### Patch Changes + +- Updated dependencies [[`2ce8a11b`](https://github.com/bluesky-social/atproto/commit/2ce8a11b8daf5d39027488c5dde8c47b0eb937bf)]: + - @atproto/api@0.6.18 + - @atproto/bsky@0.0.9 + - @atproto/pds@0.1.18 + ## 0.2.8 ### Patch Changes diff --git a/packages/dev-env/package.json b/packages/dev-env/package.json index d945103437e..926ff0b412d 100644 --- a/packages/dev-env/package.json +++ b/packages/dev-env/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/dev-env", - "version": "0.2.8", + "version": "0.2.9", "license": "MIT", "description": "Local development environment helper for atproto development", "keywords": [ diff --git a/packages/pds/CHANGELOG.md b/packages/pds/CHANGELOG.md index 3a450244149..2680326d054 100644 --- a/packages/pds/CHANGELOG.md +++ b/packages/pds/CHANGELOG.md @@ -1,5 +1,12 @@ # @atproto/pds +## 0.1.18 + +### Patch Changes + +- Updated dependencies [[`2ce8a11b`](https://github.com/bluesky-social/atproto/commit/2ce8a11b8daf5d39027488c5dde8c47b0eb937bf)]: + - @atproto/api@0.6.18 + ## 0.1.17 ### Patch Changes diff --git a/packages/pds/package.json b/packages/pds/package.json index de690dad916..833b016f4ef 100644 --- a/packages/pds/package.json +++ b/packages/pds/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/pds", - "version": "0.1.17", + "version": "0.1.18", "license": "MIT", "description": "Reference implementation of atproto Personal Data Server (PDS)", "keywords": [ From 233a132c11764c90c7edabe44d74aef02a922cc7 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Mon, 25 Sep 2023 16:56:00 -0700 Subject: [PATCH 3/3] proposed new search lexicons (#1594) * proposed new search lexicons * lexicons: lint * lexicons: fix actors typo * lexicons: camelCase bites again, ssssss * lexicons: add 'q' and mark 'term' as deprecated for search endpoints * codegen for search lexicon updates * bsky: prefer 'q' over 'term' in existing search endpoints * search: bugfix * lexicons: make unspecced search endpoints return skeleton obj * re-codegen for search skeleton obj --- lexicons/app/bsky/actor/searchActors.json | 13 +- .../app/bsky/actor/searchActorsTypeahead.json | 11 +- lexicons/app/bsky/feed/searchPosts.json | 52 ++++ lexicons/app/bsky/unspecced/defs.json | 20 ++ .../bsky/unspecced/searchActorsSkeleton.json | 56 ++++ .../bsky/unspecced/searchPostsSkeleton.json | 52 ++++ lexicons/com/atproto/admin/searchRepos.json | 6 +- packages/api/src/client/index.ts | 41 +++ packages/api/src/client/lexicons.ts | 239 +++++++++++++++++- .../types/app/bsky/actor/searchActors.ts | 3 + .../app/bsky/actor/searchActorsTypeahead.ts | 3 + .../client/types/app/bsky/feed/searchPosts.ts | 50 ++++ .../client/types/app/bsky/unspecced/defs.ts | 41 +++ .../bsky/unspecced/searchActorsSkeleton.ts | 52 ++++ .../app/bsky/unspecced/searchPostsSkeleton.ts | 50 ++++ .../types/com/atproto/admin/searchRepos.ts | 2 + .../src/api/app/bsky/actor/searchActors.ts | 8 +- .../app/bsky/actor/searchActorsTypeahead.ts | 8 +- .../src/api/com/atproto/admin/searchRepos.ts | 5 + packages/bsky/src/lexicon/index.ts | 36 +++ packages/bsky/src/lexicon/lexicons.ts | 239 +++++++++++++++++- .../types/app/bsky/actor/searchActors.ts | 3 + .../app/bsky/actor/searchActorsTypeahead.ts | 3 + .../types/app/bsky/feed/searchPosts.ts | 54 ++++ .../lexicon/types/app/bsky/unspecced/defs.ts | 41 +++ .../bsky/unspecced/searchActorsSkeleton.ts | 56 ++++ .../app/bsky/unspecced/searchPostsSkeleton.ts | 54 ++++ .../types/com/atproto/admin/searchRepos.ts | 2 + packages/pds/src/lexicon/index.ts | 36 +++ packages/pds/src/lexicon/lexicons.ts | 239 +++++++++++++++++- .../types/app/bsky/actor/searchActors.ts | 3 + .../app/bsky/actor/searchActorsTypeahead.ts | 3 + .../types/app/bsky/feed/searchPosts.ts | 54 ++++ .../lexicon/types/app/bsky/unspecced/defs.ts | 41 +++ .../bsky/unspecced/searchActorsSkeleton.ts | 56 ++++ .../app/bsky/unspecced/searchPostsSkeleton.ts | 54 ++++ .../types/com/atproto/admin/searchRepos.ts | 2 + 37 files changed, 1671 insertions(+), 17 deletions(-) create mode 100644 lexicons/app/bsky/feed/searchPosts.json create mode 100644 lexicons/app/bsky/unspecced/defs.json create mode 100644 lexicons/app/bsky/unspecced/searchActorsSkeleton.json create mode 100644 lexicons/app/bsky/unspecced/searchPostsSkeleton.json create mode 100644 packages/api/src/client/types/app/bsky/feed/searchPosts.ts create mode 100644 packages/api/src/client/types/app/bsky/unspecced/defs.ts create mode 100644 packages/api/src/client/types/app/bsky/unspecced/searchActorsSkeleton.ts create mode 100644 packages/api/src/client/types/app/bsky/unspecced/searchPostsSkeleton.ts create mode 100644 packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts create mode 100644 packages/bsky/src/lexicon/types/app/bsky/unspecced/defs.ts create mode 100644 packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts create mode 100644 packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts create mode 100644 packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts create mode 100644 packages/pds/src/lexicon/types/app/bsky/unspecced/defs.ts create mode 100644 packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts create mode 100644 packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts diff --git a/lexicons/app/bsky/actor/searchActors.json b/lexicons/app/bsky/actor/searchActors.json index dc76ad8fc39..f65e2fc953b 100644 --- a/lexicons/app/bsky/actor/searchActors.json +++ b/lexicons/app/bsky/actor/searchActors.json @@ -4,16 +4,23 @@ "defs": { "main": { "type": "query", - "description": "Find actors matching search criteria.", + "description": "Find actors (profiles) matching search criteria.", "parameters": { "type": "params", "properties": { - "term": { "type": "string" }, + "term": { + "type": "string", + "description": "DEPRECATED: use 'q' instead" + }, + "q": { + "type": "string", + "description": "search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended" + }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, - "default": 50 + "default": 25 }, "cursor": { "type": "string" } } diff --git a/lexicons/app/bsky/actor/searchActorsTypeahead.json b/lexicons/app/bsky/actor/searchActorsTypeahead.json index 7065f3d7117..f94dd6c3f69 100644 --- a/lexicons/app/bsky/actor/searchActorsTypeahead.json +++ b/lexicons/app/bsky/actor/searchActorsTypeahead.json @@ -8,12 +8,19 @@ "parameters": { "type": "params", "properties": { - "term": { "type": "string" }, + "term": { + "type": "string", + "description": "DEPRECATED: use 'q' instead" + }, + "q": { + "type": "string", + "description": "search query prefix; not a full query string" + }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, - "default": 50 + "default": 10 } } }, diff --git a/lexicons/app/bsky/feed/searchPosts.json b/lexicons/app/bsky/feed/searchPosts.json new file mode 100644 index 00000000000..34eb38f686e --- /dev/null +++ b/lexicons/app/bsky/feed/searchPosts.json @@ -0,0 +1,52 @@ +{ + "lexicon": 1, + "id": "app.bsky.feed.searchPosts", + "defs": { + "main": { + "type": "query", + "description": "Find posts matching search criteria", + "parameters": { + "type": "params", + "required": ["q"], + "properties": { + "q": { + "type": "string", + "description": "search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended" + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + }, + "cursor": { + "type": "string", + "description": "optional pagination mechanism; may not necessarily allow scrolling through entire result set" + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["posts"], + "properties": { + "cursor": { "type": "string" }, + "hitsTotal": { + "type": "integer", + "description": "count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits" + }, + "posts": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.feed.defs#postView" + } + } + } + } + }, + "errors": [{ "name": "BadQueryString" }] + } + } +} diff --git a/lexicons/app/bsky/unspecced/defs.json b/lexicons/app/bsky/unspecced/defs.json new file mode 100644 index 00000000000..e9925922a3e --- /dev/null +++ b/lexicons/app/bsky/unspecced/defs.json @@ -0,0 +1,20 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.defs", + "defs": { + "skeletonSearchPost": { + "type": "object", + "required": ["uri"], + "properties": { + "uri": { "type": "string", "format": "at-uri" } + } + }, + "skeletonSearchActor": { + "type": "object", + "required": ["did"], + "properties": { + "did": { "type": "string", "format": "did" } + } + } + } +} diff --git a/lexicons/app/bsky/unspecced/searchActorsSkeleton.json b/lexicons/app/bsky/unspecced/searchActorsSkeleton.json new file mode 100644 index 00000000000..108dacf9b14 --- /dev/null +++ b/lexicons/app/bsky/unspecced/searchActorsSkeleton.json @@ -0,0 +1,56 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.searchActorsSkeleton", + "defs": { + "main": { + "type": "query", + "description": "Backend Actors (profile) search, returning only skeleton", + "parameters": { + "type": "params", + "required": ["q"], + "properties": { + "q": { + "type": "string", + "description": "search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. For typeahead search, only simple term match is supported, not full syntax" + }, + "typeahead": { + "type": "boolean", + "description": "if true, acts as fast/simple 'typeahead' query" + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + }, + "cursor": { + "type": "string", + "description": "optional pagination mechanism; may not necessarily allow scrolling through entire result set" + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["actors"], + "properties": { + "cursor": { "type": "string" }, + "hitsTotal": { + "type": "integer", + "description": "count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits" + }, + "actors": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.unspecced.defs#skeletonSearchActor" + } + } + } + } + }, + "errors": [{ "name": "BadQueryString" }] + } + } +} diff --git a/lexicons/app/bsky/unspecced/searchPostsSkeleton.json b/lexicons/app/bsky/unspecced/searchPostsSkeleton.json new file mode 100644 index 00000000000..532bfea79f9 --- /dev/null +++ b/lexicons/app/bsky/unspecced/searchPostsSkeleton.json @@ -0,0 +1,52 @@ +{ + "lexicon": 1, + "id": "app.bsky.unspecced.searchPostsSkeleton", + "defs": { + "main": { + "type": "query", + "description": "Backend Posts search, returning only skeleton", + "parameters": { + "type": "params", + "required": ["q"], + "properties": { + "q": { + "type": "string", + "description": "search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended" + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + }, + "cursor": { + "type": "string", + "description": "optional pagination mechanism; may not necessarily allow scrolling through entire result set" + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["posts"], + "properties": { + "cursor": { "type": "string" }, + "hitsTotal": { + "type": "integer", + "description": "count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits" + }, + "posts": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.unspecced.defs#skeletonSearchPost" + } + } + } + } + }, + "errors": [{ "name": "BadQueryString" }] + } + } +} diff --git a/lexicons/com/atproto/admin/searchRepos.json b/lexicons/com/atproto/admin/searchRepos.json index fb9c90f343c..85cc6fd482a 100644 --- a/lexicons/com/atproto/admin/searchRepos.json +++ b/lexicons/com/atproto/admin/searchRepos.json @@ -8,7 +8,11 @@ "parameters": { "type": "params", "properties": { - "term": { "type": "string" }, + "term": { + "type": "string", + "description": "DEPRECATED: use 'q' instead" + }, + "q": { "type": "string" }, "invitedBy": { "type": "string" }, "limit": { "type": "integer", diff --git a/packages/api/src/client/index.ts b/packages/api/src/client/index.ts index d72fe659e50..4d9ae10936b 100644 --- a/packages/api/src/client/index.ts +++ b/packages/api/src/client/index.ts @@ -103,6 +103,7 @@ import * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline' import * as AppBskyFeedLike from './types/app/bsky/feed/like' import * as AppBskyFeedPost from './types/app/bsky/feed/post' import * as AppBskyFeedRepost from './types/app/bsky/feed/repost' +import * as AppBskyFeedSearchPosts from './types/app/bsky/feed/searchPosts' import * as AppBskyFeedThreadgate from './types/app/bsky/feed/threadgate' import * as AppBskyGraphBlock from './types/app/bsky/graph/block' import * as AppBskyGraphDefs from './types/app/bsky/graph/defs' @@ -129,9 +130,12 @@ import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/ import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen' import * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet' import * as AppBskyUnspeccedApplyLabels from './types/app/bsky/unspecced/applyLabels' +import * as AppBskyUnspeccedDefs from './types/app/bsky/unspecced/defs' import * as AppBskyUnspeccedGetPopular from './types/app/bsky/unspecced/getPopular' import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' import * as AppBskyUnspeccedGetTimelineSkeleton from './types/app/bsky/unspecced/getTimelineSkeleton' +import * as AppBskyUnspeccedSearchActorsSkeleton from './types/app/bsky/unspecced/searchActorsSkeleton' +import * as AppBskyUnspeccedSearchPostsSkeleton from './types/app/bsky/unspecced/searchPostsSkeleton' export * as ComAtprotoAdminDefs from './types/com/atproto/admin/defs' export * as ComAtprotoAdminDisableAccountInvites from './types/com/atproto/admin/disableAccountInvites' @@ -229,6 +233,7 @@ export * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline' export * as AppBskyFeedLike from './types/app/bsky/feed/like' export * as AppBskyFeedPost from './types/app/bsky/feed/post' export * as AppBskyFeedRepost from './types/app/bsky/feed/repost' +export * as AppBskyFeedSearchPosts from './types/app/bsky/feed/searchPosts' export * as AppBskyFeedThreadgate from './types/app/bsky/feed/threadgate' export * as AppBskyGraphBlock from './types/app/bsky/graph/block' export * as AppBskyGraphDefs from './types/app/bsky/graph/defs' @@ -255,9 +260,12 @@ export * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/ export * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen' export * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet' export * as AppBskyUnspeccedApplyLabels from './types/app/bsky/unspecced/applyLabels' +export * as AppBskyUnspeccedDefs from './types/app/bsky/unspecced/defs' export * as AppBskyUnspeccedGetPopular from './types/app/bsky/unspecced/getPopular' export * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' export * as AppBskyUnspeccedGetTimelineSkeleton from './types/app/bsky/unspecced/getTimelineSkeleton' +export * as AppBskyUnspeccedSearchActorsSkeleton from './types/app/bsky/unspecced/searchActorsSkeleton' +export * as AppBskyUnspeccedSearchPostsSkeleton from './types/app/bsky/unspecced/searchPostsSkeleton' export const COM_ATPROTO_ADMIN = { DefsTakedown: 'com.atproto.admin.defs#takedown', @@ -1381,6 +1389,17 @@ export class FeedNS { throw AppBskyFeedGetTimeline.toKnownErr(e) }) } + + searchPosts( + params?: AppBskyFeedSearchPosts.QueryParams, + opts?: AppBskyFeedSearchPosts.CallOptions, + ): Promise { + return this._service.xrpc + .call('app.bsky.feed.searchPosts', params, undefined, opts) + .catch((e) => { + throw AppBskyFeedSearchPosts.toKnownErr(e) + }) + } } export class GeneratorRecord { @@ -2282,4 +2301,26 @@ export class UnspeccedNS { throw AppBskyUnspeccedGetTimelineSkeleton.toKnownErr(e) }) } + + searchActorsSkeleton( + params?: AppBskyUnspeccedSearchActorsSkeleton.QueryParams, + opts?: AppBskyUnspeccedSearchActorsSkeleton.CallOptions, + ): Promise { + return this._service.xrpc + .call('app.bsky.unspecced.searchActorsSkeleton', params, undefined, opts) + .catch((e) => { + throw AppBskyUnspeccedSearchActorsSkeleton.toKnownErr(e) + }) + } + + searchPostsSkeleton( + params?: AppBskyUnspeccedSearchPostsSkeleton.QueryParams, + opts?: AppBskyUnspeccedSearchPostsSkeleton.CallOptions, + ): Promise { + return this._service.xrpc + .call('app.bsky.unspecced.searchPostsSkeleton', params, undefined, opts) + .catch((e) => { + throw AppBskyUnspeccedSearchPostsSkeleton.toKnownErr(e) + }) + } } diff --git a/packages/api/src/client/lexicons.ts b/packages/api/src/client/lexicons.ts index a5cbf08d608..b624ce335ed 100644 --- a/packages/api/src/client/lexicons.ts +++ b/packages/api/src/client/lexicons.ts @@ -1113,6 +1113,10 @@ export const schemaDict = { properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', }, invitedBy: { type: 'string', @@ -3998,18 +4002,24 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actors matching search criteria.', + description: 'Find actors (profiles) matching search criteria.', parameters: { type: 'params', properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', }, limit: { type: 'integer', minimum: 1, maximum: 100, - default: 50, + default: 25, }, cursor: { type: 'string', @@ -4050,12 +4060,17 @@ export const schemaDict = { properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', + description: 'search query prefix; not a full query string', }, limit: { type: 'integer', minimum: 1, maximum: 100, - default: 50, + default: 10, }, }, }, @@ -5713,6 +5728,67 @@ export const schemaDict = { }, }, }, + AppBskyFeedSearchPosts: { + lexicon: 1, + id: 'app.bsky.feed.searchPosts', + defs: { + main: { + type: 'query', + description: 'Find posts matching search criteria', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['posts'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + posts: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#postView', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, AppBskyFeedThreadgate: { lexicon: 1, id: 'app.bsky.feed.threadgate', @@ -6855,6 +6931,32 @@ export const schemaDict = { }, }, }, + AppBskyUnspeccedDefs: { + lexicon: 1, + id: 'app.bsky.unspecced.defs', + defs: { + skeletonSearchPost: { + type: 'object', + required: ['uri'], + properties: { + uri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + skeletonSearchActor: { + type: 'object', + required: ['did'], + properties: { + did: { + type: 'string', + format: 'did', + }, + }, + }, + }, + }, AppBskyUnspeccedGetPopular: { lexicon: 1, id: 'app.bsky.unspecced.getPopular', @@ -6997,6 +7099,132 @@ export const schemaDict = { }, }, }, + AppBskyUnspeccedSearchActorsSkeleton: { + lexicon: 1, + id: 'app.bsky.unspecced.searchActorsSkeleton', + defs: { + main: { + type: 'query', + description: 'Backend Actors (profile) search, returning only skeleton', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. For typeahead search, only simple term match is supported, not full syntax', + }, + typeahead: { + type: 'boolean', + description: "if true, acts as fast/simple 'typeahead' query", + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['actors'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + actors: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.unspecced.defs#skeletonSearchActor', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, + AppBskyUnspeccedSearchPostsSkeleton: { + lexicon: 1, + id: 'app.bsky.unspecced.searchPostsSkeleton', + defs: { + main: { + type: 'query', + description: 'Backend Posts search, returning only skeleton', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['posts'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + posts: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.unspecced.defs#skeletonSearchPost', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, } export const schemas: LexiconDoc[] = Object.values(schemaDict) as LexiconDoc[] export const lexicons: Lexicons = new Lexicons(schemas) @@ -7103,6 +7331,7 @@ export const ids = { AppBskyFeedLike: 'app.bsky.feed.like', AppBskyFeedPost: 'app.bsky.feed.post', AppBskyFeedRepost: 'app.bsky.feed.repost', + AppBskyFeedSearchPosts: 'app.bsky.feed.searchPosts', AppBskyFeedThreadgate: 'app.bsky.feed.threadgate', AppBskyGraphBlock: 'app.bsky.graph.block', AppBskyGraphDefs: 'app.bsky.graph.defs', @@ -7131,8 +7360,12 @@ export const ids = { AppBskyNotificationUpdateSeen: 'app.bsky.notification.updateSeen', AppBskyRichtextFacet: 'app.bsky.richtext.facet', AppBskyUnspeccedApplyLabels: 'app.bsky.unspecced.applyLabels', + AppBskyUnspeccedDefs: 'app.bsky.unspecced.defs', AppBskyUnspeccedGetPopular: 'app.bsky.unspecced.getPopular', AppBskyUnspeccedGetPopularFeedGenerators: 'app.bsky.unspecced.getPopularFeedGenerators', AppBskyUnspeccedGetTimelineSkeleton: 'app.bsky.unspecced.getTimelineSkeleton', + AppBskyUnspeccedSearchActorsSkeleton: + 'app.bsky.unspecced.searchActorsSkeleton', + AppBskyUnspeccedSearchPostsSkeleton: 'app.bsky.unspecced.searchPostsSkeleton', } diff --git a/packages/api/src/client/types/app/bsky/actor/searchActors.ts b/packages/api/src/client/types/app/bsky/actor/searchActors.ts index 526e012910f..5e6527606d8 100644 --- a/packages/api/src/client/types/app/bsky/actor/searchActors.ts +++ b/packages/api/src/client/types/app/bsky/actor/searchActors.ts @@ -9,7 +9,10 @@ import { CID } from 'multiformats/cid' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q?: string limit?: number cursor?: string } diff --git a/packages/api/src/client/types/app/bsky/actor/searchActorsTypeahead.ts b/packages/api/src/client/types/app/bsky/actor/searchActorsTypeahead.ts index 5bb1557b406..5818d6f64ad 100644 --- a/packages/api/src/client/types/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/api/src/client/types/app/bsky/actor/searchActorsTypeahead.ts @@ -9,7 +9,10 @@ import { CID } from 'multiformats/cid' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + /** search query prefix; not a full query string */ + q?: string limit?: number } diff --git a/packages/api/src/client/types/app/bsky/feed/searchPosts.ts b/packages/api/src/client/types/app/bsky/feed/searchPosts.ts new file mode 100644 index 00000000000..6b8613a2e1f --- /dev/null +++ b/packages/api/src/client/types/app/bsky/feed/searchPosts.ts @@ -0,0 +1,50 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { Headers, XRPCError } from '@atproto/xrpc' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { isObj, hasProp } from '../../../../util' +import { lexicons } from '../../../../lexicons' +import { CID } from 'multiformats/cid' +import * as AppBskyFeedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q: string + limit?: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + posts: AppBskyFeedDefs.PostView[] + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export class BadQueryStringError extends XRPCError { + constructor(src: XRPCError) { + super(src.status, src.error, src.message, src.headers) + } +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + if (e.error === 'BadQueryString') return new BadQueryStringError(e) + } + return e +} diff --git a/packages/api/src/client/types/app/bsky/unspecced/defs.ts b/packages/api/src/client/types/app/bsky/unspecced/defs.ts new file mode 100644 index 00000000000..ecee03578af --- /dev/null +++ b/packages/api/src/client/types/app/bsky/unspecced/defs.ts @@ -0,0 +1,41 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { isObj, hasProp } from '../../../../util' +import { lexicons } from '../../../../lexicons' +import { CID } from 'multiformats/cid' + +export interface SkeletonSearchPost { + uri: string + [k: string]: unknown +} + +export function isSkeletonSearchPost(v: unknown): v is SkeletonSearchPost { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.unspecced.defs#skeletonSearchPost' + ) +} + +export function validateSkeletonSearchPost(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.unspecced.defs#skeletonSearchPost', v) +} + +export interface SkeletonSearchActor { + did: string + [k: string]: unknown +} + +export function isSkeletonSearchActor(v: unknown): v is SkeletonSearchActor { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.unspecced.defs#skeletonSearchActor' + ) +} + +export function validateSkeletonSearchActor(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.unspecced.defs#skeletonSearchActor', v) +} diff --git a/packages/api/src/client/types/app/bsky/unspecced/searchActorsSkeleton.ts b/packages/api/src/client/types/app/bsky/unspecced/searchActorsSkeleton.ts new file mode 100644 index 00000000000..7cc2729620e --- /dev/null +++ b/packages/api/src/client/types/app/bsky/unspecced/searchActorsSkeleton.ts @@ -0,0 +1,52 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { Headers, XRPCError } from '@atproto/xrpc' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { isObj, hasProp } from '../../../../util' +import { lexicons } from '../../../../lexicons' +import { CID } from 'multiformats/cid' +import * as AppBskyUnspeccedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. For typeahead search, only simple term match is supported, not full syntax */ + q: string + /** if true, acts as fast/simple 'typeahead' query */ + typeahead?: boolean + limit?: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + actors: AppBskyUnspeccedDefs.SkeletonSearchActor[] + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export class BadQueryStringError extends XRPCError { + constructor(src: XRPCError) { + super(src.status, src.error, src.message, src.headers) + } +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + if (e.error === 'BadQueryString') return new BadQueryStringError(e) + } + return e +} diff --git a/packages/api/src/client/types/app/bsky/unspecced/searchPostsSkeleton.ts b/packages/api/src/client/types/app/bsky/unspecced/searchPostsSkeleton.ts new file mode 100644 index 00000000000..07391886f8f --- /dev/null +++ b/packages/api/src/client/types/app/bsky/unspecced/searchPostsSkeleton.ts @@ -0,0 +1,50 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { Headers, XRPCError } from '@atproto/xrpc' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { isObj, hasProp } from '../../../../util' +import { lexicons } from '../../../../lexicons' +import { CID } from 'multiformats/cid' +import * as AppBskyUnspeccedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q: string + limit?: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + posts: AppBskyUnspeccedDefs.SkeletonSearchPost[] + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export class BadQueryStringError extends XRPCError { + constructor(src: XRPCError) { + super(src.status, src.error, src.message, src.headers) + } +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + if (e.error === 'BadQueryString') return new BadQueryStringError(e) + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/admin/searchRepos.ts b/packages/api/src/client/types/com/atproto/admin/searchRepos.ts index a43e0ee7322..372cc98ff13 100644 --- a/packages/api/src/client/types/com/atproto/admin/searchRepos.ts +++ b/packages/api/src/client/types/com/atproto/admin/searchRepos.ts @@ -9,7 +9,9 @@ import { CID } from 'multiformats/cid' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + q?: string invitedBy?: string limit?: number cursor?: string diff --git a/packages/bsky/src/api/app/bsky/actor/searchActors.ts b/packages/bsky/src/api/app/bsky/actor/searchActors.ts index df5821a03f9..d4ae0a8d264 100644 --- a/packages/bsky/src/api/app/bsky/actor/searchActors.ts +++ b/packages/bsky/src/api/app/bsky/actor/searchActors.ts @@ -11,8 +11,14 @@ export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.searchActors({ auth: ctx.authOptionalVerifier, handler: async ({ auth, params }) => { - const { cursor, limit, term: rawTerm } = params + let { cursor, limit, term: rawTerm, q: rawQ } = params const requester = auth.credentials.did + + // prefer new 'q' query param over deprecated 'term' + if (rawQ) { + rawTerm = rawQ + } + const term = cleanTerm(rawTerm || '') const db = ctx.db.getReplica('search') diff --git a/packages/bsky/src/api/app/bsky/actor/searchActorsTypeahead.ts b/packages/bsky/src/api/app/bsky/actor/searchActorsTypeahead.ts index 64bcd811d02..c438c4d2324 100644 --- a/packages/bsky/src/api/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/bsky/src/api/app/bsky/actor/searchActorsTypeahead.ts @@ -9,8 +9,14 @@ export default function (server: Server, ctx: AppContext) { server.app.bsky.actor.searchActorsTypeahead({ auth: ctx.authOptionalVerifier, handler: async ({ params, auth }) => { - const { limit, term: rawTerm } = params + let { limit, term: rawTerm, q: rawQ } = params const requester = auth.credentials.did + + // prefer new 'q' query param over deprecated 'term' + if (rawQ) { + rawTerm = rawQ + } + const term = cleanTerm(rawTerm || '') const db = ctx.db.getReplica('search') diff --git a/packages/bsky/src/api/com/atproto/admin/searchRepos.ts b/packages/bsky/src/api/com/atproto/admin/searchRepos.ts index 9945b27fcb4..a17421e90cd 100644 --- a/packages/bsky/src/api/com/atproto/admin/searchRepos.ts +++ b/packages/bsky/src/api/com/atproto/admin/searchRepos.ts @@ -12,6 +12,11 @@ export default function (server: Server, ctx: AppContext) { if (invitedBy) { throw new InvalidRequestError('The invitedBy parameter is unsupported') } + // prefer new 'q' query param over deprecated 'term' + const { q } = params + if (q) { + params.term = q + } const { results, cursor } = await ctx.services .actor(db) diff --git a/packages/bsky/src/lexicon/index.ts b/packages/bsky/src/lexicon/index.ts index 52635132470..3ec69a3503f 100644 --- a/packages/bsky/src/lexicon/index.ts +++ b/packages/bsky/src/lexicon/index.ts @@ -89,6 +89,7 @@ import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts' import * as AppBskyFeedGetRepostedBy from './types/app/bsky/feed/getRepostedBy' import * as AppBskyFeedGetSuggestedFeeds from './types/app/bsky/feed/getSuggestedFeeds' import * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline' +import * as AppBskyFeedSearchPosts from './types/app/bsky/feed/searchPosts' import * as AppBskyGraphGetBlocks from './types/app/bsky/graph/getBlocks' import * as AppBskyGraphGetFollowers from './types/app/bsky/graph/getFollowers' import * as AppBskyGraphGetFollows from './types/app/bsky/graph/getFollows' @@ -110,6 +111,8 @@ import * as AppBskyUnspeccedApplyLabels from './types/app/bsky/unspecced/applyLa import * as AppBskyUnspeccedGetPopular from './types/app/bsky/unspecced/getPopular' import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' import * as AppBskyUnspeccedGetTimelineSkeleton from './types/app/bsky/unspecced/getTimelineSkeleton' +import * as AppBskyUnspeccedSearchActorsSkeleton from './types/app/bsky/unspecced/searchActorsSkeleton' +import * as AppBskyUnspeccedSearchPostsSkeleton from './types/app/bsky/unspecced/searchPostsSkeleton' export const COM_ATPROTO_ADMIN = { DefsTakedown: 'com.atproto.admin.defs#takedown', @@ -1168,6 +1171,17 @@ export class FeedNS { const nsid = 'app.bsky.feed.getTimeline' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } + + searchPosts( + cfg: ConfigOf< + AV, + AppBskyFeedSearchPosts.Handler>, + AppBskyFeedSearchPosts.HandlerReqCtx> + >, + ) { + const nsid = 'app.bsky.feed.searchPosts' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } } export class GraphNS { @@ -1431,6 +1445,28 @@ export class UnspeccedNS { const nsid = 'app.bsky.unspecced.getTimelineSkeleton' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } + + searchActorsSkeleton( + cfg: ConfigOf< + AV, + AppBskyUnspeccedSearchActorsSkeleton.Handler>, + AppBskyUnspeccedSearchActorsSkeleton.HandlerReqCtx> + >, + ) { + const nsid = 'app.bsky.unspecced.searchActorsSkeleton' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + searchPostsSkeleton( + cfg: ConfigOf< + AV, + AppBskyUnspeccedSearchPostsSkeleton.Handler>, + AppBskyUnspeccedSearchPostsSkeleton.HandlerReqCtx> + >, + ) { + const nsid = 'app.bsky.unspecced.searchPostsSkeleton' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } } type SharedRateLimitOpts = { diff --git a/packages/bsky/src/lexicon/lexicons.ts b/packages/bsky/src/lexicon/lexicons.ts index a5cbf08d608..b624ce335ed 100644 --- a/packages/bsky/src/lexicon/lexicons.ts +++ b/packages/bsky/src/lexicon/lexicons.ts @@ -1113,6 +1113,10 @@ export const schemaDict = { properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', }, invitedBy: { type: 'string', @@ -3998,18 +4002,24 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actors matching search criteria.', + description: 'Find actors (profiles) matching search criteria.', parameters: { type: 'params', properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', }, limit: { type: 'integer', minimum: 1, maximum: 100, - default: 50, + default: 25, }, cursor: { type: 'string', @@ -4050,12 +4060,17 @@ export const schemaDict = { properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', + description: 'search query prefix; not a full query string', }, limit: { type: 'integer', minimum: 1, maximum: 100, - default: 50, + default: 10, }, }, }, @@ -5713,6 +5728,67 @@ export const schemaDict = { }, }, }, + AppBskyFeedSearchPosts: { + lexicon: 1, + id: 'app.bsky.feed.searchPosts', + defs: { + main: { + type: 'query', + description: 'Find posts matching search criteria', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['posts'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + posts: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#postView', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, AppBskyFeedThreadgate: { lexicon: 1, id: 'app.bsky.feed.threadgate', @@ -6855,6 +6931,32 @@ export const schemaDict = { }, }, }, + AppBskyUnspeccedDefs: { + lexicon: 1, + id: 'app.bsky.unspecced.defs', + defs: { + skeletonSearchPost: { + type: 'object', + required: ['uri'], + properties: { + uri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + skeletonSearchActor: { + type: 'object', + required: ['did'], + properties: { + did: { + type: 'string', + format: 'did', + }, + }, + }, + }, + }, AppBskyUnspeccedGetPopular: { lexicon: 1, id: 'app.bsky.unspecced.getPopular', @@ -6997,6 +7099,132 @@ export const schemaDict = { }, }, }, + AppBskyUnspeccedSearchActorsSkeleton: { + lexicon: 1, + id: 'app.bsky.unspecced.searchActorsSkeleton', + defs: { + main: { + type: 'query', + description: 'Backend Actors (profile) search, returning only skeleton', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. For typeahead search, only simple term match is supported, not full syntax', + }, + typeahead: { + type: 'boolean', + description: "if true, acts as fast/simple 'typeahead' query", + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['actors'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + actors: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.unspecced.defs#skeletonSearchActor', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, + AppBskyUnspeccedSearchPostsSkeleton: { + lexicon: 1, + id: 'app.bsky.unspecced.searchPostsSkeleton', + defs: { + main: { + type: 'query', + description: 'Backend Posts search, returning only skeleton', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['posts'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + posts: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.unspecced.defs#skeletonSearchPost', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, } export const schemas: LexiconDoc[] = Object.values(schemaDict) as LexiconDoc[] export const lexicons: Lexicons = new Lexicons(schemas) @@ -7103,6 +7331,7 @@ export const ids = { AppBskyFeedLike: 'app.bsky.feed.like', AppBskyFeedPost: 'app.bsky.feed.post', AppBskyFeedRepost: 'app.bsky.feed.repost', + AppBskyFeedSearchPosts: 'app.bsky.feed.searchPosts', AppBskyFeedThreadgate: 'app.bsky.feed.threadgate', AppBskyGraphBlock: 'app.bsky.graph.block', AppBskyGraphDefs: 'app.bsky.graph.defs', @@ -7131,8 +7360,12 @@ export const ids = { AppBskyNotificationUpdateSeen: 'app.bsky.notification.updateSeen', AppBskyRichtextFacet: 'app.bsky.richtext.facet', AppBskyUnspeccedApplyLabels: 'app.bsky.unspecced.applyLabels', + AppBskyUnspeccedDefs: 'app.bsky.unspecced.defs', AppBskyUnspeccedGetPopular: 'app.bsky.unspecced.getPopular', AppBskyUnspeccedGetPopularFeedGenerators: 'app.bsky.unspecced.getPopularFeedGenerators', AppBskyUnspeccedGetTimelineSkeleton: 'app.bsky.unspecced.getTimelineSkeleton', + AppBskyUnspeccedSearchActorsSkeleton: + 'app.bsky.unspecced.searchActorsSkeleton', + AppBskyUnspeccedSearchPostsSkeleton: 'app.bsky.unspecced.searchPostsSkeleton', } diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/searchActors.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/searchActors.ts index f620a463cff..0222f3658da 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/searchActors.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/searchActors.ts @@ -10,7 +10,10 @@ import { HandlerAuth } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q?: string limit: number cursor?: string } diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts index 4f5bbb7c23c..ba0d62444ce 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts @@ -10,7 +10,10 @@ import { HandlerAuth } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + /** search query prefix; not a full query string */ + q?: string limit: number } diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts new file mode 100644 index 00000000000..6b5fe08e467 --- /dev/null +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts @@ -0,0 +1,54 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyFeedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q: string + limit: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + posts: AppBskyFeedDefs.PostView[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema + headers?: { [key: string]: string } +} + +export interface HandlerError { + status: number + message?: string + error?: 'BadQueryString' +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/defs.ts b/packages/bsky/src/lexicon/types/app/bsky/unspecced/defs.ts new file mode 100644 index 00000000000..59a6b38064c --- /dev/null +++ b/packages/bsky/src/lexicon/types/app/bsky/unspecced/defs.ts @@ -0,0 +1,41 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' + +export interface SkeletonSearchPost { + uri: string + [k: string]: unknown +} + +export function isSkeletonSearchPost(v: unknown): v is SkeletonSearchPost { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.unspecced.defs#skeletonSearchPost' + ) +} + +export function validateSkeletonSearchPost(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.unspecced.defs#skeletonSearchPost', v) +} + +export interface SkeletonSearchActor { + did: string + [k: string]: unknown +} + +export function isSkeletonSearchActor(v: unknown): v is SkeletonSearchActor { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.unspecced.defs#skeletonSearchActor' + ) +} + +export function validateSkeletonSearchActor(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.unspecced.defs#skeletonSearchActor', v) +} diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts new file mode 100644 index 00000000000..2cf59bf86a9 --- /dev/null +++ b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts @@ -0,0 +1,56 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyUnspeccedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. For typeahead search, only simple term match is supported, not full syntax */ + q: string + /** if true, acts as fast/simple 'typeahead' query */ + typeahead?: boolean + limit: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + actors: AppBskyUnspeccedDefs.SkeletonSearchActor[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema + headers?: { [key: string]: string } +} + +export interface HandlerError { + status: number + message?: string + error?: 'BadQueryString' +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts new file mode 100644 index 00000000000..df990d2c5c6 --- /dev/null +++ b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts @@ -0,0 +1,54 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyUnspeccedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q: string + limit: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + posts: AppBskyUnspeccedDefs.SkeletonSearchPost[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema + headers?: { [key: string]: string } +} + +export interface HandlerError { + status: number + message?: string + error?: 'BadQueryString' +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/searchRepos.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/searchRepos.ts index c79cd046ca0..32266fd66fd 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/searchRepos.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/searchRepos.ts @@ -10,7 +10,9 @@ import { HandlerAuth } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + q?: string invitedBy?: string limit: number cursor?: string diff --git a/packages/pds/src/lexicon/index.ts b/packages/pds/src/lexicon/index.ts index 52635132470..3ec69a3503f 100644 --- a/packages/pds/src/lexicon/index.ts +++ b/packages/pds/src/lexicon/index.ts @@ -89,6 +89,7 @@ import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts' import * as AppBskyFeedGetRepostedBy from './types/app/bsky/feed/getRepostedBy' import * as AppBskyFeedGetSuggestedFeeds from './types/app/bsky/feed/getSuggestedFeeds' import * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline' +import * as AppBskyFeedSearchPosts from './types/app/bsky/feed/searchPosts' import * as AppBskyGraphGetBlocks from './types/app/bsky/graph/getBlocks' import * as AppBskyGraphGetFollowers from './types/app/bsky/graph/getFollowers' import * as AppBskyGraphGetFollows from './types/app/bsky/graph/getFollows' @@ -110,6 +111,8 @@ import * as AppBskyUnspeccedApplyLabels from './types/app/bsky/unspecced/applyLa import * as AppBskyUnspeccedGetPopular from './types/app/bsky/unspecced/getPopular' import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' import * as AppBskyUnspeccedGetTimelineSkeleton from './types/app/bsky/unspecced/getTimelineSkeleton' +import * as AppBskyUnspeccedSearchActorsSkeleton from './types/app/bsky/unspecced/searchActorsSkeleton' +import * as AppBskyUnspeccedSearchPostsSkeleton from './types/app/bsky/unspecced/searchPostsSkeleton' export const COM_ATPROTO_ADMIN = { DefsTakedown: 'com.atproto.admin.defs#takedown', @@ -1168,6 +1171,17 @@ export class FeedNS { const nsid = 'app.bsky.feed.getTimeline' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } + + searchPosts( + cfg: ConfigOf< + AV, + AppBskyFeedSearchPosts.Handler>, + AppBskyFeedSearchPosts.HandlerReqCtx> + >, + ) { + const nsid = 'app.bsky.feed.searchPosts' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } } export class GraphNS { @@ -1431,6 +1445,28 @@ export class UnspeccedNS { const nsid = 'app.bsky.unspecced.getTimelineSkeleton' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } + + searchActorsSkeleton( + cfg: ConfigOf< + AV, + AppBskyUnspeccedSearchActorsSkeleton.Handler>, + AppBskyUnspeccedSearchActorsSkeleton.HandlerReqCtx> + >, + ) { + const nsid = 'app.bsky.unspecced.searchActorsSkeleton' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + searchPostsSkeleton( + cfg: ConfigOf< + AV, + AppBskyUnspeccedSearchPostsSkeleton.Handler>, + AppBskyUnspeccedSearchPostsSkeleton.HandlerReqCtx> + >, + ) { + const nsid = 'app.bsky.unspecced.searchPostsSkeleton' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } } type SharedRateLimitOpts = { diff --git a/packages/pds/src/lexicon/lexicons.ts b/packages/pds/src/lexicon/lexicons.ts index a5cbf08d608..b624ce335ed 100644 --- a/packages/pds/src/lexicon/lexicons.ts +++ b/packages/pds/src/lexicon/lexicons.ts @@ -1113,6 +1113,10 @@ export const schemaDict = { properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', }, invitedBy: { type: 'string', @@ -3998,18 +4002,24 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actors matching search criteria.', + description: 'Find actors (profiles) matching search criteria.', parameters: { type: 'params', properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', }, limit: { type: 'integer', minimum: 1, maximum: 100, - default: 50, + default: 25, }, cursor: { type: 'string', @@ -4050,12 +4060,17 @@ export const schemaDict = { properties: { term: { type: 'string', + description: "DEPRECATED: use 'q' instead", + }, + q: { + type: 'string', + description: 'search query prefix; not a full query string', }, limit: { type: 'integer', minimum: 1, maximum: 100, - default: 50, + default: 10, }, }, }, @@ -5713,6 +5728,67 @@ export const schemaDict = { }, }, }, + AppBskyFeedSearchPosts: { + lexicon: 1, + id: 'app.bsky.feed.searchPosts', + defs: { + main: { + type: 'query', + description: 'Find posts matching search criteria', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['posts'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + posts: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#postView', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, AppBskyFeedThreadgate: { lexicon: 1, id: 'app.bsky.feed.threadgate', @@ -6855,6 +6931,32 @@ export const schemaDict = { }, }, }, + AppBskyUnspeccedDefs: { + lexicon: 1, + id: 'app.bsky.unspecced.defs', + defs: { + skeletonSearchPost: { + type: 'object', + required: ['uri'], + properties: { + uri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + skeletonSearchActor: { + type: 'object', + required: ['did'], + properties: { + did: { + type: 'string', + format: 'did', + }, + }, + }, + }, + }, AppBskyUnspeccedGetPopular: { lexicon: 1, id: 'app.bsky.unspecced.getPopular', @@ -6997,6 +7099,132 @@ export const schemaDict = { }, }, }, + AppBskyUnspeccedSearchActorsSkeleton: { + lexicon: 1, + id: 'app.bsky.unspecced.searchActorsSkeleton', + defs: { + main: { + type: 'query', + description: 'Backend Actors (profile) search, returning only skeleton', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. For typeahead search, only simple term match is supported, not full syntax', + }, + typeahead: { + type: 'boolean', + description: "if true, acts as fast/simple 'typeahead' query", + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['actors'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + actors: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.unspecced.defs#skeletonSearchActor', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, + AppBskyUnspeccedSearchPostsSkeleton: { + lexicon: 1, + id: 'app.bsky.unspecced.searchPostsSkeleton', + defs: { + main: { + type: 'query', + description: 'Backend Posts search, returning only skeleton', + parameters: { + type: 'params', + required: ['q'], + properties: { + q: { + type: 'string', + description: + 'search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 25, + }, + cursor: { + type: 'string', + description: + 'optional pagination mechanism; may not necessarily allow scrolling through entire result set', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['posts'], + properties: { + cursor: { + type: 'string', + }, + hitsTotal: { + type: 'integer', + description: + 'count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits', + }, + posts: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.unspecced.defs#skeletonSearchPost', + }, + }, + }, + }, + }, + errors: [ + { + name: 'BadQueryString', + }, + ], + }, + }, + }, } export const schemas: LexiconDoc[] = Object.values(schemaDict) as LexiconDoc[] export const lexicons: Lexicons = new Lexicons(schemas) @@ -7103,6 +7331,7 @@ export const ids = { AppBskyFeedLike: 'app.bsky.feed.like', AppBskyFeedPost: 'app.bsky.feed.post', AppBskyFeedRepost: 'app.bsky.feed.repost', + AppBskyFeedSearchPosts: 'app.bsky.feed.searchPosts', AppBskyFeedThreadgate: 'app.bsky.feed.threadgate', AppBskyGraphBlock: 'app.bsky.graph.block', AppBskyGraphDefs: 'app.bsky.graph.defs', @@ -7131,8 +7360,12 @@ export const ids = { AppBskyNotificationUpdateSeen: 'app.bsky.notification.updateSeen', AppBskyRichtextFacet: 'app.bsky.richtext.facet', AppBskyUnspeccedApplyLabels: 'app.bsky.unspecced.applyLabels', + AppBskyUnspeccedDefs: 'app.bsky.unspecced.defs', AppBskyUnspeccedGetPopular: 'app.bsky.unspecced.getPopular', AppBskyUnspeccedGetPopularFeedGenerators: 'app.bsky.unspecced.getPopularFeedGenerators', AppBskyUnspeccedGetTimelineSkeleton: 'app.bsky.unspecced.getTimelineSkeleton', + AppBskyUnspeccedSearchActorsSkeleton: + 'app.bsky.unspecced.searchActorsSkeleton', + AppBskyUnspeccedSearchPostsSkeleton: 'app.bsky.unspecced.searchPostsSkeleton', } diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/searchActors.ts b/packages/pds/src/lexicon/types/app/bsky/actor/searchActors.ts index f620a463cff..0222f3658da 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/searchActors.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/searchActors.ts @@ -10,7 +10,10 @@ import { HandlerAuth } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q?: string limit: number cursor?: string } diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts b/packages/pds/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts index 4f5bbb7c23c..ba0d62444ce 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts @@ -10,7 +10,10 @@ import { HandlerAuth } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + /** search query prefix; not a full query string */ + q?: string limit: number } diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts b/packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts new file mode 100644 index 00000000000..6b5fe08e467 --- /dev/null +++ b/packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts @@ -0,0 +1,54 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyFeedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q: string + limit: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + posts: AppBskyFeedDefs.PostView[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema + headers?: { [key: string]: string } +} + +export interface HandlerError { + status: number + message?: string + error?: 'BadQueryString' +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/defs.ts b/packages/pds/src/lexicon/types/app/bsky/unspecced/defs.ts new file mode 100644 index 00000000000..59a6b38064c --- /dev/null +++ b/packages/pds/src/lexicon/types/app/bsky/unspecced/defs.ts @@ -0,0 +1,41 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' + +export interface SkeletonSearchPost { + uri: string + [k: string]: unknown +} + +export function isSkeletonSearchPost(v: unknown): v is SkeletonSearchPost { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.unspecced.defs#skeletonSearchPost' + ) +} + +export function validateSkeletonSearchPost(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.unspecced.defs#skeletonSearchPost', v) +} + +export interface SkeletonSearchActor { + did: string + [k: string]: unknown +} + +export function isSkeletonSearchActor(v: unknown): v is SkeletonSearchActor { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.unspecced.defs#skeletonSearchActor' + ) +} + +export function validateSkeletonSearchActor(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.unspecced.defs#skeletonSearchActor', v) +} diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts new file mode 100644 index 00000000000..2cf59bf86a9 --- /dev/null +++ b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts @@ -0,0 +1,56 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyUnspeccedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. For typeahead search, only simple term match is supported, not full syntax */ + q: string + /** if true, acts as fast/simple 'typeahead' query */ + typeahead?: boolean + limit: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + actors: AppBskyUnspeccedDefs.SkeletonSearchActor[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema + headers?: { [key: string]: string } +} + +export interface HandlerError { + status: number + message?: string + error?: 'BadQueryString' +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts new file mode 100644 index 00000000000..df990d2c5c6 --- /dev/null +++ b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts @@ -0,0 +1,54 @@ +/** + * GENERATED CODE - DO NOT MODIFY + */ +import express from 'express' +import { ValidationResult, BlobRef } from '@atproto/lexicon' +import { lexicons } from '../../../../lexicons' +import { isObj, hasProp } from '../../../../util' +import { CID } from 'multiformats/cid' +import { HandlerAuth } from '@atproto/xrpc-server' +import * as AppBskyUnspeccedDefs from './defs' + +export interface QueryParams { + /** search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended */ + q: string + limit: number + /** optional pagination mechanism; may not necessarily allow scrolling through entire result set */ + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + /** count of search hits. optional, may be rounded/truncated, and may not be possible to paginate through all hits */ + hitsTotal?: number + posts: AppBskyUnspeccedDefs.SkeletonSearchPost[] + [k: string]: unknown +} + +export type HandlerInput = undefined + +export interface HandlerSuccess { + encoding: 'application/json' + body: OutputSchema + headers?: { [key: string]: string } +} + +export interface HandlerError { + status: number + message?: string + error?: 'BadQueryString' +} + +export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/searchRepos.ts b/packages/pds/src/lexicon/types/com/atproto/admin/searchRepos.ts index c79cd046ca0..32266fd66fd 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/searchRepos.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/searchRepos.ts @@ -10,7 +10,9 @@ import { HandlerAuth } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { + /** DEPRECATED: use 'q' instead */ term?: string + q?: string invitedBy?: string limit: number cursor?: string