diff --git a/.changeset/cuddly-adults-beg.md b/.changeset/cuddly-adults-beg.md new file mode 100644 index 00000000000..b47c8101273 --- /dev/null +++ b/.changeset/cuddly-adults-beg.md @@ -0,0 +1,5 @@ +--- +'@atproto/syntax': minor +--- + +allow colon character in record-key syntax diff --git a/.changeset/lovely-dogs-run.md b/.changeset/lovely-dogs-run.md new file mode 100644 index 00000000000..b2ac95215b6 --- /dev/null +++ b/.changeset/lovely-dogs-run.md @@ -0,0 +1,5 @@ +--- +'@atproto/api': patch +--- + +Fix mute word upsert logic by ensuring we're comparing sanitized word values diff --git a/LICENSE.txt b/LICENSE.txt index 36f42cf81d0..a96dd61e293 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ Dual MIT/Apache-2.0 License -Copyright (c) 2022-2023 Bluesky PBC, and Contributors +Copyright (c) 2022-2024 Bluesky PBC, and Contributors Except as otherwise noted in individual files, this software is licensed under the MIT license (), or the Apache License, Version 2.0 (). diff --git a/README.md b/README.md index a54fa91fe5f..96b7ee350f2 100644 --- a/README.md +++ b/README.md @@ -61,12 +61,12 @@ make help ## About AT Protocol -The Authenticated Transfer Protocol ("ATP" or "atproto") is a decentralized social media protocol, developed by [Bluesky PBC](https://blueskyweb.xyz). Learn more at: +The Authenticated Transfer Protocol ("ATP" or "atproto") is a decentralized social media protocol, developed by [Bluesky PBC](https://bsky.social). Learn more at: - [Overview and Guides](https://atproto.com/guides/overview) 👈 Best starting point - [Github Discussions](https://github.com/bluesky-social/atproto/discussions) 👈 Great place to ask questions - [Protocol Specifications](https://atproto.com/specs/atp) -- [Blogpost on self-authenticating data structures](https://blueskyweb.xyz/blog/3-6-2022-a-self-authenticating-social-protocol) +- [Blogpost on self-authenticating data structures](https://bsky.social/about/blog/3-6-2022-a-self-authenticating-social-protocol) The Bluesky Social application encompasses a set of schemas and APIs built in the overall AT Protocol framework. The namespace for these "Lexicons" is `app.bsky.*`. diff --git a/interop-test-files/syntax/aturi_syntax_valid.txt b/interop-test-files/syntax/aturi_syntax_valid.txt index 2552a964ce0..fd4523d0de9 100644 --- a/interop-test-files/syntax/aturi_syntax_valid.txt +++ b/interop-test-files/syntax/aturi_syntax_valid.txt @@ -24,3 +24,11 @@ at://did:plc:asdf123/com.atproto.feed.post/a at://did:plc:asdf123/com.atproto.feed.post/asdf-123 at://did:abc:123 at://did:abc:123/io.nsid.someFunc/record-key + +at://did:abc:123/io.nsid.someFunc/self. +at://did:abc:123/io.nsid.someFunc/lang: +at://did:abc:123/io.nsid.someFunc/: +at://did:abc:123/io.nsid.someFunc/- +at://did:abc:123/io.nsid.someFunc/_ +at://did:abc:123/io.nsid.someFunc/~ +at://did:abc:123/io.nsid.someFunc/... diff --git a/interop-test-files/syntax/recordkey_syntax_invalid.txt b/interop-test-files/syntax/recordkey_syntax_invalid.txt index 1da3d1e7dbc..52106d873a0 100644 --- a/interop-test-files/syntax/recordkey_syntax_invalid.txt +++ b/interop-test-files/syntax/recordkey_syntax_invalid.txt @@ -1,5 +1,4 @@ # specs -literal:self alpha/beta . .. @@ -10,5 +9,7 @@ any+space number[3] number(3) "quote" -pre:fix dHJ1ZQ== + +# too long: 'o'.repeat(513) +ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo diff --git a/interop-test-files/syntax/recordkey_syntax_valid.txt b/interop-test-files/syntax/recordkey_syntax_valid.txt index 8d77d04d2b7..92e8b7e31c9 100644 --- a/interop-test-files/syntax/recordkey_syntax_valid.txt +++ b/interop-test-files/syntax/recordkey_syntax_valid.txt @@ -3,6 +3,19 @@ self example.com ~1.2-3_ dHJ1ZQ +_ +literal:self +pre:fix + +# more corner-cases +: +- +_ +~ +... +self. +lang: +:lang # very long: 'o'.repeat(512) oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo diff --git a/lexicons/app/bsky/actor/defs.json b/lexicons/app/bsky/actor/defs.json index 913957f1291..4764c7c14ae 100644 --- a/lexicons/app/bsky/actor/defs.json +++ b/lexicons/app/bsky/actor/defs.json @@ -1,7 +1,6 @@ { "lexicon": 1, "id": "app.bsky.actor.defs", - "description": "A reference to an actor in the network.", "defs": { "profileViewBasic": { "type": "object", @@ -78,6 +77,7 @@ }, "viewerState": { "type": "object", + "description": "Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests.", "properties": { "muted": { "type": "boolean" }, "mutedByList": { @@ -104,7 +104,10 @@ "#savedFeedsPref", "#personalDetailsPref", "#feedViewPref", - "#threadViewPref" + "#threadViewPref", + "#interestsPref", + "#mutedWordsPref", + "#hiddenPostsPref" ] } }, @@ -143,6 +146,9 @@ "type": "string", "format": "at-uri" } + }, + "timelineIndex": { + "type": "integer" } } }, @@ -199,6 +205,70 @@ "description": "Show followed users at the top of all replies." } } + }, + "interestsPref": { + "type": "object", + "required": ["tags"], + "properties": { + "tags": { + "type": "array", + "maxLength": 100, + "items": { "type": "string", "maxLength": 640, "maxGraphemes": 64 }, + "description": "A list of tags which describe the account owner's interests gathered during onboarding." + } + } + }, + "mutedWordTarget": { + "type": "string", + "knownValues": ["content", "tag"], + "maxLength": 640, + "maxGraphemes": 64 + }, + "mutedWord": { + "type": "object", + "description": "A word that the account owner has muted.", + "required": ["value", "targets"], + "properties": { + "value": { + "type": "string", + "description": "The muted word itself.", + "maxLength": 10000, + "maxGraphemes": 1000 + }, + "targets": { + "type": "array", + "description": "The intended targets of the muted word.", + "items": { + "type": "ref", + "ref": "app.bsky.actor.defs#mutedWordTarget" + } + } + } + }, + "mutedWordsPref": { + "type": "object", + "required": ["items"], + "properties": { + "items": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.actor.defs#mutedWord" + }, + "description": "A list of words the account owner has muted." + } + } + }, + "hiddenPostsPref": { + "type": "object", + "required": ["items"], + "properties": { + "items": { + "type": "array", + "items": { "type": "string", "format": "at-uri" }, + "description": "A list of URIs of posts the account owner has hidden." + } + } } } } diff --git a/lexicons/app/bsky/actor/getPreferences.json b/lexicons/app/bsky/actor/getPreferences.json index cbd6b60bd6a..e6356a86f47 100644 --- a/lexicons/app/bsky/actor/getPreferences.json +++ b/lexicons/app/bsky/actor/getPreferences.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get private preferences attached to the account.", + "description": "Get private preferences attached to the current account. Expected use is synchronization between multiple devices, and import/export during account migration. Requires auth.", "parameters": { "type": "params", "properties": {} diff --git a/lexicons/app/bsky/actor/getProfile.json b/lexicons/app/bsky/actor/getProfile.json index 1bb2ad2fea1..15b0fcc2ec0 100644 --- a/lexicons/app/bsky/actor/getProfile.json +++ b/lexicons/app/bsky/actor/getProfile.json @@ -4,12 +4,16 @@ "defs": { "main": { "type": "query", - "description": "Get detailed profile view of an actor.", + "description": "Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.", "parameters": { "type": "params", "required": ["actor"], "properties": { - "actor": { "type": "string", "format": "at-identifier" } + "actor": { + "type": "string", + "format": "at-identifier", + "description": "Handle or DID of account to fetch profile of." + } } }, "output": { diff --git a/lexicons/app/bsky/actor/getSuggestions.json b/lexicons/app/bsky/actor/getSuggestions.json index 74465dfdf2e..2004ae6f23e 100644 --- a/lexicons/app/bsky/actor/getSuggestions.json +++ b/lexicons/app/bsky/actor/getSuggestions.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of suggested actors, used for discovery.", + "description": "Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/actor/profile.json b/lexicons/app/bsky/actor/profile.json index e1b7c6a2b96..feb083d500a 100644 --- a/lexicons/app/bsky/actor/profile.json +++ b/lexicons/app/bsky/actor/profile.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "record", - "description": "A declaration of a profile.", + "description": "A declaration of a Bluesky account profile.", "key": "literal:self", "record": { "type": "object", @@ -16,21 +16,25 @@ }, "description": { "type": "string", + "description": "Free-form profile description text.", "maxGraphemes": 256, "maxLength": 2560 }, "avatar": { "type": "blob", + "description": "Small image to be displayed next to posts from account. AKA, 'profile picture'", "accept": ["image/png", "image/jpeg"], "maxSize": 1000000 }, "banner": { "type": "blob", + "description": "Larger horizontal image to display behind profile view.", "accept": ["image/png", "image/jpeg"], "maxSize": 1000000 }, "labels": { "type": "union", + "description": "Self-label values, specific to the Bluesky application, on the overall account.", "refs": ["com.atproto.label.defs#selfLabels"] } } diff --git a/lexicons/app/bsky/actor/searchActors.json b/lexicons/app/bsky/actor/searchActors.json index 48fbacf4fcc..15ccb082238 100644 --- a/lexicons/app/bsky/actor/searchActors.json +++ b/lexicons/app/bsky/actor/searchActors.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Find actors (profiles) matching search criteria.", + "description": "Find actors (profiles) matching search criteria. Does not require auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/actor/searchActorsTypeahead.json b/lexicons/app/bsky/actor/searchActorsTypeahead.json index 495b7081c38..4e3cb1b4e88 100644 --- a/lexicons/app/bsky/actor/searchActorsTypeahead.json +++ b/lexicons/app/bsky/actor/searchActorsTypeahead.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Find actor suggestions for a prefix search term.", + "description": "Find actor suggestions for a prefix search term. Expected use is for auto-completion during text field entry. Does not require auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/embed/external.json b/lexicons/app/bsky/embed/external.json index 8946382835f..b9c8c1596d5 100644 --- a/lexicons/app/bsky/embed/external.json +++ b/lexicons/app/bsky/embed/external.json @@ -1,10 +1,10 @@ { "lexicon": 1, "id": "app.bsky.embed.external", - "description": "A representation of some externally linked content, embedded in another form of content.", "defs": { "main": { "type": "object", + "description": "A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post).", "required": ["external"], "properties": { "external": { diff --git a/lexicons/app/bsky/embed/images.json b/lexicons/app/bsky/embed/images.json index 5baa7ab3f74..307607bb7c2 100644 --- a/lexicons/app/bsky/embed/images.json +++ b/lexicons/app/bsky/embed/images.json @@ -1,7 +1,7 @@ { "lexicon": 1, "id": "app.bsky.embed.images", - "description": "A set of images embedded in some other form of content.", + "description": "A set of images embedded in a Bluesky record (eg, a post).", "defs": { "main": { "type": "object", @@ -23,7 +23,10 @@ "accept": ["image/*"], "maxSize": 1000000 }, - "alt": { "type": "string" }, + "alt": { + "type": "string", + "description": "Alt text description of the image, for accessibility." + }, "aspectRatio": { "type": "ref", "ref": "#aspectRatio" } } }, @@ -51,9 +54,18 @@ "type": "object", "required": ["thumb", "fullsize", "alt"], "properties": { - "thumb": { "type": "string" }, - "fullsize": { "type": "string" }, - "alt": { "type": "string" }, + "thumb": { + "type": "string", + "description": "Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View." + }, + "fullsize": { + "type": "string", + "description": "Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View." + }, + "alt": { + "type": "string", + "description": "Alt text description of the image, for accessibility." + }, "aspectRatio": { "type": "ref", "ref": "#aspectRatio" } } } diff --git a/lexicons/app/bsky/embed/record.json b/lexicons/app/bsky/embed/record.json index 4b3d4f814a5..fff9730237d 100644 --- a/lexicons/app/bsky/embed/record.json +++ b/lexicons/app/bsky/embed/record.json @@ -1,7 +1,7 @@ { "lexicon": 1, "id": "app.bsky.embed.record", - "description": "A representation of a record embedded in another form of content.", + "description": "A representation of a record embedded in a Bluesky record (eg, a post). For example, a quote-post, or sharing a feed generator record.", "defs": { "main": { "type": "object", @@ -36,7 +36,10 @@ "type": "ref", "ref": "app.bsky.actor.defs#profileViewBasic" }, - "value": { "type": "unknown" }, + "value": { + "type": "unknown", + "description": "The record data itself." + }, "labels": { "type": "array", "items": { "type": "ref", "ref": "com.atproto.label.defs#label" } diff --git a/lexicons/app/bsky/embed/recordWithMedia.json b/lexicons/app/bsky/embed/recordWithMedia.json index 9bc5fe09048..46145464fe2 100644 --- a/lexicons/app/bsky/embed/recordWithMedia.json +++ b/lexicons/app/bsky/embed/recordWithMedia.json @@ -1,7 +1,7 @@ { "lexicon": 1, "id": "app.bsky.embed.recordWithMedia", - "description": "A representation of a record embedded in another form of content, alongside other compatible embeds.", + "description": "A representation of a record embedded in a Bluesky record (eg, a post), alongside other compatible embeds. For example, a quote post and image, or a quote post and external URL card.", "defs": { "main": { "type": "object", diff --git a/lexicons/app/bsky/feed/defs.json b/lexicons/app/bsky/feed/defs.json index 15a7cb7a719..7f121e88403 100644 --- a/lexicons/app/bsky/feed/defs.json +++ b/lexicons/app/bsky/feed/defs.json @@ -36,6 +36,7 @@ }, "viewerState": { "type": "object", + "description": "Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests.", "properties": { "repost": { "type": "string", "format": "at-uri" }, "like": { "type": "string", "format": "at-uri" }, diff --git a/lexicons/app/bsky/feed/describeFeedGenerator.json b/lexicons/app/bsky/feed/describeFeedGenerator.json index f95027183a1..0c7b8c8638e 100644 --- a/lexicons/app/bsky/feed/describeFeedGenerator.json +++ b/lexicons/app/bsky/feed/describeFeedGenerator.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get information about a feed generator, including policies and offered feed URIs.", + "description": "Get information about a feed generator, including policies and offered feed URIs. Does not require auth; implemented by Feed Generator services (not App View).", "output": { "encoding": "application/json", "schema": { diff --git a/lexicons/app/bsky/feed/generator.json b/lexicons/app/bsky/feed/generator.json index 8c00884ad28..d0e361b72cb 100644 --- a/lexicons/app/bsky/feed/generator.json +++ b/lexicons/app/bsky/feed/generator.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "record", - "description": "A declaration of the existence of a feed generator.", + "description": "Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.", "key": "any", "record": { "type": "object", @@ -32,6 +32,7 @@ }, "labels": { "type": "union", + "description": "Self-label values", "refs": ["com.atproto.label.defs#selfLabels"] }, "createdAt": { "type": "string", "format": "datetime" } diff --git a/lexicons/app/bsky/feed/getActorFeeds.json b/lexicons/app/bsky/feed/getActorFeeds.json index a0620477bc3..9a7dae0ad5d 100644 --- a/lexicons/app/bsky/feed/getActorFeeds.json +++ b/lexicons/app/bsky/feed/getActorFeeds.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of feeds created by the actor.", + "description": "Get a list of feeds (feed generator records) created by the actor (in the actor's repo).", "parameters": { "type": "params", "required": ["actor"], diff --git a/lexicons/app/bsky/feed/getActorLikes.json b/lexicons/app/bsky/feed/getActorLikes.json index b3baa58a457..22f8ed984ac 100644 --- a/lexicons/app/bsky/feed/getActorLikes.json +++ b/lexicons/app/bsky/feed/getActorLikes.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of posts liked by an actor.", + "description": "Get a list of posts liked by an actor. Does not require auth.", "parameters": { "type": "params", "required": ["actor"], diff --git a/lexicons/app/bsky/feed/getAuthorFeed.json b/lexicons/app/bsky/feed/getAuthorFeed.json index 1939fa9a49d..90e4d1a7708 100644 --- a/lexicons/app/bsky/feed/getAuthorFeed.json +++ b/lexicons/app/bsky/feed/getAuthorFeed.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a view of an actor's feed.", + "description": "Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth.", "parameters": { "type": "params", "required": ["actor"], @@ -19,6 +19,7 @@ "cursor": { "type": "string" }, "filter": { "type": "string", + "description": "Combinations of post/repost types to include in response.", "knownValues": [ "posts_with_replies", "posts_no_replies", diff --git a/lexicons/app/bsky/feed/getFeed.json b/lexicons/app/bsky/feed/getFeed.json index 84407bde155..ada3098b56f 100644 --- a/lexicons/app/bsky/feed/getFeed.json +++ b/lexicons/app/bsky/feed/getFeed.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a hydrated feed from an actor's selected feed generator.", + "description": "Get a hydrated feed from an actor's selected feed generator. Implemented by App View.", "parameters": { "type": "params", "required": ["feed"], diff --git a/lexicons/app/bsky/feed/getFeedGenerator.json b/lexicons/app/bsky/feed/getFeedGenerator.json index 8b3d4d0551a..190eca85b26 100644 --- a/lexicons/app/bsky/feed/getFeedGenerator.json +++ b/lexicons/app/bsky/feed/getFeedGenerator.json @@ -4,12 +4,16 @@ "defs": { "main": { "type": "query", - "description": "Get information about a feed generator.", + "description": "Get information about a feed generator. Implemented by AppView.", "parameters": { "type": "params", "required": ["feed"], "properties": { - "feed": { "type": "string", "format": "at-uri" } + "feed": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the feed generator record." + } } }, "output": { @@ -22,8 +26,14 @@ "type": "ref", "ref": "app.bsky.feed.defs#generatorView" }, - "isOnline": { "type": "boolean" }, - "isValid": { "type": "boolean" } + "isOnline": { + "type": "boolean", + "description": "Indicates whether the feed generator service has been online recently, or else seems to be inactive." + }, + "isValid": { + "type": "boolean", + "description": "Indicates whether the feed generator service is compatible with the record declaration." + } } } } diff --git a/lexicons/app/bsky/feed/getFeedSkeleton.json b/lexicons/app/bsky/feed/getFeedSkeleton.json index 03f3ba04c0f..2bcaa13d4f0 100644 --- a/lexicons/app/bsky/feed/getFeedSkeleton.json +++ b/lexicons/app/bsky/feed/getFeedSkeleton.json @@ -4,12 +4,16 @@ "defs": { "main": { "type": "query", - "description": "Get a skeleton of a feed provided by a feed generator.", + "description": "Get a skeleton of a feed provided by a feed generator. Auth is optional, depending on provider requirements, and provides the DID of the requester. Implemented by Feed Generator Service.", "parameters": { "type": "params", "required": ["feed"], "properties": { - "feed": { "type": "string", "format": "at-uri" }, + "feed": { + "type": "string", + "format": "at-uri", + "description": "Reference to feed generator record describing the specific feed being requested." + }, "limit": { "type": "integer", "minimum": 1, diff --git a/lexicons/app/bsky/feed/getLikes.json b/lexicons/app/bsky/feed/getLikes.json index ffcbc01ac53..d2c5b1a77df 100644 --- a/lexicons/app/bsky/feed/getLikes.json +++ b/lexicons/app/bsky/feed/getLikes.json @@ -4,13 +4,21 @@ "defs": { "main": { "type": "query", - "description": "Get the list of likes.", + "description": "Get like records which reference a subject (by AT-URI and CID).", "parameters": { "type": "params", "required": ["uri"], "properties": { - "uri": { "type": "string", "format": "at-uri" }, - "cid": { "type": "string", "format": "cid" }, + "uri": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the subject (eg, a post record)." + }, + "cid": { + "type": "string", + "format": "cid", + "description": "CID of the subject record (aka, specific version of record), to filter likes." + }, "limit": { "type": "integer", "minimum": 1, diff --git a/lexicons/app/bsky/feed/getListFeed.json b/lexicons/app/bsky/feed/getListFeed.json index 4c5358fcfd7..9dd9fdc70f3 100644 --- a/lexicons/app/bsky/feed/getListFeed.json +++ b/lexicons/app/bsky/feed/getListFeed.json @@ -4,12 +4,16 @@ "defs": { "main": { "type": "query", - "description": "Get a view of a recent posts from actors in a list.", + "description": "Get a feed of recent posts from a list (posts and reposts from any actors on the list). Does not require auth.", "parameters": { "type": "params", "required": ["list"], "properties": { - "list": { "type": "string", "format": "at-uri" }, + "list": { + "type": "string", + "format": "at-uri", + "description": "Reference (AT-URI) to the list record." + }, "limit": { "type": "integer", "minimum": 1, diff --git a/lexicons/app/bsky/feed/getPostThread.json b/lexicons/app/bsky/feed/getPostThread.json index b983617041f..89e99d9c6d7 100644 --- a/lexicons/app/bsky/feed/getPostThread.json +++ b/lexicons/app/bsky/feed/getPostThread.json @@ -4,20 +4,26 @@ "defs": { "main": { "type": "query", - "description": "Get posts in a thread.", + "description": "Get posts in a thread. Does not require auth, but additional metadata and filtering will be applied for authed requests.", "parameters": { "type": "params", "required": ["uri"], "properties": { - "uri": { "type": "string", "format": "at-uri" }, + "uri": { + "type": "string", + "format": "at-uri", + "description": "Reference (AT-URI) to post record." + }, "depth": { "type": "integer", + "description": "How many levels of reply depth should be included in response.", "default": 6, "minimum": 0, "maximum": 1000 }, "parentHeight": { "type": "integer", + "description": "How many levels of parent (and grandparent, etc) post to include.", "default": 80, "minimum": 0, "maximum": 1000 diff --git a/lexicons/app/bsky/feed/getPosts.json b/lexicons/app/bsky/feed/getPosts.json index c985a5cf033..e555ee16326 100644 --- a/lexicons/app/bsky/feed/getPosts.json +++ b/lexicons/app/bsky/feed/getPosts.json @@ -4,13 +4,14 @@ "defs": { "main": { "type": "query", - "description": "Get a view of an actor's feed.", + "description": "Gets post views for a specified list of posts (by AT-URI). This is sometimes referred to as 'hydrating' a 'feed skeleton'.", "parameters": { "type": "params", "required": ["uris"], "properties": { "uris": { "type": "array", + "description": "List of post AT-URIs to return hydrated views for.", "items": { "type": "string", "format": "at-uri" }, "maxLength": 25 } diff --git a/lexicons/app/bsky/feed/getRepostedBy.json b/lexicons/app/bsky/feed/getRepostedBy.json index 99abc6d5cde..db39534658b 100644 --- a/lexicons/app/bsky/feed/getRepostedBy.json +++ b/lexicons/app/bsky/feed/getRepostedBy.json @@ -4,13 +4,21 @@ "defs": { "main": { "type": "query", - "description": "Get a list of reposts.", + "description": "Get a list of reposts for a given post.", "parameters": { "type": "params", "required": ["uri"], "properties": { - "uri": { "type": "string", "format": "at-uri" }, - "cid": { "type": "string", "format": "cid" }, + "uri": { + "type": "string", + "format": "at-uri", + "description": "Reference (AT-URI) of post record" + }, + "cid": { + "type": "string", + "format": "cid", + "description": "If supplied, filters to reposts of specific version (by CID) of the post record." + }, "limit": { "type": "integer", "minimum": 1, diff --git a/lexicons/app/bsky/feed/getSuggestedFeeds.json b/lexicons/app/bsky/feed/getSuggestedFeeds.json index de7c4fef753..e643d3391e5 100644 --- a/lexicons/app/bsky/feed/getSuggestedFeeds.json +++ b/lexicons/app/bsky/feed/getSuggestedFeeds.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of suggested feeds for the viewer.", + "description": "Get a list of suggested feeds (feed generators) for the requesting account.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/feed/getTimeline.json b/lexicons/app/bsky/feed/getTimeline.json index c3b116381c6..816380fe680 100644 --- a/lexicons/app/bsky/feed/getTimeline.json +++ b/lexicons/app/bsky/feed/getTimeline.json @@ -4,11 +4,14 @@ "defs": { "main": { "type": "query", - "description": "Get a view of the actor's home timeline.", + "description": "Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed.", "parameters": { "type": "params", "properties": { - "algorithm": { "type": "string" }, + "algorithm": { + "type": "string", + "description": "Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism." + }, "limit": { "type": "integer", "minimum": 1, diff --git a/lexicons/app/bsky/feed/like.json b/lexicons/app/bsky/feed/like.json index d82f93bbb1b..c0de3b71e92 100644 --- a/lexicons/app/bsky/feed/like.json +++ b/lexicons/app/bsky/feed/like.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "record", - "description": "A declaration of a like.", + "description": "Record declaring a 'like' of a piece of subject content.", "key": "tid", "record": { "type": "object", diff --git a/lexicons/app/bsky/feed/post.json b/lexicons/app/bsky/feed/post.json index d5f92969253..b9b236b4f81 100644 --- a/lexicons/app/bsky/feed/post.json +++ b/lexicons/app/bsky/feed/post.json @@ -4,20 +4,26 @@ "defs": { "main": { "type": "record", - "description": "A declaration of a post.", + "description": "Record containing a Bluesky post.", "key": "tid", "record": { "type": "object", "required": ["text", "createdAt"], "properties": { - "text": { "type": "string", "maxLength": 3000, "maxGraphemes": 300 }, + "text": { + "type": "string", + "maxLength": 3000, + "maxGraphemes": 300, + "description": "The primary post content. May be an empty string, if there are embeds." + }, "entities": { "type": "array", - "description": "Deprecated: replaced by app.bsky.richtext.facet.", + "description": "DEPRECATED: replaced by app.bsky.richtext.facet.", "items": { "type": "ref", "ref": "#entity" } }, "facets": { "type": "array", + "description": "Annotations of text (mentions, URLs, hashtags, etc)", "items": { "type": "ref", "ref": "app.bsky.richtext.facet" } }, "reply": { "type": "ref", "ref": "#replyRef" }, @@ -32,20 +38,26 @@ }, "langs": { "type": "array", + "description": "Indicates human language of post primary text content.", "maxLength": 3, "items": { "type": "string", "format": "language" } }, "labels": { "type": "union", + "description": "Self-label values for this post. Effectively content warnings.", "refs": ["com.atproto.label.defs#selfLabels"] }, "tags": { "type": "array", + "description": "Additional hashtags, in addition to any included in post text and facets.", "maxLength": 8, - "items": { "type": "string", "maxLength": 640, "maxGraphemes": 64 }, - "description": "Additional non-inline tags describing this post." + "items": { "type": "string", "maxLength": 640, "maxGraphemes": 64 } }, - "createdAt": { "type": "string", "format": "datetime" } + "createdAt": { + "type": "string", + "format": "datetime", + "description": "Client-declared timestamp when this post was originally created." + } } } }, diff --git a/lexicons/app/bsky/feed/repost.json b/lexicons/app/bsky/feed/repost.json index 4dbef10b319..028fd627152 100644 --- a/lexicons/app/bsky/feed/repost.json +++ b/lexicons/app/bsky/feed/repost.json @@ -3,7 +3,7 @@ "id": "app.bsky.feed.repost", "defs": { "main": { - "description": "A declaration of a repost.", + "description": "Record representing a 'repost' of an existing Bluesky post.", "type": "record", "key": "tid", "record": { diff --git a/lexicons/app/bsky/feed/searchPosts.json b/lexicons/app/bsky/feed/searchPosts.json index a3e0bc47f03..c89655dd9db 100644 --- a/lexicons/app/bsky/feed/searchPosts.json +++ b/lexicons/app/bsky/feed/searchPosts.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Find posts matching search criteria.", + "description": "Find posts matching search criteria, returning views of those posts.", "parameters": { "type": "params", "required": ["q"], diff --git a/lexicons/app/bsky/feed/threadgate.json b/lexicons/app/bsky/feed/threadgate.json index 7969b6360a6..ff258da4d30 100644 --- a/lexicons/app/bsky/feed/threadgate.json +++ b/lexicons/app/bsky/feed/threadgate.json @@ -5,12 +5,16 @@ "main": { "type": "record", "key": "tid", - "description": "Defines interaction gating rules for a thread. The rkey of the threadgate record should match the rkey of the thread's root post.", + "description": "Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository..", "record": { "type": "object", "required": ["post", "createdAt"], "properties": { - "post": { "type": "string", "format": "at-uri" }, + "post": { + "type": "string", + "format": "at-uri", + "description": "Reference (AT-URI) to the post record." + }, "allow": { "type": "array", "maxLength": 5, diff --git a/lexicons/app/bsky/graph/block.json b/lexicons/app/bsky/graph/block.json index 6231eb04e10..b64b11a956d 100644 --- a/lexicons/app/bsky/graph/block.json +++ b/lexicons/app/bsky/graph/block.json @@ -4,13 +4,17 @@ "defs": { "main": { "type": "record", - "description": "A declaration of a block.", + "description": "Record declaring a 'block' relationship against another account. NOTE: blocks are public in Bluesky; see blog posts for details.", "key": "tid", "record": { "type": "object", "required": ["subject", "createdAt"], "properties": { - "subject": { "type": "string", "format": "did" }, + "subject": { + "type": "string", + "format": "did", + "description": "DID of the account to be blocked." + }, "createdAt": { "type": "string", "format": "datetime" } } } diff --git a/lexicons/app/bsky/graph/follow.json b/lexicons/app/bsky/graph/follow.json index df4f4319d92..dd6347ac76d 100644 --- a/lexicons/app/bsky/graph/follow.json +++ b/lexicons/app/bsky/graph/follow.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "record", - "description": "A declaration of a social follow.", + "description": "Record declaring a social 'follow' relationship of another account. Duplicate follows will be ignored by the AppView.", "key": "tid", "record": { "type": "object", diff --git a/lexicons/app/bsky/graph/getBlocks.json b/lexicons/app/bsky/graph/getBlocks.json index bbfe956fbe0..79a28f66a52 100644 --- a/lexicons/app/bsky/graph/getBlocks.json +++ b/lexicons/app/bsky/graph/getBlocks.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of who the actor is blocking.", + "description": "Enumerates which accounts the requesting account is currently blocking. Requires auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/graph/getFollowers.json b/lexicons/app/bsky/graph/getFollowers.json index 378c7a7a339..a6c4facd653 100644 --- a/lexicons/app/bsky/graph/getFollowers.json +++ b/lexicons/app/bsky/graph/getFollowers.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of an actor's followers.", + "description": "Enumerates accounts which follow a specified account (actor).", "parameters": { "type": "params", "required": ["actor"], diff --git a/lexicons/app/bsky/graph/getFollows.json b/lexicons/app/bsky/graph/getFollows.json index b90f7613889..81f1b6abe49 100644 --- a/lexicons/app/bsky/graph/getFollows.json +++ b/lexicons/app/bsky/graph/getFollows.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of who the actor follows.", + "description": "Enumerates accounts which a specified account (actor) follows.", "parameters": { "type": "params", "required": ["actor"], diff --git a/lexicons/app/bsky/graph/getList.json b/lexicons/app/bsky/graph/getList.json index fd24668e5bd..cb95a003a56 100644 --- a/lexicons/app/bsky/graph/getList.json +++ b/lexicons/app/bsky/graph/getList.json @@ -4,12 +4,16 @@ "defs": { "main": { "type": "query", - "description": "Get a list of actors.", + "description": "Gets a 'view' (with additional context) of a specified list.", "parameters": { "type": "params", "required": ["list"], "properties": { - "list": { "type": "string", "format": "at-uri" }, + "list": { + "type": "string", + "format": "at-uri", + "description": "Reference (AT-URI) of the list record to hydrate." + }, "limit": { "type": "integer", "minimum": 1, diff --git a/lexicons/app/bsky/graph/getListBlocks.json b/lexicons/app/bsky/graph/getListBlocks.json index 9f9f59821f2..1bc976617ef 100644 --- a/lexicons/app/bsky/graph/getListBlocks.json +++ b/lexicons/app/bsky/graph/getListBlocks.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get lists that the actor is blocking.", + "description": "Get mod lists that the requesting account (actor) is blocking. Requires auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/graph/getListMutes.json b/lexicons/app/bsky/graph/getListMutes.json index 8d42ac40f9c..a56a8257643 100644 --- a/lexicons/app/bsky/graph/getListMutes.json +++ b/lexicons/app/bsky/graph/getListMutes.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get lists that the actor is muting.", + "description": "Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/graph/getLists.json b/lexicons/app/bsky/graph/getLists.json index 602dd15307d..127b13e5558 100644 --- a/lexicons/app/bsky/graph/getLists.json +++ b/lexicons/app/bsky/graph/getLists.json @@ -4,12 +4,16 @@ "defs": { "main": { "type": "query", - "description": "Get a list of lists that belong to an actor.", + "description": "Enumerates the lists created by a specified account (actor).", "parameters": { "type": "params", "required": ["actor"], "properties": { - "actor": { "type": "string", "format": "at-identifier" }, + "actor": { + "type": "string", + "format": "at-identifier", + "description": "The account (actor) to enumerate lists from." + }, "limit": { "type": "integer", "minimum": 1, diff --git a/lexicons/app/bsky/graph/getMutes.json b/lexicons/app/bsky/graph/getMutes.json index 8ceae00f607..22eaf0d384c 100644 --- a/lexicons/app/bsky/graph/getMutes.json +++ b/lexicons/app/bsky/graph/getMutes.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of who the actor mutes.", + "description": "Enumerates accounts that the requesting account (actor) currently has muted. Requires auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/graph/getRelationships.json b/lexicons/app/bsky/graph/getRelationships.json index ccd495dea7d..03490a25ec2 100644 --- a/lexicons/app/bsky/graph/getRelationships.json +++ b/lexicons/app/bsky/graph/getRelationships.json @@ -4,14 +4,19 @@ "defs": { "main": { "type": "query", - "description": "Enumerates public relationships between one account, and a list of other accounts", + "description": "Enumerates public relationships between one account, and a list of other accounts. Does not require auth.", "parameters": { "type": "params", "required": ["actor"], "properties": { - "actor": { "type": "string", "format": "at-identifier" }, + "actor": { + "type": "string", + "format": "at-identifier", + "description": "Primary account requesting relationships for." + }, "others": { "type": "array", + "description": "List of 'other' accounts to be related back to the primary.", "maxLength": 30, "items": { "type": "string", diff --git a/lexicons/app/bsky/graph/getSuggestedFollowsByActor.json b/lexicons/app/bsky/graph/getSuggestedFollowsByActor.json index 32873a537c9..5b0cfdebb70 100644 --- a/lexicons/app/bsky/graph/getSuggestedFollowsByActor.json +++ b/lexicons/app/bsky/graph/getSuggestedFollowsByActor.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get suggested follows related to a given actor.", + "description": "Enumerates follows similar to a given account (actor). Expected use is to recommend additional accounts immediately after following one account.", "parameters": { "type": "params", "required": ["actor"], diff --git a/lexicons/app/bsky/graph/list.json b/lexicons/app/bsky/graph/list.json index ccc845a6926..131114126d3 100644 --- a/lexicons/app/bsky/graph/list.json +++ b/lexicons/app/bsky/graph/list.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "record", - "description": "A declaration of a list of actors.", + "description": "Record representing a list of accounts (actors). Scope includes both moderation-oriented lists and curration-oriented lists.", "key": "tid", "record": { "type": "object", @@ -12,9 +12,15 @@ "properties": { "purpose": { "type": "ref", + "description": "Defines the purpose of the list (aka, moderation-oriented or curration-oriented)", "ref": "app.bsky.graph.defs#listPurpose" }, - "name": { "type": "string", "maxLength": 64, "minLength": 1 }, + "name": { + "type": "string", + "maxLength": 64, + "minLength": 1, + "description": "Display name for list; can not be empty." + }, "description": { "type": "string", "maxGraphemes": 300, diff --git a/lexicons/app/bsky/graph/listblock.json b/lexicons/app/bsky/graph/listblock.json index b3a839c5316..df2e17f3c30 100644 --- a/lexicons/app/bsky/graph/listblock.json +++ b/lexicons/app/bsky/graph/listblock.json @@ -4,13 +4,17 @@ "defs": { "main": { "type": "record", - "description": "A block of an entire list of actors.", + "description": "Record representing a block relationship against an entire an entire list of accounts (actors).", "key": "tid", "record": { "type": "object", "required": ["subject", "createdAt"], "properties": { - "subject": { "type": "string", "format": "at-uri" }, + "subject": { + "type": "string", + "format": "at-uri", + "description": "Reference (AT-URI) to the mod list record." + }, "createdAt": { "type": "string", "format": "datetime" } } } diff --git a/lexicons/app/bsky/graph/listitem.json b/lexicons/app/bsky/graph/listitem.json index 2eafb1340be..adbd96e77da 100644 --- a/lexicons/app/bsky/graph/listitem.json +++ b/lexicons/app/bsky/graph/listitem.json @@ -4,14 +4,22 @@ "defs": { "main": { "type": "record", - "description": "An item under a declared list of actors.", + "description": "Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records.", "key": "tid", "record": { "type": "object", "required": ["subject", "list", "createdAt"], "properties": { - "subject": { "type": "string", "format": "did" }, - "list": { "type": "string", "format": "at-uri" }, + "subject": { + "type": "string", + "format": "did", + "description": "The account which is included on the list." + }, + "list": { + "type": "string", + "format": "at-uri", + "description": "Reference (AT-URI) to the list record (app.bsky.graph.list)." + }, "createdAt": { "type": "string", "format": "datetime" } } } diff --git a/lexicons/app/bsky/graph/muteActor.json b/lexicons/app/bsky/graph/muteActor.json index f1c3dd18f64..c2bf09a3b37 100644 --- a/lexicons/app/bsky/graph/muteActor.json +++ b/lexicons/app/bsky/graph/muteActor.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Mute an actor by DID or handle.", + "description": "Creates a mute relationship for the specified account. Mutes are private in Bluesky. Requires auth.", "input": { "encoding": "application/json", "schema": { diff --git a/lexicons/app/bsky/graph/muteActorList.json b/lexicons/app/bsky/graph/muteActorList.json index c75cc783c14..ad05e6349d7 100644 --- a/lexicons/app/bsky/graph/muteActorList.json +++ b/lexicons/app/bsky/graph/muteActorList.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Mute a list of actors.", + "description": "Creates a mute relationship for the specified list of accounts. Mutes are private in Bluesky. Requires auth.", "input": { "encoding": "application/json", "schema": { diff --git a/lexicons/app/bsky/graph/unmuteActor.json b/lexicons/app/bsky/graph/unmuteActor.json index 114af204890..bcea72db59d 100644 --- a/lexicons/app/bsky/graph/unmuteActor.json +++ b/lexicons/app/bsky/graph/unmuteActor.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Unmute an actor by DID or handle.", + "description": "Unmutes the specified account. Requires auth.", "input": { "encoding": "application/json", "schema": { diff --git a/lexicons/app/bsky/graph/unmuteActorList.json b/lexicons/app/bsky/graph/unmuteActorList.json index d9644cddc8e..a597838e112 100644 --- a/lexicons/app/bsky/graph/unmuteActorList.json +++ b/lexicons/app/bsky/graph/unmuteActorList.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Unmute a list of actors.", + "description": "Unmutes the specified list of accounts. Requires auth.", "input": { "encoding": "application/json", "schema": { diff --git a/lexicons/app/bsky/notification/getUnreadCount.json b/lexicons/app/bsky/notification/getUnreadCount.json index ab716b2a436..5eebbbf4eb5 100644 --- a/lexicons/app/bsky/notification/getUnreadCount.json +++ b/lexicons/app/bsky/notification/getUnreadCount.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get the count of unread notifications.", + "description": "Count the number of unread notifications for the requesting account. Requires auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/notification/listNotifications.json b/lexicons/app/bsky/notification/listNotifications.json index ea74c5fba53..6c5095e1eb2 100644 --- a/lexicons/app/bsky/notification/listNotifications.json +++ b/lexicons/app/bsky/notification/listNotifications.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a list of notifications.", + "description": "Enumerate notifications for the requesting account. Requires auth.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/app/bsky/notification/registerPush.json b/lexicons/app/bsky/notification/registerPush.json index 80819ece46f..c4e50d1108c 100644 --- a/lexicons/app/bsky/notification/registerPush.json +++ b/lexicons/app/bsky/notification/registerPush.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Register for push notifications with a service.", + "description": "Register to receive push notifications, via a specified service, for the requesting account. Requires auth.", "input": { "encoding": "application/json", "schema": { diff --git a/lexicons/app/bsky/notification/updateSeen.json b/lexicons/app/bsky/notification/updateSeen.json index 33626343e51..84bb0e7d52f 100644 --- a/lexicons/app/bsky/notification/updateSeen.json +++ b/lexicons/app/bsky/notification/updateSeen.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Notify server that the user has seen notifications.", + "description": "Notify server that the requesting account has seen notifications. Requires auth.", "input": { "encoding": "application/json", "schema": { diff --git a/lexicons/app/bsky/richtext/facet.json b/lexicons/app/bsky/richtext/facet.json index ea8f2cba288..388a3a5e0ef 100644 --- a/lexicons/app/bsky/richtext/facet.json +++ b/lexicons/app/bsky/richtext/facet.json @@ -4,6 +4,7 @@ "defs": { "main": { "type": "object", + "description": "Annotation of a sub-string within rich text.", "required": ["index", "features"], "properties": { "index": { "type": "ref", "ref": "#byteSlice" }, @@ -15,7 +16,7 @@ }, "mention": { "type": "object", - "description": "A facet feature for actor mentions.", + "description": "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID.", "required": ["did"], "properties": { "did": { "type": "string", "format": "did" } @@ -23,7 +24,7 @@ }, "link": { "type": "object", - "description": "A facet feature for links.", + "description": "Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.", "required": ["uri"], "properties": { "uri": { "type": "string", "format": "uri" } @@ -31,7 +32,7 @@ }, "tag": { "type": "object", - "description": "A hashtag.", + "description": "Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags').", "required": ["tag"], "properties": { "tag": { "type": "string", "maxLength": 640, "maxGraphemes": 64 } @@ -39,7 +40,7 @@ }, "byteSlice": { "type": "object", - "description": "A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings.", + "description": "Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.", "required": ["byteStart", "byteEnd"], "properties": { "byteStart": { "type": "integer", "minimum": 0 }, diff --git a/lexicons/app/bsky/unspecced/getTimelineSkeleton.json b/lexicons/app/bsky/unspecced/getTimelineSkeleton.json deleted file mode 100644 index 391c3718dc1..00000000000 --- a/lexicons/app/bsky/unspecced/getTimelineSkeleton.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "lexicon": 1, - "id": "app.bsky.unspecced.getTimelineSkeleton", - "defs": { - "main": { - "type": "query", - "description": "DEPRECATED: a skeleton of a timeline. Unspecced and will be unavailable soon.", - "parameters": { - "type": "params", - "properties": { - "limit": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 50 - }, - "cursor": { "type": "string" } - } - }, - "output": { - "encoding": "application/json", - "schema": { - "type": "object", - "required": ["feed"], - "properties": { - "cursor": { "type": "string" }, - "feed": { - "type": "array", - "items": { - "type": "ref", - "ref": "app.bsky.feed.defs#skeletonFeedPost" - } - } - } - } - }, - "errors": [{ "name": "UnknownFeed" }] - } - } -} diff --git a/lexicons/com/atproto/admin/defs.json b/lexicons/com/atproto/admin/defs.json index 5a65ae31562..e1315eb7473 100644 --- a/lexicons/com/atproto/admin/defs.json +++ b/lexicons/com/atproto/admin/defs.json @@ -33,7 +33,8 @@ "#modEventAcknowledge", "#modEventEscalate", "#modEventMute", - "#modEventEmail" + "#modEventEmail", + "#modEventResolveAppeal" ] }, "subject": { @@ -70,6 +71,7 @@ "#modEventAcknowledge", "#modEventEscalate", "#modEventMute", + "#modEventEmail", "#modEventResolveAppeal" ] }, @@ -183,6 +185,10 @@ "suspendUntil": { "type": "string", "format": "datetime" + }, + "tags": { + "type": "array", + "items": { "type": "string" } } } }, @@ -585,6 +591,27 @@ } } }, + "modEventTag": { + "type": "object", + "description": "Add/Remove a tag on a subject", + "required": ["add", "remove"], + "properties": { + "add": { + "type": "array", + "items": { "type": "string" }, + "description": "Tags to be added to the subject. If already exists, won't be duplicated." + }, + "remove": { + "type": "array", + "items": { "type": "string" }, + "description": "Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated." + }, + "comment": { + "type": "string", + "description": "Additional comment about added/removed tags." + } + } + }, "communicationTemplateView": { "type": "object", "required": [ diff --git a/lexicons/com/atproto/admin/emitModerationEvent.json b/lexicons/com/atproto/admin/emitModerationEvent.json index f32ad18461c..44ef72aad5b 100644 --- a/lexicons/com/atproto/admin/emitModerationEvent.json +++ b/lexicons/com/atproto/admin/emitModerationEvent.json @@ -23,7 +23,8 @@ "com.atproto.admin.defs#modEventMute", "com.atproto.admin.defs#modEventReverseTakedown", "com.atproto.admin.defs#modEventUnmute", - "com.atproto.admin.defs#modEventEmail" + "com.atproto.admin.defs#modEventEmail", + "com.atproto.admin.defs#modEventTag" ] }, "subject": { diff --git a/lexicons/com/atproto/admin/queryModerationEvents.json b/lexicons/com/atproto/admin/queryModerationEvents.json index 70af1bf8ae5..239c17bd115 100644 --- a/lexicons/com/atproto/admin/queryModerationEvents.json +++ b/lexicons/com/atproto/admin/queryModerationEvents.json @@ -23,6 +23,16 @@ "enum": ["asc", "desc"], "description": "Sort direction for the events. Defaults to descending order of created at timestamp." }, + "createdAfter": { + "type": "string", + "format": "datetime", + "description": "Retrieve events created after a given timestamp" + }, + "createdBefore": { + "type": "string", + "format": "datetime", + "description": "Retrieve events created before a given timestamp" + }, "subject": { "type": "string", "format": "uri" }, "includeAllUserRecords": { "type": "boolean", @@ -35,6 +45,40 @@ "maximum": 100, "default": 50 }, + "hasComment": { + "type": "boolean", + "description": "If true, only events with comments are returned" + }, + "comment": { + "type": "string", + "description": "If specified, only events with comments containing the keyword are returned" + }, + "addedLabels": { + "type": "array", + "items": { "type": "string" }, + "description": "If specified, only events where all of these labels were added are returned" + }, + "removedLabels": { + "type": "array", + "items": { "type": "string" }, + "description": "If specified, only events where all of these labels were removed are returned" + }, + "addedTags": { + "type": "array", + "items": { "type": "string" }, + "description": "If specified, only events where all of these tags were added are returned" + }, + "removedTags": { + "type": "array", + "items": { "type": "string" }, + "description": "If specified, only events where all of these tags were removed are returned" + }, + "reportTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "cursor": { "type": "string" } } }, diff --git a/lexicons/com/atproto/admin/queryModerationStatuses.json b/lexicons/com/atproto/admin/queryModerationStatuses.json index e3e2a859bd2..5ac915ceef1 100644 --- a/lexicons/com/atproto/admin/queryModerationStatuses.json +++ b/lexicons/com/atproto/admin/queryModerationStatuses.json @@ -74,6 +74,14 @@ "maximum": 100, "default": 50 }, + "tags": { + "type": "array", + "items": { "type": "string" } + }, + "excludeTags": { + "type": "array", + "items": { "type": "string" } + }, "cursor": { "type": "string" } } }, diff --git a/lexicons/com/atproto/admin/updateAccountPassword.json b/lexicons/com/atproto/admin/updateAccountPassword.json new file mode 100644 index 00000000000..76c69fec0b6 --- /dev/null +++ b/lexicons/com/atproto/admin/updateAccountPassword.json @@ -0,0 +1,21 @@ +{ + "lexicon": 1, + "id": "com.atproto.admin.updateAccountPassword", + "defs": { + "main": { + "type": "procedure", + "description": "Update the password for a user account as an administrator.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["did", "password"], + "properties": { + "did": { "type": "string", "format": "did" }, + "password": { "type": "string" } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/identity/getRecommendedDidCredentials.json b/lexicons/com/atproto/identity/getRecommendedDidCredentials.json new file mode 100644 index 00000000000..3506dbec351 --- /dev/null +++ b/lexicons/com/atproto/identity/getRecommendedDidCredentials.json @@ -0,0 +1,29 @@ +{ + "lexicon": 1, + "id": "com.atproto.identity.getRecommendedDidCredentials", + "defs": { + "main": { + "type": "query", + "description": "Describe the credentials that should be included in the DID doc of an account that is migrating to this service.", + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "rotationKeys": { + "description": "Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs.", + "type": "array", + "items": { "type": "string" } + }, + "alsoKnownAs": { + "type": "array", + "items": { "type": "string" } + }, + "verificationMethods": { "type": "unknown" }, + "services": { "type": "unknown" } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/identity/requestPlcOperationSignature.json b/lexicons/com/atproto/identity/requestPlcOperationSignature.json new file mode 100644 index 00000000000..4aa8b18fee9 --- /dev/null +++ b/lexicons/com/atproto/identity/requestPlcOperationSignature.json @@ -0,0 +1,10 @@ +{ + "lexicon": 1, + "id": "com.atproto.identity.requestPlcOperationSignature", + "defs": { + "main": { + "type": "procedure", + "description": "Request an email with a code to in order to request a signed PLC operation. Requires Auth." + } + } +} diff --git a/lexicons/com/atproto/identity/resolveHandle.json b/lexicons/com/atproto/identity/resolveHandle.json index ae5aab8f8fc..95885088a7b 100644 --- a/lexicons/com/atproto/identity/resolveHandle.json +++ b/lexicons/com/atproto/identity/resolveHandle.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Provides the DID of a repo.", + "description": "Resolves a handle (domain name) to a DID.", "parameters": { "type": "params", "required": ["handle"], diff --git a/lexicons/com/atproto/identity/signPlcOperation.json b/lexicons/com/atproto/identity/signPlcOperation.json new file mode 100644 index 00000000000..05a952cab6c --- /dev/null +++ b/lexicons/com/atproto/identity/signPlcOperation.json @@ -0,0 +1,45 @@ +{ + "lexicon": 1, + "id": "com.atproto.identity.signPlcOperation", + "defs": { + "main": { + "type": "procedure", + "description": "Signs a PLC operation to update some value(s) in the requesting DID's document.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "token": { + "description": "A token received through com.atproto.identity.requestPlcOperationSignature", + "type": "string" + }, + "rotationKeys": { + "type": "array", + "items": { "type": "string" } + }, + "alsoKnownAs": { + "type": "array", + "items": { "type": "string" } + }, + "verificationMethods": { "type": "unknown" }, + "services": { "type": "unknown" } + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["operation"], + "properties": { + "operation": { + "type": "unknown", + "description": "A signed DID PLC operation." + } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/identity/submitPlcOperation.json b/lexicons/com/atproto/identity/submitPlcOperation.json new file mode 100644 index 00000000000..280f5003b0d --- /dev/null +++ b/lexicons/com/atproto/identity/submitPlcOperation.json @@ -0,0 +1,20 @@ +{ + "lexicon": 1, + "id": "com.atproto.identity.submitPlcOperation", + "defs": { + "main": { + "type": "procedure", + "description": "Validates a PLC operation to ensure that it doesn't violate a service's constraints or get the identity into a bad state, then submits it to the PLC registry", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["operation"], + "properties": { + "operation": { "type": "unknown" } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/identity/updateHandle.json b/lexicons/com/atproto/identity/updateHandle.json index 5fe392bb838..9bb5c347d38 100644 --- a/lexicons/com/atproto/identity/updateHandle.json +++ b/lexicons/com/atproto/identity/updateHandle.json @@ -4,14 +4,18 @@ "defs": { "main": { "type": "procedure", - "description": "Updates the handle of the account.", + "description": "Updates the current account's handle. Verifies handle validity, and updates did:plc document if necessary. Implemented by PDS, and requires auth.", "input": { "encoding": "application/json", "schema": { "type": "object", "required": ["handle"], "properties": { - "handle": { "type": "string", "format": "handle" } + "handle": { + "type": "string", + "format": "handle", + "description": "The new handle." + } } } } diff --git a/lexicons/com/atproto/label/queryLabels.json b/lexicons/com/atproto/label/queryLabels.json index 7b6fbe23d54..6c81cb0bba6 100644 --- a/lexicons/com/atproto/label/queryLabels.json +++ b/lexicons/com/atproto/label/queryLabels.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Find labels relevant to the provided URI patterns.", + "description": "Find labels relevant to the provided AT-URI patterns. Public endpoint for moderation services, though may return different or additional results with auth.", "parameters": { "type": "params", "required": ["uriPatterns"], diff --git a/lexicons/com/atproto/label/subscribeLabels.json b/lexicons/com/atproto/label/subscribeLabels.json index 9813ffc192e..5fb1a852d3d 100644 --- a/lexicons/com/atproto/label/subscribeLabels.json +++ b/lexicons/com/atproto/label/subscribeLabels.json @@ -4,13 +4,13 @@ "defs": { "main": { "type": "subscription", - "description": "Subscribe to label updates.", + "description": "Subscribe to stream of labels (and negations). Public endpoint implemented by mod services. Uses same sequencing scheme as repo event stream.", "parameters": { "type": "params", "properties": { "cursor": { "type": "integer", - "description": "The last known event to backfill from." + "description": "The last known event seq number to backfill from." } } }, diff --git a/lexicons/com/atproto/moderation/createReport.json b/lexicons/com/atproto/moderation/createReport.json index 161d622fcf2..f41d28d0b15 100644 --- a/lexicons/com/atproto/moderation/createReport.json +++ b/lexicons/com/atproto/moderation/createReport.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Report a repo or a record.", + "description": "Submit a moderation report regarding an atproto account or record. Implemented by moderation services (with PDS proxying), and requires auth.", "input": { "encoding": "application/json", "schema": { @@ -13,9 +13,13 @@ "properties": { "reasonType": { "type": "ref", + "description": "Indicates the broad category of violation the report is for.", "ref": "com.atproto.moderation.defs#reasonType" }, - "reason": { "type": "string" }, + "reason": { + "type": "string", + "description": "Additional context about the content and violation." + }, "subject": { "type": "union", "refs": [ diff --git a/lexicons/com/atproto/repo/applyWrites.json b/lexicons/com/atproto/repo/applyWrites.json index 050b6efbfab..427fc84c4a5 100644 --- a/lexicons/com/atproto/repo/applyWrites.json +++ b/lexicons/com/atproto/repo/applyWrites.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Apply a batch transaction of creates, updates, and deletes.", + "description": "Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.", "input": { "encoding": "application/json", "schema": { @@ -14,12 +14,12 @@ "repo": { "type": "string", "format": "at-identifier", - "description": "The handle or DID of the repo." + "description": "The handle or DID of the repo (aka, current account)." }, "validate": { "type": "boolean", "default": true, - "description": "Flag for validating the records." + "description": "Can be set to 'false' to skip Lexicon schema validation of record data, for all operations." }, "writes": { "type": "array", @@ -31,16 +31,22 @@ }, "swapCommit": { "type": "string", + "description": "If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.", "format": "cid" } } } }, - "errors": [{ "name": "InvalidSwap" }] + "errors": [ + { + "name": "InvalidSwap", + "description": "Indicates that the 'swapCommit' parameter did not match current commit." + } + ] }, "create": { "type": "object", - "description": "Create a new record.", + "description": "Operation which creates a new record.", "required": ["collection", "value"], "properties": { "collection": { "type": "string", "format": "nsid" }, @@ -50,7 +56,7 @@ }, "update": { "type": "object", - "description": "Update an existing record.", + "description": "Operation which updates an existing record.", "required": ["collection", "rkey", "value"], "properties": { "collection": { "type": "string", "format": "nsid" }, @@ -60,7 +66,7 @@ }, "delete": { "type": "object", - "description": "Delete an existing record.", + "description": "Operation which deletes an existing record.", "required": ["collection", "rkey"], "properties": { "collection": { "type": "string", "format": "nsid" }, diff --git a/lexicons/com/atproto/repo/createRecord.json b/lexicons/com/atproto/repo/createRecord.json index baef20c88f0..185f5250850 100644 --- a/lexicons/com/atproto/repo/createRecord.json +++ b/lexicons/com/atproto/repo/createRecord.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Create a new record.", + "description": "Create a single new repository record. Requires auth, implemented by PDS.", "input": { "encoding": "application/json", "schema": { @@ -14,7 +14,7 @@ "repo": { "type": "string", "format": "at-identifier", - "description": "The handle or DID of the repo." + "description": "The handle or DID of the repo (aka, current account)." }, "collection": { "type": "string", @@ -23,17 +23,17 @@ }, "rkey": { "type": "string", - "description": "The key of the record.", + "description": "The Record Key.", "maxLength": 15 }, "validate": { "type": "boolean", "default": true, - "description": "Flag for validating the record." + "description": "Can be set to 'false' to skip Lexicon schema validation of record data." }, "record": { "type": "unknown", - "description": "The record to create." + "description": "The record itself. Must contain a $type field." }, "swapCommit": { "type": "string", @@ -54,7 +54,12 @@ } } }, - "errors": [{ "name": "InvalidSwap" }] + "errors": [ + { + "name": "InvalidSwap", + "description": "Indicates that 'swapCommit' didn't match current repo commit." + } + ] } } } diff --git a/lexicons/com/atproto/repo/deleteRecord.json b/lexicons/com/atproto/repo/deleteRecord.json index d8d7955b6a9..65b9f8f9536 100644 --- a/lexicons/com/atproto/repo/deleteRecord.json +++ b/lexicons/com/atproto/repo/deleteRecord.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Delete a record, or ensure it doesn't exist.", + "description": "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", "input": { "encoding": "application/json", "schema": { @@ -14,7 +14,7 @@ "repo": { "type": "string", "format": "at-identifier", - "description": "The handle or DID of the repo." + "description": "The handle or DID of the repo (aka, current account)." }, "collection": { "type": "string", @@ -23,7 +23,7 @@ }, "rkey": { "type": "string", - "description": "The key of the record." + "description": "The Record Key." }, "swapRecord": { "type": "string", diff --git a/lexicons/com/atproto/repo/describeRepo.json b/lexicons/com/atproto/repo/describeRepo.json index b7f283bff70..b1ce2b6cf9e 100644 --- a/lexicons/com/atproto/repo/describeRepo.json +++ b/lexicons/com/atproto/repo/describeRepo.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get information about the repo, including the list of collections.", + "description": "Get information about an account and repository, including the list of collections. Does not require auth.", "parameters": { "type": "params", "required": ["repo"], @@ -30,12 +30,19 @@ "properties": { "handle": { "type": "string", "format": "handle" }, "did": { "type": "string", "format": "did" }, - "didDoc": { "type": "unknown" }, + "didDoc": { + "type": "unknown", + "description": "The complete DID document for this account." + }, "collections": { "type": "array", + "description": "List of all the collections (NSIDs) for which this repo contains at least one record.", "items": { "type": "string", "format": "nsid" } }, - "handleIsCorrect": { "type": "boolean" } + "handleIsCorrect": { + "type": "boolean", + "description": "Indicates if handle is currently valid (resolves bi-directionally)" + } } } } diff --git a/lexicons/com/atproto/repo/getRecord.json b/lexicons/com/atproto/repo/getRecord.json index ec4d17e4260..5d8bb173470 100644 --- a/lexicons/com/atproto/repo/getRecord.json +++ b/lexicons/com/atproto/repo/getRecord.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a record.", + "description": "Get a single record from a repository. Does not require auth.", "parameters": { "type": "params", "required": ["repo", "collection", "rkey"], @@ -19,7 +19,7 @@ "format": "nsid", "description": "The NSID of the record collection." }, - "rkey": { "type": "string", "description": "The key of the record." }, + "rkey": { "type": "string", "description": "The Record Key." }, "cid": { "type": "string", "format": "cid", diff --git a/lexicons/com/atproto/repo/importRepo.json b/lexicons/com/atproto/repo/importRepo.json new file mode 100644 index 00000000000..fc850b1a2b6 --- /dev/null +++ b/lexicons/com/atproto/repo/importRepo.json @@ -0,0 +1,13 @@ +{ + "lexicon": 1, + "id": "com.atproto.repo.importRepo", + "defs": { + "main": { + "type": "procedure", + "description": "Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.", + "input": { + "encoding": "application/vnd.ipld.car" + } + } + } +} diff --git a/lexicons/com/atproto/repo/listMissingBlobs.json b/lexicons/com/atproto/repo/listMissingBlobs.json new file mode 100644 index 00000000000..c39913d566c --- /dev/null +++ b/lexicons/com/atproto/repo/listMissingBlobs.json @@ -0,0 +1,44 @@ +{ + "lexicon": 1, + "id": "com.atproto.repo.listMissingBlobs", + "defs": { + "main": { + "type": "query", + "description": "Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 1000, + "default": 500 + }, + "cursor": { "type": "string" } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["blobs"], + "properties": { + "cursor": { "type": "string" }, + "blobs": { + "type": "array", + "items": { "type": "ref", "ref": "#recordBlob" } + } + } + } + } + }, + "recordBlob": { + "type": "object", + "required": ["cid", "recordUri"], + "properties": { + "cid": { "type": "string", "format": "cid" }, + "recordUri": { "type": "string", "format": "at-uri" } + } + } + } +} diff --git a/lexicons/com/atproto/repo/listRecords.json b/lexicons/com/atproto/repo/listRecords.json index ac04e3e8782..bc91c952bb1 100644 --- a/lexicons/com/atproto/repo/listRecords.json +++ b/lexicons/com/atproto/repo/listRecords.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "List a range of records in a collection.", + "description": "List a range of records in a repository, matching a specific collection. Does not require auth.", "parameters": { "type": "params", "required": ["repo", "collection"], diff --git a/lexicons/com/atproto/repo/putRecord.json b/lexicons/com/atproto/repo/putRecord.json index ae39bd95ead..51f11c0f13f 100644 --- a/lexicons/com/atproto/repo/putRecord.json +++ b/lexicons/com/atproto/repo/putRecord.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Write a record, creating or updating it as needed.", + "description": "Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.", "input": { "encoding": "application/json", "schema": { @@ -15,7 +15,7 @@ "repo": { "type": "string", "format": "at-identifier", - "description": "The handle or DID of the repo." + "description": "The handle or DID of the repo (aka, current account)." }, "collection": { "type": "string", @@ -24,13 +24,13 @@ }, "rkey": { "type": "string", - "description": "The key of the record.", + "description": "The Record Key.", "maxLength": 15 }, "validate": { "type": "boolean", "default": true, - "description": "Flag for validating the record." + "description": "Can be set to 'false' to skip Lexicon schema validation of record data." }, "record": { "type": "unknown", @@ -39,7 +39,7 @@ "swapRecord": { "type": "string", "format": "cid", - "description": "Compare and swap with the previous record by CID." + "description": "Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation" }, "swapCommit": { "type": "string", diff --git a/lexicons/com/atproto/repo/uploadBlob.json b/lexicons/com/atproto/repo/uploadBlob.json index 63d1671bd3e..547a995a051 100644 --- a/lexicons/com/atproto/repo/uploadBlob.json +++ b/lexicons/com/atproto/repo/uploadBlob.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Upload a new blob to be added to repo in a later request.", + "description": "Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.", "input": { "encoding": "*/*" }, diff --git a/lexicons/com/atproto/server/activateAccount.json b/lexicons/com/atproto/server/activateAccount.json new file mode 100644 index 00000000000..e06935fcd07 --- /dev/null +++ b/lexicons/com/atproto/server/activateAccount.json @@ -0,0 +1,10 @@ +{ + "lexicon": 1, + "id": "com.atproto.server.activateAccount", + "defs": { + "main": { + "type": "procedure", + "description": "Activates a currently deactivated account. Used to finalize account migration after the account's repo is imported and identity is setup." + } + } +} diff --git a/lexicons/com/atproto/server/checkAccountStatus.json b/lexicons/com/atproto/server/checkAccountStatus.json new file mode 100644 index 00000000000..d34596e60e1 --- /dev/null +++ b/lexicons/com/atproto/server/checkAccountStatus.json @@ -0,0 +1,38 @@ +{ + "lexicon": 1, + "id": "com.atproto.server.checkAccountStatus", + "defs": { + "main": { + "type": "query", + "description": "Returns the status of an account, especially as pertaining to import or recovery. Can be called many times over the course of an account migration. Requires auth and can only be called pertaining to oneself.", + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "activated", + "validDid", + "repoCommit", + "repoRev", + "repoBlocks", + "indexedRecords", + "privateStateValues", + "expectedBlobs", + "importedBlobs" + ], + "properties": { + "activated": { "type": "boolean" }, + "validDid": { "type": "boolean" }, + "repoCommit": { "type": "string", "format": "cid" }, + "repoRev": { "type": "string" }, + "repoBlocks": { "type": "integer" }, + "indexedRecords": { "type": "integer" }, + "privateStateValues": { "type": "integer" }, + "expectedBlobs": { "type": "integer" }, + "importedBlobs": { "type": "integer" } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/server/createAccount.json b/lexicons/com/atproto/server/createAccount.json index d1456e095ae..b32bbe1569d 100644 --- a/lexicons/com/atproto/server/createAccount.json +++ b/lexicons/com/atproto/server/createAccount.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Create an account.", + "description": "Create an account. Implemented by PDS.", "input": { "encoding": "application/json", "schema": { @@ -12,14 +12,31 @@ "required": ["handle"], "properties": { "email": { "type": "string" }, - "handle": { "type": "string", "format": "handle" }, - "did": { "type": "string", "format": "did" }, + "handle": { + "type": "string", + "format": "handle", + "description": "Requested handle for the account." + }, + "did": { + "type": "string", + "format": "did", + "description": "Pre-existing atproto DID, being imported to a new account." + }, "inviteCode": { "type": "string" }, "verificationCode": { "type": "string" }, "verificationPhone": { "type": "string" }, - "password": { "type": "string" }, - "recoveryKey": { "type": "string" }, - "plcOp": { "type": "unknown" } + "password": { + "type": "string", + "description": "Initial account password. May need to meet instance-specific password strength requirements." + }, + "recoveryKey": { + "type": "string", + "description": "DID PLC rotation key (aka, recovery key) to be included in PLC creation operation." + }, + "plcOp": { + "type": "unknown", + "description": "A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented." + } } } }, @@ -27,13 +44,21 @@ "encoding": "application/json", "schema": { "type": "object", + "description": "Account login session returned on successful account creation.", "required": ["accessJwt", "refreshJwt", "handle", "did"], "properties": { "accessJwt": { "type": "string" }, "refreshJwt": { "type": "string" }, "handle": { "type": "string", "format": "handle" }, - "did": { "type": "string", "format": "did" }, - "didDoc": { "type": "unknown" } + "did": { + "type": "string", + "format": "did", + "description": "The DID of the new account." + }, + "didDoc": { + "type": "unknown", + "description": "Complete DID document." + } } } }, diff --git a/lexicons/com/atproto/server/createAppPassword.json b/lexicons/com/atproto/server/createAppPassword.json index f12e8e2557e..0a60e4e30b0 100644 --- a/lexicons/com/atproto/server/createAppPassword.json +++ b/lexicons/com/atproto/server/createAppPassword.json @@ -11,7 +11,10 @@ "type": "object", "required": ["name"], "properties": { - "name": { "type": "string" } + "name": { + "type": "string", + "description": "A short name for the App Password, to help distinguish them." + } } } }, diff --git a/lexicons/com/atproto/server/deactivateAccount.json b/lexicons/com/atproto/server/deactivateAccount.json new file mode 100644 index 00000000000..698fccf202e --- /dev/null +++ b/lexicons/com/atproto/server/deactivateAccount.json @@ -0,0 +1,23 @@ +{ + "lexicon": 1, + "id": "com.atproto.server.deactivateAccount", + "defs": { + "main": { + "type": "procedure", + "description": "Deactivates a currently active account. Stops serving of repo, and future writes to repo until reactivated. Used to finalize account migration with the old host after the account has been activated on the new host.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "properties": { + "deleteAfter": { + "type": "string", + "format": "datetime", + "description": "A recommendation to server as to how long they should hold onto the deactivated account before deleting." + } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/server/deleteAccount.json b/lexicons/com/atproto/server/deleteAccount.json index 3747189dca3..cf4babfe7da 100644 --- a/lexicons/com/atproto/server/deleteAccount.json +++ b/lexicons/com/atproto/server/deleteAccount.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Delete an actor's account with a token and password.", + "description": "Delete an actor's account with a token and password. Can only be called after requesting a deletion token. Requires auth.", "input": { "encoding": "application/json", "schema": { diff --git a/lexicons/com/atproto/server/deleteSession.json b/lexicons/com/atproto/server/deleteSession.json index e05d019024a..807a89dc9bd 100644 --- a/lexicons/com/atproto/server/deleteSession.json +++ b/lexicons/com/atproto/server/deleteSession.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Delete the current session." + "description": "Delete the current session. Requires auth." } } } diff --git a/lexicons/com/atproto/server/describeServer.json b/lexicons/com/atproto/server/describeServer.json index 3c60a58ecaf..d7bd4ab76f2 100644 --- a/lexicons/com/atproto/server/describeServer.json +++ b/lexicons/com/atproto/server/describeServer.json @@ -4,20 +4,35 @@ "defs": { "main": { "type": "query", - "description": "Get a document describing the service's accounts configuration.", + "description": "Describes the server's account creation requirements and capabilities. Implemented by PDS.", "output": { "encoding": "application/json", "schema": { "type": "object", - "required": ["availableUserDomains"], + "required": ["did", "availableUserDomains"], "properties": { - "inviteCodeRequired": { "type": "boolean" }, - "phoneVerificationRequired": { "type": "boolean" }, + "inviteCodeRequired": { + "type": "boolean", + "description": "If true, an invite code must be supplied to create an account on this instance." + }, + "phoneVerificationRequired": { + "type": "boolean", + "description": "If true, a phone verification token must be supplied to create an account on this instance." + }, "availableUserDomains": { "type": "array", + "description": "List of domain suffixes that can be used in account handles.", "items": { "type": "string" } }, - "links": { "type": "ref", "ref": "#links" } + "links": { + "type": "ref", + "description": "URLs of service policy documents.", + "ref": "#links" + }, + "did": { + "type": "string", + "format": "did" + } } } } diff --git a/lexicons/com/atproto/server/getAccountInviteCodes.json b/lexicons/com/atproto/server/getAccountInviteCodes.json index ac23b11f23f..72f0822703d 100644 --- a/lexicons/com/atproto/server/getAccountInviteCodes.json +++ b/lexicons/com/atproto/server/getAccountInviteCodes.json @@ -4,12 +4,16 @@ "defs": { "main": { "type": "query", - "description": "Get all invite codes for a given account.", + "description": "Get all invite codes for the current account. Requires auth.", "parameters": { "type": "params", "properties": { "includeUsed": { "type": "boolean", "default": true }, - "createAvailable": { "type": "boolean", "default": true } + "createAvailable": { + "type": "boolean", + "default": true, + "description": "Controls whether any new 'earned' but not 'created' invites should be created." + } } }, "output": { diff --git a/lexicons/com/atproto/server/getServiceAuth.json b/lexicons/com/atproto/server/getServiceAuth.json new file mode 100644 index 00000000000..95984c186ad --- /dev/null +++ b/lexicons/com/atproto/server/getServiceAuth.json @@ -0,0 +1,33 @@ +{ + "lexicon": 1, + "id": "com.atproto.server.getServiceAuth", + "defs": { + "main": { + "type": "query", + "description": "Get a signed token on behalf of the requesting DID for the requested service.", + "parameters": { + "type": "params", + "required": ["aud"], + "properties": { + "aud": { + "type": "string", + "format": "did", + "description": "The DID of the service that the token will be used to authenticate with" + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["token"], + "properties": { + "token": { + "type": "string" + } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/server/getSession.json b/lexicons/com/atproto/server/getSession.json index 5f7700882da..6b5f280e746 100644 --- a/lexicons/com/atproto/server/getSession.json +++ b/lexicons/com/atproto/server/getSession.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get information about the current session.", + "description": "Get information about the current auth session. Requires auth.", "output": { "encoding": "application/json", "schema": { diff --git a/lexicons/com/atproto/server/refreshSession.json b/lexicons/com/atproto/server/refreshSession.json index 3f4d7fdf272..0b067f86b7f 100644 --- a/lexicons/com/atproto/server/refreshSession.json +++ b/lexicons/com/atproto/server/refreshSession.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Refresh an authentication session.", + "description": "Refresh an authentication session. Requires auth using the 'refreshJwt' (not the 'accessJwt').", "output": { "encoding": "application/json", "schema": { diff --git a/lexicons/com/atproto/server/reserveSigningKey.json b/lexicons/com/atproto/server/reserveSigningKey.json index 3a67ad0a3c8..a33e1ede68e 100644 --- a/lexicons/com/atproto/server/reserveSigningKey.json +++ b/lexicons/com/atproto/server/reserveSigningKey.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Reserve a repo signing key for account creation.", + "description": "Reserve a repo signing key, for use with account creation. Necessary so that a DID PLC update operation can be constructed during an account migraiton. Public and does not require auth; implemented by PDS. NOTE: this endpoint may change when full account migration is implemented.", "input": { "encoding": "application/json", "schema": { @@ -12,7 +12,8 @@ "properties": { "did": { "type": "string", - "description": "The did to reserve a new did:key for" + "format": "did", + "description": "The DID to reserve a key for." } } } @@ -25,7 +26,7 @@ "properties": { "signingKey": { "type": "string", - "description": "Public signing key in the form of a did:key." + "description": "The public key for the reserved signing key, in did:key serialization." } } } diff --git a/lexicons/com/atproto/sync/getBlob.json b/lexicons/com/atproto/sync/getBlob.json index 23e18a4f3b5..57ece7a9d8a 100644 --- a/lexicons/com/atproto/sync/getBlob.json +++ b/lexicons/com/atproto/sync/getBlob.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get a blob associated with a given repo.", + "description": "Get a blob associated with a given account. Returns the full blob as originally uploaded. Does not require auth; implemented by PDS.", "parameters": { "type": "params", "required": ["did", "cid"], @@ -12,7 +12,7 @@ "did": { "type": "string", "format": "did", - "description": "The DID of the repo." + "description": "The DID of the account." }, "cid": { "type": "string", diff --git a/lexicons/com/atproto/sync/getBlocks.json b/lexicons/com/atproto/sync/getBlocks.json index cf776a0c88f..29dd4971904 100644 --- a/lexicons/com/atproto/sync/getBlocks.json +++ b/lexicons/com/atproto/sync/getBlocks.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get blocks from a given repo.", + "description": "Get data blocks from a given repo, by CID. For example, intermediate MST nodes, or records. Does not require auth; implemented by PDS.", "parameters": { "type": "params", "required": ["did", "cids"], diff --git a/lexicons/com/atproto/sync/getLatestCommit.json b/lexicons/com/atproto/sync/getLatestCommit.json index d8754f09062..ac7faf57570 100644 --- a/lexicons/com/atproto/sync/getLatestCommit.json +++ b/lexicons/com/atproto/sync/getLatestCommit.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get the current commit CID & revision of the repo.", + "description": "Get the current commit CID & revision of the specified repo. Does not require auth.", "parameters": { "type": "params", "required": ["did"], diff --git a/lexicons/com/atproto/sync/getRecord.json b/lexicons/com/atproto/sync/getRecord.json index cbd0ad3a5ac..718245a5195 100644 --- a/lexicons/com/atproto/sync/getRecord.json +++ b/lexicons/com/atproto/sync/getRecord.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Get blocks needed for existence or non-existence of record.", + "description": "Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.", "parameters": { "type": "params", "required": ["did", "collection", "rkey"], @@ -15,7 +15,7 @@ "description": "The DID of the repo." }, "collection": { "type": "string", "format": "nsid" }, - "rkey": { "type": "string" }, + "rkey": { "type": "string", "description": "Record Key" }, "commit": { "type": "string", "format": "cid", diff --git a/lexicons/com/atproto/sync/getRepo.json b/lexicons/com/atproto/sync/getRepo.json index fb68ab670ee..7fa710abfb5 100644 --- a/lexicons/com/atproto/sync/getRepo.json +++ b/lexicons/com/atproto/sync/getRepo.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Gets the DID's repo, optionally catching up from a specific revision.", + "description": "Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS.", "parameters": { "type": "params", "required": ["did"], @@ -16,7 +16,7 @@ }, "since": { "type": "string", - "description": "The revision of the repo to catch up from." + "description": "The revision ('rev') of the repo to create a diff from." } } }, diff --git a/lexicons/com/atproto/sync/listBlobs.json b/lexicons/com/atproto/sync/listBlobs.json index 46815eeb49a..b4c954d999a 100644 --- a/lexicons/com/atproto/sync/listBlobs.json +++ b/lexicons/com/atproto/sync/listBlobs.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "List blob CIDs since some revision.", + "description": "List blob CIDso for an account, since some repo revision. Does not require auth; implemented by PDS.", "parameters": { "type": "params", "required": ["did"], diff --git a/lexicons/com/atproto/sync/listRepos.json b/lexicons/com/atproto/sync/listRepos.json index 440e8693d5e..07ae35e2c5e 100644 --- a/lexicons/com/atproto/sync/listRepos.json +++ b/lexicons/com/atproto/sync/listRepos.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "List DIDs and root CIDs of hosted repos.", + "description": "Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.", "parameters": { "type": "params", "properties": { @@ -37,7 +37,11 @@ "required": ["did", "head", "rev"], "properties": { "did": { "type": "string", "format": "did" }, - "head": { "type": "string", "format": "cid" }, + "head": { + "type": "string", + "format": "cid", + "description": "Current repo commit CID" + }, "rev": { "type": "string" } } } diff --git a/lexicons/com/atproto/sync/notifyOfUpdate.json b/lexicons/com/atproto/sync/notifyOfUpdate.json index 48cb4b24678..034a9655a08 100644 --- a/lexicons/com/atproto/sync/notifyOfUpdate.json +++ b/lexicons/com/atproto/sync/notifyOfUpdate.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Notify a crawling service of a recent update; often when a long break between updates causes the connection with the crawling service to break.", + "description": "Notify a crawling service of a recent update, and that crawling should resume. Intended use is after a gap between repo stream events caused the crawling service to disconnect. Does not require auth; implemented by Relay.", "input": { "encoding": "application/json", "schema": { @@ -13,7 +13,7 @@ "properties": { "hostname": { "type": "string", - "description": "Hostname of the service that is notifying of update." + "description": "Hostname of the current service (usually a PDS) that is notifying of update." } } } diff --git a/lexicons/com/atproto/sync/requestCrawl.json b/lexicons/com/atproto/sync/requestCrawl.json index a3520a33180..8e075a376fc 100644 --- a/lexicons/com/atproto/sync/requestCrawl.json +++ b/lexicons/com/atproto/sync/requestCrawl.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "procedure", - "description": "Request a service to persistently crawl hosted repos.", + "description": "Request a service to persistently crawl hosted repos. Expected use is new PDS instances declaring their existence to Relays. Does not require auth.", "input": { "encoding": "application/json", "schema": { @@ -13,7 +13,7 @@ "properties": { "hostname": { "type": "string", - "description": "Hostname of the service that is requesting to be crawled." + "description": "Hostname of the current service (eg, PDS) that is requesting to be crawled." } } } diff --git a/lexicons/com/atproto/sync/subscribeRepos.json b/lexicons/com/atproto/sync/subscribeRepos.json index 9a5c0f6153c..31d68b91c07 100644 --- a/lexicons/com/atproto/sync/subscribeRepos.json +++ b/lexicons/com/atproto/sync/subscribeRepos.json @@ -4,26 +4,40 @@ "defs": { "main": { "type": "subscription", - "description": "Subscribe to repo updates.", + "description": "Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.", "parameters": { "type": "params", "properties": { "cursor": { "type": "integer", - "description": "The last known event to backfill from." + "description": "The last known event seq number to backfill from." } } }, "message": { "schema": { "type": "union", - "refs": ["#commit", "#handle", "#migrate", "#tombstone", "#info"] + "refs": [ + "#commit", + "#identity", + "#handle", + "#migrate", + "#tombstone", + "#info" + ] } }, - "errors": [{ "name": "FutureCursor" }, { "name": "ConsumerTooSlow" }] + "errors": [ + { "name": "FutureCursor" }, + { + "name": "ConsumerTooSlow", + "description": "If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection." + } + ] }, "commit": { "type": "object", + "description": "Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.", "required": [ "seq", "rebase", @@ -39,39 +53,77 @@ ], "nullable": ["prev", "since"], "properties": { - "seq": { "type": "integer" }, - "rebase": { "type": "boolean" }, - "tooBig": { "type": "boolean" }, - "repo": { "type": "string", "format": "did" }, - "commit": { "type": "cid-link" }, - "prev": { "type": "cid-link" }, + "seq": { + "type": "integer", + "description": "The stream sequence number of this message." + }, + "rebase": { "type": "boolean", "description": "DEPRECATED -- unused" }, + "tooBig": { + "type": "boolean", + "description": "Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data." + }, + "repo": { + "type": "string", + "format": "did", + "description": "The repo this event comes from." + }, + "commit": { + "type": "cid-link", + "description": "Repo commit object CID." + }, + "prev": { + "type": "cid-link", + "description": "DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability." + }, "rev": { "type": "string", - "description": "The rev of the emitted commit." + "description": "The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event." }, "since": { "type": "string", - "description": "The rev of the last emitted commit from this repo." + "description": "The rev of the last emitted commit from this repo (if any)." }, "blocks": { "type": "bytes", - "description": "CAR file containing relevant blocks.", + "description": "CAR file containing relevant blocks, as a diff since the previous repo state.", "maxLength": 1000000 }, "ops": { "type": "array", - "items": { "type": "ref", "ref": "#repoOp" }, + "items": { + "type": "ref", + "ref": "#repoOp", + "description": "List of repo mutation operations in this commit (eg, records created, updated, or deleted)." + }, "maxLength": 200 }, "blobs": { "type": "array", - "items": { "type": "cid-link" } + "items": { + "type": "cid-link", + "description": "List of new blobs (by CID) referenced by records in this commit." + } }, + "time": { + "type": "string", + "format": "datetime", + "description": "Timestamp of when this message was originally broadcast." + } + } + }, + "identity": { + "type": "object", + "description": "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.", + "required": ["seq", "did", "time"], + "properties": { + "seq": { "type": "integer" }, + "did": { "type": "string", "format": "did" }, "time": { "type": "string", "format": "datetime" } } }, "handle": { "type": "object", + "description": "Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity.", "required": ["seq", "did", "handle", "time"], "properties": { "seq": { "type": "integer" }, @@ -82,6 +134,7 @@ }, "migrate": { "type": "object", + "description": "Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead", "required": ["seq", "did", "migrateTo", "time"], "nullable": ["migrateTo"], "properties": { @@ -93,6 +146,7 @@ }, "tombstone": { "type": "object", + "description": "Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event", "required": ["seq", "did", "time"], "properties": { "seq": { "type": "integer" }, @@ -115,7 +169,7 @@ }, "repoOp": { "type": "object", - "description": "A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null.", + "description": "A repo operation, ie a mutation of a single record.", "required": ["action", "path", "cid"], "nullable": ["cid"], "properties": { @@ -124,7 +178,10 @@ "knownValues": ["create", "update", "delete"] }, "path": { "type": "string" }, - "cid": { "type": "cid-link" } + "cid": { + "type": "cid-link", + "description": "For creates and updates, the new record CID. For deletions, null." + } } } } diff --git a/lexicons/com/atproto/temp/checkSignupQueue.json b/lexicons/com/atproto/temp/checkSignupQueue.json new file mode 100644 index 00000000000..b7d9e65d7cf --- /dev/null +++ b/lexicons/com/atproto/temp/checkSignupQueue.json @@ -0,0 +1,22 @@ +{ + "lexicon": 1, + "id": "com.atproto.temp.checkSignupQueue", + "defs": { + "main": { + "type": "query", + "description": "Check accounts location in signup queue.", + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["activated"], + "properties": { + "activated": { "type": "boolean" }, + "placeInQueue": { "type": "integer" }, + "estimatedTimeMs": { "type": "integer" } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/temp/fetchLabels.json b/lexicons/com/atproto/temp/fetchLabels.json index 14e392fd5e7..57c3f732cdb 100644 --- a/lexicons/com/atproto/temp/fetchLabels.json +++ b/lexicons/com/atproto/temp/fetchLabels.json @@ -4,7 +4,7 @@ "defs": { "main": { "type": "query", - "description": "Fetch all labels from a labeler created after a certain date.", + "description": "DEPRECATED: use queryLabels or subscribeLabels instead -- Fetch all labels from a labeler created after a certain date.", "parameters": { "type": "params", "properties": { diff --git a/lexicons/com/atproto/temp/importRepo.json b/lexicons/com/atproto/temp/importRepo.json deleted file mode 100644 index f06daa09d73..00000000000 --- a/lexicons/com/atproto/temp/importRepo.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "lexicon": 1, - "id": "com.atproto.temp.importRepo", - "defs": { - "main": { - "type": "procedure", - "description": "Gets the did's repo, optionally catching up from a specific revision.", - "parameters": { - "type": "params", - "required": ["did"], - "properties": { - "did": { - "type": "string", - "format": "did", - "description": "The DID of the repo." - } - } - }, - "input": { - "encoding": "application/vnd.ipld.car" - }, - "output": { - "encoding": "text/plain" - } - } - } -} diff --git a/lexicons/com/atproto/temp/pushBlob.json b/lexicons/com/atproto/temp/pushBlob.json deleted file mode 100644 index 9babc8f8e43..00000000000 --- a/lexicons/com/atproto/temp/pushBlob.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "lexicon": 1, - "id": "com.atproto.temp.pushBlob", - "defs": { - "main": { - "type": "procedure", - "description": "Gets the did's repo, optionally catching up from a specific revision.", - "parameters": { - "type": "params", - "required": ["did"], - "properties": { - "did": { - "type": "string", - "format": "did", - "description": "The DID of the repo." - } - } - }, - "input": { - "encoding": "*/*" - } - } - } -} diff --git a/lexicons/com/atproto/temp/transferAccount.json b/lexicons/com/atproto/temp/transferAccount.json deleted file mode 100644 index 3cb2035ac0e..00000000000 --- a/lexicons/com/atproto/temp/transferAccount.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "lexicon": 1, - "id": "com.atproto.temp.transferAccount", - "defs": { - "main": { - "type": "procedure", - "description": "Transfer an account.", - "input": { - "encoding": "application/json", - "schema": { - "type": "object", - "required": ["handle", "did", "plcOp"], - "properties": { - "handle": { "type": "string", "format": "handle" }, - "did": { "type": "string", "format": "did" }, - "plcOp": { "type": "unknown" } - } - } - }, - "output": { - "encoding": "application/json", - "schema": { - "type": "object", - "required": ["accessJwt", "refreshJwt", "handle", "did"], - "properties": { - "accessJwt": { "type": "string" }, - "refreshJwt": { "type": "string" }, - "handle": { "type": "string", "format": "handle" }, - "did": { "type": "string", "format": "did" } - } - } - }, - "errors": [ - { "name": "InvalidHandle" }, - { "name": "InvalidPassword" }, - { "name": "InvalidInviteCode" }, - { "name": "HandleNotAvailable" }, - { "name": "UnsupportedDomain" }, - { "name": "UnresolvableDid" }, - { "name": "IncompatibleDidDoc" } - ] - } - } -} diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 77500f38527..58732dbd074 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -1,5 +1,52 @@ # @atproto/api +## 0.10.1 + +### Patch Changes + +- [#2215](https://github.com/bluesky-social/atproto/pull/2215) [`514aab92d`](https://github.com/bluesky-social/atproto/commit/514aab92d26acd43859285f46318e386846522b1) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add missing `getPreferences` union return types + +## 0.10.0 + +### Minor Changes + +- [#2170](https://github.com/bluesky-social/atproto/pull/2170) [`4c511b3d9`](https://github.com/bluesky-social/atproto/commit/4c511b3d9de41ffeae3fc11db941e7df04f4468a) Thanks [@dholms](https://github.com/dholms)! - Add lexicons and methods for account migration + +### Patch Changes + +- [#2195](https://github.com/bluesky-social/atproto/pull/2195) [`b60719480`](https://github.com/bluesky-social/atproto/commit/b60719480f5f00bffd074a40e8ddc03aa93d137d) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add muted words/tags and hidden posts prefs and methods" + +## 0.9.8 + +### Patch Changes + +- [#2192](https://github.com/bluesky-social/atproto/pull/2192) [`f79cc6339`](https://github.com/bluesky-social/atproto/commit/f79cc63390ae9dbd47a4ff5d694eec25b78b788e) Thanks [@foysalit](https://github.com/foysalit)! - Tag event on moderation subjects and allow filtering events and subjects by tags + +## 0.9.7 + +### Patch Changes + +- [#2188](https://github.com/bluesky-social/atproto/pull/2188) [`8c94979f7`](https://github.com/bluesky-social/atproto/commit/8c94979f73fc5057449e24e66ef2e09b0e17e55b) Thanks [@dholms](https://github.com/dholms)! - Added timelineIndex to savedFeedsPref + +## 0.9.6 + +### Patch Changes + +- [#2124](https://github.com/bluesky-social/atproto/pull/2124) [`e4ec7af03`](https://github.com/bluesky-social/atproto/commit/e4ec7af03608949fc3b00a845f547a77599b5ad0) Thanks [@foysalit](https://github.com/foysalit)! - Allow filtering for comment, label, report type and date range on queryModerationEvents endpoint. + +## 0.9.5 + +### Patch Changes + +- [#2090](https://github.com/bluesky-social/atproto/pull/2090) [`8994d363`](https://github.com/bluesky-social/atproto/commit/8994d3633adad1c02569d6d44ae896e18195e8e2) Thanks [@dholms](https://github.com/dholms)! - add checkSignupQueue method and expose refreshSession on agent + +## 0.9.4 + +### Patch Changes + +- [#2086](https://github.com/bluesky-social/atproto/pull/2086) [`4171c04a`](https://github.com/bluesky-social/atproto/commit/4171c04ad81c5734a4558bc41fa1c4f3a1aba18c) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add `setInterestsPref` method to BskyAgent, and `interests` prop to + `getPreferences` response. + ## 0.9.3 ### Patch Changes diff --git a/packages/api/package.json b/packages/api/package.json index 31827bd53b3..ab76c7b4249 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/api", - "version": "0.9.3", + "version": "0.10.1", "license": "MIT", "description": "Client library for atproto and Bluesky", "keywords": [ diff --git a/packages/api/src/agent.ts b/packages/api/src/agent.ts index 54f599492b5..d46e2aa9e3c 100644 --- a/packages/api/src/agent.ts +++ b/packages/api/src/agent.ts @@ -231,7 +231,7 @@ export class AtpAgent { // handle session-refreshes as needed if (isErrorResponse(res, ['ExpiredToken']) && this.session?.refreshJwt) { // attempt refresh - await this._refreshSession() + await this.refreshSession() // resend the request with the new access token res = await AtpAgent.fetch( @@ -250,7 +250,7 @@ export class AtpAgent { * - Wraps the actual implementation in a promise-guard to ensure only * one refresh is attempted at a time. */ - private async _refreshSession() { + async refreshSession() { if (this._refreshSessionPromise) { return this._refreshSessionPromise } diff --git a/packages/api/src/bsky-agent.ts b/packages/api/src/bsky-agent.ts index ce166a59490..305348bea0b 100644 --- a/packages/api/src/bsky-agent.ts +++ b/packages/api/src/bsky-agent.ts @@ -11,6 +11,7 @@ import { BskyLabelPreference, BskyFeedViewPreference, BskyThreadViewPreference, + BskyInterestsPreference, } from './types' const FEED_VIEW_PREF_DEFAULTS = { @@ -323,6 +324,11 @@ export class BskyAgent extends AtpAgent { adultContentEnabled: false, contentLabels: {}, birthDate: undefined, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], } const res = await this.app.bsky.actor.getPreferences({}) for (const pref of res.data.preferences) { @@ -369,6 +375,27 @@ export class BskyAgent extends AtpAgent { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { $type, ...v } = pref prefs.threadViewPrefs = { ...prefs.threadViewPrefs, ...v } + } else if ( + AppBskyActorDefs.isInterestsPref(pref) && + AppBskyActorDefs.validateInterestsPref(pref).success + ) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { $type, ...v } = pref + prefs.interests = { ...prefs.interests, ...v } + } else if ( + AppBskyActorDefs.isMutedWordsPref(pref) && + AppBskyActorDefs.validateMutedWordsPref(pref).success + ) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { $type, ...v } = pref + prefs.mutedWords = v.items + } else if ( + AppBskyActorDefs.isHiddenPostsPref(pref) && + AppBskyActorDefs.validateHiddenPostsPref(pref).success + ) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { $type, ...v } = pref + prefs.hiddenPosts = v.items } } return prefs @@ -521,6 +548,42 @@ export class BskyAgent extends AtpAgent { .concat([{ ...pref, $type: 'app.bsky.actor.defs#threadViewPref' }]) }) } + + async setInterestsPref(pref: Partial) { + await updatePreferences(this, (prefs: AppBskyActorDefs.Preferences) => { + const existing = prefs.findLast( + (pref) => + AppBskyActorDefs.isInterestsPref(pref) && + AppBskyActorDefs.validateInterestsPref(pref).success, + ) + if (existing) { + pref = { ...existing, ...pref } + } + return prefs + .filter((p) => !AppBskyActorDefs.isInterestsPref(p)) + .concat([{ ...pref, $type: 'app.bsky.actor.defs#interestsPref' }]) + }) + } + + async upsertMutedWords(mutedWords: AppBskyActorDefs.MutedWord[]) { + await updateMutedWords(this, mutedWords, 'upsert') + } + + async updateMutedWord(mutedWord: AppBskyActorDefs.MutedWord) { + await updateMutedWords(this, [mutedWord], 'update') + } + + async removeMutedWord(mutedWord: AppBskyActorDefs.MutedWord) { + await updateMutedWords(this, [mutedWord], 'remove') + } + + async hidePost(postUri: string) { + await updateHiddenPost(this, postUri, 'hide') + } + + async unhidePost(postUri: string) { + await updateHiddenPost(this, postUri, 'unhide') + } } /** @@ -582,3 +645,103 @@ async function updateFeedPreferences( }) return res } + +/** + * A helper specifically for updating muted words preferences + */ +async function updateMutedWords( + agent: BskyAgent, + mutedWords: AppBskyActorDefs.MutedWord[], + action: 'upsert' | 'update' | 'remove', +) { + const sanitizeMutedWord = (word: AppBskyActorDefs.MutedWord) => ({ + value: word.value.replace(/^#/, ''), + targets: word.targets, + }) + + await updatePreferences(agent, (prefs: AppBskyActorDefs.Preferences) => { + let mutedWordsPref = prefs.findLast( + (pref) => + AppBskyActorDefs.isMutedWordsPref(pref) && + AppBskyActorDefs.validateMutedWordsPref(pref).success, + ) + + if (mutedWordsPref && AppBskyActorDefs.isMutedWordsPref(mutedWordsPref)) { + if (action === 'upsert' || action === 'update') { + for (const word of mutedWords) { + let foundMatch = false + + for (const existingItem of mutedWordsPref.items) { + if (existingItem.value === sanitizeMutedWord(word).value) { + existingItem.targets = + action === 'upsert' + ? Array.from( + new Set([...existingItem.targets, ...word.targets]), + ) + : word.targets + foundMatch = true + break + } + } + + if (action === 'upsert' && !foundMatch) { + mutedWordsPref.items.push(sanitizeMutedWord(word)) + } + } + } else if (action === 'remove') { + for (const word of mutedWords) { + for (let i = 0; i < mutedWordsPref.items.length; i++) { + const existing = mutedWordsPref.items[i] + if (existing.value === sanitizeMutedWord(word).value) { + mutedWordsPref.items.splice(i, 1) + break + } + } + } + } + } else { + // if the pref doesn't exist, create it + if (action === 'upsert') { + mutedWordsPref = { + items: mutedWords.map(sanitizeMutedWord), + } + } + } + + return prefs + .filter((p) => !AppBskyActorDefs.isMutedWordsPref(p)) + .concat([ + { ...mutedWordsPref, $type: 'app.bsky.actor.defs#mutedWordsPref' }, + ]) + }) +} + +async function updateHiddenPost( + agent: BskyAgent, + postUri: string, + action: 'hide' | 'unhide', +) { + await updatePreferences(agent, (prefs: AppBskyActorDefs.Preferences) => { + let pref = prefs.findLast( + (pref) => + AppBskyActorDefs.isHiddenPostsPref(pref) && + AppBskyActorDefs.validateHiddenPostsPref(pref).success, + ) + if (pref && AppBskyActorDefs.isHiddenPostsPref(pref)) { + pref.items = + action === 'hide' + ? Array.from(new Set([...pref.items, postUri])) + : pref.items.filter((uri) => uri !== postUri) + } else { + if (action === 'hide') { + pref = { + $type: 'app.bsky.actor.defs#hiddenPostsPref', + items: [postUri], + } + } + } + return prefs + .filter((p) => !AppBskyActorDefs.isInterestsPref(p)) + .concat([{ ...pref, $type: 'app.bsky.actor.defs#hiddenPostsPref' }]) + }) +} diff --git a/packages/api/src/client/index.ts b/packages/api/src/client/index.ts index c6463e93534..846c379b7a8 100644 --- a/packages/api/src/client/index.ts +++ b/packages/api/src/client/index.ts @@ -29,9 +29,14 @@ import * as ComAtprotoAdminSearchRepos from './types/com/atproto/admin/searchRep import * as ComAtprotoAdminSendEmail from './types/com/atproto/admin/sendEmail' import * as ComAtprotoAdminUpdateAccountEmail from './types/com/atproto/admin/updateAccountEmail' import * as ComAtprotoAdminUpdateAccountHandle from './types/com/atproto/admin/updateAccountHandle' +import * as ComAtprotoAdminUpdateAccountPassword from './types/com/atproto/admin/updateAccountPassword' import * as ComAtprotoAdminUpdateCommunicationTemplate from './types/com/atproto/admin/updateCommunicationTemplate' import * as ComAtprotoAdminUpdateSubjectStatus from './types/com/atproto/admin/updateSubjectStatus' +import * as ComAtprotoIdentityGetRecommendedDidCredentials from './types/com/atproto/identity/getRecommendedDidCredentials' +import * as ComAtprotoIdentityRequestPlcOperationSignature from './types/com/atproto/identity/requestPlcOperationSignature' import * as ComAtprotoIdentityResolveHandle from './types/com/atproto/identity/resolveHandle' +import * as ComAtprotoIdentitySignPlcOperation from './types/com/atproto/identity/signPlcOperation' +import * as ComAtprotoIdentitySubmitPlcOperation from './types/com/atproto/identity/submitPlcOperation' import * as ComAtprotoIdentityUpdateHandle from './types/com/atproto/identity/updateHandle' import * as ComAtprotoLabelDefs from './types/com/atproto/label/defs' import * as ComAtprotoLabelQueryLabels from './types/com/atproto/label/queryLabels' @@ -43,21 +48,27 @@ import * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createReco import * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord' import * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo' import * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord' +import * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo' +import * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs' import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords' import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord' import * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef' import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob' +import * as ComAtprotoServerActivateAccount from './types/com/atproto/server/activateAccount' +import * as ComAtprotoServerCheckAccountStatus from './types/com/atproto/server/checkAccountStatus' import * as ComAtprotoServerConfirmEmail from './types/com/atproto/server/confirmEmail' import * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount' import * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword' import * as ComAtprotoServerCreateInviteCode from './types/com/atproto/server/createInviteCode' import * as ComAtprotoServerCreateInviteCodes from './types/com/atproto/server/createInviteCodes' import * as ComAtprotoServerCreateSession from './types/com/atproto/server/createSession' +import * as ComAtprotoServerDeactivateAccount from './types/com/atproto/server/deactivateAccount' import * as ComAtprotoServerDefs from './types/com/atproto/server/defs' import * as ComAtprotoServerDeleteAccount from './types/com/atproto/server/deleteAccount' import * as ComAtprotoServerDeleteSession from './types/com/atproto/server/deleteSession' import * as ComAtprotoServerDescribeServer from './types/com/atproto/server/describeServer' import * as ComAtprotoServerGetAccountInviteCodes from './types/com/atproto/server/getAccountInviteCodes' +import * as ComAtprotoServerGetServiceAuth from './types/com/atproto/server/getServiceAuth' import * as ComAtprotoServerGetSession from './types/com/atproto/server/getSession' import * as ComAtprotoServerListAppPasswords from './types/com/atproto/server/listAppPasswords' import * as ComAtprotoServerRefreshSession from './types/com/atproto/server/refreshSession' @@ -81,11 +92,9 @@ import * as ComAtprotoSyncListRepos from './types/com/atproto/sync/listRepos' import * as ComAtprotoSyncNotifyOfUpdate from './types/com/atproto/sync/notifyOfUpdate' import * as ComAtprotoSyncRequestCrawl from './types/com/atproto/sync/requestCrawl' import * as ComAtprotoSyncSubscribeRepos from './types/com/atproto/sync/subscribeRepos' +import * as ComAtprotoTempCheckSignupQueue from './types/com/atproto/temp/checkSignupQueue' import * as ComAtprotoTempFetchLabels from './types/com/atproto/temp/fetchLabels' -import * as ComAtprotoTempImportRepo from './types/com/atproto/temp/importRepo' -import * as ComAtprotoTempPushBlob from './types/com/atproto/temp/pushBlob' import * as ComAtprotoTempRequestPhoneVerification from './types/com/atproto/temp/requestPhoneVerification' -import * as ComAtprotoTempTransferAccount from './types/com/atproto/temp/transferAccount' import * as AppBskyActorDefs from './types/app/bsky/actor/defs' import * as AppBskyActorGetPreferences from './types/app/bsky/actor/getPreferences' import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile' @@ -149,7 +158,6 @@ import * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet' import * as AppBskyUnspeccedDefs from './types/app/bsky/unspecced/defs' import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' import * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions' -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' @@ -175,9 +183,14 @@ export * as ComAtprotoAdminSearchRepos from './types/com/atproto/admin/searchRep export * as ComAtprotoAdminSendEmail from './types/com/atproto/admin/sendEmail' export * as ComAtprotoAdminUpdateAccountEmail from './types/com/atproto/admin/updateAccountEmail' export * as ComAtprotoAdminUpdateAccountHandle from './types/com/atproto/admin/updateAccountHandle' +export * as ComAtprotoAdminUpdateAccountPassword from './types/com/atproto/admin/updateAccountPassword' export * as ComAtprotoAdminUpdateCommunicationTemplate from './types/com/atproto/admin/updateCommunicationTemplate' export * as ComAtprotoAdminUpdateSubjectStatus from './types/com/atproto/admin/updateSubjectStatus' +export * as ComAtprotoIdentityGetRecommendedDidCredentials from './types/com/atproto/identity/getRecommendedDidCredentials' +export * as ComAtprotoIdentityRequestPlcOperationSignature from './types/com/atproto/identity/requestPlcOperationSignature' export * as ComAtprotoIdentityResolveHandle from './types/com/atproto/identity/resolveHandle' +export * as ComAtprotoIdentitySignPlcOperation from './types/com/atproto/identity/signPlcOperation' +export * as ComAtprotoIdentitySubmitPlcOperation from './types/com/atproto/identity/submitPlcOperation' export * as ComAtprotoIdentityUpdateHandle from './types/com/atproto/identity/updateHandle' export * as ComAtprotoLabelDefs from './types/com/atproto/label/defs' export * as ComAtprotoLabelQueryLabels from './types/com/atproto/label/queryLabels' @@ -189,21 +202,27 @@ export * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createReco export * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord' export * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo' export * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord' +export * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo' +export * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs' export * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords' export * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord' export * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef' export * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob' +export * as ComAtprotoServerActivateAccount from './types/com/atproto/server/activateAccount' +export * as ComAtprotoServerCheckAccountStatus from './types/com/atproto/server/checkAccountStatus' export * as ComAtprotoServerConfirmEmail from './types/com/atproto/server/confirmEmail' export * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount' export * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword' export * as ComAtprotoServerCreateInviteCode from './types/com/atproto/server/createInviteCode' export * as ComAtprotoServerCreateInviteCodes from './types/com/atproto/server/createInviteCodes' export * as ComAtprotoServerCreateSession from './types/com/atproto/server/createSession' +export * as ComAtprotoServerDeactivateAccount from './types/com/atproto/server/deactivateAccount' export * as ComAtprotoServerDefs from './types/com/atproto/server/defs' export * as ComAtprotoServerDeleteAccount from './types/com/atproto/server/deleteAccount' export * as ComAtprotoServerDeleteSession from './types/com/atproto/server/deleteSession' export * as ComAtprotoServerDescribeServer from './types/com/atproto/server/describeServer' export * as ComAtprotoServerGetAccountInviteCodes from './types/com/atproto/server/getAccountInviteCodes' +export * as ComAtprotoServerGetServiceAuth from './types/com/atproto/server/getServiceAuth' export * as ComAtprotoServerGetSession from './types/com/atproto/server/getSession' export * as ComAtprotoServerListAppPasswords from './types/com/atproto/server/listAppPasswords' export * as ComAtprotoServerRefreshSession from './types/com/atproto/server/refreshSession' @@ -227,11 +246,9 @@ export * as ComAtprotoSyncListRepos from './types/com/atproto/sync/listRepos' export * as ComAtprotoSyncNotifyOfUpdate from './types/com/atproto/sync/notifyOfUpdate' export * as ComAtprotoSyncRequestCrawl from './types/com/atproto/sync/requestCrawl' export * as ComAtprotoSyncSubscribeRepos from './types/com/atproto/sync/subscribeRepos' +export * as ComAtprotoTempCheckSignupQueue from './types/com/atproto/temp/checkSignupQueue' export * as ComAtprotoTempFetchLabels from './types/com/atproto/temp/fetchLabels' -export * as ComAtprotoTempImportRepo from './types/com/atproto/temp/importRepo' -export * as ComAtprotoTempPushBlob from './types/com/atproto/temp/pushBlob' export * as ComAtprotoTempRequestPhoneVerification from './types/com/atproto/temp/requestPhoneVerification' -export * as ComAtprotoTempTransferAccount from './types/com/atproto/temp/transferAccount' export * as AppBskyActorDefs from './types/app/bsky/actor/defs' export * as AppBskyActorGetPreferences from './types/app/bsky/actor/getPreferences' export * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile' @@ -295,7 +312,6 @@ export * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet' export * as AppBskyUnspeccedDefs from './types/app/bsky/unspecced/defs' export * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' export * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions' -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' @@ -640,6 +656,17 @@ export class ComAtprotoAdminNS { }) } + updateAccountPassword( + data?: ComAtprotoAdminUpdateAccountPassword.InputSchema, + opts?: ComAtprotoAdminUpdateAccountPassword.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.admin.updateAccountPassword', opts?.qp, data, opts) + .catch((e) => { + throw ComAtprotoAdminUpdateAccountPassword.toKnownErr(e) + }) + } + updateCommunicationTemplate( data?: ComAtprotoAdminUpdateCommunicationTemplate.InputSchema, opts?: ComAtprotoAdminUpdateCommunicationTemplate.CallOptions, @@ -675,6 +702,38 @@ export class ComAtprotoIdentityNS { this._service = service } + getRecommendedDidCredentials( + params?: ComAtprotoIdentityGetRecommendedDidCredentials.QueryParams, + opts?: ComAtprotoIdentityGetRecommendedDidCredentials.CallOptions, + ): Promise { + return this._service.xrpc + .call( + 'com.atproto.identity.getRecommendedDidCredentials', + params, + undefined, + opts, + ) + .catch((e) => { + throw ComAtprotoIdentityGetRecommendedDidCredentials.toKnownErr(e) + }) + } + + requestPlcOperationSignature( + data?: ComAtprotoIdentityRequestPlcOperationSignature.InputSchema, + opts?: ComAtprotoIdentityRequestPlcOperationSignature.CallOptions, + ): Promise { + return this._service.xrpc + .call( + 'com.atproto.identity.requestPlcOperationSignature', + opts?.qp, + data, + opts, + ) + .catch((e) => { + throw ComAtprotoIdentityRequestPlcOperationSignature.toKnownErr(e) + }) + } + resolveHandle( params?: ComAtprotoIdentityResolveHandle.QueryParams, opts?: ComAtprotoIdentityResolveHandle.CallOptions, @@ -686,6 +745,28 @@ export class ComAtprotoIdentityNS { }) } + signPlcOperation( + data?: ComAtprotoIdentitySignPlcOperation.InputSchema, + opts?: ComAtprotoIdentitySignPlcOperation.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.identity.signPlcOperation', opts?.qp, data, opts) + .catch((e) => { + throw ComAtprotoIdentitySignPlcOperation.toKnownErr(e) + }) + } + + submitPlcOperation( + data?: ComAtprotoIdentitySubmitPlcOperation.InputSchema, + opts?: ComAtprotoIdentitySubmitPlcOperation.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.identity.submitPlcOperation', opts?.qp, data, opts) + .catch((e) => { + throw ComAtprotoIdentitySubmitPlcOperation.toKnownErr(e) + }) + } + updateHandle( data?: ComAtprotoIdentityUpdateHandle.InputSchema, opts?: ComAtprotoIdentityUpdateHandle.CallOptions, @@ -798,6 +879,28 @@ export class ComAtprotoRepoNS { }) } + importRepo( + data?: ComAtprotoRepoImportRepo.InputSchema, + opts?: ComAtprotoRepoImportRepo.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.repo.importRepo', opts?.qp, data, opts) + .catch((e) => { + throw ComAtprotoRepoImportRepo.toKnownErr(e) + }) + } + + listMissingBlobs( + params?: ComAtprotoRepoListMissingBlobs.QueryParams, + opts?: ComAtprotoRepoListMissingBlobs.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.repo.listMissingBlobs', params, undefined, opts) + .catch((e) => { + throw ComAtprotoRepoListMissingBlobs.toKnownErr(e) + }) + } + listRecords( params?: ComAtprotoRepoListRecords.QueryParams, opts?: ComAtprotoRepoListRecords.CallOptions, @@ -839,6 +942,28 @@ export class ComAtprotoServerNS { this._service = service } + activateAccount( + data?: ComAtprotoServerActivateAccount.InputSchema, + opts?: ComAtprotoServerActivateAccount.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.server.activateAccount', opts?.qp, data, opts) + .catch((e) => { + throw ComAtprotoServerActivateAccount.toKnownErr(e) + }) + } + + checkAccountStatus( + params?: ComAtprotoServerCheckAccountStatus.QueryParams, + opts?: ComAtprotoServerCheckAccountStatus.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.server.checkAccountStatus', params, undefined, opts) + .catch((e) => { + throw ComAtprotoServerCheckAccountStatus.toKnownErr(e) + }) + } + confirmEmail( data?: ComAtprotoServerConfirmEmail.InputSchema, opts?: ComAtprotoServerConfirmEmail.CallOptions, @@ -905,6 +1030,17 @@ export class ComAtprotoServerNS { }) } + deactivateAccount( + data?: ComAtprotoServerDeactivateAccount.InputSchema, + opts?: ComAtprotoServerDeactivateAccount.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.server.deactivateAccount', opts?.qp, data, opts) + .catch((e) => { + throw ComAtprotoServerDeactivateAccount.toKnownErr(e) + }) + } + deleteAccount( data?: ComAtprotoServerDeleteAccount.InputSchema, opts?: ComAtprotoServerDeleteAccount.CallOptions, @@ -949,6 +1085,17 @@ export class ComAtprotoServerNS { }) } + getServiceAuth( + params?: ComAtprotoServerGetServiceAuth.QueryParams, + opts?: ComAtprotoServerGetServiceAuth.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.server.getServiceAuth', params, undefined, opts) + .catch((e) => { + throw ComAtprotoServerGetServiceAuth.toKnownErr(e) + }) + } + getSession( params?: ComAtprotoServerGetSession.QueryParams, opts?: ComAtprotoServerGetSession.CallOptions, @@ -1207,6 +1354,17 @@ export class ComAtprotoTempNS { this._service = service } + checkSignupQueue( + params?: ComAtprotoTempCheckSignupQueue.QueryParams, + opts?: ComAtprotoTempCheckSignupQueue.CallOptions, + ): Promise { + return this._service.xrpc + .call('com.atproto.temp.checkSignupQueue', params, undefined, opts) + .catch((e) => { + throw ComAtprotoTempCheckSignupQueue.toKnownErr(e) + }) + } + fetchLabels( params?: ComAtprotoTempFetchLabels.QueryParams, opts?: ComAtprotoTempFetchLabels.CallOptions, @@ -1218,28 +1376,6 @@ export class ComAtprotoTempNS { }) } - importRepo( - data?: ComAtprotoTempImportRepo.InputSchema, - opts?: ComAtprotoTempImportRepo.CallOptions, - ): Promise { - return this._service.xrpc - .call('com.atproto.temp.importRepo', opts?.qp, data, opts) - .catch((e) => { - throw ComAtprotoTempImportRepo.toKnownErr(e) - }) - } - - pushBlob( - data?: ComAtprotoTempPushBlob.InputSchema, - opts?: ComAtprotoTempPushBlob.CallOptions, - ): Promise { - return this._service.xrpc - .call('com.atproto.temp.pushBlob', opts?.qp, data, opts) - .catch((e) => { - throw ComAtprotoTempPushBlob.toKnownErr(e) - }) - } - requestPhoneVerification( data?: ComAtprotoTempRequestPhoneVerification.InputSchema, opts?: ComAtprotoTempRequestPhoneVerification.CallOptions, @@ -1250,17 +1386,6 @@ export class ComAtprotoTempNS { throw ComAtprotoTempRequestPhoneVerification.toKnownErr(e) }) } - - transferAccount( - data?: ComAtprotoTempTransferAccount.InputSchema, - opts?: ComAtprotoTempTransferAccount.CallOptions, - ): Promise { - return this._service.xrpc - .call('com.atproto.temp.transferAccount', opts?.qp, data, opts) - .catch((e) => { - throw ComAtprotoTempTransferAccount.toKnownErr(e) - }) - } } export class AppNS { @@ -2534,17 +2659,6 @@ export class AppBskyUnspeccedNS { }) } - getTimelineSkeleton( - params?: AppBskyUnspeccedGetTimelineSkeleton.QueryParams, - opts?: AppBskyUnspeccedGetTimelineSkeleton.CallOptions, - ): Promise { - return this._service.xrpc - .call('app.bsky.unspecced.getTimelineSkeleton', params, undefined, opts) - .catch((e) => { - throw AppBskyUnspeccedGetTimelineSkeleton.toKnownErr(e) - }) - } - searchActorsSkeleton( params?: AppBskyUnspeccedSearchActorsSkeleton.QueryParams, opts?: AppBskyUnspeccedSearchActorsSkeleton.CallOptions, diff --git a/packages/api/src/client/lexicons.ts b/packages/api/src/client/lexicons.ts index fea624e9a04..14e4c1cb81e 100644 --- a/packages/api/src/client/lexicons.ts +++ b/packages/api/src/client/lexicons.ts @@ -91,6 +91,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, subject: { @@ -147,6 +148,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventAcknowledge', 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', + 'lex:com.atproto.admin.defs#modEventEmail', 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, @@ -301,6 +303,12 @@ export const schemaDict = { type: 'string', format: 'datetime', }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, }, }, reportViewDetail: { @@ -895,6 +903,33 @@ export const schemaDict = { }, }, }, + modEventTag: { + type: 'object', + description: 'Add/Remove a tag on a subject', + required: ['add', 'remove'], + properties: { + add: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be added to the subject. If already exists, won't be duplicated.", + }, + remove: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated.", + }, + comment: { + type: 'string', + description: 'Additional comment about added/removed tags.', + }, + }, + }, communicationTemplateView: { type: 'object', required: [ @@ -1073,6 +1108,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventReverseTakedown', 'lex:com.atproto.admin.defs#modEventUnmute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventTag', ], }, subject: { @@ -1450,6 +1486,16 @@ export const schemaDict = { description: 'Sort direction for the events. Defaults to descending order of created at timestamp.', }, + createdAfter: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created after a given timestamp', + }, + createdBefore: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created before a given timestamp', + }, subject: { type: 'string', format: 'uri', @@ -1466,6 +1512,53 @@ export const schemaDict = { maximum: 100, default: 50, }, + hasComment: { + type: 'boolean', + description: 'If true, only events with comments are returned', + }, + comment: { + type: 'string', + description: + 'If specified, only events with comments containing the keyword are returned', + }, + addedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were added are returned', + }, + removedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were removed are returned', + }, + addedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were added are returned', + }, + removedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were removed are returned', + }, + reportTypes: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1577,6 +1670,18 @@ export const schemaDict = { maximum: 100, default: 50, }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, + excludeTags: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1758,6 +1863,33 @@ export const schemaDict = { }, }, }, + ComAtprotoAdminUpdateAccountPassword: { + lexicon: 1, + id: 'com.atproto.admin.updateAccountPassword', + defs: { + main: { + type: 'procedure', + description: + 'Update the password for a user account as an administrator.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['did', 'password'], + properties: { + did: { + type: 'string', + format: 'did', + }, + password: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoAdminUpdateCommunicationTemplate: { lexicon: 1, id: 'com.atproto.admin.updateCommunicationTemplate', @@ -1863,13 +1995,63 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentityGetRecommendedDidCredentials: { + lexicon: 1, + id: 'com.atproto.identity.getRecommendedDidCredentials', + defs: { + main: { + type: 'query', + description: + 'Describe the credentials that should be included in the DID doc of an account that is migrating to this service.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + rotationKeys: { + description: + 'Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs.', + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentityRequestPlcOperationSignature: { + lexicon: 1, + id: 'com.atproto.identity.requestPlcOperationSignature', + defs: { + main: { + type: 'procedure', + description: + 'Request an email with a code to in order to request a signed PLC operation. Requires Auth.', + }, + }, + }, ComAtprotoIdentityResolveHandle: { lexicon: 1, id: 'com.atproto.identity.resolveHandle', defs: { main: { type: 'query', - description: 'Provides the DID of a repo.', + description: 'Resolves a handle (domain name) to a DID.', parameters: { type: 'params', required: ['handle'], @@ -1897,13 +2079,92 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentitySignPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.signPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Signs a PLC operation to update some value(s) in the requesting DID's document.", + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + token: { + description: + 'A token received through com.atproto.identity.requestPlcOperationSignature', + type: 'string', + }, + rotationKeys: { + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + description: 'A signed DID PLC operation.', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentitySubmitPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.submitPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Validates a PLC operation to ensure that it doesn't violate a service's constraints or get the identity into a bad state, then submits it to the PLC registry", + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, ComAtprotoIdentityUpdateHandle: { lexicon: 1, id: 'com.atproto.identity.updateHandle', defs: { main: { type: 'procedure', - description: 'Updates the handle of the account.', + description: + "Updates the current account's handle. Verifies handle validity, and updates did:plc document if necessary. Implemented by PDS, and requires auth.", input: { encoding: 'application/json', schema: { @@ -1913,6 +2174,7 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'The new handle.', }, }, }, @@ -2003,7 +2265,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find labels relevant to the provided URI patterns.', + description: + 'Find labels relevant to the provided AT-URI patterns. Public endpoint for moderation services, though may return different or additional results with auth.', parameters: { type: 'params', required: ['uriPatterns'], @@ -2064,13 +2327,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to label updates.', + description: + 'Subscribe to stream of labels (and negations). Public endpoint implemented by mod services. Uses same sequencing scheme as repo event stream.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -2126,7 +2390,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Report a repo or a record.', + description: + 'Submit a moderation report regarding an atproto account or record. Implemented by moderation services (with PDS proxying), and requires auth.', input: { encoding: 'application/json', schema: { @@ -2135,10 +2400,14 @@ export const schemaDict = { properties: { reasonType: { type: 'ref', + description: + 'Indicates the broad category of violation the report is for.', ref: 'lex:com.atproto.moderation.defs#reasonType', }, reason: { type: 'string', + description: + 'Additional context about the content and violation.', }, subject: { type: 'union', @@ -2249,7 +2518,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Apply a batch transaction of creates, updates, and deletes.', + 'Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2259,12 +2528,14 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the records.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data, for all operations.", }, writes: { type: 'array', @@ -2280,6 +2551,8 @@ export const schemaDict = { }, swapCommit: { type: 'string', + description: + 'If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.', format: 'cid', }, }, @@ -2288,12 +2561,14 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that the 'swapCommit' parameter did not match current commit.", }, ], }, create: { type: 'object', - description: 'Create a new record.', + description: 'Operation which creates a new record.', required: ['collection', 'value'], properties: { collection: { @@ -2311,7 +2586,7 @@ export const schemaDict = { }, update: { type: 'object', - description: 'Update an existing record.', + description: 'Operation which updates an existing record.', required: ['collection', 'rkey', 'value'], properties: { collection: { @@ -2328,7 +2603,7 @@ export const schemaDict = { }, delete: { type: 'object', - description: 'Delete an existing record.', + description: 'Operation which deletes an existing record.', required: ['collection', 'rkey'], properties: { collection: { @@ -2348,7 +2623,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create a new record.', + description: + 'Create a single new repository record. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2358,7 +2634,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2367,17 +2644,18 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', - description: 'The record to create.', + description: 'The record itself. Must contain a $type field.', }, swapCommit: { type: 'string', @@ -2408,6 +2686,8 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that 'swapCommit' didn't match current repo commit.", }, ], }, @@ -2419,7 +2699,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete a record, or ensure it doesn't exist.", + description: + "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", input: { encoding: 'application/json', schema: { @@ -2429,7 +2710,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2438,7 +2720,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, swapRecord: { type: 'string', @@ -2470,7 +2752,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about the repo, including the list of collections.', + 'Get information about an account and repository, including the list of collections. Does not require auth.', parameters: { type: 'params', required: ['repo'], @@ -2504,9 +2786,12 @@ export const schemaDict = { }, didDoc: { type: 'unknown', + description: 'The complete DID document for this account.', }, collections: { type: 'array', + description: + 'List of all the collections (NSIDs) for which this repo contains at least one record.', items: { type: 'string', format: 'nsid', @@ -2514,6 +2799,8 @@ export const schemaDict = { }, handleIsCorrect: { type: 'boolean', + description: + 'Indicates if handle is currently valid (resolves bi-directionally)', }, }, }, @@ -2527,7 +2814,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a record.', + description: + 'Get a single record from a repository. Does not require auth.', parameters: { type: 'params', required: ['repo', 'collection', 'rkey'], @@ -2544,7 +2832,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, cid: { type: 'string', @@ -2577,39 +2865,112 @@ export const schemaDict = { }, }, }, - ComAtprotoRepoListRecords: { + ComAtprotoRepoImportRepo: { lexicon: 1, - id: 'com.atproto.repo.listRecords', + id: 'com.atproto.repo.importRepo', + defs: { + main: { + type: 'procedure', + description: + 'Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.', + input: { + encoding: 'application/vnd.ipld.car', + }, + }, + }, + }, + ComAtprotoRepoListMissingBlobs: { + lexicon: 1, + id: 'com.atproto.repo.listMissingBlobs', defs: { main: { type: 'query', - description: 'List a range of records in a collection.', + description: + 'Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.', parameters: { type: 'params', - required: ['repo', 'collection'], properties: { - repo: { - type: 'string', - format: 'at-identifier', - description: 'The handle or DID of the repo.', - }, - collection: { - type: 'string', - format: 'nsid', - description: 'The NSID of the record type.', - }, limit: { type: 'integer', minimum: 1, - maximum: 100, - default: 50, - description: 'The number of records to return.', + maximum: 1000, + default: 500, }, cursor: { type: 'string', }, - rkeyStart: { - type: 'string', + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['blobs'], + properties: { + cursor: { + type: 'string', + }, + blobs: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.repo.listMissingBlobs#recordBlob', + }, + }, + }, + }, + }, + }, + recordBlob: { + type: 'object', + required: ['cid', 'recordUri'], + properties: { + cid: { + type: 'string', + format: 'cid', + }, + recordUri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + }, + }, + ComAtprotoRepoListRecords: { + lexicon: 1, + id: 'com.atproto.repo.listRecords', + defs: { + main: { + type: 'query', + description: + 'List a range of records in a repository, matching a specific collection. Does not require auth.', + parameters: { + type: 'params', + required: ['repo', 'collection'], + properties: { + repo: { + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', + }, + collection: { + type: 'string', + format: 'nsid', + description: 'The NSID of the record type.', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + description: 'The number of records to return.', + }, + cursor: { + type: 'string', + }, + rkeyStart: { + type: 'string', description: 'DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)', }, @@ -2669,7 +3030,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Write a record, creating or updating it as needed.', + description: + 'Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2680,7 +3042,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2689,13 +3052,14 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', @@ -2705,7 +3069,7 @@ export const schemaDict = { type: 'string', format: 'cid', description: - 'Compare and swap with the previous record by CID.', + 'Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation', }, swapCommit: { type: 'string', @@ -2769,7 +3133,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Upload a new blob to be added to repo in a later request.', + 'Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.', input: { encoding: '*/*', }, @@ -2788,6 +3152,75 @@ export const schemaDict = { }, }, }, + ComAtprotoServerActivateAccount: { + lexicon: 1, + id: 'com.atproto.server.activateAccount', + defs: { + main: { + type: 'procedure', + description: + "Activates a currently deactivated account. Used to finalize account migration after the account's repo is imported and identity is setup.", + }, + }, + }, + ComAtprotoServerCheckAccountStatus: { + lexicon: 1, + id: 'com.atproto.server.checkAccountStatus', + defs: { + main: { + type: 'query', + description: + 'Returns the status of an account, especially as pertaining to import or recovery. Can be called many times over the course of an account migration. Requires auth and can only be called pertaining to oneself.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: [ + 'activated', + 'validDid', + 'repoCommit', + 'repoRev', + 'repoBlocks', + 'indexedRecords', + 'privateStateValues', + 'expectedBlobs', + 'importedBlobs', + ], + properties: { + activated: { + type: 'boolean', + }, + validDid: { + type: 'boolean', + }, + repoCommit: { + type: 'string', + format: 'cid', + }, + repoRev: { + type: 'string', + }, + repoBlocks: { + type: 'integer', + }, + indexedRecords: { + type: 'integer', + }, + privateStateValues: { + type: 'integer', + }, + expectedBlobs: { + type: 'integer', + }, + importedBlobs: { + type: 'integer', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerConfirmEmail: { lexicon: 1, id: 'com.atproto.server.confirmEmail', @@ -2834,7 +3267,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create an account.', + description: 'Create an account. Implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2847,10 +3280,13 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'Requested handle for the account.', }, did: { type: 'string', format: 'did', + description: + 'Pre-existing atproto DID, being imported to a new account.', }, inviteCode: { type: 'string', @@ -2863,12 +3299,18 @@ export const schemaDict = { }, password: { type: 'string', + description: + 'Initial account password. May need to meet instance-specific password strength requirements.', }, recoveryKey: { type: 'string', + description: + 'DID PLC rotation key (aka, recovery key) to be included in PLC creation operation.', }, plcOp: { type: 'unknown', + description: + 'A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented.', }, }, }, @@ -2877,6 +3319,8 @@ export const schemaDict = { encoding: 'application/json', schema: { type: 'object', + description: + 'Account login session returned on successful account creation.', required: ['accessJwt', 'refreshJwt', 'handle', 'did'], properties: { accessJwt: { @@ -2892,9 +3336,11 @@ export const schemaDict = { did: { type: 'string', format: 'did', + description: 'The DID of the new account.', }, didDoc: { type: 'unknown', + description: 'Complete DID document.', }, }, }, @@ -2940,6 +3386,8 @@ export const schemaDict = { properties: { name: { type: 'string', + description: + 'A short name for the App Password, to help distinguish them.', }, }, }, @@ -3141,6 +3589,31 @@ export const schemaDict = { }, }, }, + ComAtprotoServerDeactivateAccount: { + lexicon: 1, + id: 'com.atproto.server.deactivateAccount', + defs: { + main: { + type: 'procedure', + description: + 'Deactivates a currently active account. Stops serving of repo, and future writes to repo until reactivated. Used to finalize account migration with the old host after the account has been activated on the new host.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + deleteAfter: { + type: 'string', + format: 'datetime', + description: + 'A recommendation to server as to how long they should hold onto the deactivated account before deleting.', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerDefs: { lexicon: 1, id: 'com.atproto.server.defs', @@ -3207,7 +3680,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete an actor's account with a token and password.", + description: + "Delete an actor's account with a token and password. Can only be called after requesting a deletion token. Requires auth.", input: { encoding: 'application/json', schema: { @@ -3244,7 +3718,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Delete the current session.', + description: 'Delete the current session. Requires auth.', }, }, }, @@ -3255,29 +3729,40 @@ export const schemaDict = { main: { type: 'query', description: - "Get a document describing the service's accounts configuration.", + "Describes the server's account creation requirements and capabilities. Implemented by PDS.", output: { encoding: 'application/json', schema: { type: 'object', - required: ['availableUserDomains'], + required: ['did', 'availableUserDomains'], properties: { inviteCodeRequired: { type: 'boolean', + description: + 'If true, an invite code must be supplied to create an account on this instance.', }, phoneVerificationRequired: { type: 'boolean', + description: + 'If true, a phone verification token must be supplied to create an account on this instance.', }, availableUserDomains: { type: 'array', + description: + 'List of domain suffixes that can be used in account handles.', items: { type: 'string', }, }, links: { type: 'ref', + description: 'URLs of service policy documents.', ref: 'lex:com.atproto.server.describeServer#links', }, + did: { + type: 'string', + format: 'did', + }, }, }, }, @@ -3301,7 +3786,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get all invite codes for a given account.', + description: + 'Get all invite codes for the current account. Requires auth.', parameters: { type: 'params', properties: { @@ -3312,6 +3798,8 @@ export const schemaDict = { createAvailable: { type: 'boolean', default: true, + description: + "Controls whether any new 'earned' but not 'created' invites should be created.", }, }, }, @@ -3339,13 +3827,49 @@ export const schemaDict = { }, }, }, + ComAtprotoServerGetServiceAuth: { + lexicon: 1, + id: 'com.atproto.server.getServiceAuth', + defs: { + main: { + type: 'query', + description: + 'Get a signed token on behalf of the requesting DID for the requested service.', + parameters: { + type: 'params', + required: ['aud'], + properties: { + aud: { + type: 'string', + format: 'did', + description: + 'The DID of the service that the token will be used to authenticate with', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['token'], + properties: { + token: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerGetSession: { lexicon: 1, id: 'com.atproto.server.getSession', defs: { main: { type: 'query', - description: 'Get information about the current session.', + description: + 'Get information about the current auth session. Requires auth.', output: { encoding: 'application/json', schema: { @@ -3425,7 +3949,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Refresh an authentication session.', + description: + "Refresh an authentication session. Requires auth using the 'refreshJwt' (not the 'accessJwt').", output: { encoding: 'application/json', schema: { @@ -3531,7 +4056,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Reserve a repo signing key for account creation.', + description: + 'Reserve a repo signing key, for use with account creation. Necessary so that a DID PLC update operation can be constructed during an account migraiton. Public and does not require auth; implemented by PDS. NOTE: this endpoint may change when full account migration is implemented.', input: { encoding: 'application/json', schema: { @@ -3539,7 +4065,8 @@ export const schemaDict = { properties: { did: { type: 'string', - description: 'The did to reserve a new did:key for', + format: 'did', + description: 'The DID to reserve a key for.', }, }, }, @@ -3552,7 +4079,8 @@ export const schemaDict = { properties: { signingKey: { type: 'string', - description: 'Public signing key in the form of a did:key.', + description: + 'The public key for the reserved signing key, in did:key serialization.', }, }, }, @@ -3659,7 +4187,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a blob associated with a given repo.', + description: + 'Get a blob associated with a given account. Returns the full blob as originally uploaded. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cid'], @@ -3667,7 +4196,7 @@ export const schemaDict = { did: { type: 'string', format: 'did', - description: 'The DID of the repo.', + description: 'The DID of the account.', }, cid: { type: 'string', @@ -3688,7 +4217,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get blocks from a given repo.', + description: + 'Get data blocks from a given repo, by CID. For example, intermediate MST nodes, or records. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cids'], @@ -3783,7 +4313,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the current commit CID & revision of the repo.', + description: + 'Get the current commit CID & revision of the specified repo. Does not require auth.', parameters: { type: 'params', required: ['did'], @@ -3826,7 +4357,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get blocks needed for existence or non-existence of record.', + 'Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.', parameters: { type: 'params', required: ['did', 'collection', 'rkey'], @@ -3842,6 +4373,7 @@ export const schemaDict = { }, rkey: { type: 'string', + description: 'Record Key', }, commit: { type: 'string', @@ -3863,7 +4395,7 @@ export const schemaDict = { main: { type: 'query', description: - "Gets the DID's repo, optionally catching up from a specific revision.", + "Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS.", parameters: { type: 'params', required: ['did'], @@ -3875,7 +4407,8 @@ export const schemaDict = { }, since: { type: 'string', - description: 'The revision of the repo to catch up from.', + description: + "The revision ('rev') of the repo to create a diff from.", }, }, }, @@ -3891,7 +4424,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List blob CIDs since some revision.', + description: + 'List blob CIDso for an account, since some repo revision. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did'], @@ -3944,7 +4478,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List DIDs and root CIDs of hosted repos.', + description: + 'Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { @@ -3990,6 +4525,7 @@ export const schemaDict = { head: { type: 'string', format: 'cid', + description: 'Current repo commit CID', }, rev: { type: 'string', @@ -4005,7 +4541,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Notify a crawling service of a recent update; often when a long break between updates causes the connection with the crawling service to break.', + 'Notify a crawling service of a recent update, and that crawling should resume. Intended use is after a gap between repo stream events caused the crawling service to disconnect. Does not require auth; implemented by Relay.', input: { encoding: 'application/json', schema: { @@ -4015,7 +4551,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is notifying of update.', + 'Hostname of the current service (usually a PDS) that is notifying of update.', }, }, }, @@ -4029,7 +4565,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Request a service to persistently crawl hosted repos.', + description: + 'Request a service to persistently crawl hosted repos. Expected use is new PDS instances declaring their existence to Relays. Does not require auth.', input: { encoding: 'application/json', schema: { @@ -4039,7 +4576,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is requesting to be crawled.', + 'Hostname of the current service (eg, PDS) that is requesting to be crawled.', }, }, }, @@ -4053,13 +4590,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to repo updates.', + description: + 'Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -4068,6 +4606,7 @@ export const schemaDict = { type: 'union', refs: [ 'lex:com.atproto.sync.subscribeRepos#commit', + 'lex:com.atproto.sync.subscribeRepos#identity', 'lex:com.atproto.sync.subscribeRepos#handle', 'lex:com.atproto.sync.subscribeRepos#migrate', 'lex:com.atproto.sync.subscribeRepos#tombstone', @@ -4081,11 +4620,15 @@ export const schemaDict = { }, { name: 'ConsumerTooSlow', + description: + 'If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection.', }, ], }, commit: { type: 'object', + description: + 'Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.', required: [ 'seq', 'rebase', @@ -4103,34 +4646,45 @@ export const schemaDict = { properties: { seq: { type: 'integer', + description: 'The stream sequence number of this message.', }, rebase: { type: 'boolean', + description: 'DEPRECATED -- unused', }, tooBig: { type: 'boolean', + description: + 'Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data.', }, repo: { type: 'string', format: 'did', + description: 'The repo this event comes from.', }, commit: { type: 'cid-link', + description: 'Repo commit object CID.', }, prev: { type: 'cid-link', + description: + 'DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability.', }, rev: { type: 'string', - description: 'The rev of the emitted commit.', + description: + 'The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event.', }, since: { type: 'string', - description: 'The rev of the last emitted commit from this repo.', + description: + 'The rev of the last emitted commit from this repo (if any).', }, blocks: { type: 'bytes', - description: 'CAR file containing relevant blocks.', + description: + 'CAR file containing relevant blocks, as a diff since the previous repo state.', maxLength: 1000000, }, ops: { @@ -4138,6 +4692,8 @@ export const schemaDict = { items: { type: 'ref', ref: 'lex:com.atproto.sync.subscribeRepos#repoOp', + description: + 'List of repo mutation operations in this commit (eg, records created, updated, or deleted).', }, maxLength: 200, }, @@ -4145,8 +4701,31 @@ export const schemaDict = { type: 'array', items: { type: 'cid-link', + description: + 'List of new blobs (by CID) referenced by records in this commit.', }, }, + time: { + type: 'string', + format: 'datetime', + description: + 'Timestamp of when this message was originally broadcast.', + }, + }, + }, + identity: { + type: 'object', + description: + "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.", + required: ['seq', 'did', 'time'], + properties: { + seq: { + type: 'integer', + }, + did: { + type: 'string', + format: 'did', + }, time: { type: 'string', format: 'datetime', @@ -4155,6 +4734,8 @@ export const schemaDict = { }, handle: { type: 'object', + description: + "Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity.", required: ['seq', 'did', 'handle', 'time'], properties: { seq: { @@ -4176,6 +4757,8 @@ export const schemaDict = { }, migrate: { type: 'object', + description: + 'Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead', required: ['seq', 'did', 'migrateTo', 'time'], nullable: ['migrateTo'], properties: { @@ -4197,6 +4780,8 @@ export const schemaDict = { }, tombstone: { type: 'object', + description: + 'Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event', required: ['seq', 'did', 'time'], properties: { seq: { @@ -4227,8 +4812,7 @@ export const schemaDict = { }, repoOp: { type: 'object', - description: - "A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null.", + description: 'A repo operation, ie a mutation of a single record.', required: ['action', 'path', 'cid'], nullable: ['cid'], properties: { @@ -4241,45 +4825,34 @@ export const schemaDict = { }, cid: { type: 'cid-link', + description: + 'For creates and updates, the new record CID. For deletions, null.', }, }, }, }, }, - ComAtprotoTempFetchLabels: { + ComAtprotoTempCheckSignupQueue: { lexicon: 1, - id: 'com.atproto.temp.fetchLabels', + id: 'com.atproto.temp.checkSignupQueue', defs: { main: { type: 'query', - description: - 'Fetch all labels from a labeler created after a certain date.', - parameters: { - type: 'params', - properties: { - since: { - type: 'integer', - }, - limit: { - type: 'integer', - minimum: 1, - maximum: 250, - default: 50, - }, - }, - }, + description: 'Check accounts location in signup queue.', output: { encoding: 'application/json', schema: { type: 'object', - required: ['labels'], + required: ['activated'], properties: { - labels: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:com.atproto.label.defs#label', - }, + activated: { + type: 'boolean', + }, + placeInQueue: { + type: 'integer', + }, + estimatedTimeMs: { + type: 'integer', }, }, }, @@ -4287,75 +4860,40 @@ export const schemaDict = { }, }, }, - ComAtprotoTempImportRepo: { - lexicon: 1, - id: 'com.atproto.temp.importRepo', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: 'application/vnd.ipld.car', - }, - output: { - encoding: 'text/plain', - }, - }, - }, - }, - ComAtprotoTempPushBlob: { - lexicon: 1, - id: 'com.atproto.temp.pushBlob', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: '*/*', - }, - }, - }, - }, - ComAtprotoTempRequestPhoneVerification: { + ComAtprotoTempFetchLabels: { lexicon: 1, - id: 'com.atproto.temp.requestPhoneVerification', + id: 'com.atproto.temp.fetchLabels', defs: { main: { - type: 'procedure', + type: 'query', description: - 'Request a verification code to be sent to the supplied phone number', - input: { + 'DEPRECATED: use queryLabels or subscribeLabels instead -- Fetch all labels from a labeler created after a certain date.', + parameters: { + type: 'params', + properties: { + since: { + type: 'integer', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 250, + default: 50, + }, + }, + }, + output: { encoding: 'application/json', schema: { type: 'object', - required: ['phoneNumber'], + required: ['labels'], properties: { - phoneNumber: { - type: 'string', + labels: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.label.defs#label', + }, }, }, }, @@ -4363,86 +4901,32 @@ export const schemaDict = { }, }, }, - ComAtprotoTempTransferAccount: { + ComAtprotoTempRequestPhoneVerification: { lexicon: 1, - id: 'com.atproto.temp.transferAccount', + id: 'com.atproto.temp.requestPhoneVerification', defs: { main: { type: 'procedure', - description: 'Transfer an account.', + description: + 'Request a verification code to be sent to the supplied phone number', input: { encoding: 'application/json', schema: { type: 'object', - required: ['handle', 'did', 'plcOp'], - properties: { - handle: { - type: 'string', - format: 'handle', - }, - did: { - type: 'string', - format: 'did', - }, - plcOp: { - type: 'unknown', - }, - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['accessJwt', 'refreshJwt', 'handle', 'did'], + required: ['phoneNumber'], properties: { - accessJwt: { - type: 'string', - }, - refreshJwt: { - type: 'string', - }, - handle: { - type: 'string', - format: 'handle', - }, - did: { + phoneNumber: { type: 'string', - format: 'did', }, }, }, }, - errors: [ - { - name: 'InvalidHandle', - }, - { - name: 'InvalidPassword', - }, - { - name: 'InvalidInviteCode', - }, - { - name: 'HandleNotAvailable', - }, - { - name: 'UnsupportedDomain', - }, - { - name: 'UnresolvableDid', - }, - { - name: 'IncompatibleDidDoc', - }, - ], }, }, }, AppBskyActorDefs: { lexicon: 1, id: 'app.bsky.actor.defs', - description: 'A reference to an actor in the network.', defs: { profileViewBasic: { type: 'object', @@ -4575,6 +5059,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests.", properties: { muted: { type: 'boolean', @@ -4615,6 +5101,9 @@ export const schemaDict = { 'lex:app.bsky.actor.defs#personalDetailsPref', 'lex:app.bsky.actor.defs#feedViewPref', 'lex:app.bsky.actor.defs#threadViewPref', + 'lex:app.bsky.actor.defs#interestsPref', + 'lex:app.bsky.actor.defs#mutedWordsPref', + 'lex:app.bsky.actor.defs#hiddenPostsPref', ], }, }, @@ -4659,6 +5148,9 @@ export const schemaDict = { format: 'at-uri', }, }, + timelineIndex: { + type: 'integer', + }, }, }, personalDetailsPref: { @@ -4718,6 +5210,79 @@ export const schemaDict = { }, }, }, + interestsPref: { + type: 'object', + required: ['tags'], + properties: { + tags: { + type: 'array', + maxLength: 100, + items: { + type: 'string', + maxLength: 640, + maxGraphemes: 64, + }, + description: + "A list of tags which describe the account owner's interests gathered during onboarding.", + }, + }, + }, + mutedWordTarget: { + type: 'string', + knownValues: ['content', 'tag'], + maxLength: 640, + maxGraphemes: 64, + }, + mutedWord: { + type: 'object', + description: 'A word that the account owner has muted.', + required: ['value', 'targets'], + properties: { + value: { + type: 'string', + description: 'The muted word itself.', + maxLength: 10000, + maxGraphemes: 1000, + }, + targets: { + type: 'array', + description: 'The intended targets of the muted word.', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWordTarget', + }, + }, + }, + }, + mutedWordsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWord', + }, + description: 'A list of words the account owner has muted.', + }, + }, + }, + hiddenPostsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'string', + format: 'at-uri', + }, + description: + 'A list of URIs of posts the account owner has hidden.', + }, + }, + }, }, }, AppBskyActorGetPreferences: { @@ -4726,7 +5291,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get private preferences attached to the account.', + description: + 'Get private preferences attached to the current account. Expected use is synchronization between multiple devices, and import/export during account migration. Requires auth.', parameters: { type: 'params', properties: {}, @@ -4753,7 +5319,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get detailed profile view of an actor.', + description: + 'Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.', parameters: { type: 'params', required: ['actor'], @@ -4761,6 +5328,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Handle or DID of account to fetch profile of.', }, }, }, @@ -4820,7 +5388,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested actors, used for discovery.', + description: + 'Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding.', parameters: { type: 'params', properties: { @@ -4863,7 +5432,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a profile.', + description: 'A declaration of a Bluesky account profile.', key: 'literal:self', record: { type: 'object', @@ -4875,21 +5444,28 @@ export const schemaDict = { }, description: { type: 'string', + description: 'Free-form profile description text.', maxGraphemes: 256, maxLength: 2560, }, avatar: { type: 'blob', + description: + "Small image to be displayed next to posts from account. AKA, 'profile picture'", accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, banner: { type: 'blob', + description: + 'Larger horizontal image to display behind profile view.', accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, labels: { type: 'union', + description: + 'Self-label values, specific to the Bluesky application, on the overall account.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, }, @@ -4926,7 +5502,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actors (profiles) matching search criteria.', + description: + 'Find actors (profiles) matching search criteria. Does not require auth.', parameters: { type: 'params', properties: { @@ -4978,7 +5555,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actor suggestions for a prefix search term.', + description: + 'Find actor suggestions for a prefix search term. Expected use is for auto-completion during text field entry. Does not require auth.', parameters: { type: 'params', properties: { @@ -5020,11 +5598,11 @@ export const schemaDict = { AppBskyEmbedExternal: { lexicon: 1, id: 'app.bsky.embed.external', - description: - 'A representation of some externally linked content, embedded in another form of content.', defs: { main: { type: 'object', + description: + "A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post).", required: ['external'], properties: { external: { @@ -5088,7 +5666,7 @@ export const schemaDict = { AppBskyEmbedImages: { lexicon: 1, id: 'app.bsky.embed.images', - description: 'A set of images embedded in some other form of content.', + description: 'A set of images embedded in a Bluesky record (eg, a post).', defs: { main: { type: 'object', @@ -5115,6 +5693,8 @@ export const schemaDict = { }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5158,12 +5738,18 @@ export const schemaDict = { properties: { thumb: { type: 'string', + description: + 'Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View.', }, fullsize: { type: 'string', + description: + 'Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View.', }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5177,7 +5763,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.record', description: - 'A representation of a record embedded in another form of content.', + 'A representation of a record embedded in a Bluesky record (eg, a post). For example, a quote-post, or sharing a feed generator record.', defs: { main: { type: 'object', @@ -5223,6 +5809,7 @@ export const schemaDict = { }, value: { type: 'unknown', + description: 'The record data itself.', }, labels: { type: 'array', @@ -5287,7 +5874,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.recordWithMedia', description: - 'A representation of a record embedded in another form of content, alongside other compatible embeds.', + 'A representation of a record embedded in a Bluesky record (eg, a post), alongside other compatible embeds. For example, a quote post and image, or a quote post and external URL card.', defs: { main: { type: 'object', @@ -5386,6 +5973,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests.", properties: { repost: { type: 'string', @@ -5646,7 +6235,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about a feed generator, including policies and offered feed URIs.', + 'Get information about a feed generator, including policies and offered feed URIs. Does not require auth; implemented by Feed Generator services (not App View).', output: { encoding: 'application/json', schema: { @@ -5701,7 +6290,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of the existence of a feed generator.', + description: + 'Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.', key: 'any', record: { type: 'object', @@ -5735,6 +6325,7 @@ export const schemaDict = { }, labels: { type: 'union', + description: 'Self-label values', refs: ['lex:com.atproto.label.defs#selfLabels'], }, createdAt: { @@ -5752,7 +6343,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of feeds created by the actor.', + description: + "Get a list of feeds (feed generator records) created by the actor (in the actor's repo).", parameters: { type: 'params', required: ['actor'], @@ -5800,7 +6392,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of posts liked by an actor.', + description: + 'Get a list of posts liked by an actor. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -5856,7 +6449,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth.", parameters: { type: 'params', required: ['actor'], @@ -5876,6 +6470,8 @@ export const schemaDict = { }, filter: { type: 'string', + description: + 'Combinations of post/repost types to include in response.', knownValues: [ 'posts_with_replies', 'posts_no_replies', @@ -5923,7 +6519,7 @@ export const schemaDict = { main: { type: 'query', description: - "Get a hydrated feed from an actor's selected feed generator.", + "Get a hydrated feed from an actor's selected feed generator. Implemented by App View.", parameters: { type: 'params', required: ['feed'], @@ -5976,7 +6572,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get information about a feed generator.', + description: + 'Get information about a feed generator. Implemented by AppView.', parameters: { type: 'params', required: ['feed'], @@ -5984,6 +6581,7 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: 'AT-URI of the feed generator record.', }, }, }, @@ -5999,9 +6597,13 @@ export const schemaDict = { }, isOnline: { type: 'boolean', + description: + 'Indicates whether the feed generator service has been online recently, or else seems to be inactive.', }, isValid: { type: 'boolean', + description: + 'Indicates whether the feed generator service is compatible with the record declaration.', }, }, }, @@ -6054,7 +6656,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a skeleton of a feed provided by a feed generator.', + description: + 'Get a skeleton of a feed provided by a feed generator. Auth is optional, depending on provider requirements, and provides the DID of the requester. Implemented by Feed Generator Service.', parameters: { type: 'params', required: ['feed'], @@ -6062,6 +6665,8 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: + 'Reference to feed generator record describing the specific feed being requested.', }, limit: { type: 'integer', @@ -6107,7 +6712,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the list of likes.', + description: + 'Get like records which reference a subject (by AT-URI and CID).', parameters: { type: 'params', required: ['uri'], @@ -6115,10 +6721,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'AT-URI of the subject (eg, a post record).', }, cid: { type: 'string', format: 'cid', + description: + 'CID of the subject record (aka, specific version of record), to filter likes.', }, limit: { type: 'integer', @@ -6185,7 +6794,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a view of a recent posts from actors in a list.', + description: + 'Get a feed of recent posts from a list (posts and reposts from any actors on the list). Does not require auth.', parameters: { type: 'params', required: ['list'], @@ -6193,6 +6803,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the list record.', }, limit: { type: 'integer', @@ -6238,7 +6849,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get posts in a thread.', + description: + 'Get posts in a thread. Does not require auth, but additional metadata and filtering will be applied for authed requests.', parameters: { type: 'params', required: ['uri'], @@ -6246,15 +6858,20 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to post record.', }, depth: { type: 'integer', + description: + 'How many levels of reply depth should be included in response.', default: 6, minimum: 0, maximum: 1000, }, parentHeight: { type: 'integer', + description: + 'How many levels of parent (and grandparent, etc) post to include.', default: 80, minimum: 0, maximum: 1000, @@ -6292,13 +6909,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Gets post views for a specified list of posts (by AT-URI). This is sometimes referred to as 'hydrating' a 'feed skeleton'.", parameters: { type: 'params', required: ['uris'], properties: { uris: { type: 'array', + description: 'List of post AT-URIs to return hydrated views for.', items: { type: 'string', format: 'at-uri', @@ -6332,7 +6951,7 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of reposts.', + description: 'Get a list of reposts for a given post.', parameters: { type: 'params', required: ['uri'], @@ -6340,10 +6959,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of post record', }, cid: { type: 'string', format: 'cid', + description: + 'If supplied, filters to reposts of specific version (by CID) of the post record.', }, limit: { type: 'integer', @@ -6392,7 +7014,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested feeds for the viewer.', + description: + 'Get a list of suggested feeds (feed generators) for the requesting account.', parameters: { type: 'params', properties: { @@ -6435,12 +7058,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of the actor's home timeline.", + description: + "Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed.", parameters: { type: 'params', properties: { algorithm: { type: 'string', + description: + "Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism.", }, limit: { type: 'integer', @@ -6481,7 +7107,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a like.', + description: "Record declaring a 'like' of a piece of subject content.", key: 'tid', record: { type: 'object', @@ -6506,7 +7132,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a post.', + description: 'Record containing a Bluesky post.', key: 'tid', record: { type: 'object', @@ -6516,10 +7142,12 @@ export const schemaDict = { type: 'string', maxLength: 3000, maxGraphemes: 300, + description: + 'The primary post content. May be an empty string, if there are embeds.', }, entities: { type: 'array', - description: 'Deprecated: replaced by app.bsky.richtext.facet.', + description: 'DEPRECATED: replaced by app.bsky.richtext.facet.', items: { type: 'ref', ref: 'lex:app.bsky.feed.post#entity', @@ -6527,6 +7155,8 @@ export const schemaDict = { }, facets: { type: 'array', + description: + 'Annotations of text (mentions, URLs, hashtags, etc)', items: { type: 'ref', ref: 'lex:app.bsky.richtext.facet', @@ -6547,6 +7177,8 @@ export const schemaDict = { }, langs: { type: 'array', + description: + 'Indicates human language of post primary text content.', maxLength: 3, items: { type: 'string', @@ -6555,21 +7187,26 @@ export const schemaDict = { }, labels: { type: 'union', + description: + 'Self-label values for this post. Effectively content warnings.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, tags: { type: 'array', + description: + 'Additional hashtags, in addition to any included in post text and facets.', maxLength: 8, items: { type: 'string', maxLength: 640, maxGraphemes: 64, }, - description: 'Additional non-inline tags describing this post.', }, createdAt: { type: 'string', format: 'datetime', + description: + 'Client-declared timestamp when this post was originally created.', }, }, }, @@ -6629,7 +7266,8 @@ export const schemaDict = { id: 'app.bsky.feed.repost', defs: { main: { - description: 'A declaration of a repost.', + description: + "Record representing a 'repost' of an existing Bluesky post.", type: 'record', key: 'tid', record: { @@ -6655,7 +7293,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find posts matching search criteria.', + description: + 'Find posts matching search criteria, returning views of those posts.', parameters: { type: 'params', required: ['q'], @@ -6718,7 +7357,7 @@ export const schemaDict = { type: 'record', key: 'tid', description: - "Defines interaction gating rules for a thread. The rkey of the threadgate record should match the rkey of the thread's root post.", + "Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository..", record: { type: 'object', required: ['post', 'createdAt'], @@ -6726,6 +7365,7 @@ export const schemaDict = { post: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the post record.', }, allow: { type: 'array', @@ -6775,7 +7415,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a block.', + description: + "Record declaring a 'block' relationship against another account. NOTE: blocks are public in Bluesky; see blog posts for details.", key: 'tid', record: { type: 'object', @@ -6784,6 +7425,7 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'DID of the account to be blocked.', }, createdAt: { type: 'string', @@ -6972,7 +7614,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a social follow.', + description: + "Record declaring a social 'follow' relationship of another account. Duplicate follows will be ignored by the AppView.", key: 'tid', record: { type: 'object', @@ -6997,7 +7640,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor is blocking.', + description: + 'Enumerates which accounts the requesting account is currently blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7040,7 +7684,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a list of an actor's followers.", + description: + 'Enumerates accounts which follow a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7092,7 +7737,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor follows.', + description: + 'Enumerates accounts which a specified account (actor) follows.', parameters: { type: 'params', required: ['actor'], @@ -7144,7 +7790,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of actors.', + description: + "Gets a 'view' (with additional context) of a specified list.", parameters: { type: 'params', required: ['list'], @@ -7152,6 +7799,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of the list record to hydrate.', }, limit: { type: 'integer', @@ -7196,7 +7844,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is blocking.', + description: + 'Get mod lists that the requesting account (actor) is blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7239,7 +7888,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is muting.', + description: + 'Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7282,7 +7932,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of lists that belong to an actor.', + description: + 'Enumerates the lists created by a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7290,6 +7941,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'The account (actor) to enumerate lists from.', }, limit: { type: 'integer', @@ -7330,7 +7982,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor mutes.', + description: + 'Enumerates accounts that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7374,7 +8027,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Enumerates public relationships between one account, and a list of other accounts', + 'Enumerates public relationships between one account, and a list of other accounts. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -7382,9 +8035,12 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Primary account requesting relationships for.', }, others: { type: 'array', + description: + "List of 'other' accounts to be related back to the primary.", maxLength: 30, items: { type: 'string', @@ -7432,7 +8088,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get suggested follows related to a given actor.', + description: + 'Enumerates follows similar to a given account (actor). Expected use is to recommend additional accounts immediately after following one account.', parameters: { type: 'params', required: ['actor'], @@ -7468,7 +8125,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a list of actors.', + description: + 'Record representing a list of accounts (actors). Scope includes both moderation-oriented lists and curration-oriented lists.', key: 'tid', record: { type: 'object', @@ -7476,12 +8134,15 @@ export const schemaDict = { properties: { purpose: { type: 'ref', + description: + 'Defines the purpose of the list (aka, moderation-oriented or curration-oriented)', ref: 'lex:app.bsky.graph.defs#listPurpose', }, name: { type: 'string', maxLength: 64, minLength: 1, + description: 'Display name for list; can not be empty.', }, description: { type: 'string', @@ -7519,7 +8180,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A block of an entire list of actors.', + description: + 'Record representing a block relationship against an entire an entire list of accounts (actors).', key: 'tid', record: { type: 'object', @@ -7528,6 +8190,7 @@ export const schemaDict = { subject: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the mod list record.', }, createdAt: { type: 'string', @@ -7544,7 +8207,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'An item under a declared list of actors.', + description: + "Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records.", key: 'tid', record: { type: 'object', @@ -7553,10 +8217,13 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'The account which is included on the list.', }, list: { type: 'string', format: 'at-uri', + description: + 'Reference (AT-URI) to the list record (app.bsky.graph.list).', }, createdAt: { type: 'string', @@ -7573,7 +8240,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute an actor by DID or handle.', + description: + 'Creates a mute relationship for the specified account. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7596,7 +8264,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute a list of actors.', + description: + 'Creates a mute relationship for the specified list of accounts. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7619,7 +8288,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute an actor by DID or handle.', + description: 'Unmutes the specified account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7642,7 +8311,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute a list of actors.', + description: 'Unmutes the specified list of accounts. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7665,7 +8334,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the count of unread notifications.', + description: + 'Count the number of unread notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7696,7 +8366,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of notifications.', + description: + 'Enumerate notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7807,7 +8478,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Register for push notifications with a service.', + description: + 'Register to receive push notifications, via a specified service, for the requesting account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7840,7 +8512,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Notify server that the user has seen notifications.', + description: + 'Notify server that the requesting account has seen notifications. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7863,6 +8536,7 @@ export const schemaDict = { defs: { main: { type: 'object', + description: 'Annotation of a sub-string within rich text.', required: ['index', 'features'], properties: { index: { @@ -7884,7 +8558,8 @@ export const schemaDict = { }, mention: { type: 'object', - description: 'A facet feature for actor mentions.', + description: + "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID.", required: ['did'], properties: { did: { @@ -7895,7 +8570,8 @@ export const schemaDict = { }, link: { type: 'object', - description: 'A facet feature for links.', + description: + 'Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.', required: ['uri'], properties: { uri: { @@ -7906,7 +8582,8 @@ export const schemaDict = { }, tag: { type: 'object', - description: 'A hashtag.', + description: + "Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags').", required: ['tag'], properties: { tag: { @@ -7919,7 +8596,7 @@ export const schemaDict = { byteSlice: { type: 'object', description: - 'A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings.', + 'Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.', required: ['byteStart', 'byteEnd'], properties: { byteStart: { @@ -8054,55 +8731,6 @@ export const schemaDict = { }, }, }, - AppBskyUnspeccedGetTimelineSkeleton: { - lexicon: 1, - id: 'app.bsky.unspecced.getTimelineSkeleton', - defs: { - main: { - type: 'query', - description: - 'DEPRECATED: a skeleton of a timeline. Unspecced and will be unavailable soon.', - parameters: { - type: 'params', - properties: { - limit: { - type: 'integer', - minimum: 1, - maximum: 100, - default: 50, - }, - cursor: { - type: 'string', - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['feed'], - properties: { - cursor: { - type: 'string', - }, - feed: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:app.bsky.feed.defs#skeletonFeedPost', - }, - }, - }, - }, - }, - errors: [ - { - name: 'UnknownFeed', - }, - ], - }, - }, - }, AppBskyUnspeccedSearchActorsSkeleton: { lexicon: 1, id: 'app.bsky.unspecced.searchActorsSkeleton', @@ -8261,10 +8889,19 @@ export const ids = { ComAtprotoAdminSendEmail: 'com.atproto.admin.sendEmail', ComAtprotoAdminUpdateAccountEmail: 'com.atproto.admin.updateAccountEmail', ComAtprotoAdminUpdateAccountHandle: 'com.atproto.admin.updateAccountHandle', + ComAtprotoAdminUpdateAccountPassword: + 'com.atproto.admin.updateAccountPassword', ComAtprotoAdminUpdateCommunicationTemplate: 'com.atproto.admin.updateCommunicationTemplate', ComAtprotoAdminUpdateSubjectStatus: 'com.atproto.admin.updateSubjectStatus', + ComAtprotoIdentityGetRecommendedDidCredentials: + 'com.atproto.identity.getRecommendedDidCredentials', + ComAtprotoIdentityRequestPlcOperationSignature: + 'com.atproto.identity.requestPlcOperationSignature', ComAtprotoIdentityResolveHandle: 'com.atproto.identity.resolveHandle', + ComAtprotoIdentitySignPlcOperation: 'com.atproto.identity.signPlcOperation', + ComAtprotoIdentitySubmitPlcOperation: + 'com.atproto.identity.submitPlcOperation', ComAtprotoIdentityUpdateHandle: 'com.atproto.identity.updateHandle', ComAtprotoLabelDefs: 'com.atproto.label.defs', ComAtprotoLabelQueryLabels: 'com.atproto.label.queryLabels', @@ -8276,22 +8913,28 @@ export const ids = { ComAtprotoRepoDeleteRecord: 'com.atproto.repo.deleteRecord', ComAtprotoRepoDescribeRepo: 'com.atproto.repo.describeRepo', ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord', + ComAtprotoRepoImportRepo: 'com.atproto.repo.importRepo', + ComAtprotoRepoListMissingBlobs: 'com.atproto.repo.listMissingBlobs', ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords', ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord', ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob', + ComAtprotoServerActivateAccount: 'com.atproto.server.activateAccount', + ComAtprotoServerCheckAccountStatus: 'com.atproto.server.checkAccountStatus', ComAtprotoServerConfirmEmail: 'com.atproto.server.confirmEmail', ComAtprotoServerCreateAccount: 'com.atproto.server.createAccount', ComAtprotoServerCreateAppPassword: 'com.atproto.server.createAppPassword', ComAtprotoServerCreateInviteCode: 'com.atproto.server.createInviteCode', ComAtprotoServerCreateInviteCodes: 'com.atproto.server.createInviteCodes', ComAtprotoServerCreateSession: 'com.atproto.server.createSession', + ComAtprotoServerDeactivateAccount: 'com.atproto.server.deactivateAccount', ComAtprotoServerDefs: 'com.atproto.server.defs', ComAtprotoServerDeleteAccount: 'com.atproto.server.deleteAccount', ComAtprotoServerDeleteSession: 'com.atproto.server.deleteSession', ComAtprotoServerDescribeServer: 'com.atproto.server.describeServer', ComAtprotoServerGetAccountInviteCodes: 'com.atproto.server.getAccountInviteCodes', + ComAtprotoServerGetServiceAuth: 'com.atproto.server.getServiceAuth', ComAtprotoServerGetSession: 'com.atproto.server.getSession', ComAtprotoServerListAppPasswords: 'com.atproto.server.listAppPasswords', ComAtprotoServerRefreshSession: 'com.atproto.server.refreshSession', @@ -8318,12 +8961,10 @@ export const ids = { ComAtprotoSyncNotifyOfUpdate: 'com.atproto.sync.notifyOfUpdate', ComAtprotoSyncRequestCrawl: 'com.atproto.sync.requestCrawl', ComAtprotoSyncSubscribeRepos: 'com.atproto.sync.subscribeRepos', + ComAtprotoTempCheckSignupQueue: 'com.atproto.temp.checkSignupQueue', ComAtprotoTempFetchLabels: 'com.atproto.temp.fetchLabels', - ComAtprotoTempImportRepo: 'com.atproto.temp.importRepo', - ComAtprotoTempPushBlob: 'com.atproto.temp.pushBlob', ComAtprotoTempRequestPhoneVerification: 'com.atproto.temp.requestPhoneVerification', - ComAtprotoTempTransferAccount: 'com.atproto.temp.transferAccount', AppBskyActorDefs: 'app.bsky.actor.defs', AppBskyActorGetPreferences: 'app.bsky.actor.getPreferences', AppBskyActorGetProfile: 'app.bsky.actor.getProfile', @@ -8391,7 +9032,6 @@ export const ids = { 'app.bsky.unspecced.getPopularFeedGenerators', AppBskyUnspeccedGetTaggedSuggestions: 'app.bsky.unspecced.getTaggedSuggestions', - 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/defs.ts b/packages/api/src/client/types/app/bsky/actor/defs.ts index 0cb22ea5797..630f2454056 100644 --- a/packages/api/src/client/types/app/bsky/actor/defs.ts +++ b/packages/api/src/client/types/app/bsky/actor/defs.ts @@ -82,6 +82,7 @@ export function validateProfileViewDetailed(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#profileViewDetailed', v) } +/** Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests. */ export interface ViewerState { muted?: boolean mutedByList?: AppBskyGraphDefs.ListViewBasic @@ -112,6 +113,9 @@ export type Preferences = ( | PersonalDetailsPref | FeedViewPref | ThreadViewPref + | InterestsPref + | MutedWordsPref + | HiddenPostsPref | { $type: string; [k: string]: unknown } )[] @@ -153,6 +157,7 @@ export function validateContentLabelPref(v: unknown): ValidationResult { export interface SavedFeedsPref { pinned: string[] saved: string[] + timelineIndex?: number [k: string]: unknown } @@ -233,3 +238,80 @@ export function isThreadViewPref(v: unknown): v is ThreadViewPref { export function validateThreadViewPref(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#threadViewPref', v) } + +export interface InterestsPref { + /** A list of tags which describe the account owner's interests gathered during onboarding. */ + tags: string[] + [k: string]: unknown +} + +export function isInterestsPref(v: unknown): v is InterestsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#interestsPref' + ) +} + +export function validateInterestsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#interestsPref', v) +} + +export type MutedWordTarget = 'content' | 'tag' | (string & {}) + +/** A word that the account owner has muted. */ +export interface MutedWord { + /** The muted word itself. */ + value: string + /** The intended targets of the muted word. */ + targets: MutedWordTarget[] + [k: string]: unknown +} + +export function isMutedWord(v: unknown): v is MutedWord { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWord' + ) +} + +export function validateMutedWord(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWord', v) +} + +export interface MutedWordsPref { + /** A list of words the account owner has muted. */ + items: MutedWord[] + [k: string]: unknown +} + +export function isMutedWordsPref(v: unknown): v is MutedWordsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWordsPref' + ) +} + +export function validateMutedWordsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWordsPref', v) +} + +export interface HiddenPostsPref { + /** A list of URIs of posts the account owner has hidden. */ + items: string[] + [k: string]: unknown +} + +export function isHiddenPostsPref(v: unknown): v is HiddenPostsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#hiddenPostsPref' + ) +} + +export function validateHiddenPostsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#hiddenPostsPref', v) +} diff --git a/packages/api/src/client/types/app/bsky/actor/getProfile.ts b/packages/api/src/client/types/app/bsky/actor/getProfile.ts index 47e36fe974a..bbd88c30a7b 100644 --- a/packages/api/src/client/types/app/bsky/actor/getProfile.ts +++ b/packages/api/src/client/types/app/bsky/actor/getProfile.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** Handle or DID of account to fetch profile of. */ actor: string } diff --git a/packages/api/src/client/types/app/bsky/actor/profile.ts b/packages/api/src/client/types/app/bsky/actor/profile.ts index fa36f4298f1..a0c51e060c5 100644 --- a/packages/api/src/client/types/app/bsky/actor/profile.ts +++ b/packages/api/src/client/types/app/bsky/actor/profile.ts @@ -9,8 +9,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { displayName?: string + /** Free-form profile description text. */ description?: string + /** Small image to be displayed next to posts from account. AKA, 'profile picture' */ avatar?: BlobRef + /** Larger horizontal image to display behind profile view. */ banner?: BlobRef labels?: | ComAtprotoLabelDefs.SelfLabels diff --git a/packages/api/src/client/types/app/bsky/embed/external.ts b/packages/api/src/client/types/app/bsky/embed/external.ts index 271c103dbba..5832cbb3987 100644 --- a/packages/api/src/client/types/app/bsky/embed/external.ts +++ b/packages/api/src/client/types/app/bsky/embed/external.ts @@ -6,6 +6,7 @@ import { isObj, hasProp } from '../../../../util' import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' +/** A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). */ export interface Main { external: External [k: string]: unknown diff --git a/packages/api/src/client/types/app/bsky/embed/images.ts b/packages/api/src/client/types/app/bsky/embed/images.ts index 77909a4b3b0..ddfdf4c156c 100644 --- a/packages/api/src/client/types/app/bsky/embed/images.ts +++ b/packages/api/src/client/types/app/bsky/embed/images.ts @@ -26,6 +26,7 @@ export function validateMain(v: unknown): ValidationResult { export interface Image { image: BlobRef + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown @@ -76,8 +77,11 @@ export function validateView(v: unknown): ValidationResult { } export interface ViewImage { + /** Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. */ thumb: string + /** Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. */ fullsize: string + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown diff --git a/packages/api/src/client/types/app/bsky/embed/record.ts b/packages/api/src/client/types/app/bsky/embed/record.ts index caee8f08cdd..388687fd665 100644 --- a/packages/api/src/client/types/app/bsky/embed/record.ts +++ b/packages/api/src/client/types/app/bsky/embed/record.ts @@ -57,6 +57,7 @@ export interface ViewRecord { uri: string cid: string author: AppBskyActorDefs.ProfileViewBasic + /** The record data itself. */ value: {} labels?: ComAtprotoLabelDefs.Label[] embeds?: ( diff --git a/packages/api/src/client/types/app/bsky/feed/defs.ts b/packages/api/src/client/types/app/bsky/feed/defs.ts index 82cbfd9951a..949b8fb975e 100644 --- a/packages/api/src/client/types/app/bsky/feed/defs.ts +++ b/packages/api/src/client/types/app/bsky/feed/defs.ts @@ -45,6 +45,7 @@ export function validatePostView(v: unknown): ValidationResult { return lexicons.validate('app.bsky.feed.defs#postView', v) } +/** Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests. */ export interface ViewerState { repost?: string like?: string diff --git a/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts b/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts index a070dad6ff7..3f498e49514 100644 --- a/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts +++ b/packages/api/src/client/types/app/bsky/feed/getAuthorFeed.ts @@ -12,6 +12,7 @@ export interface QueryParams { actor: string limit?: number cursor?: string + /** Combinations of post/repost types to include in response. */ filter?: | 'posts_with_replies' | 'posts_no_replies' diff --git a/packages/api/src/client/types/app/bsky/feed/getFeedGenerator.ts b/packages/api/src/client/types/app/bsky/feed/getFeedGenerator.ts index a2f9b405c97..f08c9b59340 100644 --- a/packages/api/src/client/types/app/bsky/feed/getFeedGenerator.ts +++ b/packages/api/src/client/types/app/bsky/feed/getFeedGenerator.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** AT-URI of the feed generator record. */ feed: string } @@ -16,7 +17,9 @@ export type InputSchema = undefined export interface OutputSchema { view: AppBskyFeedDefs.GeneratorView + /** Indicates whether the feed generator service has been online recently, or else seems to be inactive. */ isOnline: boolean + /** Indicates whether the feed generator service is compatible with the record declaration. */ isValid: boolean [k: string]: unknown } diff --git a/packages/api/src/client/types/app/bsky/feed/getFeedSkeleton.ts b/packages/api/src/client/types/app/bsky/feed/getFeedSkeleton.ts index 0aa325d7fec..1426469c84d 100644 --- a/packages/api/src/client/types/app/bsky/feed/getFeedSkeleton.ts +++ b/packages/api/src/client/types/app/bsky/feed/getFeedSkeleton.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference to feed generator record describing the specific feed being requested. */ feed: string limit?: number cursor?: string diff --git a/packages/api/src/client/types/app/bsky/feed/getLikes.ts b/packages/api/src/client/types/app/bsky/feed/getLikes.ts index d78047feb6e..9725ef065d9 100644 --- a/packages/api/src/client/types/app/bsky/feed/getLikes.ts +++ b/packages/api/src/client/types/app/bsky/feed/getLikes.ts @@ -9,7 +9,9 @@ import { CID } from 'multiformats/cid' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** AT-URI of the subject (eg, a post record). */ uri: string + /** CID of the subject record (aka, specific version of record), to filter likes. */ cid?: string limit?: number cursor?: string diff --git a/packages/api/src/client/types/app/bsky/feed/getListFeed.ts b/packages/api/src/client/types/app/bsky/feed/getListFeed.ts index 511e9526c6d..6b4156ddda9 100644 --- a/packages/api/src/client/types/app/bsky/feed/getListFeed.ts +++ b/packages/api/src/client/types/app/bsky/feed/getListFeed.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to the list record. */ list: string limit?: number cursor?: string diff --git a/packages/api/src/client/types/app/bsky/feed/getPostThread.ts b/packages/api/src/client/types/app/bsky/feed/getPostThread.ts index d3865db9ee2..d03ad7de127 100644 --- a/packages/api/src/client/types/app/bsky/feed/getPostThread.ts +++ b/packages/api/src/client/types/app/bsky/feed/getPostThread.ts @@ -9,8 +9,11 @@ import { CID } from 'multiformats/cid' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to post record. */ uri: string + /** How many levels of reply depth should be included in response. */ depth?: number + /** How many levels of parent (and grandparent, etc) post to include. */ parentHeight?: number } diff --git a/packages/api/src/client/types/app/bsky/feed/getPosts.ts b/packages/api/src/client/types/app/bsky/feed/getPosts.ts index 933919bdcc1..cd932d88047 100644 --- a/packages/api/src/client/types/app/bsky/feed/getPosts.ts +++ b/packages/api/src/client/types/app/bsky/feed/getPosts.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** List of post AT-URIs to return hydrated views for. */ uris: string[] } diff --git a/packages/api/src/client/types/app/bsky/feed/getRepostedBy.ts b/packages/api/src/client/types/app/bsky/feed/getRepostedBy.ts index 30a1a109aaa..d27aa1dec0a 100644 --- a/packages/api/src/client/types/app/bsky/feed/getRepostedBy.ts +++ b/packages/api/src/client/types/app/bsky/feed/getRepostedBy.ts @@ -9,7 +9,9 @@ import { CID } from 'multiformats/cid' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** Reference (AT-URI) of post record */ uri: string + /** If supplied, filters to reposts of specific version (by CID) of the post record. */ cid?: string limit?: number cursor?: string diff --git a/packages/api/src/client/types/app/bsky/feed/getTimeline.ts b/packages/api/src/client/types/app/bsky/feed/getTimeline.ts index 6d8dacff99a..5ab2c7c4b1f 100644 --- a/packages/api/src/client/types/app/bsky/feed/getTimeline.ts +++ b/packages/api/src/client/types/app/bsky/feed/getTimeline.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. */ algorithm?: string limit?: number cursor?: string diff --git a/packages/api/src/client/types/app/bsky/feed/post.ts b/packages/api/src/client/types/app/bsky/feed/post.ts index a3299e19035..0de5192af77 100644 --- a/packages/api/src/client/types/app/bsky/feed/post.ts +++ b/packages/api/src/client/types/app/bsky/feed/post.ts @@ -14,9 +14,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' import * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef' export interface Record { + /** The primary post content. May be an empty string, if there are embeds. */ text: string - /** Deprecated: replaced by app.bsky.richtext.facet. */ + /** DEPRECATED: replaced by app.bsky.richtext.facet. */ entities?: Entity[] + /** Annotations of text (mentions, URLs, hashtags, etc) */ facets?: AppBskyRichtextFacet.Main[] reply?: ReplyRef embed?: @@ -25,12 +27,14 @@ export interface Record { | AppBskyEmbedRecord.Main | AppBskyEmbedRecordWithMedia.Main | { $type: string; [k: string]: unknown } + /** Indicates human language of post primary text content. */ langs?: string[] labels?: | ComAtprotoLabelDefs.SelfLabels | { $type: string; [k: string]: unknown } - /** Additional non-inline tags describing this post. */ + /** Additional hashtags, in addition to any included in post text and facets. */ tags?: string[] + /** Client-declared timestamp when this post was originally created. */ createdAt: string [k: string]: unknown } diff --git a/packages/api/src/client/types/app/bsky/feed/threadgate.ts b/packages/api/src/client/types/app/bsky/feed/threadgate.ts index a1afec85673..cc8c05a78ec 100644 --- a/packages/api/src/client/types/app/bsky/feed/threadgate.ts +++ b/packages/api/src/client/types/app/bsky/feed/threadgate.ts @@ -7,6 +7,7 @@ import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the post record. */ post: string allow?: ( | MentionRule diff --git a/packages/api/src/client/types/app/bsky/graph/block.ts b/packages/api/src/client/types/app/bsky/graph/block.ts index c35258d979a..f2455fc08a2 100644 --- a/packages/api/src/client/types/app/bsky/graph/block.ts +++ b/packages/api/src/client/types/app/bsky/graph/block.ts @@ -7,6 +7,7 @@ import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' export interface Record { + /** DID of the account to be blocked. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/api/src/client/types/app/bsky/graph/getList.ts b/packages/api/src/client/types/app/bsky/graph/getList.ts index 13ebd9d3ae6..36c4cf0aa86 100644 --- a/packages/api/src/client/types/app/bsky/graph/getList.ts +++ b/packages/api/src/client/types/app/bsky/graph/getList.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) of the list record to hydrate. */ list: string limit?: number cursor?: string diff --git a/packages/api/src/client/types/app/bsky/graph/getLists.ts b/packages/api/src/client/types/app/bsky/graph/getLists.ts index 80a7edfb759..644aeea3b4b 100644 --- a/packages/api/src/client/types/app/bsky/graph/getLists.ts +++ b/packages/api/src/client/types/app/bsky/graph/getLists.ts @@ -9,6 +9,7 @@ import { CID } from 'multiformats/cid' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** The account (actor) to enumerate lists from. */ actor: string limit?: number cursor?: string diff --git a/packages/api/src/client/types/app/bsky/graph/getRelationships.ts b/packages/api/src/client/types/app/bsky/graph/getRelationships.ts index 5fce53f635c..9aa58ad2699 100644 --- a/packages/api/src/client/types/app/bsky/graph/getRelationships.ts +++ b/packages/api/src/client/types/app/bsky/graph/getRelationships.ts @@ -9,7 +9,9 @@ import { CID } from 'multiformats/cid' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Primary account requesting relationships for. */ actor: string + /** List of 'other' accounts to be related back to the primary. */ others?: string[] } diff --git a/packages/api/src/client/types/app/bsky/graph/list.ts b/packages/api/src/client/types/app/bsky/graph/list.ts index 4fe6dd8ed8b..fec652ccb12 100644 --- a/packages/api/src/client/types/app/bsky/graph/list.ts +++ b/packages/api/src/client/types/app/bsky/graph/list.ts @@ -11,6 +11,7 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { purpose: AppBskyGraphDefs.ListPurpose + /** Display name for list; can not be empty. */ name: string description?: string descriptionFacets?: AppBskyRichtextFacet.Main[] diff --git a/packages/api/src/client/types/app/bsky/graph/listblock.ts b/packages/api/src/client/types/app/bsky/graph/listblock.ts index 770dfbb0775..e0f02be268f 100644 --- a/packages/api/src/client/types/app/bsky/graph/listblock.ts +++ b/packages/api/src/client/types/app/bsky/graph/listblock.ts @@ -7,6 +7,7 @@ import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the mod list record. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/api/src/client/types/app/bsky/graph/listitem.ts b/packages/api/src/client/types/app/bsky/graph/listitem.ts index 5059ef69c10..d4fb5631e84 100644 --- a/packages/api/src/client/types/app/bsky/graph/listitem.ts +++ b/packages/api/src/client/types/app/bsky/graph/listitem.ts @@ -7,7 +7,9 @@ import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' export interface Record { + /** The account which is included on the list. */ subject: string + /** Reference (AT-URI) to the list record (app.bsky.graph.list). */ list: string createdAt: string [k: string]: unknown diff --git a/packages/api/src/client/types/app/bsky/richtext/facet.ts b/packages/api/src/client/types/app/bsky/richtext/facet.ts index 96573bb06fe..836136b7dac 100644 --- a/packages/api/src/client/types/app/bsky/richtext/facet.ts +++ b/packages/api/src/client/types/app/bsky/richtext/facet.ts @@ -6,6 +6,7 @@ import { isObj, hasProp } from '../../../../util' import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' +/** Annotation of a sub-string within rich text. */ export interface Main { index: ByteSlice features: (Mention | Link | Tag | { $type: string; [k: string]: unknown })[] @@ -25,7 +26,7 @@ export function validateMain(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#main', v) } -/** A facet feature for actor mentions. */ +/** Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID. */ export interface Mention { did: string [k: string]: unknown @@ -43,7 +44,7 @@ export function validateMention(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#mention', v) } -/** A facet feature for links. */ +/** Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. */ export interface Link { uri: string [k: string]: unknown @@ -61,7 +62,7 @@ export function validateLink(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#link', v) } -/** A hashtag. */ +/** Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). */ export interface Tag { tag: string [k: string]: unknown @@ -77,7 +78,7 @@ export function validateTag(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#tag', v) } -/** A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings. */ +/** Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. */ export interface ByteSlice { byteStart: number byteEnd: number diff --git a/packages/api/src/client/types/com/atproto/admin/defs.ts b/packages/api/src/client/types/com/atproto/admin/defs.ts index da154f8a845..4e3d35a869f 100644 --- a/packages/api/src/client/types/com/atproto/admin/defs.ts +++ b/packages/api/src/client/types/com/atproto/admin/defs.ts @@ -40,6 +40,7 @@ export interface ModEventView { | ModEventEscalate | ModEventMute | ModEventEmail + | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: | RepoRef @@ -76,6 +77,7 @@ export interface ModEventViewDetail { | ModEventAcknowledge | ModEventEscalate | ModEventMute + | ModEventEmail | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: @@ -154,6 +156,7 @@ export interface SubjectStatusView { /** True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators. */ appealed?: boolean suspendUntil?: string + tags?: string[] [k: string]: unknown } @@ -718,6 +721,29 @@ export function validateModEventEmail(v: unknown): ValidationResult { return lexicons.validate('com.atproto.admin.defs#modEventEmail', v) } +/** Add/Remove a tag on a subject */ +export interface ModEventTag { + /** Tags to be added to the subject. If already exists, won't be duplicated. */ + add: string[] + /** Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated. */ + remove: string[] + /** Additional comment about added/removed tags. */ + comment?: string + [k: string]: unknown +} + +export function isModEventTag(v: unknown): v is ModEventTag { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.admin.defs#modEventTag' + ) +} + +export function validateModEventTag(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.admin.defs#modEventTag', v) +} + export interface CommunicationTemplateView { id: string /** Name of the template. */ diff --git a/packages/api/src/client/types/com/atproto/admin/emitModerationEvent.ts b/packages/api/src/client/types/com/atproto/admin/emitModerationEvent.ts index 77b460ed1ff..6e7827bdc6a 100644 --- a/packages/api/src/client/types/com/atproto/admin/emitModerationEvent.ts +++ b/packages/api/src/client/types/com/atproto/admin/emitModerationEvent.ts @@ -23,6 +23,7 @@ export interface InputSchema { | ComAtprotoAdminDefs.ModEventReverseTakedown | ComAtprotoAdminDefs.ModEventUnmute | ComAtprotoAdminDefs.ModEventEmail + | ComAtprotoAdminDefs.ModEventTag | { $type: string; [k: string]: unknown } subject: | ComAtprotoAdminDefs.RepoRef diff --git a/packages/api/src/client/types/com/atproto/admin/queryModerationEvents.ts b/packages/api/src/client/types/com/atproto/admin/queryModerationEvents.ts index ed21c739bcb..2dd3081ef8f 100644 --- a/packages/api/src/client/types/com/atproto/admin/queryModerationEvents.ts +++ b/packages/api/src/client/types/com/atproto/admin/queryModerationEvents.ts @@ -14,10 +14,27 @@ export interface QueryParams { createdBy?: string /** Sort direction for the events. Defaults to descending order of created at timestamp. */ sortDirection?: 'asc' | 'desc' + /** Retrieve events created after a given timestamp */ + createdAfter?: string + /** Retrieve events created before a given timestamp */ + createdBefore?: string subject?: string /** If true, events on all record types (posts, lists, profile etc.) owned by the did are returned */ includeAllUserRecords?: boolean limit?: number + /** If true, only events with comments are returned */ + hasComment?: boolean + /** If specified, only events with comments containing the keyword are returned */ + comment?: string + /** If specified, only events where all of these labels were added are returned */ + addedLabels?: string[] + /** If specified, only events where all of these labels were removed are returned */ + removedLabels?: string[] + /** If specified, only events where all of these tags were added are returned */ + addedTags?: string[] + /** If specified, only events where all of these tags were removed are returned */ + removedTags?: string[] + reportTypes?: string[] cursor?: string } diff --git a/packages/api/src/client/types/com/atproto/admin/queryModerationStatuses.ts b/packages/api/src/client/types/com/atproto/admin/queryModerationStatuses.ts index 0039016a353..c16bb94fec3 100644 --- a/packages/api/src/client/types/com/atproto/admin/queryModerationStatuses.ts +++ b/packages/api/src/client/types/com/atproto/admin/queryModerationStatuses.ts @@ -34,6 +34,8 @@ export interface QueryParams { /** Get subjects in unresolved appealed status */ appealed?: boolean limit?: number + tags?: string[] + excludeTags?: string[] cursor?: string } diff --git a/packages/api/src/client/types/com/atproto/temp/pushBlob.ts b/packages/api/src/client/types/com/atproto/admin/updateAccountPassword.ts similarity index 79% rename from packages/api/src/client/types/com/atproto/temp/pushBlob.ts rename to packages/api/src/client/types/com/atproto/admin/updateAccountPassword.ts index 32165bc8014..99ef3881c37 100644 --- a/packages/api/src/client/types/com/atproto/temp/pushBlob.ts +++ b/packages/api/src/client/types/com/atproto/admin/updateAccountPassword.ts @@ -7,17 +7,18 @@ import { isObj, hasProp } from '../../../../util' import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' -export interface QueryParams { - /** The DID of the repo. */ +export interface QueryParams {} + +export interface InputSchema { did: string + password: string + [k: string]: unknown } -export type InputSchema = string | Uint8Array - export interface CallOptions { headers?: Headers qp?: QueryParams - encoding: string + encoding: 'application/json' } export interface Response { diff --git a/packages/api/src/client/types/com/atproto/identity/getRecommendedDidCredentials.ts b/packages/api/src/client/types/com/atproto/identity/getRecommendedDidCredentials.ts new file mode 100644 index 00000000000..dfa143e4ab3 --- /dev/null +++ b/packages/api/src/client/types/com/atproto/identity/getRecommendedDidCredentials.ts @@ -0,0 +1,37 @@ +/** + * 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' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + /** Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs. */ + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/identity/requestPlcOperationSignature.ts b/packages/api/src/client/types/com/atproto/identity/requestPlcOperationSignature.ts new file mode 100644 index 00000000000..ef2ed1ac47c --- /dev/null +++ b/packages/api/src/client/types/com/atproto/identity/requestPlcOperationSignature.ts @@ -0,0 +1,28 @@ +/** + * 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' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface CallOptions { + headers?: Headers + qp?: QueryParams +} + +export interface Response { + success: boolean + headers: Headers +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/identity/signPlcOperation.ts b/packages/api/src/client/types/com/atproto/identity/signPlcOperation.ts new file mode 100644 index 00000000000..3060c1e3f4d --- /dev/null +++ b/packages/api/src/client/types/com/atproto/identity/signPlcOperation.ts @@ -0,0 +1,44 @@ +/** + * 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' + +export interface QueryParams {} + +export interface InputSchema { + /** A token received through com.atproto.identity.requestPlcOperationSignature */ + token?: string + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} + [k: string]: unknown +} + +export interface OutputSchema { + /** A signed DID PLC operation. */ + operation: {} + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers + qp?: QueryParams + encoding: 'application/json' +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/identity/submitPlcOperation.ts b/packages/api/src/client/types/com/atproto/identity/submitPlcOperation.ts new file mode 100644 index 00000000000..4ba52f74fc7 --- /dev/null +++ b/packages/api/src/client/types/com/atproto/identity/submitPlcOperation.ts @@ -0,0 +1,32 @@ +/** + * 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' + +export interface QueryParams {} + +export interface InputSchema { + operation: {} + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers + qp?: QueryParams + encoding: 'application/json' +} + +export interface Response { + success: boolean + headers: Headers +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/identity/updateHandle.ts b/packages/api/src/client/types/com/atproto/identity/updateHandle.ts index 4c01e105c28..2bd2c4c9d6a 100644 --- a/packages/api/src/client/types/com/atproto/identity/updateHandle.ts +++ b/packages/api/src/client/types/com/atproto/identity/updateHandle.ts @@ -10,6 +10,7 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { + /** The new handle. */ handle: string [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/moderation/createReport.ts b/packages/api/src/client/types/com/atproto/moderation/createReport.ts index 826b32ff67c..7bf3cc1a380 100644 --- a/packages/api/src/client/types/com/atproto/moderation/createReport.ts +++ b/packages/api/src/client/types/com/atproto/moderation/createReport.ts @@ -14,6 +14,7 @@ export interface QueryParams {} export interface InputSchema { reasonType: ComAtprotoModerationDefs.ReasonType + /** Additional context about the content and violation. */ reason?: string subject: | ComAtprotoAdminDefs.RepoRef diff --git a/packages/api/src/client/types/com/atproto/repo/applyWrites.ts b/packages/api/src/client/types/com/atproto/repo/applyWrites.ts index f4a8a269201..df35ec7dcbf 100644 --- a/packages/api/src/client/types/com/atproto/repo/applyWrites.ts +++ b/packages/api/src/client/types/com/atproto/repo/applyWrites.ts @@ -10,11 +10,12 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string - /** Flag for validating the records. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data, for all operations. */ validate?: boolean writes: (Create | Update | Delete)[] + /** If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations. */ swapCommit?: string [k: string]: unknown } @@ -43,7 +44,7 @@ export function toKnownErr(e: any) { return e } -/** Create a new record. */ +/** Operation which creates a new record. */ export interface Create { collection: string rkey?: string @@ -63,7 +64,7 @@ export function validateCreate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#create', v) } -/** Update an existing record. */ +/** Operation which updates an existing record. */ export interface Update { collection: string rkey: string @@ -83,7 +84,7 @@ export function validateUpdate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#update', v) } -/** Delete an existing record. */ +/** Operation which deletes an existing record. */ export interface Delete { collection: string rkey: string diff --git a/packages/api/src/client/types/com/atproto/repo/createRecord.ts b/packages/api/src/client/types/com/atproto/repo/createRecord.ts index 2056778c71c..6b13f67db7f 100644 --- a/packages/api/src/client/types/com/atproto/repo/createRecord.ts +++ b/packages/api/src/client/types/com/atproto/repo/createRecord.ts @@ -10,15 +10,15 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey?: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate?: boolean - /** The record to create. */ + /** The record itself. Must contain a $type field. */ record: {} /** Compare and swap with the previous commit by CID. */ swapCommit?: string diff --git a/packages/api/src/client/types/com/atproto/repo/deleteRecord.ts b/packages/api/src/client/types/com/atproto/repo/deleteRecord.ts index 5bf9237abbb..54109b62f31 100644 --- a/packages/api/src/client/types/com/atproto/repo/deleteRecord.ts +++ b/packages/api/src/client/types/com/atproto/repo/deleteRecord.ts @@ -10,11 +10,11 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** Compare and swap with the previous record by CID. */ swapRecord?: string diff --git a/packages/api/src/client/types/com/atproto/repo/describeRepo.ts b/packages/api/src/client/types/com/atproto/repo/describeRepo.ts index e6ecedb3297..f17a8410782 100644 --- a/packages/api/src/client/types/com/atproto/repo/describeRepo.ts +++ b/packages/api/src/client/types/com/atproto/repo/describeRepo.ts @@ -17,8 +17,11 @@ export type InputSchema = undefined export interface OutputSchema { handle: string did: string + /** The complete DID document for this account. */ didDoc: {} + /** List of all the collections (NSIDs) for which this repo contains at least one record. */ collections: string[] + /** Indicates if handle is currently valid (resolves bi-directionally) */ handleIsCorrect: boolean [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/repo/getRecord.ts b/packages/api/src/client/types/com/atproto/repo/getRecord.ts index 56338d016ee..a6d2bd39e8c 100644 --- a/packages/api/src/client/types/com/atproto/repo/getRecord.ts +++ b/packages/api/src/client/types/com/atproto/repo/getRecord.ts @@ -12,7 +12,7 @@ export interface QueryParams { repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** The CID of the version of the record. If not specified, then return the most recent version. */ cid?: string diff --git a/packages/api/src/client/types/com/atproto/temp/importRepo.ts b/packages/api/src/client/types/com/atproto/repo/importRepo.ts similarity index 86% rename from packages/api/src/client/types/com/atproto/temp/importRepo.ts rename to packages/api/src/client/types/com/atproto/repo/importRepo.ts index 6f9f99f2b9d..040cca671bf 100644 --- a/packages/api/src/client/types/com/atproto/temp/importRepo.ts +++ b/packages/api/src/client/types/com/atproto/repo/importRepo.ts @@ -7,10 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' -export interface QueryParams { - /** The DID of the repo. */ - did: string -} +export interface QueryParams {} export type InputSchema = string | Uint8Array @@ -23,7 +20,6 @@ export interface CallOptions { export interface Response { success: boolean headers: Headers - data: Uint8Array } export function toKnownErr(e: any) { diff --git a/packages/api/src/client/types/com/atproto/repo/listMissingBlobs.ts b/packages/api/src/client/types/com/atproto/repo/listMissingBlobs.ts new file mode 100644 index 00000000000..b66f617eea7 --- /dev/null +++ b/packages/api/src/client/types/com/atproto/repo/listMissingBlobs.ts @@ -0,0 +1,55 @@ +/** + * 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' + +export interface QueryParams { + limit?: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + blobs: RecordBlob[] + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} + +export interface RecordBlob { + cid: string + recordUri: string + [k: string]: unknown +} + +export function isRecordBlob(v: unknown): v is RecordBlob { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.repo.listMissingBlobs#recordBlob' + ) +} + +export function validateRecordBlob(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.repo.listMissingBlobs#recordBlob', v) +} diff --git a/packages/api/src/client/types/com/atproto/repo/putRecord.ts b/packages/api/src/client/types/com/atproto/repo/putRecord.ts index 269ef759401..7421ee19780 100644 --- a/packages/api/src/client/types/com/atproto/repo/putRecord.ts +++ b/packages/api/src/client/types/com/atproto/repo/putRecord.ts @@ -10,17 +10,17 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate?: boolean /** The record to write. */ record: {} - /** Compare and swap with the previous record by CID. */ + /** Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation */ swapRecord?: string | null /** Compare and swap with the previous commit by CID. */ swapCommit?: string diff --git a/packages/api/src/client/types/com/atproto/server/activateAccount.ts b/packages/api/src/client/types/com/atproto/server/activateAccount.ts new file mode 100644 index 00000000000..ef2ed1ac47c --- /dev/null +++ b/packages/api/src/client/types/com/atproto/server/activateAccount.ts @@ -0,0 +1,28 @@ +/** + * 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' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface CallOptions { + headers?: Headers + qp?: QueryParams +} + +export interface Response { + success: boolean + headers: Headers +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/server/checkAccountStatus.ts b/packages/api/src/client/types/com/atproto/server/checkAccountStatus.ts new file mode 100644 index 00000000000..86a942f81f3 --- /dev/null +++ b/packages/api/src/client/types/com/atproto/server/checkAccountStatus.ts @@ -0,0 +1,41 @@ +/** + * 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' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + activated: boolean + validDid: boolean + repoCommit: string + repoRev: string + repoBlocks: number + indexedRecords: number + privateStateValues: number + expectedBlobs: number + importedBlobs: number + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/server/createAccount.ts b/packages/api/src/client/types/com/atproto/server/createAccount.ts index b62adf97cb1..5e36eca0ee3 100644 --- a/packages/api/src/client/types/com/atproto/server/createAccount.ts +++ b/packages/api/src/client/types/com/atproto/server/createAccount.ts @@ -11,22 +11,30 @@ export interface QueryParams {} export interface InputSchema { email?: string + /** Requested handle for the account. */ handle: string + /** Pre-existing atproto DID, being imported to a new account. */ did?: string inviteCode?: string verificationCode?: string verificationPhone?: string + /** Initial account password. May need to meet instance-specific password strength requirements. */ password?: string + /** DID PLC rotation key (aka, recovery key) to be included in PLC creation operation. */ recoveryKey?: string + /** A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented. */ plcOp?: {} [k: string]: unknown } +/** Account login session returned on successful account creation. */ export interface OutputSchema { accessJwt: string refreshJwt: string handle: string + /** The DID of the new account. */ did: string + /** Complete DID document. */ didDoc?: {} [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/server/createAppPassword.ts b/packages/api/src/client/types/com/atproto/server/createAppPassword.ts index d6e9ce3ddf5..8b9a5d53a7c 100644 --- a/packages/api/src/client/types/com/atproto/server/createAppPassword.ts +++ b/packages/api/src/client/types/com/atproto/server/createAppPassword.ts @@ -10,6 +10,7 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { + /** A short name for the App Password, to help distinguish them. */ name: string [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/server/deactivateAccount.ts b/packages/api/src/client/types/com/atproto/server/deactivateAccount.ts new file mode 100644 index 00000000000..c88bd548243 --- /dev/null +++ b/packages/api/src/client/types/com/atproto/server/deactivateAccount.ts @@ -0,0 +1,33 @@ +/** + * 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' + +export interface QueryParams {} + +export interface InputSchema { + /** A recommendation to server as to how long they should hold onto the deactivated account before deleting. */ + deleteAfter?: string + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers + qp?: QueryParams + encoding: 'application/json' +} + +export interface Response { + success: boolean + headers: Headers +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/server/describeServer.ts b/packages/api/src/client/types/com/atproto/server/describeServer.ts index fb6c9d5c662..c4b749c7ada 100644 --- a/packages/api/src/client/types/com/atproto/server/describeServer.ts +++ b/packages/api/src/client/types/com/atproto/server/describeServer.ts @@ -12,10 +12,14 @@ export interface QueryParams {} export type InputSchema = undefined export interface OutputSchema { + /** If true, an invite code must be supplied to create an account on this instance. */ inviteCodeRequired?: boolean + /** If true, a phone verification token must be supplied to create an account on this instance. */ phoneVerificationRequired?: boolean + /** List of domain suffixes that can be used in account handles. */ availableUserDomains: string[] links?: Links + did: string [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/server/getAccountInviteCodes.ts b/packages/api/src/client/types/com/atproto/server/getAccountInviteCodes.ts index d019ed3fa23..5438cbc96d6 100644 --- a/packages/api/src/client/types/com/atproto/server/getAccountInviteCodes.ts +++ b/packages/api/src/client/types/com/atproto/server/getAccountInviteCodes.ts @@ -10,6 +10,7 @@ import * as ComAtprotoServerDefs from './defs' export interface QueryParams { includeUsed?: boolean + /** Controls whether any new 'earned' but not 'created' invites should be created. */ createAvailable?: boolean } diff --git a/packages/api/src/client/types/app/bsky/unspecced/getTimelineSkeleton.ts b/packages/api/src/client/types/com/atproto/server/getServiceAuth.ts similarity index 64% rename from packages/api/src/client/types/app/bsky/unspecced/getTimelineSkeleton.ts rename to packages/api/src/client/types/com/atproto/server/getServiceAuth.ts index 91acf9d5e3d..6056960effc 100644 --- a/packages/api/src/client/types/app/bsky/unspecced/getTimelineSkeleton.ts +++ b/packages/api/src/client/types/com/atproto/server/getServiceAuth.ts @@ -6,18 +6,16 @@ import { ValidationResult, BlobRef } from '@atproto/lexicon' import { isObj, hasProp } from '../../../../util' import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' -import * as AppBskyFeedDefs from '../feed/defs' export interface QueryParams { - limit?: number - cursor?: string + /** The DID of the service that the token will be used to authenticate with */ + aud: string } export type InputSchema = undefined export interface OutputSchema { - cursor?: string - feed: AppBskyFeedDefs.SkeletonFeedPost[] + token: string [k: string]: unknown } @@ -31,15 +29,8 @@ export interface Response { data: OutputSchema } -export class UnknownFeedError 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 === 'UnknownFeed') return new UnknownFeedError(e) } return e } diff --git a/packages/api/src/client/types/com/atproto/server/reserveSigningKey.ts b/packages/api/src/client/types/com/atproto/server/reserveSigningKey.ts index f5e515ff5cf..324dee9665a 100644 --- a/packages/api/src/client/types/com/atproto/server/reserveSigningKey.ts +++ b/packages/api/src/client/types/com/atproto/server/reserveSigningKey.ts @@ -10,13 +10,13 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { - /** The did to reserve a new did:key for */ + /** The DID to reserve a key for. */ did?: string [k: string]: unknown } export interface OutputSchema { - /** Public signing key in the form of a did:key. */ + /** The public key for the reserved signing key, in did:key serialization. */ signingKey: string [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/sync/getBlob.ts b/packages/api/src/client/types/com/atproto/sync/getBlob.ts index 57bc271ce5a..83d8b79ca08 100644 --- a/packages/api/src/client/types/com/atproto/sync/getBlob.ts +++ b/packages/api/src/client/types/com/atproto/sync/getBlob.ts @@ -8,7 +8,7 @@ import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' export interface QueryParams { - /** The DID of the repo. */ + /** The DID of the account. */ did: string /** The CID of the blob to fetch */ cid: string diff --git a/packages/api/src/client/types/com/atproto/sync/getRecord.ts b/packages/api/src/client/types/com/atproto/sync/getRecord.ts index e7bbcf36343..1fc9a94b406 100644 --- a/packages/api/src/client/types/com/atproto/sync/getRecord.ts +++ b/packages/api/src/client/types/com/atproto/sync/getRecord.ts @@ -11,6 +11,7 @@ export interface QueryParams { /** The DID of the repo. */ did: string collection: string + /** Record Key */ rkey: string /** An optional past commit CID. */ commit?: string diff --git a/packages/api/src/client/types/com/atproto/sync/getRepo.ts b/packages/api/src/client/types/com/atproto/sync/getRepo.ts index 0a45536779e..53e0883d74e 100644 --- a/packages/api/src/client/types/com/atproto/sync/getRepo.ts +++ b/packages/api/src/client/types/com/atproto/sync/getRepo.ts @@ -10,7 +10,7 @@ import { CID } from 'multiformats/cid' export interface QueryParams { /** The DID of the repo. */ did: string - /** The revision of the repo to catch up from. */ + /** The revision ('rev') of the repo to create a diff from. */ since?: string } diff --git a/packages/api/src/client/types/com/atproto/sync/listRepos.ts b/packages/api/src/client/types/com/atproto/sync/listRepos.ts index 669dba37e85..eccf796acb6 100644 --- a/packages/api/src/client/types/com/atproto/sync/listRepos.ts +++ b/packages/api/src/client/types/com/atproto/sync/listRepos.ts @@ -38,6 +38,7 @@ export function toKnownErr(e: any) { export interface Repo { did: string + /** Current repo commit CID */ head: string rev: string [k: string]: unknown diff --git a/packages/api/src/client/types/com/atproto/sync/notifyOfUpdate.ts b/packages/api/src/client/types/com/atproto/sync/notifyOfUpdate.ts index 2b098982684..f53e4a55385 100644 --- a/packages/api/src/client/types/com/atproto/sync/notifyOfUpdate.ts +++ b/packages/api/src/client/types/com/atproto/sync/notifyOfUpdate.ts @@ -10,7 +10,7 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is notifying of update. */ + /** Hostname of the current service (usually a PDS) that is notifying of update. */ hostname: string [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/sync/requestCrawl.ts b/packages/api/src/client/types/com/atproto/sync/requestCrawl.ts index c07330a6fb1..089eb84e089 100644 --- a/packages/api/src/client/types/com/atproto/sync/requestCrawl.ts +++ b/packages/api/src/client/types/com/atproto/sync/requestCrawl.ts @@ -10,7 +10,7 @@ import { CID } from 'multiformats/cid' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is requesting to be crawled. */ + /** Hostname of the current service (eg, PDS) that is requesting to be crawled. */ hostname: string [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/sync/subscribeRepos.ts b/packages/api/src/client/types/com/atproto/sync/subscribeRepos.ts index a4fec035874..f4a362f755f 100644 --- a/packages/api/src/client/types/com/atproto/sync/subscribeRepos.ts +++ b/packages/api/src/client/types/com/atproto/sync/subscribeRepos.ts @@ -7,21 +7,29 @@ import { isObj, hasProp } from '../../../../util' import { lexicons } from '../../../../lexicons' import { CID } from 'multiformats/cid' +/** Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature. */ export interface Commit { + /** The stream sequence number of this message. */ seq: number + /** DEPRECATED -- unused */ rebase: boolean + /** Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data. */ tooBig: boolean + /** The repo this event comes from. */ repo: string + /** Repo commit object CID. */ commit: CID + /** DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability. */ prev?: CID | null - /** The rev of the emitted commit. */ + /** The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event. */ rev: string - /** The rev of the last emitted commit from this repo. */ + /** The rev of the last emitted commit from this repo (if any). */ since: string | null - /** CAR file containing relevant blocks. */ + /** CAR file containing relevant blocks, as a diff since the previous repo state. */ blocks: Uint8Array ops: RepoOp[] blobs: CID[] + /** Timestamp of when this message was originally broadcast. */ time: string [k: string]: unknown } @@ -38,6 +46,27 @@ export function validateCommit(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#commit', v) } +/** Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache. */ +export interface Identity { + seq: number + did: string + time: string + [k: string]: unknown +} + +export function isIdentity(v: unknown): v is Identity { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.sync.subscribeRepos#identity' + ) +} + +export function validateIdentity(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.sync.subscribeRepos#identity', v) +} + +/** Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity. */ export interface Handle { seq: number did: string @@ -58,6 +87,7 @@ export function validateHandle(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#handle', v) } +/** Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead */ export interface Migrate { seq: number did: string @@ -78,6 +108,7 @@ export function validateMigrate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#migrate', v) } +/** Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event */ export interface Tombstone { seq: number did: string @@ -115,10 +146,11 @@ export function validateInfo(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#info', v) } -/** A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null. */ +/** A repo operation, ie a mutation of a single record. */ export interface RepoOp { action: 'create' | 'update' | 'delete' | (string & {}) path: string + /** For creates and updates, the new record CID. For deletions, null. */ cid: CID | null [k: string]: unknown } diff --git a/packages/api/src/client/types/com/atproto/temp/checkSignupQueue.ts b/packages/api/src/client/types/com/atproto/temp/checkSignupQueue.ts new file mode 100644 index 00000000000..2f80322c82e --- /dev/null +++ b/packages/api/src/client/types/com/atproto/temp/checkSignupQueue.ts @@ -0,0 +1,35 @@ +/** + * 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' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + activated: boolean + placeInQueue?: number + estimatedTimeMs?: number + [k: string]: unknown +} + +export interface CallOptions { + headers?: Headers +} + +export interface Response { + success: boolean + headers: Headers + data: OutputSchema +} + +export function toKnownErr(e: any) { + if (e instanceof XRPCError) { + } + return e +} diff --git a/packages/api/src/client/types/com/atproto/temp/transferAccount.ts b/packages/api/src/client/types/com/atproto/temp/transferAccount.ts deleted file mode 100644 index 7ae16c01290..00000000000 --- a/packages/api/src/client/types/com/atproto/temp/transferAccount.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * 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' - -export interface QueryParams {} - -export interface InputSchema { - handle: string - did: string - plcOp: {} - [k: string]: unknown -} - -export interface OutputSchema { - accessJwt: string - refreshJwt: string - handle: string - did: string - [k: string]: unknown -} - -export interface CallOptions { - headers?: Headers - qp?: QueryParams - encoding: 'application/json' -} - -export interface Response { - success: boolean - headers: Headers - data: OutputSchema -} - -export class InvalidHandleError extends XRPCError { - constructor(src: XRPCError) { - super(src.status, src.error, src.message, src.headers) - } -} - -export class InvalidPasswordError extends XRPCError { - constructor(src: XRPCError) { - super(src.status, src.error, src.message, src.headers) - } -} - -export class InvalidInviteCodeError extends XRPCError { - constructor(src: XRPCError) { - super(src.status, src.error, src.message, src.headers) - } -} - -export class HandleNotAvailableError extends XRPCError { - constructor(src: XRPCError) { - super(src.status, src.error, src.message, src.headers) - } -} - -export class UnsupportedDomainError extends XRPCError { - constructor(src: XRPCError) { - super(src.status, src.error, src.message, src.headers) - } -} - -export class UnresolvableDidError extends XRPCError { - constructor(src: XRPCError) { - super(src.status, src.error, src.message, src.headers) - } -} - -export class IncompatibleDidDocError 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 === 'InvalidHandle') return new InvalidHandleError(e) - if (e.error === 'InvalidPassword') return new InvalidPasswordError(e) - if (e.error === 'InvalidInviteCode') return new InvalidInviteCodeError(e) - if (e.error === 'HandleNotAvailable') return new HandleNotAvailableError(e) - if (e.error === 'UnsupportedDomain') return new UnsupportedDomainError(e) - if (e.error === 'UnresolvableDid') return new UnresolvableDidError(e) - if (e.error === 'IncompatibleDidDoc') return new IncompatibleDidDocError(e) - } - return e -} diff --git a/packages/api/src/types.ts b/packages/api/src/types.ts index 45684a3ef27..7e36e77de58 100644 --- a/packages/api/src/types.ts +++ b/packages/api/src/types.ts @@ -1,3 +1,4 @@ +import { AppBskyActorNS, AppBskyActorDefs } from './client' import { LabelPreference } from './moderation/types' /** @@ -97,6 +98,14 @@ export interface BskyThreadViewPreference { [key: string]: any } +/** + * Bluesky interests preferences + */ +export interface BskyInterestsPreference { + tags: string[] + [key: string]: any +} + /** * Bluesky preferences */ @@ -110,4 +119,7 @@ export interface BskyPreferences { adultContentEnabled: boolean contentLabels: Record birthDate: Date | undefined + interests: BskyInterestsPreference + mutedWords: AppBskyActorDefs.MutedWord[] + hiddenPosts: string[] } diff --git a/packages/api/tests/agent.test.ts b/packages/api/tests/agent.test.ts index cff4e3517a8..7bebb8a1bcf 100644 --- a/packages/api/tests/agent.test.ts +++ b/packages/api/tests/agent.test.ts @@ -439,6 +439,7 @@ describe('agent', () => { expect(originalHandlerCallCount).toEqual(1) agent.setPersistSessionHandler(newPersistSession) + agent.session = undefined await agent.createAccount({ handle: 'user8.test', diff --git a/packages/api/tests/bsky-agent.test.ts b/packages/api/tests/bsky-agent.test.ts index 5582f7ac021..db8ee0a1567 100644 --- a/packages/api/tests/bsky-agent.test.ts +++ b/packages/api/tests/bsky-agent.test.ts @@ -236,6 +236,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setAdultContentEnabled(true) @@ -257,6 +262,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setAdultContentEnabled(false) @@ -278,6 +288,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setContentLabelPref('impersonation', 'warn') @@ -301,6 +316,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setContentLabelPref('spam', 'show') // will convert to 'ignore' @@ -326,6 +346,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.addSavedFeed('at://bob.com/app.bsky.feed.generator/fake') @@ -353,6 +378,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.addPinnedFeed('at://bob.com/app.bsky.feed.generator/fake') @@ -380,6 +410,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.removePinnedFeed('at://bob.com/app.bsky.feed.generator/fake') @@ -407,6 +442,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.removeSavedFeed('at://bob.com/app.bsky.feed.generator/fake') @@ -434,6 +474,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.addPinnedFeed('at://bob.com/app.bsky.feed.generator/fake') @@ -461,6 +506,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.addPinnedFeed('at://bob.com/app.bsky.feed.generator/fake2') @@ -494,6 +544,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.removeSavedFeed('at://bob.com/app.bsky.feed.generator/fake') @@ -521,6 +576,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setPersonalDetails({ birthDate: '2023-09-11T18:05:42.556Z' }) @@ -548,6 +608,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setFeedViewPrefs('home', { hideReplies: true }) @@ -575,6 +640,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setFeedViewPrefs('home', { hideReplies: false }) @@ -602,6 +672,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setFeedViewPrefs('other', { hideReplies: true }) @@ -636,6 +711,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setThreadViewPrefs({ sort: 'random' }) @@ -670,6 +750,11 @@ describe('agent', () => { sort: 'random', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setThreadViewPrefs({ sort: 'oldest' }) @@ -704,6 +789,50 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], + }) + + await agent.setInterestsPref({ tags: ['foo', 'bar'] }) + await expect(agent.getPreferences()).resolves.toStrictEqual({ + feeds: { + pinned: ['at://bob.com/app.bsky.feed.generator/fake2'], + saved: ['at://bob.com/app.bsky.feed.generator/fake2'], + }, + adultContentEnabled: false, + contentLabels: { + impersonation: 'hide', + spam: 'ignore', + }, + birthDate: new Date('2023-09-11T18:05:42.556Z'), + feedViewPrefs: { + home: { + hideReplies: false, + hideRepliesByUnfollowed: false, + hideRepliesByLikeCount: 0, + hideReposts: false, + hideQuotePosts: false, + }, + other: { + hideReplies: true, + hideRepliesByUnfollowed: false, + hideRepliesByLikeCount: 0, + hideReposts: false, + hideQuotePosts: false, + }, + }, + threadViewPrefs: { + sort: 'oldest', + prioritizeFollowedUsers: true, + }, + interests: { + tags: ['foo', 'bar'], + }, + mutedWords: [], + hiddenPosts: [], }) }) @@ -827,6 +956,11 @@ describe('agent', () => { sort: 'newest', prioritizeFollowedUsers: false, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setAdultContentEnabled(false) @@ -853,6 +987,11 @@ describe('agent', () => { sort: 'newest', prioritizeFollowedUsers: false, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setContentLabelPref('nsfw', 'hide') @@ -879,6 +1018,11 @@ describe('agent', () => { sort: 'newest', prioritizeFollowedUsers: false, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.addPinnedFeed('at://bob.com/app.bsky.feed.generator/fake') @@ -905,6 +1049,11 @@ describe('agent', () => { sort: 'newest', prioritizeFollowedUsers: false, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setPersonalDetails({ birthDate: '2023-09-11T18:05:42.556Z' }) @@ -931,6 +1080,11 @@ describe('agent', () => { sort: 'newest', prioritizeFollowedUsers: false, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) await agent.setFeedViewPrefs('home', { @@ -968,6 +1122,11 @@ describe('agent', () => { sort: 'oldest', prioritizeFollowedUsers: true, }, + interests: { + tags: [], + }, + mutedWords: [], + hiddenPosts: [], }) const res = await agent.app.bsky.actor.getPreferences() @@ -1009,6 +1168,146 @@ describe('agent', () => { ].sort(byType), ) }) + + describe('muted words', () => { + let agent: BskyAgent + const mutedWords = [ + { value: 'both', targets: ['content', 'tag'] }, + { value: 'content', targets: ['content'] }, + { value: 'tag', targets: ['tag'] }, + { value: 'tag_then_both', targets: ['tag'] }, + { value: 'tag_then_content', targets: ['tag'] }, + { value: 'tag_then_none', targets: ['tag'] }, + ] + + beforeAll(async () => { + agent = new BskyAgent({ service: network.pds.url }) + await agent.createAccount({ + handle: 'user7.test', + email: 'user7@test.com', + password: 'password', + }) + }) + + it('upsertMutedWords', async () => { + await agent.upsertMutedWords(mutedWords) + await agent.upsertMutedWords(mutedWords) // double + await expect(agent.getPreferences()).resolves.toHaveProperty( + 'mutedWords', + mutedWords, + ) + }) + + it('upsertMutedWords with #', async () => { + await agent.upsertMutedWords([ + { value: 'hashtag', targets: ['content'] }, + ]) + await agent.upsertMutedWords([{ value: '#hashtag', targets: ['tag'] }]) + const { mutedWords } = await agent.getPreferences() + expect(mutedWords.find((m) => m.value === '#hashtag')).toBeFalsy() + expect(mutedWords.find((m) => m.value === 'hashtag')).toStrictEqual({ + value: 'hashtag', + targets: ['content', 'tag'], + }) + expect(mutedWords.filter((m) => m.value === 'hashtag').length).toBe(1) + }) + + it('updateMutedWord', async () => { + await agent.updateMutedWord({ + value: 'tag_then_content', + targets: ['content'], + }) + await agent.updateMutedWord({ + value: 'tag_then_both', + targets: ['content', 'tag'], + }) + await agent.updateMutedWord({ value: 'tag_then_none', targets: [] }) + await agent.updateMutedWord({ value: 'no_exist', targets: ['tag'] }) + const { mutedWords } = await agent.getPreferences() + + expect( + mutedWords.find((m) => m.value === 'tag_then_content'), + ).toHaveProperty('targets', ['content']) + expect( + mutedWords.find((m) => m.value === 'tag_then_both'), + ).toHaveProperty('targets', ['content', 'tag']) + expect( + mutedWords.find((m) => m.value === 'tag_then_none'), + ).toHaveProperty('targets', []) + expect(mutedWords.find((m) => m.value === 'no_exist')).toBeFalsy() + }) + + it('updateMutedWord with #', async () => { + await agent.updateMutedWord({ + value: 'hashtag', + targets: ['tag', 'content'], + }) + const { mutedWords } = await agent.getPreferences() + expect(mutedWords.find((m) => m.value === 'hashtag')).toStrictEqual({ + value: 'hashtag', + targets: ['tag', 'content'], + }) + }) + + it('removeMutedWord', async () => { + await agent.removeMutedWord({ value: 'tag_then_content', targets: [] }) + await agent.removeMutedWord({ value: 'tag_then_both', targets: [] }) + await agent.removeMutedWord({ value: 'tag_then_none', targets: [] }) + const { mutedWords } = await agent.getPreferences() + + expect( + mutedWords.find((m) => m.value === 'tag_then_content'), + ).toBeFalsy() + expect(mutedWords.find((m) => m.value === 'tag_then_both')).toBeFalsy() + expect(mutedWords.find((m) => m.value === 'tag_then_none')).toBeFalsy() + }) + + it('removeMutedWord with #', async () => { + await agent.removeMutedWord({ value: '#hashtag', targets: [] }) + const { mutedWords } = await agent.getPreferences() + + expect(mutedWords.find((m) => m.value === 'hashtag')).toBeFalsy() + }) + }) + + describe('hidden posts', () => { + let agent: BskyAgent + const postUri = 'at://did:plc:fake/app.bsky.feed.post/fake' + + beforeAll(async () => { + agent = new BskyAgent({ service: network.pds.url }) + await agent.createAccount({ + handle: 'user8.test', + email: 'user8@test.com', + password: 'password', + }) + }) + + it('hidePost', async () => { + await agent.hidePost(postUri) + await agent.hidePost(postUri) // double, should dedupe + await expect(agent.getPreferences()).resolves.toHaveProperty( + 'hiddenPosts', + [postUri], + ) + }) + + it('unhidePost', async () => { + await agent.unhidePost(postUri) + await expect(agent.getPreferences()).resolves.toHaveProperty( + 'hiddenPosts', + [], + ) + // no issues calling a second time + await agent.unhidePost(postUri) + await expect(agent.getPreferences()).resolves.toHaveProperty( + 'hiddenPosts', + [], + ) + }) + }) + + // end }) }) diff --git a/packages/aws/CHANGELOG.md b/packages/aws/CHANGELOG.md index b804e0719e4..f8f0c521f18 100644 --- a/packages/aws/CHANGELOG.md +++ b/packages/aws/CHANGELOG.md @@ -1,5 +1,12 @@ # @atproto/aws +## 0.1.7 + +### Patch Changes + +- Updated dependencies [[`fcf8e3faf`](https://github.com/bluesky-social/atproto/commit/fcf8e3faf311559162c3aa0d9af36f84951914bc)]: + - @atproto/repo@0.3.7 + ## 0.1.6 ### Patch Changes diff --git a/packages/aws/package.json b/packages/aws/package.json index 949cfaa845e..55638b88552 100644 --- a/packages/aws/package.json +++ b/packages/aws/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/aws", - "version": "0.1.6", + "version": "0.1.7", "license": "MIT", "description": "Shared AWS cloud API helpers for atproto services", "keywords": [ diff --git a/packages/bsky/CHANGELOG.md b/packages/bsky/CHANGELOG.md index 24fa1992926..91a5493cb3f 100644 --- a/packages/bsky/CHANGELOG.md +++ b/packages/bsky/CHANGELOG.md @@ -1,5 +1,55 @@ # @atproto/bsky +## 0.0.33 + +### Patch Changes + +- Updated dependencies [[`514aab92d`](https://github.com/bluesky-social/atproto/commit/514aab92d26acd43859285f46318e386846522b1)]: + - @atproto/api@0.10.1 + +## 0.0.32 + +### Patch Changes + +- Updated dependencies [[`b60719480`](https://github.com/bluesky-social/atproto/commit/b60719480f5f00bffd074a40e8ddc03aa93d137d), [`4c511b3d9`](https://github.com/bluesky-social/atproto/commit/4c511b3d9de41ffeae3fc11db941e7df04f4468a)]: + - @atproto/api@0.10.0 + +## 0.0.31 + +### Patch Changes + +- Updated dependencies [[`f79cc6339`](https://github.com/bluesky-social/atproto/commit/f79cc63390ae9dbd47a4ff5d694eec25b78b788e)]: + - @atproto/api@0.9.8 + +## 0.0.30 + +### Patch Changes + +- Updated dependencies [[`fcf8e3faf`](https://github.com/bluesky-social/atproto/commit/fcf8e3faf311559162c3aa0d9af36f84951914bc), [`8c94979f7`](https://github.com/bluesky-social/atproto/commit/8c94979f73fc5057449e24e66ef2e09b0e17e55b)]: + - @atproto/repo@0.3.7 + - @atproto/api@0.9.7 + +## 0.0.29 + +### Patch Changes + +- Updated dependencies [[`e4ec7af03`](https://github.com/bluesky-social/atproto/commit/e4ec7af03608949fc3b00a845f547a77599b5ad0)]: + - @atproto/api@0.9.6 + +## 0.0.28 + +### Patch Changes + +- Updated dependencies [[`8994d363`](https://github.com/bluesky-social/atproto/commit/8994d3633adad1c02569d6d44ae896e18195e8e2)]: + - @atproto/api@0.9.5 + +## 0.0.27 + +### Patch Changes + +- Updated dependencies [[`4171c04a`](https://github.com/bluesky-social/atproto/commit/4171c04ad81c5734a4558bc41fa1c4f3a1aba18c)]: + - @atproto/api@0.9.4 + ## 0.0.26 ### Patch Changes diff --git a/packages/bsky/package.json b/packages/bsky/package.json index ebe149d859f..099501296ed 100644 --- a/packages/bsky/package.json +++ b/packages/bsky/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/bsky", - "version": "0.0.26", + "version": "0.0.33", "license": "MIT", "description": "Reference implementation of app.bsky App View (Bluesky API)", "keywords": [ @@ -54,6 +54,7 @@ "http-errors": "^2.0.0", "http-terminator": "^3.2.0", "ioredis": "^5.3.2", + "jose": "^5.0.1", "kysely": "^0.22.0", "multiformats": "^9.9.0", "murmurhash": "^2.0.1", diff --git a/packages/bsky/src/api/app/bsky/feed/getFeed.ts b/packages/bsky/src/api/app/bsky/feed/getFeed.ts index 00dd417ce3b..aae633e4f2a 100644 --- a/packages/bsky/src/api/app/bsky/feed/getFeed.ts +++ b/packages/bsky/src/api/app/bsky/feed/getFeed.ts @@ -43,7 +43,6 @@ export default function (server: Server, ctx: AppContext) { authorization: req.headers['authorization'], 'accept-language': req.headers['accept-language'], }) - // @NOTE feed cursors should not be affected by appview swap const { timerSkele, timerHydr, resHeaders, ...result } = await getFeed( { ...params, viewer, headers }, diff --git a/packages/bsky/src/data-plane/server/subscription/index.ts b/packages/bsky/src/data-plane/server/subscription/index.ts index dddc07aa39c..a020eb0542d 100644 --- a/packages/bsky/src/data-plane/server/subscription/index.ts +++ b/packages/bsky/src/data-plane/server/subscription/index.ts @@ -100,6 +100,8 @@ export class RepoSubscription { await this.handleCommit(msg) } else if (message.isHandle(msg)) { await this.handleUpdateHandle(msg) + } else if (message.isIdentity(msg)) { + await this.handleIdentityEvt(msg) } else if (message.isTombstone(msg)) { await this.handleTombstone(msg) } else if (message.isMigrate(msg)) { @@ -192,6 +194,10 @@ export class RepoSubscription { await this.indexingSvc.indexHandle(msg.did, msg.time, true) } + private async handleIdentityEvt(msg: message.Identity) { + await this.indexingSvc.indexHandle(msg.did, msg.time, true) + } + private async handleTombstone(msg: message.Tombstone) { await this.indexingSvc.tombstoneActor(msg.did) } @@ -262,6 +268,8 @@ function getMessageDetails(msg: Message): return { seq: msg.seq, repo: msg.repo, message: msg } } else if (message.isHandle(msg)) { return { seq: msg.seq, repo: msg.did, message: msg } + } else if (message.isIdentity(msg)) { + return { seq: msg.seq, repo: msg.did, message: msg } } else if (message.isMigrate(msg)) { return { seq: msg.seq, repo: msg.did, message: msg } } else if (message.isTombstone(msg)) { diff --git a/packages/bsky/src/data-plane/server/subscription/util.ts b/packages/bsky/src/data-plane/server/subscription/util.ts index ff04eae4f50..40bf30f73c8 100644 --- a/packages/bsky/src/data-plane/server/subscription/util.ts +++ b/packages/bsky/src/data-plane/server/subscription/util.ts @@ -108,6 +108,7 @@ export class PerfectMap extends Map { export type ProcessableMessage = | message.Commit | message.Handle + | message.Identity | message.Migrate | message.Tombstone @@ -127,6 +128,8 @@ export function loggableMessage(msg: RepoMessage) { } } else if (message.isHandle(msg)) { return msg + } else if (message.isIdentity(msg)) { + return msg } else if (message.isMigrate(msg)) { return msg } else if (message.isTombstone(msg)) { diff --git a/packages/bsky/src/lexicon/index.ts b/packages/bsky/src/lexicon/index.ts index 0e30f4d172c..cf2c613e686 100644 --- a/packages/bsky/src/lexicon/index.ts +++ b/packages/bsky/src/lexicon/index.ts @@ -30,9 +30,14 @@ import * as ComAtprotoAdminSearchRepos from './types/com/atproto/admin/searchRep import * as ComAtprotoAdminSendEmail from './types/com/atproto/admin/sendEmail' import * as ComAtprotoAdminUpdateAccountEmail from './types/com/atproto/admin/updateAccountEmail' import * as ComAtprotoAdminUpdateAccountHandle from './types/com/atproto/admin/updateAccountHandle' +import * as ComAtprotoAdminUpdateAccountPassword from './types/com/atproto/admin/updateAccountPassword' import * as ComAtprotoAdminUpdateCommunicationTemplate from './types/com/atproto/admin/updateCommunicationTemplate' import * as ComAtprotoAdminUpdateSubjectStatus from './types/com/atproto/admin/updateSubjectStatus' +import * as ComAtprotoIdentityGetRecommendedDidCredentials from './types/com/atproto/identity/getRecommendedDidCredentials' +import * as ComAtprotoIdentityRequestPlcOperationSignature from './types/com/atproto/identity/requestPlcOperationSignature' import * as ComAtprotoIdentityResolveHandle from './types/com/atproto/identity/resolveHandle' +import * as ComAtprotoIdentitySignPlcOperation from './types/com/atproto/identity/signPlcOperation' +import * as ComAtprotoIdentitySubmitPlcOperation from './types/com/atproto/identity/submitPlcOperation' import * as ComAtprotoIdentityUpdateHandle from './types/com/atproto/identity/updateHandle' import * as ComAtprotoLabelQueryLabels from './types/com/atproto/label/queryLabels' import * as ComAtprotoLabelSubscribeLabels from './types/com/atproto/label/subscribeLabels' @@ -42,19 +47,25 @@ import * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createReco import * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord' import * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo' import * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord' +import * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo' +import * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs' import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords' import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord' import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob' +import * as ComAtprotoServerActivateAccount from './types/com/atproto/server/activateAccount' +import * as ComAtprotoServerCheckAccountStatus from './types/com/atproto/server/checkAccountStatus' import * as ComAtprotoServerConfirmEmail from './types/com/atproto/server/confirmEmail' import * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount' import * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword' import * as ComAtprotoServerCreateInviteCode from './types/com/atproto/server/createInviteCode' import * as ComAtprotoServerCreateInviteCodes from './types/com/atproto/server/createInviteCodes' import * as ComAtprotoServerCreateSession from './types/com/atproto/server/createSession' +import * as ComAtprotoServerDeactivateAccount from './types/com/atproto/server/deactivateAccount' import * as ComAtprotoServerDeleteAccount from './types/com/atproto/server/deleteAccount' import * as ComAtprotoServerDeleteSession from './types/com/atproto/server/deleteSession' import * as ComAtprotoServerDescribeServer from './types/com/atproto/server/describeServer' import * as ComAtprotoServerGetAccountInviteCodes from './types/com/atproto/server/getAccountInviteCodes' +import * as ComAtprotoServerGetServiceAuth from './types/com/atproto/server/getServiceAuth' import * as ComAtprotoServerGetSession from './types/com/atproto/server/getSession' import * as ComAtprotoServerListAppPasswords from './types/com/atproto/server/listAppPasswords' import * as ComAtprotoServerRefreshSession from './types/com/atproto/server/refreshSession' @@ -78,11 +89,9 @@ import * as ComAtprotoSyncListRepos from './types/com/atproto/sync/listRepos' import * as ComAtprotoSyncNotifyOfUpdate from './types/com/atproto/sync/notifyOfUpdate' import * as ComAtprotoSyncRequestCrawl from './types/com/atproto/sync/requestCrawl' import * as ComAtprotoSyncSubscribeRepos from './types/com/atproto/sync/subscribeRepos' +import * as ComAtprotoTempCheckSignupQueue from './types/com/atproto/temp/checkSignupQueue' import * as ComAtprotoTempFetchLabels from './types/com/atproto/temp/fetchLabels' -import * as ComAtprotoTempImportRepo from './types/com/atproto/temp/importRepo' -import * as ComAtprotoTempPushBlob from './types/com/atproto/temp/pushBlob' import * as ComAtprotoTempRequestPhoneVerification from './types/com/atproto/temp/requestPhoneVerification' -import * as ComAtprotoTempTransferAccount from './types/com/atproto/temp/transferAccount' import * as AppBskyActorGetPreferences from './types/app/bsky/actor/getPreferences' import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile' import * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles' @@ -126,7 +135,6 @@ import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/ import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen' import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' import * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions' -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' @@ -437,6 +445,17 @@ export class ComAtprotoAdminNS { return this._server.xrpc.method(nsid, cfg) } + updateAccountPassword( + cfg: ConfigOf< + AV, + ComAtprotoAdminUpdateAccountPassword.Handler>, + ComAtprotoAdminUpdateAccountPassword.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.admin.updateAccountPassword' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + updateCommunicationTemplate( cfg: ConfigOf< AV, @@ -467,6 +486,32 @@ export class ComAtprotoIdentityNS { this._server = server } + getRecommendedDidCredentials( + cfg: ConfigOf< + AV, + ComAtprotoIdentityGetRecommendedDidCredentials.Handler>, + ComAtprotoIdentityGetRecommendedDidCredentials.HandlerReqCtx< + ExtractAuth + > + >, + ) { + const nsid = 'com.atproto.identity.getRecommendedDidCredentials' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + requestPlcOperationSignature( + cfg: ConfigOf< + AV, + ComAtprotoIdentityRequestPlcOperationSignature.Handler>, + ComAtprotoIdentityRequestPlcOperationSignature.HandlerReqCtx< + ExtractAuth + > + >, + ) { + const nsid = 'com.atproto.identity.requestPlcOperationSignature' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + resolveHandle( cfg: ConfigOf< AV, @@ -478,6 +523,28 @@ export class ComAtprotoIdentityNS { return this._server.xrpc.method(nsid, cfg) } + signPlcOperation( + cfg: ConfigOf< + AV, + ComAtprotoIdentitySignPlcOperation.Handler>, + ComAtprotoIdentitySignPlcOperation.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.identity.signPlcOperation' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + submitPlcOperation( + cfg: ConfigOf< + AV, + ComAtprotoIdentitySubmitPlcOperation.Handler>, + ComAtprotoIdentitySubmitPlcOperation.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.identity.submitPlcOperation' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + updateHandle( cfg: ConfigOf< AV, @@ -601,6 +668,28 @@ export class ComAtprotoRepoNS { return this._server.xrpc.method(nsid, cfg) } + importRepo( + cfg: ConfigOf< + AV, + ComAtprotoRepoImportRepo.Handler>, + ComAtprotoRepoImportRepo.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.repo.importRepo' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + listMissingBlobs( + cfg: ConfigOf< + AV, + ComAtprotoRepoListMissingBlobs.Handler>, + ComAtprotoRepoListMissingBlobs.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.repo.listMissingBlobs' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + listRecords( cfg: ConfigOf< AV, @@ -642,6 +731,28 @@ export class ComAtprotoServerNS { this._server = server } + activateAccount( + cfg: ConfigOf< + AV, + ComAtprotoServerActivateAccount.Handler>, + ComAtprotoServerActivateAccount.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.activateAccount' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + checkAccountStatus( + cfg: ConfigOf< + AV, + ComAtprotoServerCheckAccountStatus.Handler>, + ComAtprotoServerCheckAccountStatus.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.checkAccountStatus' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + confirmEmail( cfg: ConfigOf< AV, @@ -708,6 +819,17 @@ export class ComAtprotoServerNS { return this._server.xrpc.method(nsid, cfg) } + deactivateAccount( + cfg: ConfigOf< + AV, + ComAtprotoServerDeactivateAccount.Handler>, + ComAtprotoServerDeactivateAccount.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.deactivateAccount' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + deleteAccount( cfg: ConfigOf< AV, @@ -752,6 +874,17 @@ export class ComAtprotoServerNS { return this._server.xrpc.method(nsid, cfg) } + getServiceAuth( + cfg: ConfigOf< + AV, + ComAtprotoServerGetServiceAuth.Handler>, + ComAtprotoServerGetServiceAuth.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.getServiceAuth' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getSession( cfg: ConfigOf< AV, @@ -1021,36 +1154,25 @@ export class ComAtprotoTempNS { this._server = server } - fetchLabels( - cfg: ConfigOf< - AV, - ComAtprotoTempFetchLabels.Handler>, - ComAtprotoTempFetchLabels.HandlerReqCtx> - >, - ) { - const nsid = 'com.atproto.temp.fetchLabels' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } - - importRepo( + checkSignupQueue( cfg: ConfigOf< AV, - ComAtprotoTempImportRepo.Handler>, - ComAtprotoTempImportRepo.HandlerReqCtx> + ComAtprotoTempCheckSignupQueue.Handler>, + ComAtprotoTempCheckSignupQueue.HandlerReqCtx> >, ) { - const nsid = 'com.atproto.temp.importRepo' // @ts-ignore + const nsid = 'com.atproto.temp.checkSignupQueue' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - pushBlob( + fetchLabels( cfg: ConfigOf< AV, - ComAtprotoTempPushBlob.Handler>, - ComAtprotoTempPushBlob.HandlerReqCtx> + ComAtprotoTempFetchLabels.Handler>, + ComAtprotoTempFetchLabels.HandlerReqCtx> >, ) { - const nsid = 'com.atproto.temp.pushBlob' // @ts-ignore + const nsid = 'com.atproto.temp.fetchLabels' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } @@ -1064,17 +1186,6 @@ export class ComAtprotoTempNS { const nsid = 'com.atproto.temp.requestPhoneVerification' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - - transferAccount( - cfg: ConfigOf< - AV, - ComAtprotoTempTransferAccount.Handler>, - ComAtprotoTempTransferAccount.HandlerReqCtx> - >, - ) { - const nsid = 'com.atproto.temp.transferAccount' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } } export class AppNS { @@ -1637,17 +1748,6 @@ export class AppBskyUnspeccedNS { return this._server.xrpc.method(nsid, cfg) } - getTimelineSkeleton( - cfg: ConfigOf< - AV, - AppBskyUnspeccedGetTimelineSkeleton.Handler>, - AppBskyUnspeccedGetTimelineSkeleton.HandlerReqCtx> - >, - ) { - const nsid = 'app.bsky.unspecced.getTimelineSkeleton' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } - searchActorsSkeleton( cfg: ConfigOf< AV, diff --git a/packages/bsky/src/lexicon/lexicons.ts b/packages/bsky/src/lexicon/lexicons.ts index fea624e9a04..14e4c1cb81e 100644 --- a/packages/bsky/src/lexicon/lexicons.ts +++ b/packages/bsky/src/lexicon/lexicons.ts @@ -91,6 +91,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, subject: { @@ -147,6 +148,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventAcknowledge', 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', + 'lex:com.atproto.admin.defs#modEventEmail', 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, @@ -301,6 +303,12 @@ export const schemaDict = { type: 'string', format: 'datetime', }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, }, }, reportViewDetail: { @@ -895,6 +903,33 @@ export const schemaDict = { }, }, }, + modEventTag: { + type: 'object', + description: 'Add/Remove a tag on a subject', + required: ['add', 'remove'], + properties: { + add: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be added to the subject. If already exists, won't be duplicated.", + }, + remove: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated.", + }, + comment: { + type: 'string', + description: 'Additional comment about added/removed tags.', + }, + }, + }, communicationTemplateView: { type: 'object', required: [ @@ -1073,6 +1108,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventReverseTakedown', 'lex:com.atproto.admin.defs#modEventUnmute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventTag', ], }, subject: { @@ -1450,6 +1486,16 @@ export const schemaDict = { description: 'Sort direction for the events. Defaults to descending order of created at timestamp.', }, + createdAfter: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created after a given timestamp', + }, + createdBefore: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created before a given timestamp', + }, subject: { type: 'string', format: 'uri', @@ -1466,6 +1512,53 @@ export const schemaDict = { maximum: 100, default: 50, }, + hasComment: { + type: 'boolean', + description: 'If true, only events with comments are returned', + }, + comment: { + type: 'string', + description: + 'If specified, only events with comments containing the keyword are returned', + }, + addedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were added are returned', + }, + removedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were removed are returned', + }, + addedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were added are returned', + }, + removedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were removed are returned', + }, + reportTypes: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1577,6 +1670,18 @@ export const schemaDict = { maximum: 100, default: 50, }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, + excludeTags: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1758,6 +1863,33 @@ export const schemaDict = { }, }, }, + ComAtprotoAdminUpdateAccountPassword: { + lexicon: 1, + id: 'com.atproto.admin.updateAccountPassword', + defs: { + main: { + type: 'procedure', + description: + 'Update the password for a user account as an administrator.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['did', 'password'], + properties: { + did: { + type: 'string', + format: 'did', + }, + password: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoAdminUpdateCommunicationTemplate: { lexicon: 1, id: 'com.atproto.admin.updateCommunicationTemplate', @@ -1863,13 +1995,63 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentityGetRecommendedDidCredentials: { + lexicon: 1, + id: 'com.atproto.identity.getRecommendedDidCredentials', + defs: { + main: { + type: 'query', + description: + 'Describe the credentials that should be included in the DID doc of an account that is migrating to this service.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + rotationKeys: { + description: + 'Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs.', + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentityRequestPlcOperationSignature: { + lexicon: 1, + id: 'com.atproto.identity.requestPlcOperationSignature', + defs: { + main: { + type: 'procedure', + description: + 'Request an email with a code to in order to request a signed PLC operation. Requires Auth.', + }, + }, + }, ComAtprotoIdentityResolveHandle: { lexicon: 1, id: 'com.atproto.identity.resolveHandle', defs: { main: { type: 'query', - description: 'Provides the DID of a repo.', + description: 'Resolves a handle (domain name) to a DID.', parameters: { type: 'params', required: ['handle'], @@ -1897,13 +2079,92 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentitySignPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.signPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Signs a PLC operation to update some value(s) in the requesting DID's document.", + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + token: { + description: + 'A token received through com.atproto.identity.requestPlcOperationSignature', + type: 'string', + }, + rotationKeys: { + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + description: 'A signed DID PLC operation.', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentitySubmitPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.submitPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Validates a PLC operation to ensure that it doesn't violate a service's constraints or get the identity into a bad state, then submits it to the PLC registry", + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, ComAtprotoIdentityUpdateHandle: { lexicon: 1, id: 'com.atproto.identity.updateHandle', defs: { main: { type: 'procedure', - description: 'Updates the handle of the account.', + description: + "Updates the current account's handle. Verifies handle validity, and updates did:plc document if necessary. Implemented by PDS, and requires auth.", input: { encoding: 'application/json', schema: { @@ -1913,6 +2174,7 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'The new handle.', }, }, }, @@ -2003,7 +2265,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find labels relevant to the provided URI patterns.', + description: + 'Find labels relevant to the provided AT-URI patterns. Public endpoint for moderation services, though may return different or additional results with auth.', parameters: { type: 'params', required: ['uriPatterns'], @@ -2064,13 +2327,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to label updates.', + description: + 'Subscribe to stream of labels (and negations). Public endpoint implemented by mod services. Uses same sequencing scheme as repo event stream.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -2126,7 +2390,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Report a repo or a record.', + description: + 'Submit a moderation report regarding an atproto account or record. Implemented by moderation services (with PDS proxying), and requires auth.', input: { encoding: 'application/json', schema: { @@ -2135,10 +2400,14 @@ export const schemaDict = { properties: { reasonType: { type: 'ref', + description: + 'Indicates the broad category of violation the report is for.', ref: 'lex:com.atproto.moderation.defs#reasonType', }, reason: { type: 'string', + description: + 'Additional context about the content and violation.', }, subject: { type: 'union', @@ -2249,7 +2518,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Apply a batch transaction of creates, updates, and deletes.', + 'Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2259,12 +2528,14 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the records.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data, for all operations.", }, writes: { type: 'array', @@ -2280,6 +2551,8 @@ export const schemaDict = { }, swapCommit: { type: 'string', + description: + 'If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.', format: 'cid', }, }, @@ -2288,12 +2561,14 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that the 'swapCommit' parameter did not match current commit.", }, ], }, create: { type: 'object', - description: 'Create a new record.', + description: 'Operation which creates a new record.', required: ['collection', 'value'], properties: { collection: { @@ -2311,7 +2586,7 @@ export const schemaDict = { }, update: { type: 'object', - description: 'Update an existing record.', + description: 'Operation which updates an existing record.', required: ['collection', 'rkey', 'value'], properties: { collection: { @@ -2328,7 +2603,7 @@ export const schemaDict = { }, delete: { type: 'object', - description: 'Delete an existing record.', + description: 'Operation which deletes an existing record.', required: ['collection', 'rkey'], properties: { collection: { @@ -2348,7 +2623,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create a new record.', + description: + 'Create a single new repository record. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2358,7 +2634,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2367,17 +2644,18 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', - description: 'The record to create.', + description: 'The record itself. Must contain a $type field.', }, swapCommit: { type: 'string', @@ -2408,6 +2686,8 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that 'swapCommit' didn't match current repo commit.", }, ], }, @@ -2419,7 +2699,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete a record, or ensure it doesn't exist.", + description: + "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", input: { encoding: 'application/json', schema: { @@ -2429,7 +2710,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2438,7 +2720,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, swapRecord: { type: 'string', @@ -2470,7 +2752,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about the repo, including the list of collections.', + 'Get information about an account and repository, including the list of collections. Does not require auth.', parameters: { type: 'params', required: ['repo'], @@ -2504,9 +2786,12 @@ export const schemaDict = { }, didDoc: { type: 'unknown', + description: 'The complete DID document for this account.', }, collections: { type: 'array', + description: + 'List of all the collections (NSIDs) for which this repo contains at least one record.', items: { type: 'string', format: 'nsid', @@ -2514,6 +2799,8 @@ export const schemaDict = { }, handleIsCorrect: { type: 'boolean', + description: + 'Indicates if handle is currently valid (resolves bi-directionally)', }, }, }, @@ -2527,7 +2814,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a record.', + description: + 'Get a single record from a repository. Does not require auth.', parameters: { type: 'params', required: ['repo', 'collection', 'rkey'], @@ -2544,7 +2832,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, cid: { type: 'string', @@ -2577,39 +2865,112 @@ export const schemaDict = { }, }, }, - ComAtprotoRepoListRecords: { + ComAtprotoRepoImportRepo: { lexicon: 1, - id: 'com.atproto.repo.listRecords', + id: 'com.atproto.repo.importRepo', + defs: { + main: { + type: 'procedure', + description: + 'Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.', + input: { + encoding: 'application/vnd.ipld.car', + }, + }, + }, + }, + ComAtprotoRepoListMissingBlobs: { + lexicon: 1, + id: 'com.atproto.repo.listMissingBlobs', defs: { main: { type: 'query', - description: 'List a range of records in a collection.', + description: + 'Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.', parameters: { type: 'params', - required: ['repo', 'collection'], properties: { - repo: { - type: 'string', - format: 'at-identifier', - description: 'The handle or DID of the repo.', - }, - collection: { - type: 'string', - format: 'nsid', - description: 'The NSID of the record type.', - }, limit: { type: 'integer', minimum: 1, - maximum: 100, - default: 50, - description: 'The number of records to return.', + maximum: 1000, + default: 500, }, cursor: { type: 'string', }, - rkeyStart: { - type: 'string', + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['blobs'], + properties: { + cursor: { + type: 'string', + }, + blobs: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.repo.listMissingBlobs#recordBlob', + }, + }, + }, + }, + }, + }, + recordBlob: { + type: 'object', + required: ['cid', 'recordUri'], + properties: { + cid: { + type: 'string', + format: 'cid', + }, + recordUri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + }, + }, + ComAtprotoRepoListRecords: { + lexicon: 1, + id: 'com.atproto.repo.listRecords', + defs: { + main: { + type: 'query', + description: + 'List a range of records in a repository, matching a specific collection. Does not require auth.', + parameters: { + type: 'params', + required: ['repo', 'collection'], + properties: { + repo: { + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', + }, + collection: { + type: 'string', + format: 'nsid', + description: 'The NSID of the record type.', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + description: 'The number of records to return.', + }, + cursor: { + type: 'string', + }, + rkeyStart: { + type: 'string', description: 'DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)', }, @@ -2669,7 +3030,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Write a record, creating or updating it as needed.', + description: + 'Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2680,7 +3042,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2689,13 +3052,14 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', @@ -2705,7 +3069,7 @@ export const schemaDict = { type: 'string', format: 'cid', description: - 'Compare and swap with the previous record by CID.', + 'Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation', }, swapCommit: { type: 'string', @@ -2769,7 +3133,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Upload a new blob to be added to repo in a later request.', + 'Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.', input: { encoding: '*/*', }, @@ -2788,6 +3152,75 @@ export const schemaDict = { }, }, }, + ComAtprotoServerActivateAccount: { + lexicon: 1, + id: 'com.atproto.server.activateAccount', + defs: { + main: { + type: 'procedure', + description: + "Activates a currently deactivated account. Used to finalize account migration after the account's repo is imported and identity is setup.", + }, + }, + }, + ComAtprotoServerCheckAccountStatus: { + lexicon: 1, + id: 'com.atproto.server.checkAccountStatus', + defs: { + main: { + type: 'query', + description: + 'Returns the status of an account, especially as pertaining to import or recovery. Can be called many times over the course of an account migration. Requires auth and can only be called pertaining to oneself.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: [ + 'activated', + 'validDid', + 'repoCommit', + 'repoRev', + 'repoBlocks', + 'indexedRecords', + 'privateStateValues', + 'expectedBlobs', + 'importedBlobs', + ], + properties: { + activated: { + type: 'boolean', + }, + validDid: { + type: 'boolean', + }, + repoCommit: { + type: 'string', + format: 'cid', + }, + repoRev: { + type: 'string', + }, + repoBlocks: { + type: 'integer', + }, + indexedRecords: { + type: 'integer', + }, + privateStateValues: { + type: 'integer', + }, + expectedBlobs: { + type: 'integer', + }, + importedBlobs: { + type: 'integer', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerConfirmEmail: { lexicon: 1, id: 'com.atproto.server.confirmEmail', @@ -2834,7 +3267,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create an account.', + description: 'Create an account. Implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2847,10 +3280,13 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'Requested handle for the account.', }, did: { type: 'string', format: 'did', + description: + 'Pre-existing atproto DID, being imported to a new account.', }, inviteCode: { type: 'string', @@ -2863,12 +3299,18 @@ export const schemaDict = { }, password: { type: 'string', + description: + 'Initial account password. May need to meet instance-specific password strength requirements.', }, recoveryKey: { type: 'string', + description: + 'DID PLC rotation key (aka, recovery key) to be included in PLC creation operation.', }, plcOp: { type: 'unknown', + description: + 'A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented.', }, }, }, @@ -2877,6 +3319,8 @@ export const schemaDict = { encoding: 'application/json', schema: { type: 'object', + description: + 'Account login session returned on successful account creation.', required: ['accessJwt', 'refreshJwt', 'handle', 'did'], properties: { accessJwt: { @@ -2892,9 +3336,11 @@ export const schemaDict = { did: { type: 'string', format: 'did', + description: 'The DID of the new account.', }, didDoc: { type: 'unknown', + description: 'Complete DID document.', }, }, }, @@ -2940,6 +3386,8 @@ export const schemaDict = { properties: { name: { type: 'string', + description: + 'A short name for the App Password, to help distinguish them.', }, }, }, @@ -3141,6 +3589,31 @@ export const schemaDict = { }, }, }, + ComAtprotoServerDeactivateAccount: { + lexicon: 1, + id: 'com.atproto.server.deactivateAccount', + defs: { + main: { + type: 'procedure', + description: + 'Deactivates a currently active account. Stops serving of repo, and future writes to repo until reactivated. Used to finalize account migration with the old host after the account has been activated on the new host.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + deleteAfter: { + type: 'string', + format: 'datetime', + description: + 'A recommendation to server as to how long they should hold onto the deactivated account before deleting.', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerDefs: { lexicon: 1, id: 'com.atproto.server.defs', @@ -3207,7 +3680,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete an actor's account with a token and password.", + description: + "Delete an actor's account with a token and password. Can only be called after requesting a deletion token. Requires auth.", input: { encoding: 'application/json', schema: { @@ -3244,7 +3718,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Delete the current session.', + description: 'Delete the current session. Requires auth.', }, }, }, @@ -3255,29 +3729,40 @@ export const schemaDict = { main: { type: 'query', description: - "Get a document describing the service's accounts configuration.", + "Describes the server's account creation requirements and capabilities. Implemented by PDS.", output: { encoding: 'application/json', schema: { type: 'object', - required: ['availableUserDomains'], + required: ['did', 'availableUserDomains'], properties: { inviteCodeRequired: { type: 'boolean', + description: + 'If true, an invite code must be supplied to create an account on this instance.', }, phoneVerificationRequired: { type: 'boolean', + description: + 'If true, a phone verification token must be supplied to create an account on this instance.', }, availableUserDomains: { type: 'array', + description: + 'List of domain suffixes that can be used in account handles.', items: { type: 'string', }, }, links: { type: 'ref', + description: 'URLs of service policy documents.', ref: 'lex:com.atproto.server.describeServer#links', }, + did: { + type: 'string', + format: 'did', + }, }, }, }, @@ -3301,7 +3786,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get all invite codes for a given account.', + description: + 'Get all invite codes for the current account. Requires auth.', parameters: { type: 'params', properties: { @@ -3312,6 +3798,8 @@ export const schemaDict = { createAvailable: { type: 'boolean', default: true, + description: + "Controls whether any new 'earned' but not 'created' invites should be created.", }, }, }, @@ -3339,13 +3827,49 @@ export const schemaDict = { }, }, }, + ComAtprotoServerGetServiceAuth: { + lexicon: 1, + id: 'com.atproto.server.getServiceAuth', + defs: { + main: { + type: 'query', + description: + 'Get a signed token on behalf of the requesting DID for the requested service.', + parameters: { + type: 'params', + required: ['aud'], + properties: { + aud: { + type: 'string', + format: 'did', + description: + 'The DID of the service that the token will be used to authenticate with', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['token'], + properties: { + token: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerGetSession: { lexicon: 1, id: 'com.atproto.server.getSession', defs: { main: { type: 'query', - description: 'Get information about the current session.', + description: + 'Get information about the current auth session. Requires auth.', output: { encoding: 'application/json', schema: { @@ -3425,7 +3949,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Refresh an authentication session.', + description: + "Refresh an authentication session. Requires auth using the 'refreshJwt' (not the 'accessJwt').", output: { encoding: 'application/json', schema: { @@ -3531,7 +4056,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Reserve a repo signing key for account creation.', + description: + 'Reserve a repo signing key, for use with account creation. Necessary so that a DID PLC update operation can be constructed during an account migraiton. Public and does not require auth; implemented by PDS. NOTE: this endpoint may change when full account migration is implemented.', input: { encoding: 'application/json', schema: { @@ -3539,7 +4065,8 @@ export const schemaDict = { properties: { did: { type: 'string', - description: 'The did to reserve a new did:key for', + format: 'did', + description: 'The DID to reserve a key for.', }, }, }, @@ -3552,7 +4079,8 @@ export const schemaDict = { properties: { signingKey: { type: 'string', - description: 'Public signing key in the form of a did:key.', + description: + 'The public key for the reserved signing key, in did:key serialization.', }, }, }, @@ -3659,7 +4187,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a blob associated with a given repo.', + description: + 'Get a blob associated with a given account. Returns the full blob as originally uploaded. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cid'], @@ -3667,7 +4196,7 @@ export const schemaDict = { did: { type: 'string', format: 'did', - description: 'The DID of the repo.', + description: 'The DID of the account.', }, cid: { type: 'string', @@ -3688,7 +4217,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get blocks from a given repo.', + description: + 'Get data blocks from a given repo, by CID. For example, intermediate MST nodes, or records. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cids'], @@ -3783,7 +4313,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the current commit CID & revision of the repo.', + description: + 'Get the current commit CID & revision of the specified repo. Does not require auth.', parameters: { type: 'params', required: ['did'], @@ -3826,7 +4357,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get blocks needed for existence or non-existence of record.', + 'Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.', parameters: { type: 'params', required: ['did', 'collection', 'rkey'], @@ -3842,6 +4373,7 @@ export const schemaDict = { }, rkey: { type: 'string', + description: 'Record Key', }, commit: { type: 'string', @@ -3863,7 +4395,7 @@ export const schemaDict = { main: { type: 'query', description: - "Gets the DID's repo, optionally catching up from a specific revision.", + "Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS.", parameters: { type: 'params', required: ['did'], @@ -3875,7 +4407,8 @@ export const schemaDict = { }, since: { type: 'string', - description: 'The revision of the repo to catch up from.', + description: + "The revision ('rev') of the repo to create a diff from.", }, }, }, @@ -3891,7 +4424,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List blob CIDs since some revision.', + description: + 'List blob CIDso for an account, since some repo revision. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did'], @@ -3944,7 +4478,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List DIDs and root CIDs of hosted repos.', + description: + 'Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { @@ -3990,6 +4525,7 @@ export const schemaDict = { head: { type: 'string', format: 'cid', + description: 'Current repo commit CID', }, rev: { type: 'string', @@ -4005,7 +4541,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Notify a crawling service of a recent update; often when a long break between updates causes the connection with the crawling service to break.', + 'Notify a crawling service of a recent update, and that crawling should resume. Intended use is after a gap between repo stream events caused the crawling service to disconnect. Does not require auth; implemented by Relay.', input: { encoding: 'application/json', schema: { @@ -4015,7 +4551,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is notifying of update.', + 'Hostname of the current service (usually a PDS) that is notifying of update.', }, }, }, @@ -4029,7 +4565,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Request a service to persistently crawl hosted repos.', + description: + 'Request a service to persistently crawl hosted repos. Expected use is new PDS instances declaring their existence to Relays. Does not require auth.', input: { encoding: 'application/json', schema: { @@ -4039,7 +4576,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is requesting to be crawled.', + 'Hostname of the current service (eg, PDS) that is requesting to be crawled.', }, }, }, @@ -4053,13 +4590,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to repo updates.', + description: + 'Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -4068,6 +4606,7 @@ export const schemaDict = { type: 'union', refs: [ 'lex:com.atproto.sync.subscribeRepos#commit', + 'lex:com.atproto.sync.subscribeRepos#identity', 'lex:com.atproto.sync.subscribeRepos#handle', 'lex:com.atproto.sync.subscribeRepos#migrate', 'lex:com.atproto.sync.subscribeRepos#tombstone', @@ -4081,11 +4620,15 @@ export const schemaDict = { }, { name: 'ConsumerTooSlow', + description: + 'If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection.', }, ], }, commit: { type: 'object', + description: + 'Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.', required: [ 'seq', 'rebase', @@ -4103,34 +4646,45 @@ export const schemaDict = { properties: { seq: { type: 'integer', + description: 'The stream sequence number of this message.', }, rebase: { type: 'boolean', + description: 'DEPRECATED -- unused', }, tooBig: { type: 'boolean', + description: + 'Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data.', }, repo: { type: 'string', format: 'did', + description: 'The repo this event comes from.', }, commit: { type: 'cid-link', + description: 'Repo commit object CID.', }, prev: { type: 'cid-link', + description: + 'DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability.', }, rev: { type: 'string', - description: 'The rev of the emitted commit.', + description: + 'The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event.', }, since: { type: 'string', - description: 'The rev of the last emitted commit from this repo.', + description: + 'The rev of the last emitted commit from this repo (if any).', }, blocks: { type: 'bytes', - description: 'CAR file containing relevant blocks.', + description: + 'CAR file containing relevant blocks, as a diff since the previous repo state.', maxLength: 1000000, }, ops: { @@ -4138,6 +4692,8 @@ export const schemaDict = { items: { type: 'ref', ref: 'lex:com.atproto.sync.subscribeRepos#repoOp', + description: + 'List of repo mutation operations in this commit (eg, records created, updated, or deleted).', }, maxLength: 200, }, @@ -4145,8 +4701,31 @@ export const schemaDict = { type: 'array', items: { type: 'cid-link', + description: + 'List of new blobs (by CID) referenced by records in this commit.', }, }, + time: { + type: 'string', + format: 'datetime', + description: + 'Timestamp of when this message was originally broadcast.', + }, + }, + }, + identity: { + type: 'object', + description: + "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.", + required: ['seq', 'did', 'time'], + properties: { + seq: { + type: 'integer', + }, + did: { + type: 'string', + format: 'did', + }, time: { type: 'string', format: 'datetime', @@ -4155,6 +4734,8 @@ export const schemaDict = { }, handle: { type: 'object', + description: + "Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity.", required: ['seq', 'did', 'handle', 'time'], properties: { seq: { @@ -4176,6 +4757,8 @@ export const schemaDict = { }, migrate: { type: 'object', + description: + 'Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead', required: ['seq', 'did', 'migrateTo', 'time'], nullable: ['migrateTo'], properties: { @@ -4197,6 +4780,8 @@ export const schemaDict = { }, tombstone: { type: 'object', + description: + 'Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event', required: ['seq', 'did', 'time'], properties: { seq: { @@ -4227,8 +4812,7 @@ export const schemaDict = { }, repoOp: { type: 'object', - description: - "A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null.", + description: 'A repo operation, ie a mutation of a single record.', required: ['action', 'path', 'cid'], nullable: ['cid'], properties: { @@ -4241,45 +4825,34 @@ export const schemaDict = { }, cid: { type: 'cid-link', + description: + 'For creates and updates, the new record CID. For deletions, null.', }, }, }, }, }, - ComAtprotoTempFetchLabels: { + ComAtprotoTempCheckSignupQueue: { lexicon: 1, - id: 'com.atproto.temp.fetchLabels', + id: 'com.atproto.temp.checkSignupQueue', defs: { main: { type: 'query', - description: - 'Fetch all labels from a labeler created after a certain date.', - parameters: { - type: 'params', - properties: { - since: { - type: 'integer', - }, - limit: { - type: 'integer', - minimum: 1, - maximum: 250, - default: 50, - }, - }, - }, + description: 'Check accounts location in signup queue.', output: { encoding: 'application/json', schema: { type: 'object', - required: ['labels'], + required: ['activated'], properties: { - labels: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:com.atproto.label.defs#label', - }, + activated: { + type: 'boolean', + }, + placeInQueue: { + type: 'integer', + }, + estimatedTimeMs: { + type: 'integer', }, }, }, @@ -4287,75 +4860,40 @@ export const schemaDict = { }, }, }, - ComAtprotoTempImportRepo: { - lexicon: 1, - id: 'com.atproto.temp.importRepo', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: 'application/vnd.ipld.car', - }, - output: { - encoding: 'text/plain', - }, - }, - }, - }, - ComAtprotoTempPushBlob: { - lexicon: 1, - id: 'com.atproto.temp.pushBlob', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: '*/*', - }, - }, - }, - }, - ComAtprotoTempRequestPhoneVerification: { + ComAtprotoTempFetchLabels: { lexicon: 1, - id: 'com.atproto.temp.requestPhoneVerification', + id: 'com.atproto.temp.fetchLabels', defs: { main: { - type: 'procedure', + type: 'query', description: - 'Request a verification code to be sent to the supplied phone number', - input: { + 'DEPRECATED: use queryLabels or subscribeLabels instead -- Fetch all labels from a labeler created after a certain date.', + parameters: { + type: 'params', + properties: { + since: { + type: 'integer', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 250, + default: 50, + }, + }, + }, + output: { encoding: 'application/json', schema: { type: 'object', - required: ['phoneNumber'], + required: ['labels'], properties: { - phoneNumber: { - type: 'string', + labels: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.label.defs#label', + }, }, }, }, @@ -4363,86 +4901,32 @@ export const schemaDict = { }, }, }, - ComAtprotoTempTransferAccount: { + ComAtprotoTempRequestPhoneVerification: { lexicon: 1, - id: 'com.atproto.temp.transferAccount', + id: 'com.atproto.temp.requestPhoneVerification', defs: { main: { type: 'procedure', - description: 'Transfer an account.', + description: + 'Request a verification code to be sent to the supplied phone number', input: { encoding: 'application/json', schema: { type: 'object', - required: ['handle', 'did', 'plcOp'], - properties: { - handle: { - type: 'string', - format: 'handle', - }, - did: { - type: 'string', - format: 'did', - }, - plcOp: { - type: 'unknown', - }, - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['accessJwt', 'refreshJwt', 'handle', 'did'], + required: ['phoneNumber'], properties: { - accessJwt: { - type: 'string', - }, - refreshJwt: { - type: 'string', - }, - handle: { - type: 'string', - format: 'handle', - }, - did: { + phoneNumber: { type: 'string', - format: 'did', }, }, }, }, - errors: [ - { - name: 'InvalidHandle', - }, - { - name: 'InvalidPassword', - }, - { - name: 'InvalidInviteCode', - }, - { - name: 'HandleNotAvailable', - }, - { - name: 'UnsupportedDomain', - }, - { - name: 'UnresolvableDid', - }, - { - name: 'IncompatibleDidDoc', - }, - ], }, }, }, AppBskyActorDefs: { lexicon: 1, id: 'app.bsky.actor.defs', - description: 'A reference to an actor in the network.', defs: { profileViewBasic: { type: 'object', @@ -4575,6 +5059,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests.", properties: { muted: { type: 'boolean', @@ -4615,6 +5101,9 @@ export const schemaDict = { 'lex:app.bsky.actor.defs#personalDetailsPref', 'lex:app.bsky.actor.defs#feedViewPref', 'lex:app.bsky.actor.defs#threadViewPref', + 'lex:app.bsky.actor.defs#interestsPref', + 'lex:app.bsky.actor.defs#mutedWordsPref', + 'lex:app.bsky.actor.defs#hiddenPostsPref', ], }, }, @@ -4659,6 +5148,9 @@ export const schemaDict = { format: 'at-uri', }, }, + timelineIndex: { + type: 'integer', + }, }, }, personalDetailsPref: { @@ -4718,6 +5210,79 @@ export const schemaDict = { }, }, }, + interestsPref: { + type: 'object', + required: ['tags'], + properties: { + tags: { + type: 'array', + maxLength: 100, + items: { + type: 'string', + maxLength: 640, + maxGraphemes: 64, + }, + description: + "A list of tags which describe the account owner's interests gathered during onboarding.", + }, + }, + }, + mutedWordTarget: { + type: 'string', + knownValues: ['content', 'tag'], + maxLength: 640, + maxGraphemes: 64, + }, + mutedWord: { + type: 'object', + description: 'A word that the account owner has muted.', + required: ['value', 'targets'], + properties: { + value: { + type: 'string', + description: 'The muted word itself.', + maxLength: 10000, + maxGraphemes: 1000, + }, + targets: { + type: 'array', + description: 'The intended targets of the muted word.', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWordTarget', + }, + }, + }, + }, + mutedWordsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWord', + }, + description: 'A list of words the account owner has muted.', + }, + }, + }, + hiddenPostsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'string', + format: 'at-uri', + }, + description: + 'A list of URIs of posts the account owner has hidden.', + }, + }, + }, }, }, AppBskyActorGetPreferences: { @@ -4726,7 +5291,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get private preferences attached to the account.', + description: + 'Get private preferences attached to the current account. Expected use is synchronization between multiple devices, and import/export during account migration. Requires auth.', parameters: { type: 'params', properties: {}, @@ -4753,7 +5319,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get detailed profile view of an actor.', + description: + 'Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.', parameters: { type: 'params', required: ['actor'], @@ -4761,6 +5328,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Handle or DID of account to fetch profile of.', }, }, }, @@ -4820,7 +5388,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested actors, used for discovery.', + description: + 'Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding.', parameters: { type: 'params', properties: { @@ -4863,7 +5432,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a profile.', + description: 'A declaration of a Bluesky account profile.', key: 'literal:self', record: { type: 'object', @@ -4875,21 +5444,28 @@ export const schemaDict = { }, description: { type: 'string', + description: 'Free-form profile description text.', maxGraphemes: 256, maxLength: 2560, }, avatar: { type: 'blob', + description: + "Small image to be displayed next to posts from account. AKA, 'profile picture'", accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, banner: { type: 'blob', + description: + 'Larger horizontal image to display behind profile view.', accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, labels: { type: 'union', + description: + 'Self-label values, specific to the Bluesky application, on the overall account.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, }, @@ -4926,7 +5502,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actors (profiles) matching search criteria.', + description: + 'Find actors (profiles) matching search criteria. Does not require auth.', parameters: { type: 'params', properties: { @@ -4978,7 +5555,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actor suggestions for a prefix search term.', + description: + 'Find actor suggestions for a prefix search term. Expected use is for auto-completion during text field entry. Does not require auth.', parameters: { type: 'params', properties: { @@ -5020,11 +5598,11 @@ export const schemaDict = { AppBskyEmbedExternal: { lexicon: 1, id: 'app.bsky.embed.external', - description: - 'A representation of some externally linked content, embedded in another form of content.', defs: { main: { type: 'object', + description: + "A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post).", required: ['external'], properties: { external: { @@ -5088,7 +5666,7 @@ export const schemaDict = { AppBskyEmbedImages: { lexicon: 1, id: 'app.bsky.embed.images', - description: 'A set of images embedded in some other form of content.', + description: 'A set of images embedded in a Bluesky record (eg, a post).', defs: { main: { type: 'object', @@ -5115,6 +5693,8 @@ export const schemaDict = { }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5158,12 +5738,18 @@ export const schemaDict = { properties: { thumb: { type: 'string', + description: + 'Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View.', }, fullsize: { type: 'string', + description: + 'Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View.', }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5177,7 +5763,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.record', description: - 'A representation of a record embedded in another form of content.', + 'A representation of a record embedded in a Bluesky record (eg, a post). For example, a quote-post, or sharing a feed generator record.', defs: { main: { type: 'object', @@ -5223,6 +5809,7 @@ export const schemaDict = { }, value: { type: 'unknown', + description: 'The record data itself.', }, labels: { type: 'array', @@ -5287,7 +5874,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.recordWithMedia', description: - 'A representation of a record embedded in another form of content, alongside other compatible embeds.', + 'A representation of a record embedded in a Bluesky record (eg, a post), alongside other compatible embeds. For example, a quote post and image, or a quote post and external URL card.', defs: { main: { type: 'object', @@ -5386,6 +5973,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests.", properties: { repost: { type: 'string', @@ -5646,7 +6235,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about a feed generator, including policies and offered feed URIs.', + 'Get information about a feed generator, including policies and offered feed URIs. Does not require auth; implemented by Feed Generator services (not App View).', output: { encoding: 'application/json', schema: { @@ -5701,7 +6290,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of the existence of a feed generator.', + description: + 'Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.', key: 'any', record: { type: 'object', @@ -5735,6 +6325,7 @@ export const schemaDict = { }, labels: { type: 'union', + description: 'Self-label values', refs: ['lex:com.atproto.label.defs#selfLabels'], }, createdAt: { @@ -5752,7 +6343,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of feeds created by the actor.', + description: + "Get a list of feeds (feed generator records) created by the actor (in the actor's repo).", parameters: { type: 'params', required: ['actor'], @@ -5800,7 +6392,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of posts liked by an actor.', + description: + 'Get a list of posts liked by an actor. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -5856,7 +6449,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth.", parameters: { type: 'params', required: ['actor'], @@ -5876,6 +6470,8 @@ export const schemaDict = { }, filter: { type: 'string', + description: + 'Combinations of post/repost types to include in response.', knownValues: [ 'posts_with_replies', 'posts_no_replies', @@ -5923,7 +6519,7 @@ export const schemaDict = { main: { type: 'query', description: - "Get a hydrated feed from an actor's selected feed generator.", + "Get a hydrated feed from an actor's selected feed generator. Implemented by App View.", parameters: { type: 'params', required: ['feed'], @@ -5976,7 +6572,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get information about a feed generator.', + description: + 'Get information about a feed generator. Implemented by AppView.', parameters: { type: 'params', required: ['feed'], @@ -5984,6 +6581,7 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: 'AT-URI of the feed generator record.', }, }, }, @@ -5999,9 +6597,13 @@ export const schemaDict = { }, isOnline: { type: 'boolean', + description: + 'Indicates whether the feed generator service has been online recently, or else seems to be inactive.', }, isValid: { type: 'boolean', + description: + 'Indicates whether the feed generator service is compatible with the record declaration.', }, }, }, @@ -6054,7 +6656,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a skeleton of a feed provided by a feed generator.', + description: + 'Get a skeleton of a feed provided by a feed generator. Auth is optional, depending on provider requirements, and provides the DID of the requester. Implemented by Feed Generator Service.', parameters: { type: 'params', required: ['feed'], @@ -6062,6 +6665,8 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: + 'Reference to feed generator record describing the specific feed being requested.', }, limit: { type: 'integer', @@ -6107,7 +6712,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the list of likes.', + description: + 'Get like records which reference a subject (by AT-URI and CID).', parameters: { type: 'params', required: ['uri'], @@ -6115,10 +6721,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'AT-URI of the subject (eg, a post record).', }, cid: { type: 'string', format: 'cid', + description: + 'CID of the subject record (aka, specific version of record), to filter likes.', }, limit: { type: 'integer', @@ -6185,7 +6794,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a view of a recent posts from actors in a list.', + description: + 'Get a feed of recent posts from a list (posts and reposts from any actors on the list). Does not require auth.', parameters: { type: 'params', required: ['list'], @@ -6193,6 +6803,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the list record.', }, limit: { type: 'integer', @@ -6238,7 +6849,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get posts in a thread.', + description: + 'Get posts in a thread. Does not require auth, but additional metadata and filtering will be applied for authed requests.', parameters: { type: 'params', required: ['uri'], @@ -6246,15 +6858,20 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to post record.', }, depth: { type: 'integer', + description: + 'How many levels of reply depth should be included in response.', default: 6, minimum: 0, maximum: 1000, }, parentHeight: { type: 'integer', + description: + 'How many levels of parent (and grandparent, etc) post to include.', default: 80, minimum: 0, maximum: 1000, @@ -6292,13 +6909,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Gets post views for a specified list of posts (by AT-URI). This is sometimes referred to as 'hydrating' a 'feed skeleton'.", parameters: { type: 'params', required: ['uris'], properties: { uris: { type: 'array', + description: 'List of post AT-URIs to return hydrated views for.', items: { type: 'string', format: 'at-uri', @@ -6332,7 +6951,7 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of reposts.', + description: 'Get a list of reposts for a given post.', parameters: { type: 'params', required: ['uri'], @@ -6340,10 +6959,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of post record', }, cid: { type: 'string', format: 'cid', + description: + 'If supplied, filters to reposts of specific version (by CID) of the post record.', }, limit: { type: 'integer', @@ -6392,7 +7014,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested feeds for the viewer.', + description: + 'Get a list of suggested feeds (feed generators) for the requesting account.', parameters: { type: 'params', properties: { @@ -6435,12 +7058,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of the actor's home timeline.", + description: + "Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed.", parameters: { type: 'params', properties: { algorithm: { type: 'string', + description: + "Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism.", }, limit: { type: 'integer', @@ -6481,7 +7107,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a like.', + description: "Record declaring a 'like' of a piece of subject content.", key: 'tid', record: { type: 'object', @@ -6506,7 +7132,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a post.', + description: 'Record containing a Bluesky post.', key: 'tid', record: { type: 'object', @@ -6516,10 +7142,12 @@ export const schemaDict = { type: 'string', maxLength: 3000, maxGraphemes: 300, + description: + 'The primary post content. May be an empty string, if there are embeds.', }, entities: { type: 'array', - description: 'Deprecated: replaced by app.bsky.richtext.facet.', + description: 'DEPRECATED: replaced by app.bsky.richtext.facet.', items: { type: 'ref', ref: 'lex:app.bsky.feed.post#entity', @@ -6527,6 +7155,8 @@ export const schemaDict = { }, facets: { type: 'array', + description: + 'Annotations of text (mentions, URLs, hashtags, etc)', items: { type: 'ref', ref: 'lex:app.bsky.richtext.facet', @@ -6547,6 +7177,8 @@ export const schemaDict = { }, langs: { type: 'array', + description: + 'Indicates human language of post primary text content.', maxLength: 3, items: { type: 'string', @@ -6555,21 +7187,26 @@ export const schemaDict = { }, labels: { type: 'union', + description: + 'Self-label values for this post. Effectively content warnings.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, tags: { type: 'array', + description: + 'Additional hashtags, in addition to any included in post text and facets.', maxLength: 8, items: { type: 'string', maxLength: 640, maxGraphemes: 64, }, - description: 'Additional non-inline tags describing this post.', }, createdAt: { type: 'string', format: 'datetime', + description: + 'Client-declared timestamp when this post was originally created.', }, }, }, @@ -6629,7 +7266,8 @@ export const schemaDict = { id: 'app.bsky.feed.repost', defs: { main: { - description: 'A declaration of a repost.', + description: + "Record representing a 'repost' of an existing Bluesky post.", type: 'record', key: 'tid', record: { @@ -6655,7 +7293,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find posts matching search criteria.', + description: + 'Find posts matching search criteria, returning views of those posts.', parameters: { type: 'params', required: ['q'], @@ -6718,7 +7357,7 @@ export const schemaDict = { type: 'record', key: 'tid', description: - "Defines interaction gating rules for a thread. The rkey of the threadgate record should match the rkey of the thread's root post.", + "Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository..", record: { type: 'object', required: ['post', 'createdAt'], @@ -6726,6 +7365,7 @@ export const schemaDict = { post: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the post record.', }, allow: { type: 'array', @@ -6775,7 +7415,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a block.', + description: + "Record declaring a 'block' relationship against another account. NOTE: blocks are public in Bluesky; see blog posts for details.", key: 'tid', record: { type: 'object', @@ -6784,6 +7425,7 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'DID of the account to be blocked.', }, createdAt: { type: 'string', @@ -6972,7 +7614,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a social follow.', + description: + "Record declaring a social 'follow' relationship of another account. Duplicate follows will be ignored by the AppView.", key: 'tid', record: { type: 'object', @@ -6997,7 +7640,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor is blocking.', + description: + 'Enumerates which accounts the requesting account is currently blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7040,7 +7684,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a list of an actor's followers.", + description: + 'Enumerates accounts which follow a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7092,7 +7737,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor follows.', + description: + 'Enumerates accounts which a specified account (actor) follows.', parameters: { type: 'params', required: ['actor'], @@ -7144,7 +7790,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of actors.', + description: + "Gets a 'view' (with additional context) of a specified list.", parameters: { type: 'params', required: ['list'], @@ -7152,6 +7799,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of the list record to hydrate.', }, limit: { type: 'integer', @@ -7196,7 +7844,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is blocking.', + description: + 'Get mod lists that the requesting account (actor) is blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7239,7 +7888,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is muting.', + description: + 'Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7282,7 +7932,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of lists that belong to an actor.', + description: + 'Enumerates the lists created by a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7290,6 +7941,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'The account (actor) to enumerate lists from.', }, limit: { type: 'integer', @@ -7330,7 +7982,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor mutes.', + description: + 'Enumerates accounts that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7374,7 +8027,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Enumerates public relationships between one account, and a list of other accounts', + 'Enumerates public relationships between one account, and a list of other accounts. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -7382,9 +8035,12 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Primary account requesting relationships for.', }, others: { type: 'array', + description: + "List of 'other' accounts to be related back to the primary.", maxLength: 30, items: { type: 'string', @@ -7432,7 +8088,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get suggested follows related to a given actor.', + description: + 'Enumerates follows similar to a given account (actor). Expected use is to recommend additional accounts immediately after following one account.', parameters: { type: 'params', required: ['actor'], @@ -7468,7 +8125,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a list of actors.', + description: + 'Record representing a list of accounts (actors). Scope includes both moderation-oriented lists and curration-oriented lists.', key: 'tid', record: { type: 'object', @@ -7476,12 +8134,15 @@ export const schemaDict = { properties: { purpose: { type: 'ref', + description: + 'Defines the purpose of the list (aka, moderation-oriented or curration-oriented)', ref: 'lex:app.bsky.graph.defs#listPurpose', }, name: { type: 'string', maxLength: 64, minLength: 1, + description: 'Display name for list; can not be empty.', }, description: { type: 'string', @@ -7519,7 +8180,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A block of an entire list of actors.', + description: + 'Record representing a block relationship against an entire an entire list of accounts (actors).', key: 'tid', record: { type: 'object', @@ -7528,6 +8190,7 @@ export const schemaDict = { subject: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the mod list record.', }, createdAt: { type: 'string', @@ -7544,7 +8207,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'An item under a declared list of actors.', + description: + "Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records.", key: 'tid', record: { type: 'object', @@ -7553,10 +8217,13 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'The account which is included on the list.', }, list: { type: 'string', format: 'at-uri', + description: + 'Reference (AT-URI) to the list record (app.bsky.graph.list).', }, createdAt: { type: 'string', @@ -7573,7 +8240,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute an actor by DID or handle.', + description: + 'Creates a mute relationship for the specified account. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7596,7 +8264,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute a list of actors.', + description: + 'Creates a mute relationship for the specified list of accounts. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7619,7 +8288,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute an actor by DID or handle.', + description: 'Unmutes the specified account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7642,7 +8311,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute a list of actors.', + description: 'Unmutes the specified list of accounts. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7665,7 +8334,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the count of unread notifications.', + description: + 'Count the number of unread notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7696,7 +8366,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of notifications.', + description: + 'Enumerate notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7807,7 +8478,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Register for push notifications with a service.', + description: + 'Register to receive push notifications, via a specified service, for the requesting account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7840,7 +8512,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Notify server that the user has seen notifications.', + description: + 'Notify server that the requesting account has seen notifications. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7863,6 +8536,7 @@ export const schemaDict = { defs: { main: { type: 'object', + description: 'Annotation of a sub-string within rich text.', required: ['index', 'features'], properties: { index: { @@ -7884,7 +8558,8 @@ export const schemaDict = { }, mention: { type: 'object', - description: 'A facet feature for actor mentions.', + description: + "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID.", required: ['did'], properties: { did: { @@ -7895,7 +8570,8 @@ export const schemaDict = { }, link: { type: 'object', - description: 'A facet feature for links.', + description: + 'Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.', required: ['uri'], properties: { uri: { @@ -7906,7 +8582,8 @@ export const schemaDict = { }, tag: { type: 'object', - description: 'A hashtag.', + description: + "Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags').", required: ['tag'], properties: { tag: { @@ -7919,7 +8596,7 @@ export const schemaDict = { byteSlice: { type: 'object', description: - 'A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings.', + 'Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.', required: ['byteStart', 'byteEnd'], properties: { byteStart: { @@ -8054,55 +8731,6 @@ export const schemaDict = { }, }, }, - AppBskyUnspeccedGetTimelineSkeleton: { - lexicon: 1, - id: 'app.bsky.unspecced.getTimelineSkeleton', - defs: { - main: { - type: 'query', - description: - 'DEPRECATED: a skeleton of a timeline. Unspecced and will be unavailable soon.', - parameters: { - type: 'params', - properties: { - limit: { - type: 'integer', - minimum: 1, - maximum: 100, - default: 50, - }, - cursor: { - type: 'string', - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['feed'], - properties: { - cursor: { - type: 'string', - }, - feed: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:app.bsky.feed.defs#skeletonFeedPost', - }, - }, - }, - }, - }, - errors: [ - { - name: 'UnknownFeed', - }, - ], - }, - }, - }, AppBskyUnspeccedSearchActorsSkeleton: { lexicon: 1, id: 'app.bsky.unspecced.searchActorsSkeleton', @@ -8261,10 +8889,19 @@ export const ids = { ComAtprotoAdminSendEmail: 'com.atproto.admin.sendEmail', ComAtprotoAdminUpdateAccountEmail: 'com.atproto.admin.updateAccountEmail', ComAtprotoAdminUpdateAccountHandle: 'com.atproto.admin.updateAccountHandle', + ComAtprotoAdminUpdateAccountPassword: + 'com.atproto.admin.updateAccountPassword', ComAtprotoAdminUpdateCommunicationTemplate: 'com.atproto.admin.updateCommunicationTemplate', ComAtprotoAdminUpdateSubjectStatus: 'com.atproto.admin.updateSubjectStatus', + ComAtprotoIdentityGetRecommendedDidCredentials: + 'com.atproto.identity.getRecommendedDidCredentials', + ComAtprotoIdentityRequestPlcOperationSignature: + 'com.atproto.identity.requestPlcOperationSignature', ComAtprotoIdentityResolveHandle: 'com.atproto.identity.resolveHandle', + ComAtprotoIdentitySignPlcOperation: 'com.atproto.identity.signPlcOperation', + ComAtprotoIdentitySubmitPlcOperation: + 'com.atproto.identity.submitPlcOperation', ComAtprotoIdentityUpdateHandle: 'com.atproto.identity.updateHandle', ComAtprotoLabelDefs: 'com.atproto.label.defs', ComAtprotoLabelQueryLabels: 'com.atproto.label.queryLabels', @@ -8276,22 +8913,28 @@ export const ids = { ComAtprotoRepoDeleteRecord: 'com.atproto.repo.deleteRecord', ComAtprotoRepoDescribeRepo: 'com.atproto.repo.describeRepo', ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord', + ComAtprotoRepoImportRepo: 'com.atproto.repo.importRepo', + ComAtprotoRepoListMissingBlobs: 'com.atproto.repo.listMissingBlobs', ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords', ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord', ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob', + ComAtprotoServerActivateAccount: 'com.atproto.server.activateAccount', + ComAtprotoServerCheckAccountStatus: 'com.atproto.server.checkAccountStatus', ComAtprotoServerConfirmEmail: 'com.atproto.server.confirmEmail', ComAtprotoServerCreateAccount: 'com.atproto.server.createAccount', ComAtprotoServerCreateAppPassword: 'com.atproto.server.createAppPassword', ComAtprotoServerCreateInviteCode: 'com.atproto.server.createInviteCode', ComAtprotoServerCreateInviteCodes: 'com.atproto.server.createInviteCodes', ComAtprotoServerCreateSession: 'com.atproto.server.createSession', + ComAtprotoServerDeactivateAccount: 'com.atproto.server.deactivateAccount', ComAtprotoServerDefs: 'com.atproto.server.defs', ComAtprotoServerDeleteAccount: 'com.atproto.server.deleteAccount', ComAtprotoServerDeleteSession: 'com.atproto.server.deleteSession', ComAtprotoServerDescribeServer: 'com.atproto.server.describeServer', ComAtprotoServerGetAccountInviteCodes: 'com.atproto.server.getAccountInviteCodes', + ComAtprotoServerGetServiceAuth: 'com.atproto.server.getServiceAuth', ComAtprotoServerGetSession: 'com.atproto.server.getSession', ComAtprotoServerListAppPasswords: 'com.atproto.server.listAppPasswords', ComAtprotoServerRefreshSession: 'com.atproto.server.refreshSession', @@ -8318,12 +8961,10 @@ export const ids = { ComAtprotoSyncNotifyOfUpdate: 'com.atproto.sync.notifyOfUpdate', ComAtprotoSyncRequestCrawl: 'com.atproto.sync.requestCrawl', ComAtprotoSyncSubscribeRepos: 'com.atproto.sync.subscribeRepos', + ComAtprotoTempCheckSignupQueue: 'com.atproto.temp.checkSignupQueue', ComAtprotoTempFetchLabels: 'com.atproto.temp.fetchLabels', - ComAtprotoTempImportRepo: 'com.atproto.temp.importRepo', - ComAtprotoTempPushBlob: 'com.atproto.temp.pushBlob', ComAtprotoTempRequestPhoneVerification: 'com.atproto.temp.requestPhoneVerification', - ComAtprotoTempTransferAccount: 'com.atproto.temp.transferAccount', AppBskyActorDefs: 'app.bsky.actor.defs', AppBskyActorGetPreferences: 'app.bsky.actor.getPreferences', AppBskyActorGetProfile: 'app.bsky.actor.getProfile', @@ -8391,7 +9032,6 @@ export const ids = { 'app.bsky.unspecced.getPopularFeedGenerators', AppBskyUnspeccedGetTaggedSuggestions: 'app.bsky.unspecced.getTaggedSuggestions', - 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/defs.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/defs.ts index c20177ca50e..6836fa7e516 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/defs.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/defs.ts @@ -82,6 +82,7 @@ export function validateProfileViewDetailed(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#profileViewDetailed', v) } +/** Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests. */ export interface ViewerState { muted?: boolean mutedByList?: AppBskyGraphDefs.ListViewBasic @@ -112,6 +113,9 @@ export type Preferences = ( | PersonalDetailsPref | FeedViewPref | ThreadViewPref + | InterestsPref + | MutedWordsPref + | HiddenPostsPref | { $type: string; [k: string]: unknown } )[] @@ -153,6 +157,7 @@ export function validateContentLabelPref(v: unknown): ValidationResult { export interface SavedFeedsPref { pinned: string[] saved: string[] + timelineIndex?: number [k: string]: unknown } @@ -233,3 +238,80 @@ export function isThreadViewPref(v: unknown): v is ThreadViewPref { export function validateThreadViewPref(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#threadViewPref', v) } + +export interface InterestsPref { + /** A list of tags which describe the account owner's interests gathered during onboarding. */ + tags: string[] + [k: string]: unknown +} + +export function isInterestsPref(v: unknown): v is InterestsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#interestsPref' + ) +} + +export function validateInterestsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#interestsPref', v) +} + +export type MutedWordTarget = 'content' | 'tag' | (string & {}) + +/** A word that the account owner has muted. */ +export interface MutedWord { + /** The muted word itself. */ + value: string + /** The intended targets of the muted word. */ + targets: MutedWordTarget[] + [k: string]: unknown +} + +export function isMutedWord(v: unknown): v is MutedWord { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWord' + ) +} + +export function validateMutedWord(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWord', v) +} + +export interface MutedWordsPref { + /** A list of words the account owner has muted. */ + items: MutedWord[] + [k: string]: unknown +} + +export function isMutedWordsPref(v: unknown): v is MutedWordsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWordsPref' + ) +} + +export function validateMutedWordsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWordsPref', v) +} + +export interface HiddenPostsPref { + /** A list of URIs of posts the account owner has hidden. */ + items: string[] + [k: string]: unknown +} + +export function isHiddenPostsPref(v: unknown): v is HiddenPostsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#hiddenPostsPref' + ) +} + +export function validateHiddenPostsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#hiddenPostsPref', v) +} diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/getPreferences.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/getPreferences.ts index 88d78a57cba..305e80484be 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/getPreferences.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/getPreferences.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/getProfile.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/getProfile.ts index 802afda5361..5a7b1f25bfc 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/getProfile.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/getProfile.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** Handle or DID of account to fetch profile of. */ actor: string } @@ -28,7 +29,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/getProfiles.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/getProfiles.ts index 2549b264e33..16438505654 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/getProfiles.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/getProfiles.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/getSuggestions.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/getSuggestions.ts index a6d4d6102af..33b89a18bfa 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/getSuggestions.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/getSuggestions.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/profile.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/profile.ts index 7dbc4c1ccec..8810ce7bed9 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/profile.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/profile.ts @@ -9,8 +9,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { displayName?: string + /** Free-form profile description text. */ description?: string + /** Small image to be displayed next to posts from account. AKA, 'profile picture' */ avatar?: BlobRef + /** Larger horizontal image to display behind profile view. */ banner?: BlobRef labels?: | ComAtprotoLabelDefs.SelfLabels diff --git a/packages/bsky/src/lexicon/types/app/bsky/actor/putPreferences.ts b/packages/bsky/src/lexicon/types/app/bsky/actor/putPreferences.ts index 1e5ee2d834e..670e752fea3 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/putPreferences.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/putPreferences.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams {} 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 f072b8a4d04..dcda0c41854 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/searchActors.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/searchActors.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -39,7 +39,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams 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 0cf56753db2..0198b23d790 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/embed/external.ts b/packages/bsky/src/lexicon/types/app/bsky/embed/external.ts index f42a6cfd95c..b137ee4b6f5 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/embed/external.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/embed/external.ts @@ -6,6 +6,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' +/** A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). */ export interface Main { external: External [k: string]: unknown diff --git a/packages/bsky/src/lexicon/types/app/bsky/embed/images.ts b/packages/bsky/src/lexicon/types/app/bsky/embed/images.ts index 4864fad3dea..96399867a1a 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/embed/images.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/embed/images.ts @@ -26,6 +26,7 @@ export function validateMain(v: unknown): ValidationResult { export interface Image { image: BlobRef + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown @@ -76,8 +77,11 @@ export function validateView(v: unknown): ValidationResult { } export interface ViewImage { + /** Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. */ thumb: string + /** Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. */ fullsize: string + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown diff --git a/packages/bsky/src/lexicon/types/app/bsky/embed/record.ts b/packages/bsky/src/lexicon/types/app/bsky/embed/record.ts index cea5742a45e..dbe7f13152b 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/embed/record.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/embed/record.ts @@ -57,6 +57,7 @@ export interface ViewRecord { uri: string cid: string author: AppBskyActorDefs.ProfileViewBasic + /** The record data itself. */ value: {} labels?: ComAtprotoLabelDefs.Label[] embeds?: ( diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/defs.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/defs.ts index 382d3f58ecf..261d8a622ec 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/defs.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/defs.ts @@ -45,6 +45,7 @@ export function validatePostView(v: unknown): ValidationResult { return lexicons.validate('app.bsky.feed.defs#postView', v) } +/** Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests. */ export interface ViewerState { repost?: string like?: string diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts index d329bf20a5a..5bf8699a3ca 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -32,7 +32,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getActorFeeds.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getActorFeeds.ts index 3e930cbe201..0b8afff4ec8 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getActorFeeds.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getActorFeeds.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getActorLikes.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getActorLikes.ts index df2f291e1a7..da315ae33c7 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getActorLikes.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getActorLikes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { error?: 'BlockedActor' | 'BlockedByActor' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts index 25f51f6fe5f..017c7a6a2d4 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts @@ -6,13 +6,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { actor: string limit: number cursor?: string + /** Combinations of post/repost types to include in response. */ filter: | 'posts_with_replies' | 'posts_no_replies' @@ -43,7 +44,7 @@ export interface HandlerError { error?: 'BlockedActor' | 'BlockedByActor' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeed.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeed.ts index e72b1010aea..e03913a6fb3 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeed.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeed.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts index fab3b30c316..7ab89057a8c 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** AT-URI of the feed generator record. */ feed: string } @@ -17,7 +18,9 @@ export type InputSchema = undefined export interface OutputSchema { view: AppBskyFeedDefs.GeneratorView + /** Indicates whether the feed generator service has been online recently, or else seems to be inactive. */ isOnline: boolean + /** Indicates whether the feed generator service is compatible with the record declaration. */ isValid: boolean [k: string]: unknown } @@ -35,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts index d7e082f2362..21963a91e2e 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts index 1c8f349b42b..ca1cef20f08 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference to feed generator record describing the specific feed being requested. */ feed: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getLikes.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getLikes.ts index d581f5bfa9c..275d99bba3d 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getLikes.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getLikes.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** AT-URI of the subject (eg, a post record). */ uri: string + /** CID of the subject record (aka, specific version of record), to filter likes. */ cid?: string limit: number cursor?: string @@ -39,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getListFeed.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getListFeed.ts index e24c3f8ed22..84e12deaa92 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getListFeed.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getListFeed.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to the list record. */ list: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { error?: 'UnknownList' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts index 61de94b729d..ae232fd91a2 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts @@ -6,12 +6,15 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to post record. */ uri: string + /** How many levels of reply depth should be included in response. */ depth: number + /** How many levels of parent (and grandparent, etc) post to include. */ parentHeight: number } @@ -40,7 +43,7 @@ export interface HandlerError { error?: 'NotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getPosts.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getPosts.ts index 4282f5d349f..85000c74787 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getPosts.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getPosts.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** List of post AT-URIs to return hydrated views for. */ uris: string[] } @@ -33,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getRepostedBy.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getRepostedBy.ts index 0b9c1a6f68b..40e008815d9 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getRepostedBy.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getRepostedBy.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** Reference (AT-URI) of post record */ uri: string + /** If supplied, filters to reposts of specific version (by CID) of the post record. */ cid?: string limit: number cursor?: string @@ -39,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts index 9b271335466..d1ec590f33d 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getTimeline.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getTimeline.ts index 832caf5c6f7..5202c9eb6e3 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getTimeline.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getTimeline.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. */ algorithm?: string limit: number cursor?: string @@ -36,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/post.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/post.ts index 93870b4452d..881e3d199aa 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/post.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/post.ts @@ -14,9 +14,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' import * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef' export interface Record { + /** The primary post content. May be an empty string, if there are embeds. */ text: string - /** Deprecated: replaced by app.bsky.richtext.facet. */ + /** DEPRECATED: replaced by app.bsky.richtext.facet. */ entities?: Entity[] + /** Annotations of text (mentions, URLs, hashtags, etc) */ facets?: AppBskyRichtextFacet.Main[] reply?: ReplyRef embed?: @@ -25,12 +27,14 @@ export interface Record { | AppBskyEmbedRecord.Main | AppBskyEmbedRecordWithMedia.Main | { $type: string; [k: string]: unknown } + /** Indicates human language of post primary text content. */ langs?: string[] labels?: | ComAtprotoLabelDefs.SelfLabels | { $type: string; [k: string]: unknown } - /** Additional non-inline tags describing this post. */ + /** Additional hashtags, in addition to any included in post text and facets. */ tags?: string[] + /** Client-declared timestamp when this post was originally created. */ createdAt: string [k: string]: unknown } diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts index 36ac7cbb67d..9dae079c226 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/searchPosts.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -41,7 +41,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/threadgate.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/threadgate.ts index 6a190d6e98a..e14140d5609 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/threadgate.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/threadgate.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the post record. */ post: string allow?: ( | MentionRule diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/block.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/block.ts index 947463af422..b7f19f126b7 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/block.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/block.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** DID of the account to be blocked. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getBlocks.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getBlocks.ts index d380a14880a..1fc9cd8ce37 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getBlocks.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getBlocks.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getFollowers.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getFollowers.ts index b337be52c1b..f5645eaef29 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getFollowers.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getFollowers.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getFollows.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getFollows.ts index 71e9ca0270c..b9bd249da45 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getFollows.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getFollows.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getList.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getList.ts index fc45dd20985..864a81b3833 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getList.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getList.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) of the list record to hydrate. */ list: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getListBlocks.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getListBlocks.ts index 04cca70b44d..7399a14fadc 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getListBlocks.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getListBlocks.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getListMutes.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getListMutes.ts index 04cca70b44d..7399a14fadc 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getListMutes.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getListMutes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getLists.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getLists.ts index 8acf9362c00..dc0c4f18bea 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getLists.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getLists.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** The account (actor) to enumerate lists from. */ actor: string limit: number cursor?: string @@ -36,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getMutes.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getMutes.ts index 0034095b975..f450393522d 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getMutes.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getMutes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getRelationships.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getRelationships.ts index 32a27434782..bd6b6e765ed 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getRelationships.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getRelationships.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Primary account requesting relationships for. */ actor: string + /** List of 'other' accounts to be related back to the primary. */ others?: string[] } @@ -40,7 +42,7 @@ export interface HandlerError { error?: 'ActorNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts index a2245846fd2..8f310334d0a 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/list.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/list.ts index 36a7fb17a3f..91c8ccee5bb 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/list.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/list.ts @@ -11,6 +11,7 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { purpose: AppBskyGraphDefs.ListPurpose + /** Display name for list; can not be empty. */ name: string description?: string descriptionFacets?: AppBskyRichtextFacet.Main[] diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/listblock.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/listblock.ts index 59f2e057eb5..592778c7a51 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/listblock.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/listblock.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the mod list record. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/listitem.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/listitem.ts index 69eff329ed4..5e93b34a111 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/listitem.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/listitem.ts @@ -7,7 +7,9 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** The account which is included on the list. */ subject: string + /** Reference (AT-URI) to the list record (app.bsky.graph.list). */ list: string createdAt: string [k: string]: unknown diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/muteActor.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/muteActor.ts index 52d1b864989..baa9844046a 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/muteActor.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/muteActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/muteActorList.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/muteActorList.ts index bf803f388af..6a68f680a1c 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/muteActorList.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/muteActorList.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActor.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActor.ts index 52d1b864989..baa9844046a 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActor.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActorList.ts b/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActorList.ts index bf803f388af..6a68f680a1c 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActorList.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/graph/unmuteActorList.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/app/bsky/notification/getUnreadCount.ts b/packages/bsky/src/lexicon/types/app/bsky/notification/getUnreadCount.ts index 6cf3c84beb5..eae30df7c1b 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/notification/getUnreadCount.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/notification/getUnreadCount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { seenAt?: string @@ -32,7 +32,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/notification/listNotifications.ts b/packages/bsky/src/lexicon/types/app/bsky/notification/listNotifications.ts index b50d6e8282e..d494494e569 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/notification/listNotifications.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/notification/listNotifications.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/notification/registerPush.ts b/packages/bsky/src/lexicon/types/app/bsky/notification/registerPush.ts index 9923aeb058e..cce8f95839d 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/notification/registerPush.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/notification/registerPush.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/app/bsky/notification/updateSeen.ts b/packages/bsky/src/lexicon/types/app/bsky/notification/updateSeen.ts index 136191edc40..93db017a152 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/notification/updateSeen.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/notification/updateSeen.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/app/bsky/richtext/facet.ts b/packages/bsky/src/lexicon/types/app/bsky/richtext/facet.ts index 2c5b2d723a9..139b5382caf 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/richtext/facet.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/richtext/facet.ts @@ -6,6 +6,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' +/** Annotation of a sub-string within rich text. */ export interface Main { index: ByteSlice features: (Mention | Link | Tag | { $type: string; [k: string]: unknown })[] @@ -25,7 +26,7 @@ export function validateMain(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#main', v) } -/** A facet feature for actor mentions. */ +/** Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID. */ export interface Mention { did: string [k: string]: unknown @@ -43,7 +44,7 @@ export function validateMention(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#mention', v) } -/** A facet feature for links. */ +/** Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. */ export interface Link { uri: string [k: string]: unknown @@ -61,7 +62,7 @@ export function validateLink(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#link', v) } -/** A hashtag. */ +/** Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). */ export interface Tag { tag: string [k: string]: unknown @@ -77,7 +78,7 @@ export function validateTag(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#tag', v) } -/** A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings. */ +/** Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. */ export interface ByteSlice { byteStart: number byteEnd: number diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts b/packages/bsky/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts index 97937e926c2..02f19f3cc6a 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from '../feed/defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts b/packages/bsky/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts index e6319c54b4e..a03f442140d 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts index 5c45b9fb622..4634407b890 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyUnspeccedDefs from './defs' export interface QueryParams { @@ -43,7 +43,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts index 15532087b82..860d4e8407c 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyUnspeccedDefs from './defs' export interface QueryParams { @@ -41,7 +41,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts index d42a8f2ef1d..b910b7987b4 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/defs.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/defs.ts index 41be2ad96e7..a713a635635 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/defs.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/defs.ts @@ -40,6 +40,7 @@ export interface ModEventView { | ModEventEscalate | ModEventMute | ModEventEmail + | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: | RepoRef @@ -76,6 +77,7 @@ export interface ModEventViewDetail { | ModEventAcknowledge | ModEventEscalate | ModEventMute + | ModEventEmail | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: @@ -154,6 +156,7 @@ export interface SubjectStatusView { /** True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators. */ appealed?: boolean suspendUntil?: string + tags?: string[] [k: string]: unknown } @@ -718,6 +721,29 @@ export function validateModEventEmail(v: unknown): ValidationResult { return lexicons.validate('com.atproto.admin.defs#modEventEmail', v) } +/** Add/Remove a tag on a subject */ +export interface ModEventTag { + /** Tags to be added to the subject. If already exists, won't be duplicated. */ + add: string[] + /** Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated. */ + remove: string[] + /** Additional comment about added/removed tags. */ + comment?: string + [k: string]: unknown +} + +export function isModEventTag(v: unknown): v is ModEventTag { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.admin.defs#modEventTag' + ) +} + +export function validateModEventTag(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.admin.defs#modEventTag', v) +} + export interface CommunicationTemplateView { id: string /** Name of the template. */ diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/deleteAccount.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/deleteAccount.ts index 13e68eb5c7d..003c1b5ebcd 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/deleteAccount.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/deleteAccount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts index 4bc6ec86fe4..c5ae5cd469f 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts index 62864923dfd..68c6503d95e 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts index 2b64371f1ed..2bf8de35583 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts index df44702b51c..99d08c7f1b7 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -24,6 +24,7 @@ export interface InputSchema { | ComAtprotoAdminDefs.ModEventReverseTakedown | ComAtprotoAdminDefs.ModEventUnmute | ComAtprotoAdminDefs.ModEventEmail + | ComAtprotoAdminDefs.ModEventTag | { $type: string; [k: string]: unknown } subject: | ComAtprotoAdminDefs.RepoRef @@ -53,7 +54,7 @@ export interface HandlerError { error?: 'SubjectHasAction' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts index fb3aa8b8375..3f2836e7142 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfo.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfo.ts index 88a2b17a4b8..c7b840a153d 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfo.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfos.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfos.ts index 46d917293a8..99ef44a99f5 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfos.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/getAccountInfos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/getInviteCodes.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/getInviteCodes.ts index 1eb099aae66..d68b97d775a 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/getInviteCodes.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/getInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoServerDefs from '../server/defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/getModerationEvent.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/getModerationEvent.ts index 7de567a73db..99c8bbe20ef 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/getModerationEvent.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/getModerationEvent.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/getRecord.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/getRecord.ts index 48222d9d819..557945e2fbd 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/getRecord.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/getRecord.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -30,7 +30,7 @@ export interface HandlerError { error?: 'RecordNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/getRepo.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/getRepo.ts index 19911baa90a..ede9fcf3ce8 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/getRepo.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/getRepo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -29,7 +29,7 @@ export interface HandlerError { error?: 'RepoNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts index 7315e51e8c2..d5976db70b1 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts index cb479533d39..843c228e6f9 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts index f3c4f1fbb95..9f4738578aa 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -15,10 +15,27 @@ export interface QueryParams { createdBy?: string /** Sort direction for the events. Defaults to descending order of created at timestamp. */ sortDirection: 'asc' | 'desc' + /** Retrieve events created after a given timestamp */ + createdAfter?: string + /** Retrieve events created before a given timestamp */ + createdBefore?: string subject?: string /** If true, events on all record types (posts, lists, profile etc.) owned by the did are returned */ includeAllUserRecords: boolean limit: number + /** If true, only events with comments are returned */ + hasComment?: boolean + /** If specified, only events with comments containing the keyword are returned */ + comment?: string + /** If specified, only events where all of these labels were added are returned */ + addedLabels?: string[] + /** If specified, only events where all of these labels were removed are returned */ + removedLabels?: string[] + /** If specified, only events where all of these tags were added are returned */ + addedTags?: string[] + /** If specified, only events where all of these tags were removed are returned */ + removedTags?: string[] + reportTypes?: string[] cursor?: string } @@ -43,7 +60,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts index 6e1aea1f679..f5031d25117 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -35,6 +35,8 @@ export interface QueryParams { /** Get subjects in unresolved appealed status */ appealed?: boolean limit: number + tags?: string[] + excludeTags?: string[] cursor?: string } @@ -59,7 +61,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams 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 1e7e1a36bb6..d1529956c17 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/searchRepos.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/searchRepos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/sendEmail.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/sendEmail.ts index f94cfb3a083..836fba39f79 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/sendEmail.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/sendEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts index 9e6140256ef..ebabffbccdb 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts index c378f421926..d6dc4a2dc25 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/temp/importRepo.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts similarity index 60% rename from packages/bsky/src/lexicon/types/com/atproto/temp/importRepo.ts rename to packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts index d88361d9856..948568f0d3d 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/temp/importRepo.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts @@ -2,29 +2,23 @@ * GENERATED CODE - DO NOT MODIFY */ import express from 'express' -import stream from 'stream' 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' -export interface QueryParams { - /** The DID of the repo. */ +export interface QueryParams {} + +export interface InputSchema { did: string + password: string + [k: string]: unknown } -export type InputSchema = string | Uint8Array - export interface HandlerInput { - encoding: 'application/vnd.ipld.car' - body: stream.Readable -} - -export interface HandlerSuccess { - encoding: 'text/plain' - body: Uint8Array | stream.Readable - headers?: { [key: string]: string } + encoding: 'application/json' + body: InputSchema } export interface HandlerError { @@ -32,7 +26,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | void export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts index 5dc5cecda4a..73e079cfe58 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -44,7 +44,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts b/packages/bsky/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts index 559ee948380..94df3041cf3 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -48,7 +48,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts b/packages/bsky/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts new file mode 100644 index 00000000000..5fa374de737 --- /dev/null +++ b/packages/bsky/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts @@ -0,0 +1,47 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + /** Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs. */ + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/identity/requestPlcOperationSignature.ts b/packages/bsky/src/lexicon/types/com/atproto/identity/requestPlcOperationSignature.ts new file mode 100644 index 00000000000..82672f1d1c7 --- /dev/null +++ b/packages/bsky/src/lexicon/types/com/atproto/identity/requestPlcOperationSignature.ts @@ -0,0 +1,31 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined +export type HandlerInput = undefined + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/identity/resolveHandle.ts b/packages/bsky/src/lexicon/types/com/atproto/identity/resolveHandle.ts index ef90e99bb30..05019df6166 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/identity/resolveHandle.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/identity/resolveHandle.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle to resolve. */ @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/temp/transferAccount.ts b/packages/bsky/src/lexicon/types/com/atproto/identity/signPlcOperation.ts similarity index 70% rename from packages/ozone/src/lexicon/types/com/atproto/temp/transferAccount.ts rename to packages/bsky/src/lexicon/types/com/atproto/identity/signPlcOperation.ts index 86c1d750e07..3c908c049f2 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/temp/transferAccount.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/identity/signPlcOperation.ts @@ -6,22 +6,23 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - handle: string - did: string - plcOp: {} + /** A token received through com.atproto.identity.requestPlcOperationSignature */ + token?: string + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} [k: string]: unknown } export interface OutputSchema { - accessJwt: string - refreshJwt: string - handle: string - did: string + /** A signed DID PLC operation. */ + operation: {} [k: string]: unknown } @@ -39,17 +40,9 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string - error?: - | 'InvalidHandle' - | 'InvalidPassword' - | 'InvalidInviteCode' - | 'HandleNotAvailable' - | 'UnsupportedDomain' - | 'UnresolvableDid' - | 'IncompatibleDidDoc' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts b/packages/bsky/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts new file mode 100644 index 00000000000..5290b55d023 --- /dev/null +++ b/packages/bsky/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts @@ -0,0 +1,38 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + operation: {} + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/identity/updateHandle.ts b/packages/bsky/src/lexicon/types/com/atproto/identity/updateHandle.ts index 1f639c344e9..f451d1f57c7 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/identity/updateHandle.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/identity/updateHandle.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { + /** The new handle. */ handle: string [k: string]: unknown } diff --git a/packages/bsky/src/lexicon/types/com/atproto/label/queryLabels.ts b/packages/bsky/src/lexicon/types/com/atproto/label/queryLabels.ts index 1d7f8a4def5..0c9d55a6961 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/label/queryLabels.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/label/queryLabels.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoLabelDefs from './defs' export interface QueryParams { @@ -39,7 +39,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/label/subscribeLabels.ts b/packages/bsky/src/lexicon/types/com/atproto/label/subscribeLabels.ts index 9d4b4441ae0..6034b35d895 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/label/subscribeLabels.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/label/subscribeLabels.ts @@ -10,7 +10,7 @@ import { IncomingMessage } from 'http' import * as ComAtprotoLabelDefs from './defs' export interface QueryParams { - /** The last known event to backfill from. */ + /** The last known event seq number to backfill from. */ cursor?: number } diff --git a/packages/bsky/src/lexicon/types/com/atproto/moderation/createReport.ts b/packages/bsky/src/lexicon/types/com/atproto/moderation/createReport.ts index 96aaf4a9c29..aa3f810a91c 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/moderation/createReport.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/moderation/createReport.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoModerationDefs from './defs' import * as ComAtprotoAdminDefs from '../admin/defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -15,6 +15,7 @@ export interface QueryParams {} export interface InputSchema { reasonType: ComAtprotoModerationDefs.ReasonType + /** Additional context about the content and violation. */ reason?: string subject: | ComAtprotoAdminDefs.RepoRef @@ -52,7 +53,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/applyWrites.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/applyWrites.ts index 61d1e7c28e4..3956d7c3048 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/applyWrites.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/applyWrites.ts @@ -6,16 +6,17 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string - /** Flag for validating the records. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data, for all operations. */ validate: boolean writes: (Create | Update | Delete)[] + /** If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations. */ swapCommit?: string [k: string]: unknown } @@ -43,7 +44,7 @@ export type Handler = ( ctx: HandlerReqCtx, ) => Promise | HandlerOutput -/** Create a new record. */ +/** Operation which creates a new record. */ export interface Create { collection: string rkey?: string @@ -63,7 +64,7 @@ export function validateCreate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#create', v) } -/** Update an existing record. */ +/** Operation which updates an existing record. */ export interface Update { collection: string rkey: string @@ -83,7 +84,7 @@ export function validateUpdate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#update', v) } -/** Delete an existing record. */ +/** Operation which deletes an existing record. */ export interface Delete { collection: string rkey: string diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/createRecord.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/createRecord.ts index df8c5d9e600..55cc95d0ad7 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/createRecord.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/createRecord.ts @@ -6,20 +6,20 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey?: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate: boolean - /** The record to create. */ + /** The record itself. Must contain a $type field. */ record: {} /** Compare and swap with the previous commit by CID. */ swapCommit?: string @@ -49,7 +49,7 @@ export interface HandlerError { error?: 'InvalidSwap' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/deleteRecord.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/deleteRecord.ts index f45118a3769..3bb97be0aad 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/deleteRecord.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/deleteRecord.ts @@ -6,16 +6,16 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** Compare and swap with the previous record by CID. */ swapRecord?: string diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/describeRepo.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/describeRepo.ts index 7b8a2b995eb..749bedcfeb7 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/describeRepo.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/describeRepo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ @@ -18,8 +18,11 @@ export type InputSchema = undefined export interface OutputSchema { handle: string did: string + /** The complete DID document for this account. */ didDoc: {} + /** List of all the collections (NSIDs) for which this repo contains at least one record. */ collections: string[] + /** Indicates if handle is currently valid (resolves bi-directionally) */ handleIsCorrect: boolean [k: string]: unknown } @@ -37,7 +40,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/getRecord.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/getRecord.ts index 35c9b4b7166..1a737a848be 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/getRecord.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/getRecord.ts @@ -6,14 +6,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** The CID of the version of the record. If not specified, then return the most recent version. */ cid?: string @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/temp/pushBlob.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/importRepo.ts similarity index 84% rename from packages/pds/src/lexicon/types/com/atproto/temp/pushBlob.ts rename to packages/bsky/src/lexicon/types/com/atproto/repo/importRepo.ts index 97e890dbb14..921798c0ded 100644 --- a/packages/pds/src/lexicon/types/com/atproto/temp/pushBlob.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/importRepo.ts @@ -7,17 +7,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' -export interface QueryParams { - /** The DID of the repo. */ - did: string -} +export interface QueryParams {} export type InputSchema = string | Uint8Array export interface HandlerInput { - encoding: '*/*' + encoding: 'application/vnd.ipld.car' body: stream.Readable } diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts new file mode 100644 index 00000000000..40f4d385e47 --- /dev/null +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts @@ -0,0 +1,65 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams { + limit: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + blobs: RecordBlob[] + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput + +export interface RecordBlob { + cid: string + recordUri: string + [k: string]: unknown +} + +export function isRecordBlob(v: unknown): v is RecordBlob { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.repo.listMissingBlobs#recordBlob' + ) +} + +export function validateRecordBlob(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.repo.listMissingBlobs#recordBlob', v) +} diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/listRecords.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/listRecords.ts index a6cf6abd1f3..f46f6eb0f7f 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/listRecords.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/listRecords.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ @@ -45,7 +45,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/putRecord.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/putRecord.ts index f10f773c1c4..193841a2294 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/putRecord.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/putRecord.ts @@ -6,22 +6,22 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate: boolean /** The record to write. */ record: {} - /** Compare and swap with the previous record by CID. */ + /** Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation */ swapRecord?: string | null /** Compare and swap with the previous commit by CID. */ swapCommit?: string @@ -51,7 +51,7 @@ export interface HandlerError { error?: 'InvalidSwap' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/repo/uploadBlob.ts b/packages/bsky/src/lexicon/types/com/atproto/repo/uploadBlob.ts index ad6002df925..febbbff9d16 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/repo/uploadBlob.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/repo/uploadBlob.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/activateAccount.ts b/packages/bsky/src/lexicon/types/com/atproto/server/activateAccount.ts new file mode 100644 index 00000000000..82672f1d1c7 --- /dev/null +++ b/packages/bsky/src/lexicon/types/com/atproto/server/activateAccount.ts @@ -0,0 +1,31 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined +export type HandlerInput = undefined + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/server/checkAccountStatus.ts b/packages/bsky/src/lexicon/types/com/atproto/server/checkAccountStatus.ts new file mode 100644 index 00000000000..f17182a8dce --- /dev/null +++ b/packages/bsky/src/lexicon/types/com/atproto/server/checkAccountStatus.ts @@ -0,0 +1,51 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + activated: boolean + validDid: boolean + repoCommit: string + repoRev: string + repoBlocks: number + indexedRecords: number + privateStateValues: number + expectedBlobs: number + importedBlobs: number + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/server/confirmEmail.ts b/packages/bsky/src/lexicon/types/com/atproto/server/confirmEmail.ts index ffaeeb8fe75..b667a04b996 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/confirmEmail.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/confirmEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts b/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts index bbf2c009bf5..6e9b2f9f3c2 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/createAccount.ts @@ -6,28 +6,36 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { email?: string + /** Requested handle for the account. */ handle: string + /** Pre-existing atproto DID, being imported to a new account. */ did?: string inviteCode?: string verificationCode?: string verificationPhone?: string + /** Initial account password. May need to meet instance-specific password strength requirements. */ password?: string + /** DID PLC rotation key (aka, recovery key) to be included in PLC creation operation. */ recoveryKey?: string + /** A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented. */ plcOp?: {} [k: string]: unknown } +/** Account login session returned on successful account creation. */ export interface OutputSchema { accessJwt: string refreshJwt: string handle: string + /** The DID of the new account. */ did: string + /** Complete DID document. */ didDoc?: {} [k: string]: unknown } @@ -56,7 +64,7 @@ export interface HandlerError { | 'IncompatibleDidDoc' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/createAppPassword.ts b/packages/bsky/src/lexicon/types/com/atproto/server/createAppPassword.ts index 8e4a0a519e0..dcc5178ecfa 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/createAppPassword.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/createAppPassword.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { + /** A short name for the App Password, to help distinguish them. */ name: string [k: string]: unknown } @@ -34,7 +35,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCode.ts b/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCode.ts index acfac56ba76..9cfeacc7e28 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCode.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCode.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCodes.ts b/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCodes.ts index 5887d77fada..eb6cd2bb1b1 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCodes.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/createInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/createSession.ts b/packages/bsky/src/lexicon/types/com/atproto/server/createSession.ts index 2cd448703a6..3952959fe5e 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/createSession.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/createSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -45,7 +45,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/deactivateAccount.ts b/packages/bsky/src/lexicon/types/com/atproto/server/deactivateAccount.ts new file mode 100644 index 00000000000..b3793d6b2e0 --- /dev/null +++ b/packages/bsky/src/lexicon/types/com/atproto/server/deactivateAccount.ts @@ -0,0 +1,39 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + /** A recommendation to server as to how long they should hold onto the deactivated account before deleting. */ + deleteAfter?: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/server/deleteAccount.ts b/packages/bsky/src/lexicon/types/com/atproto/server/deleteAccount.ts index 37ddbba13e0..4fcec360a11 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/deleteAccount.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/deleteAccount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/deleteSession.ts b/packages/bsky/src/lexicon/types/com/atproto/server/deleteSession.ts index e4244870425..82672f1d1c7 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/deleteSession.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/deleteSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/describeServer.ts b/packages/bsky/src/lexicon/types/com/atproto/server/describeServer.ts index bb574dba9ff..c2625347f20 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/describeServer.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/describeServer.ts @@ -6,17 +6,21 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export type InputSchema = undefined export interface OutputSchema { + /** If true, an invite code must be supplied to create an account on this instance. */ inviteCodeRequired?: boolean + /** If true, a phone verification token must be supplied to create an account on this instance. */ phoneVerificationRequired?: boolean + /** List of domain suffixes that can be used in account handles. */ availableUserDomains: string[] links?: Links + did: string [k: string]: unknown } @@ -33,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts b/packages/bsky/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts index e387a5e38e4..82c3ffa8c31 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoServerDefs from './defs' export interface QueryParams { includeUsed: boolean + /** Controls whether any new 'earned' but not 'created' invites should be created. */ createAvailable: boolean } @@ -35,7 +36,7 @@ export interface HandlerError { error?: 'DuplicateCreate' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts b/packages/bsky/src/lexicon/types/com/atproto/server/getServiceAuth.ts similarity index 77% rename from packages/pds/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts rename to packages/bsky/src/lexicon/types/com/atproto/server/getServiceAuth.ts index 4ccad20c902..73efe2313a9 100644 --- a/packages/pds/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/getServiceAuth.ts @@ -6,19 +6,17 @@ 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 '../feed/defs' +import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { - limit: number - cursor?: string + /** The DID of the service that the token will be used to authenticate with */ + aud: string } export type InputSchema = undefined export interface OutputSchema { - cursor?: string - feed: AppBskyFeedDefs.SkeletonFeedPost[] + token: string [k: string]: unknown } @@ -33,10 +31,9 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string - error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/getSession.ts b/packages/bsky/src/lexicon/types/com/atproto/server/getSession.ts index 4f95acf523d..5a8c40b947e 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/getSession.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/getSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/listAppPasswords.ts b/packages/bsky/src/lexicon/types/com/atproto/server/listAppPasswords.ts index ebd74da9d39..241418d932d 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/listAppPasswords.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/listAppPasswords.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/refreshSession.ts b/packages/bsky/src/lexicon/types/com/atproto/server/refreshSession.ts index 35874f78a69..3adeb7fc20e 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/refreshSession.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/refreshSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -35,7 +35,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/requestAccountDelete.ts b/packages/bsky/src/lexicon/types/com/atproto/server/requestAccountDelete.ts index e4244870425..82672f1d1c7 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/requestAccountDelete.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/requestAccountDelete.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts b/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts index e4244870425..82672f1d1c7 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts b/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts index 6876d44ca46..24dce3e12af 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/requestPasswordReset.ts b/packages/bsky/src/lexicon/types/com/atproto/server/requestPasswordReset.ts index 47fb4bb62f3..d0f3f2ad769 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/requestPasswordReset.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/requestPasswordReset.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/reserveSigningKey.ts b/packages/bsky/src/lexicon/types/com/atproto/server/reserveSigningKey.ts index ad5a5a8758c..0ec1e80c77c 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/reserveSigningKey.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/reserveSigningKey.ts @@ -6,18 +6,18 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The did to reserve a new did:key for */ + /** The DID to reserve a key for. */ did?: string [k: string]: unknown } export interface OutputSchema { - /** Public signing key in the form of a did:key. */ + /** The public key for the reserved signing key, in did:key serialization. */ signingKey: string [k: string]: unknown } @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/resetPassword.ts b/packages/bsky/src/lexicon/types/com/atproto/server/resetPassword.ts index 9e6ece3e4c4..38f63382cf0 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/resetPassword.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/resetPassword.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/revokeAppPassword.ts b/packages/bsky/src/lexicon/types/com/atproto/server/revokeAppPassword.ts index 4627f68eaa2..769ad6aa521 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/revokeAppPassword.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/revokeAppPassword.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/server/updateEmail.ts b/packages/bsky/src/lexicon/types/com/atproto/server/updateEmail.ts index c88bd3021b2..5473d7571e9 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/server/updateEmail.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/server/updateEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/getBlob.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/getBlob.ts index 60750902472..93e50403f20 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/getBlob.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/getBlob.ts @@ -7,10 +7,10 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { - /** The DID of the repo. */ + /** The DID of the account. */ did: string /** The CID of the blob to fetch */ cid: string @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/getBlocks.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/getBlocks.ts index e73410efb41..f1b8ebe5db1 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/getBlocks.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/getBlocks.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -29,7 +29,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/getCheckout.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/getCheckout.ts index 63a657e56b9..51856b9088d 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/getCheckout.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/getCheckout.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/getHead.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/getHead.ts index 586ae1a4189..adedd4cf211 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/getHead.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/getHead.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -34,7 +34,7 @@ export interface HandlerError { error?: 'HeadNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/getLatestCommit.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/getLatestCommit.ts index 9b91e878724..bbae68bbe76 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/getLatestCommit.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/getLatestCommit.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -35,7 +35,7 @@ export interface HandlerError { error?: 'RepoNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/getRecord.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/getRecord.ts index 297f0ac7794..c78ff8c2089 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/getRecord.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/getRecord.ts @@ -7,12 +7,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ did: string collection: string + /** Record Key */ rkey: string /** An optional past commit CID. */ commit?: string @@ -32,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/getRepo.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/getRepo.ts index 495d31a1a22..0d426557c5f 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/getRepo.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/getRepo.ts @@ -7,12 +7,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ did: string - /** The revision of the repo to catch up from. */ + /** The revision ('rev') of the repo to create a diff from. */ since?: string } @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/listBlobs.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/listBlobs.ts index b397bb3b3df..67a66577809 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/listBlobs.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/listBlobs.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/listRepos.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/listRepos.ts index 783a8e314c2..e5a8e2ca9d6 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/listRepos.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/listRepos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { limit: number @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams @@ -48,6 +48,7 @@ export type Handler = ( export interface Repo { did: string + /** Current repo commit CID */ head: string rev: string [k: string]: unknown diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts index 3d310c1139a..8a0af577c7c 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts @@ -6,12 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is notifying of update. */ + /** Hostname of the current service (usually a PDS) that is notifying of update. */ hostname: string [k: string]: unknown } diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/requestCrawl.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/requestCrawl.ts index 87ef20d7297..31180aabf58 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/requestCrawl.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/requestCrawl.ts @@ -6,12 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is requesting to be crawled. */ + /** Hostname of the current service (eg, PDS) that is requesting to be crawled. */ hostname: string [k: string]: unknown } diff --git a/packages/bsky/src/lexicon/types/com/atproto/sync/subscribeRepos.ts b/packages/bsky/src/lexicon/types/com/atproto/sync/subscribeRepos.ts index fb334778bf6..19874b06083 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/sync/subscribeRepos.ts @@ -9,12 +9,13 @@ import { HandlerAuth, ErrorFrame } from '@atproto/xrpc-server' import { IncomingMessage } from 'http' export interface QueryParams { - /** The last known event to backfill from. */ + /** The last known event seq number to backfill from. */ cursor?: number } export type OutputSchema = | Commit + | Identity | Handle | Migrate | Tombstone @@ -32,21 +33,29 @@ export type Handler = ( ctx: HandlerReqCtx, ) => AsyncIterable +/** Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature. */ export interface Commit { + /** The stream sequence number of this message. */ seq: number + /** DEPRECATED -- unused */ rebase: boolean + /** Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data. */ tooBig: boolean + /** The repo this event comes from. */ repo: string + /** Repo commit object CID. */ commit: CID + /** DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability. */ prev?: CID | null - /** The rev of the emitted commit. */ + /** The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event. */ rev: string - /** The rev of the last emitted commit from this repo. */ + /** The rev of the last emitted commit from this repo (if any). */ since: string | null - /** CAR file containing relevant blocks. */ + /** CAR file containing relevant blocks, as a diff since the previous repo state. */ blocks: Uint8Array ops: RepoOp[] blobs: CID[] + /** Timestamp of when this message was originally broadcast. */ time: string [k: string]: unknown } @@ -63,6 +72,27 @@ export function validateCommit(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#commit', v) } +/** Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache. */ +export interface Identity { + seq: number + did: string + time: string + [k: string]: unknown +} + +export function isIdentity(v: unknown): v is Identity { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.sync.subscribeRepos#identity' + ) +} + +export function validateIdentity(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.sync.subscribeRepos#identity', v) +} + +/** Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity. */ export interface Handle { seq: number did: string @@ -83,6 +113,7 @@ export function validateHandle(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#handle', v) } +/** Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead */ export interface Migrate { seq: number did: string @@ -103,6 +134,7 @@ export function validateMigrate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#migrate', v) } +/** Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event */ export interface Tombstone { seq: number did: string @@ -140,10 +172,11 @@ export function validateInfo(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#info', v) } -/** A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null. */ +/** A repo operation, ie a mutation of a single record. */ export interface RepoOp { action: 'create' | 'update' | 'delete' | (string & {}) path: string + /** For creates and updates, the new record CID. For deletions, null. */ cid: CID | null [k: string]: unknown } diff --git a/packages/ozone/src/lexicon/types/com/atproto/temp/importRepo.ts b/packages/bsky/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts similarity index 62% rename from packages/ozone/src/lexicon/types/com/atproto/temp/importRepo.ts rename to packages/bsky/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts index d88361d9856..9486bce2b2b 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/temp/importRepo.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts @@ -2,28 +2,28 @@ * GENERATED CODE - DO NOT MODIFY */ import express from 'express' -import stream from 'stream' 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' -export interface QueryParams { - /** The DID of the repo. */ - did: string -} +export interface QueryParams {} -export type InputSchema = string | Uint8Array +export type InputSchema = undefined -export interface HandlerInput { - encoding: 'application/vnd.ipld.car' - body: stream.Readable +export interface OutputSchema { + activated: boolean + placeInQueue?: number + estimatedTimeMs?: number + [k: string]: unknown } +export type HandlerInput = undefined + export interface HandlerSuccess { - encoding: 'text/plain' - body: Uint8Array | stream.Readable + encoding: 'application/json' + body: OutputSchema headers?: { [key: string]: string } } @@ -32,7 +32,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/temp/fetchLabels.ts b/packages/bsky/src/lexicon/types/com/atproto/temp/fetchLabels.ts index 39341fd3a0e..0fbdeed1196 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/temp/fetchLabels.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/temp/fetchLabels.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoLabelDefs from '../label/defs' export interface QueryParams { @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts b/packages/bsky/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts index 5a295f701eb..c977500fc33 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts +++ b/packages/bsky/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/bsky/src/logger.ts b/packages/bsky/src/logger.ts index d6fad590eef..935b929d6f3 100644 --- a/packages/bsky/src/logger.ts +++ b/packages/bsky/src/logger.ts @@ -1,5 +1,8 @@ +import pino from 'pino' import pinoHttp from 'pino-http' +import * as jose from 'jose' import { subsystemLogger } from '@atproto/common' +import { parseBasicAuth } from './auth-verifier' export const dbLogger: ReturnType = subsystemLogger('bsky:db') @@ -21,5 +24,34 @@ export const loggerMiddleware = pinoHttp({ message: err?.message, } }, + req: (req) => { + const serialized = pino.stdSerializers.req(req) + const authHeader = serialized.headers.authorization || '' + let auth: string | undefined = undefined + if (authHeader.startsWith('Bearer ')) { + const token = authHeader.slice('Bearer '.length) + const { iss } = jose.decodeJwt(token) + if (iss) { + auth = 'Bearer ' + iss + } else { + auth = 'Bearer Invalid' + } + } + if (authHeader.startsWith('Basic ')) { + const parsed = parseBasicAuth(authHeader) + if (!parsed) { + auth = 'Basic Invalid' + } else { + auth = 'Basic ' + parsed.username + } + } + return { + ...serialized, + headers: { + ...serialized.headers, + authorization: auth, + }, + } + }, }, }) diff --git a/packages/bsky/tests/views/author-feed.test.ts b/packages/bsky/tests/views/author-feed.test.ts index 3ce69a48286..160608744a6 100644 --- a/packages/bsky/tests/views/author-feed.test.ts +++ b/packages/bsky/tests/views/author-feed.test.ts @@ -158,7 +158,7 @@ describe('pds author feed views', () => { const attemptAsAdmin = await agent.api.app.bsky.feed.getAuthorFeed( { actor: alice }, - { headers: await network.bsky.adminAuthHeaders() }, + { headers: network.bsky.adminAuthHeaders() }, ) expect(attemptAsAdmin.data.feed.length).toEqual(preBlock.feed.length) @@ -182,13 +182,26 @@ describe('pds author feed views', () => { recordUri: post.uri, }) - const { data: postBlock } = await agent.api.app.bsky.feed.getAuthorFeed( - { actor: alice }, - { headers: await network.serviceHeaders(carol) }, + const [{ data: postBlockAsUser }, { data: postBlockAsAdmin }] = + await Promise.all([ + agent.api.app.bsky.feed.getAuthorFeed( + { actor: alice }, + { headers: await network.serviceHeaders(carol) }, + ), + agent.api.app.bsky.feed.getAuthorFeed( + { actor: alice }, + { headers: network.bsky.adminAuthHeaders() }, + ), + ]) + + expect(postBlockAsUser.feed.length).toEqual(preBlock.feed.length - 1) + expect(postBlockAsUser.feed.map((item) => item.post.uri)).not.toContain( + post.uri, + ) + expect(postBlockAsAdmin.feed.length).toEqual(preBlock.feed.length) + expect(postBlockAsAdmin.feed.map((item) => item.post.uri)).toContain( + post.uri, ) - - expect(postBlock.feed.length).toEqual(preBlock.feed.length - 1) - expect(postBlock.feed.map((item) => item.post.uri)).not.toContain(post.uri) // Cleanup await network.bsky.ctx.dataplane.untakedownRecord({ diff --git a/packages/common-web/src/did-doc.ts b/packages/common-web/src/did-doc.ts index c2a05b796d3..541e10d0937 100644 --- a/packages/common-web/src/did-doc.ts +++ b/packages/common-web/src/did-doc.ts @@ -44,6 +44,11 @@ export const getSigningKey = ( publicKeyMultibase: found.publicKeyMultibase, } } +export const getSigningDidKey = (doc: DidDocument): string | undefined => { + const parsed = getSigningKey(doc) + if (!parsed) return + return `did:key:${parsed.publicKeyMultibase}` +} export const getPdsEndpoint = (doc: DidDocument): string | undefined => { return getServiceEndpoint(doc, { diff --git a/packages/dev-env/CHANGELOG.md b/packages/dev-env/CHANGELOG.md index 6e105a0efd3..dd5af8ef139 100644 --- a/packages/dev-env/CHANGELOG.md +++ b/packages/dev-env/CHANGELOG.md @@ -1,5 +1,75 @@ # @atproto/dev-env +## 0.2.33 + +### Patch Changes + +- Updated dependencies [[`514aab92d`](https://github.com/bluesky-social/atproto/commit/514aab92d26acd43859285f46318e386846522b1)]: + - @atproto/api@0.10.1 + - @atproto/bsky@0.0.33 + - @atproto/ozone@0.0.12 + - @atproto/pds@0.4.1 + +## 0.2.32 + +### Patch Changes + +- Updated dependencies [[`b60719480`](https://github.com/bluesky-social/atproto/commit/b60719480f5f00bffd074a40e8ddc03aa93d137d), [`4c511b3d9`](https://github.com/bluesky-social/atproto/commit/4c511b3d9de41ffeae3fc11db941e7df04f4468a)]: + - @atproto/api@0.10.0 + - @atproto/bsky@0.0.32 + - @atproto/ozone@0.0.11 + - @atproto/pds@0.4.0 + +## 0.2.31 + +### Patch Changes + +- Updated dependencies [[`f79cc6339`](https://github.com/bluesky-social/atproto/commit/f79cc63390ae9dbd47a4ff5d694eec25b78b788e)]: + - @atproto/api@0.9.8 + - @atproto/ozone@0.0.10 + - @atproto/bsky@0.0.31 + - @atproto/pds@0.3.19 + +## 0.2.30 + +### Patch Changes + +- Updated dependencies [[`8c94979f7`](https://github.com/bluesky-social/atproto/commit/8c94979f73fc5057449e24e66ef2e09b0e17e55b)]: + - @atproto/api@0.9.7 + - @atproto/bsky@0.0.30 + - @atproto/pds@0.3.18 + - @atproto/ozone@0.0.9 + +## 0.2.29 + +### Patch Changes + +- Updated dependencies [[`e4ec7af03`](https://github.com/bluesky-social/atproto/commit/e4ec7af03608949fc3b00a845f547a77599b5ad0)]: + - @atproto/api@0.9.6 + - @atproto/bsky@0.0.29 + - @atproto/ozone@0.0.8 + - @atproto/pds@0.3.17 + +## 0.2.28 + +### Patch Changes + +- Updated dependencies [[`8994d363`](https://github.com/bluesky-social/atproto/commit/8994d3633adad1c02569d6d44ae896e18195e8e2)]: + - @atproto/api@0.9.5 + - @atproto/bsky@0.0.28 + - @atproto/ozone@0.0.7 + - @atproto/pds@0.3.16 + +## 0.2.27 + +### Patch Changes + +- Updated dependencies [[`4171c04a`](https://github.com/bluesky-social/atproto/commit/4171c04ad81c5734a4558bc41fa1c4f3a1aba18c)]: + - @atproto/api@0.9.4 + - @atproto/bsky@0.0.27 + - @atproto/ozone@0.0.6 + - @atproto/pds@0.3.15 + ## 0.2.26 ### Patch Changes diff --git a/packages/dev-env/package.json b/packages/dev-env/package.json index ca45170a4fd..ee5165e9273 100644 --- a/packages/dev-env/package.json +++ b/packages/dev-env/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/dev-env", - "version": "0.2.26", + "version": "0.2.33", "license": "MIT", "description": "Local development environment helper for atproto development", "keywords": [ @@ -39,7 +39,7 @@ "@did-plc/lib": "^0.0.1", "@did-plc/server": "^0.0.1", "axios": "^0.27.2", - "better-sqlite3": "^7.6.2", + "better-sqlite3": "^9.4.0", "chalk": "^5.0.1", "dotenv": "^16.0.3", "express": "^4.18.2", diff --git a/packages/lex-cli/src/codegen/server.ts b/packages/lex-cli/src/codegen/server.ts index 13e6ecd8e87..f220ed315c4 100644 --- a/packages/lex-cli/src/codegen/server.ts +++ b/packages/lex-cli/src/codegen/server.ts @@ -408,7 +408,7 @@ function genServerXrpcMethod( file.addImportDeclaration({ moduleSpecifier: '@atproto/xrpc-server', - namedImports: [{ name: 'HandlerAuth' }], + namedImports: [{ name: 'HandlerAuth' }, { name: 'HandlerPipeThrough' }], }) //= export interface HandlerInput {...} if (def.type === 'procedure' && def.input?.encoding) { @@ -452,6 +452,7 @@ function genServerXrpcMethod( name: 'HandlerSuccess', isExported: true, }) + if (def.output.encoding) { handlerSuccess.addProperty({ name: 'encoding', @@ -502,7 +503,9 @@ function genServerXrpcMethod( file.addTypeAlias({ isExported: true, name: 'HandlerOutput', - type: `HandlerError | ${hasHandlerSuccess ? 'HandlerSuccess' : 'void'}`, + type: `HandlerError | ${ + hasHandlerSuccess ? 'HandlerSuccess | HandlerPipeThrough' : 'void' + }`, }) file.addTypeAlias({ diff --git a/packages/ozone/CHANGELOG.md b/packages/ozone/CHANGELOG.md index 23244c3bd8f..ca4d4954d97 100644 --- a/packages/ozone/CHANGELOG.md +++ b/packages/ozone/CHANGELOG.md @@ -1,5 +1,56 @@ # @atproto/ozone +## 0.0.12 + +### Patch Changes + +- Updated dependencies [[`514aab92d`](https://github.com/bluesky-social/atproto/commit/514aab92d26acd43859285f46318e386846522b1)]: + - @atproto/api@0.10.1 + +## 0.0.11 + +### Patch Changes + +- Updated dependencies [[`b60719480`](https://github.com/bluesky-social/atproto/commit/b60719480f5f00bffd074a40e8ddc03aa93d137d), [`4c511b3d9`](https://github.com/bluesky-social/atproto/commit/4c511b3d9de41ffeae3fc11db941e7df04f4468a)]: + - @atproto/api@0.10.0 + +## 0.0.10 + +### Patch Changes + +- [#2192](https://github.com/bluesky-social/atproto/pull/2192) [`f79cc6339`](https://github.com/bluesky-social/atproto/commit/f79cc63390ae9dbd47a4ff5d694eec25b78b788e) Thanks [@foysalit](https://github.com/foysalit)! - Tag event on moderation subjects and allow filtering events and subjects by tags + +- Updated dependencies [[`f79cc6339`](https://github.com/bluesky-social/atproto/commit/f79cc63390ae9dbd47a4ff5d694eec25b78b788e)]: + - @atproto/api@0.9.8 + +## 0.0.9 + +### Patch Changes + +- Updated dependencies [[`8c94979f7`](https://github.com/bluesky-social/atproto/commit/8c94979f73fc5057449e24e66ef2e09b0e17e55b)]: + - @atproto/api@0.9.7 + +## 0.0.8 + +### Patch Changes + +- Updated dependencies [[`e4ec7af03`](https://github.com/bluesky-social/atproto/commit/e4ec7af03608949fc3b00a845f547a77599b5ad0)]: + - @atproto/api@0.9.6 + +## 0.0.7 + +### Patch Changes + +- Updated dependencies [[`8994d363`](https://github.com/bluesky-social/atproto/commit/8994d3633adad1c02569d6d44ae896e18195e8e2)]: + - @atproto/api@0.9.5 + +## 0.0.6 + +### Patch Changes + +- Updated dependencies [[`4171c04a`](https://github.com/bluesky-social/atproto/commit/4171c04ad81c5734a4558bc41fa1c4f3a1aba18c)]: + - @atproto/api@0.9.4 + ## 0.0.5 ### Patch Changes diff --git a/packages/ozone/package.json b/packages/ozone/package.json index 22b0f2c47a5..e76dc644f10 100644 --- a/packages/ozone/package.json +++ b/packages/ozone/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/ozone", - "version": "0.0.5", + "version": "0.0.12", "license": "MIT", "description": "Backend service for moderating the Bluesky network.", "keywords": [ @@ -34,9 +34,9 @@ "@atproto/api": "workspace:^", "@atproto/common": "workspace:^", "@atproto/crypto": "workspace:^", - "@atproto/syntax": "workspace:^", "@atproto/identity": "workspace:^", "@atproto/lexicon": "workspace:^", + "@atproto/syntax": "workspace:^", "@atproto/xrpc-server": "workspace:^", "@did-plc/lib": "^0.0.1", "compression": "^1.7.4", diff --git a/packages/ozone/src/api/admin/emitModerationEvent.ts b/packages/ozone/src/api/admin/emitModerationEvent.ts index 7aed324608b..c04dfbecae6 100644 --- a/packages/ozone/src/api/admin/emitModerationEvent.ts +++ b/packages/ozone/src/api/admin/emitModerationEvent.ts @@ -7,6 +7,7 @@ import { isModEventTakedown, } from '../../lexicon/types/com/atproto/admin/defs' import { subjectFromInput } from '../../mod-service/subject' +import { ModerationLangService } from '../../mod-service/lang' export default function (server: Server, ctx: AppContext) { server.com.atproto.admin.emitModerationEvent({ @@ -51,17 +52,21 @@ export default function (server: Server, ctx: AppContext) { } if (isTakedownEvent || isReverseTakedownEvent) { - const isSubjectTakendown = await moderationService.isSubjectTakendown( - subject, - ) + const status = await moderationService.getStatus(subject) - if (isSubjectTakendown && isTakedownEvent) { + if (status?.takendown && isTakedownEvent) { throw new InvalidRequestError(`Subject is already taken down`) } - if (!isSubjectTakendown && isReverseTakedownEvent) { + if (!status?.takendown && isReverseTakedownEvent) { throw new InvalidRequestError(`Subject is not taken down`) } + + if (status?.takendown && isReverseTakedownEvent && subject.isRecord()) { + // due to the way blob status is modeled, we should reverse takedown on all + // blobs for the record being restored, which aren't taken down on another record. + subject.blobCids = status.blobCids ?? [] + } } const moderationEvent = await db.transaction(async (dbTxn) => { @@ -73,10 +78,21 @@ export default function (server: Server, ctx: AppContext) { createdBy, }) + const moderationLangService = new ModerationLangService(moderationTxn) + await moderationLangService.tagSubjectWithLang({ + subject, + createdBy: ctx.cfg.service.did, + subjectStatus: result.subjectStatus, + }) + if (subject.isRepo()) { if (isTakedownEvent) { - const isSuspend = !!result.durationInHours - await moderationTxn.takedownRepo(subject, result.id, isSuspend) + const isSuspend = !!result.event.durationInHours + await moderationTxn.takedownRepo( + subject, + result.event.id, + isSuspend, + ) } else if (isReverseTakedownEvent) { await moderationTxn.reverseTakedownRepo(subject) } @@ -84,7 +100,7 @@ export default function (server: Server, ctx: AppContext) { if (subject.isRecord()) { if (isTakedownEvent) { - await moderationTxn.takedownRecord(subject, result.id) + await moderationTxn.takedownRecord(subject, result.event.id) } else if (isReverseTakedownEvent) { await moderationTxn.reverseTakedownRecord(subject) } @@ -92,21 +108,20 @@ export default function (server: Server, ctx: AppContext) { if (isLabelEvent) { await moderationTxn.formatAndCreateLabels( - ctx.cfg.service.did, - result.subjectUri ?? result.subjectDid, - result.subjectCid, + result.event.subjectUri ?? result.event.subjectDid, + result.event.subjectCid, { - create: result.createLabelVals?.length - ? result.createLabelVals.split(' ') + create: result.event.createLabelVals?.length + ? result.event.createLabelVals.split(' ') : undefined, - negate: result.negateLabelVals?.length - ? result.negateLabelVals.split(' ') + negate: result.event.negateLabelVals?.length + ? result.event.negateLabelVals.split(' ') : undefined, }, ) } - return result + return result.event }) return { diff --git a/packages/ozone/src/api/admin/queryModerationEvents.ts b/packages/ozone/src/api/admin/queryModerationEvents.ts index 4c0cbdd1500..670cda96cbc 100644 --- a/packages/ozone/src/api/admin/queryModerationEvents.ts +++ b/packages/ozone/src/api/admin/queryModerationEvents.ts @@ -13,7 +13,16 @@ export default function (server: Server, ctx: AppContext) { sortDirection = 'desc', types, includeAllUserRecords = false, + hasComment, + comment, createdBy, + createdAfter, + createdBefore, + addedLabels = [], + removedLabels = [], + addedTags = [], + removedTags = [], + reportTypes, } = params const db = ctx.db const modService = ctx.modService(db) @@ -25,6 +34,15 @@ export default function (server: Server, ctx: AppContext) { cursor, sortDirection, includeAllUserRecords, + hasComment, + comment, + createdAfter, + createdBefore, + addedLabels, + addedTags, + removedLabels, + removedTags, + reportTypes, }) return { encoding: 'application/json', diff --git a/packages/ozone/src/api/admin/queryModerationStatuses.ts b/packages/ozone/src/api/admin/queryModerationStatuses.ts index fc935e5917a..fc491339ffa 100644 --- a/packages/ozone/src/api/admin/queryModerationStatuses.ts +++ b/packages/ozone/src/api/admin/queryModerationStatuses.ts @@ -22,6 +22,8 @@ export default function (server: Server, ctx: AppContext) { includeMuted = false, limit = 50, cursor, + tags = [], + excludeTags = [], } = params const db = ctx.db const modService = ctx.modService(db) @@ -41,6 +43,8 @@ export default function (server: Server, ctx: AppContext) { sortField, limit, cursor, + tags, + excludeTags, }) const subjectStatuses = results.statuses.map((status) => modService.views.formatSubjectStatus(status), diff --git a/packages/ozone/src/api/moderation/createReport.ts b/packages/ozone/src/api/moderation/createReport.ts index 6ede6dcd0e4..e87b957e8d0 100644 --- a/packages/ozone/src/api/moderation/createReport.ts +++ b/packages/ozone/src/api/moderation/createReport.ts @@ -4,6 +4,7 @@ import { getReasonType } from './util' import { subjectFromInput } from '../../mod-service/subject' import { REASONAPPEAL } from '../../lexicon/types/com/atproto/moderation/defs' import { ForbiddenError } from '@atproto/xrpc-server' +import { ModerationLangService } from '../../mod-service/lang' export default function (server: Server, ctx: AppContext) { server.com.atproto.moderation.createReport({ @@ -23,12 +24,22 @@ export default function (server: Server, ctx: AppContext) { const db = ctx.db const report = await db.transaction(async (dbTxn) => { const moderationTxn = ctx.modService(dbTxn) - return moderationTxn.report({ - reasonType: getReasonType(reasonType), - reason, + const { event: reportEvent, subjectStatus } = + await moderationTxn.report({ + reasonType: getReasonType(reasonType), + reason, + subject, + reportedBy: requester || ctx.cfg.service.did, + }) + + const moderationLangService = new ModerationLangService(moderationTxn) + await moderationLangService.tagSubjectWithLang({ subject, - reportedBy: requester || ctx.cfg.service.did, + subjectStatus, + createdBy: ctx.cfg.service.did, }) + + return reportEvent }) const body = ctx.modService(db).views.formatReport(report) diff --git a/packages/ozone/src/api/moderation/util.ts b/packages/ozone/src/api/moderation/util.ts index 040007d5e79..e64229891a5 100644 --- a/packages/ozone/src/api/moderation/util.ts +++ b/packages/ozone/src/api/moderation/util.ts @@ -62,4 +62,6 @@ const eventTypes = new Set([ 'com.atproto.admin.defs#modEventUnmute', 'com.atproto.admin.defs#modEventReverseTakedown', 'com.atproto.admin.defs#modEventEmail', + 'com.atproto.admin.defs#modEventResolveAppeal', + 'com.atproto.admin.defs#modEventTag', ]) diff --git a/packages/ozone/src/api/temp/fetchLabels.ts b/packages/ozone/src/api/temp/fetchLabels.ts index 69ead2cb28e..f11cb2028bb 100644 --- a/packages/ozone/src/api/temp/fetchLabels.ts +++ b/packages/ozone/src/api/temp/fetchLabels.ts @@ -1,29 +1,44 @@ import { Server } from '../../lexicon' import AppContext from '../../context' +import { + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + UNSPECCED_TAKEDOWN_LABEL, +} from '../../mod-service/types' export default function (server: Server, ctx: AppContext) { - server.com.atproto.temp.fetchLabels(async ({ params }) => { - const { limit } = params - const since = - params.since !== undefined ? new Date(params.since).toISOString() : '' - const labelRes = await ctx.db.db - .selectFrom('label') - .selectAll() - .orderBy('label.cts', 'asc') - .where('cts', '>', since) - .limit(limit) - .execute() + server.com.atproto.temp.fetchLabels({ + auth: ctx.authOptionalAccessOrRoleVerifier, + handler: async ({ auth, params }) => { + const { limit } = params + const since = + params.since !== undefined ? new Date(params.since).toISOString() : '' + const includeUnspeccedTakedowns = + auth.credentials.type === 'role' && auth.credentials.admin + const labelRes = await ctx.db.db + .selectFrom('label') + .selectAll() + .orderBy('label.cts', 'asc') + .where('cts', '>', since) + .if(!includeUnspeccedTakedowns, (q) => + q.where('label.val', 'not in', [ + UNSPECCED_TAKEDOWN_LABEL, + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + ]), + ) + .limit(limit) + .execute() - const labels = labelRes.map((l) => ({ - ...l, - cid: l.cid === '' ? undefined : l.cid, - })) + const labels = labelRes.map((l) => ({ + ...l, + cid: l.cid === '' ? undefined : l.cid, + })) - return { - encoding: 'application/json', - body: { - labels, - }, - } + return { + encoding: 'application/json', + body: { + labels, + }, + } + }, }) } diff --git a/packages/ozone/src/context.ts b/packages/ozone/src/context.ts index b346bfe74ba..1cb0ec1bd83 100644 --- a/packages/ozone/src/context.ts +++ b/packages/ozone/src/context.ts @@ -65,6 +65,7 @@ export class AppContext { eventPusher, appviewAgent, appviewAuth, + cfg.service.did, ) const communicationTemplateService = CommunicationTemplateService.creator() diff --git a/packages/ozone/src/daemon/context.ts b/packages/ozone/src/daemon/context.ts index 42c2a54cea5..5af19d89bc4 100644 --- a/packages/ozone/src/daemon/context.ts +++ b/packages/ozone/src/daemon/context.ts @@ -52,6 +52,7 @@ export class DaemonContext { eventPusher, appviewAgent, appviewAuth, + cfg.service.did, ) const eventReverser = new EventReverser(db, modService) diff --git a/packages/ozone/src/db/migrations/20240201T051104136Z-mod-event-blobs.ts b/packages/ozone/src/db/migrations/20240201T051104136Z-mod-event-blobs.ts new file mode 100644 index 00000000000..21b5e893b23 --- /dev/null +++ b/packages/ozone/src/db/migrations/20240201T051104136Z-mod-event-blobs.ts @@ -0,0 +1,15 @@ +import { Kysely } from 'kysely' + +export async function up(db: Kysely): Promise { + await db.schema + .alterTable('moderation_event') + .addColumn('subjectBlobCids', 'jsonb') + .execute() +} + +export async function down(db: Kysely): Promise { + await db.schema + .alterTable('moderation_event') + .dropColumn('subjectBlobCids') + .execute() +} diff --git a/packages/ozone/src/db/migrations/20240208T213404429Z-add-tags-column-to-moderation-subject.ts b/packages/ozone/src/db/migrations/20240208T213404429Z-add-tags-column-to-moderation-subject.ts new file mode 100644 index 00000000000..0c323ace91c --- /dev/null +++ b/packages/ozone/src/db/migrations/20240208T213404429Z-add-tags-column-to-moderation-subject.ts @@ -0,0 +1,31 @@ +import { Kysely } from 'kysely' + +export async function up(db: Kysely): Promise { + await db.schema + .alterTable('moderation_event') + .addColumn('addedTags', 'jsonb') + .execute() + await db.schema + .alterTable('moderation_event') + .addColumn('removedTags', 'jsonb') + .execute() + await db.schema + .alterTable('moderation_subject_status') + .addColumn('tags', 'jsonb') + .execute() +} + +export async function down(db: Kysely): Promise { + await db.schema + .alterTable('moderation_event') + .dropColumn('addedTags') + .execute() + await db.schema + .alterTable('moderation_event') + .dropColumn('removedTags') + .execute() + await db.schema + .alterTable('moderation_subject_status') + .dropColumn('tags') + .execute() +} diff --git a/packages/ozone/src/db/migrations/index.ts b/packages/ozone/src/db/migrations/index.ts index d00857bf575..1a823f860c5 100644 --- a/packages/ozone/src/db/migrations/index.ts +++ b/packages/ozone/src/db/migrations/index.ts @@ -4,3 +4,5 @@ export * as _20231219T205730722Z from './20231219T205730722Z-init' export * as _20240116T085607200Z from './20240116T085607200Z-communication-template' +export * as _20240201T051104136Z from './20240201T051104136Z-mod-event-blobs' +export * as _20240208T213404429Z from './20240208T213404429Z-add-tags-column-to-moderation-subject' diff --git a/packages/ozone/src/db/schema/moderation_event.ts b/packages/ozone/src/db/schema/moderation_event.ts index 0cf7d07c1e5..50bfb5edccf 100644 --- a/packages/ozone/src/db/schema/moderation_event.ts +++ b/packages/ozone/src/db/schema/moderation_event.ts @@ -15,10 +15,12 @@ export interface ModerationEvent { | 'com.atproto.admin.defs#modEventReverseTakedown' | 'com.atproto.admin.defs#modEventEmail' | 'com.atproto.admin.defs#modEventResolveAppeal' + | 'com.atproto.admin.defs#modEventTag' subjectType: 'com.atproto.admin.defs#repoRef' | 'com.atproto.repo.strongRef' subjectDid: string subjectUri: string | null subjectCid: string | null + subjectBlobCids: string[] | null createLabelVals: string | null negateLabelVals: string | null comment: string | null @@ -27,6 +29,8 @@ export interface ModerationEvent { durationInHours: number | null expiresAt: string | null meta: Record | null + addedTags: string[] | null + removedTags: string[] | null legacyRefId: number | null } diff --git a/packages/ozone/src/db/schema/moderation_subject_status.ts b/packages/ozone/src/db/schema/moderation_subject_status.ts index 6e67082f31c..59803133bcb 100644 --- a/packages/ozone/src/db/schema/moderation_subject_status.ts +++ b/packages/ozone/src/db/schema/moderation_subject_status.ts @@ -25,6 +25,7 @@ export interface ModerationSubjectStatus { takendown: boolean appealed: boolean | null comment: string | null + tags: string[] | null } export type PartialDB = { diff --git a/packages/ozone/src/db/types.ts b/packages/ozone/src/db/types.ts index c38271ee119..b7a2b9bb8ec 100644 --- a/packages/ozone/src/db/types.ts +++ b/packages/ozone/src/db/types.ts @@ -1,5 +1,5 @@ import { Pool as PgPool } from 'pg' -import { DynamicModule, RawBuilder, SelectQueryBuilder } from 'kysely' +import { DynamicModule, RawBuilder, SelectQueryBuilder, sql } from 'kysely' export type DbRef = RawBuilder | ReturnType @@ -13,3 +13,8 @@ export type PgOptions = { poolMaxUses?: number poolIdleTimeoutMs?: number } + +export const jsonb = (val: T) => { + if (val === null) return sql`null` + return sql`${JSON.stringify(val)}::jsonb` +} diff --git a/packages/ozone/src/lexicon/index.ts b/packages/ozone/src/lexicon/index.ts index 0e30f4d172c..cf2c613e686 100644 --- a/packages/ozone/src/lexicon/index.ts +++ b/packages/ozone/src/lexicon/index.ts @@ -30,9 +30,14 @@ import * as ComAtprotoAdminSearchRepos from './types/com/atproto/admin/searchRep import * as ComAtprotoAdminSendEmail from './types/com/atproto/admin/sendEmail' import * as ComAtprotoAdminUpdateAccountEmail from './types/com/atproto/admin/updateAccountEmail' import * as ComAtprotoAdminUpdateAccountHandle from './types/com/atproto/admin/updateAccountHandle' +import * as ComAtprotoAdminUpdateAccountPassword from './types/com/atproto/admin/updateAccountPassword' import * as ComAtprotoAdminUpdateCommunicationTemplate from './types/com/atproto/admin/updateCommunicationTemplate' import * as ComAtprotoAdminUpdateSubjectStatus from './types/com/atproto/admin/updateSubjectStatus' +import * as ComAtprotoIdentityGetRecommendedDidCredentials from './types/com/atproto/identity/getRecommendedDidCredentials' +import * as ComAtprotoIdentityRequestPlcOperationSignature from './types/com/atproto/identity/requestPlcOperationSignature' import * as ComAtprotoIdentityResolveHandle from './types/com/atproto/identity/resolveHandle' +import * as ComAtprotoIdentitySignPlcOperation from './types/com/atproto/identity/signPlcOperation' +import * as ComAtprotoIdentitySubmitPlcOperation from './types/com/atproto/identity/submitPlcOperation' import * as ComAtprotoIdentityUpdateHandle from './types/com/atproto/identity/updateHandle' import * as ComAtprotoLabelQueryLabels from './types/com/atproto/label/queryLabels' import * as ComAtprotoLabelSubscribeLabels from './types/com/atproto/label/subscribeLabels' @@ -42,19 +47,25 @@ import * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createReco import * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord' import * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo' import * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord' +import * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo' +import * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs' import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords' import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord' import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob' +import * as ComAtprotoServerActivateAccount from './types/com/atproto/server/activateAccount' +import * as ComAtprotoServerCheckAccountStatus from './types/com/atproto/server/checkAccountStatus' import * as ComAtprotoServerConfirmEmail from './types/com/atproto/server/confirmEmail' import * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount' import * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword' import * as ComAtprotoServerCreateInviteCode from './types/com/atproto/server/createInviteCode' import * as ComAtprotoServerCreateInviteCodes from './types/com/atproto/server/createInviteCodes' import * as ComAtprotoServerCreateSession from './types/com/atproto/server/createSession' +import * as ComAtprotoServerDeactivateAccount from './types/com/atproto/server/deactivateAccount' import * as ComAtprotoServerDeleteAccount from './types/com/atproto/server/deleteAccount' import * as ComAtprotoServerDeleteSession from './types/com/atproto/server/deleteSession' import * as ComAtprotoServerDescribeServer from './types/com/atproto/server/describeServer' import * as ComAtprotoServerGetAccountInviteCodes from './types/com/atproto/server/getAccountInviteCodes' +import * as ComAtprotoServerGetServiceAuth from './types/com/atproto/server/getServiceAuth' import * as ComAtprotoServerGetSession from './types/com/atproto/server/getSession' import * as ComAtprotoServerListAppPasswords from './types/com/atproto/server/listAppPasswords' import * as ComAtprotoServerRefreshSession from './types/com/atproto/server/refreshSession' @@ -78,11 +89,9 @@ import * as ComAtprotoSyncListRepos from './types/com/atproto/sync/listRepos' import * as ComAtprotoSyncNotifyOfUpdate from './types/com/atproto/sync/notifyOfUpdate' import * as ComAtprotoSyncRequestCrawl from './types/com/atproto/sync/requestCrawl' import * as ComAtprotoSyncSubscribeRepos from './types/com/atproto/sync/subscribeRepos' +import * as ComAtprotoTempCheckSignupQueue from './types/com/atproto/temp/checkSignupQueue' import * as ComAtprotoTempFetchLabels from './types/com/atproto/temp/fetchLabels' -import * as ComAtprotoTempImportRepo from './types/com/atproto/temp/importRepo' -import * as ComAtprotoTempPushBlob from './types/com/atproto/temp/pushBlob' import * as ComAtprotoTempRequestPhoneVerification from './types/com/atproto/temp/requestPhoneVerification' -import * as ComAtprotoTempTransferAccount from './types/com/atproto/temp/transferAccount' import * as AppBskyActorGetPreferences from './types/app/bsky/actor/getPreferences' import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile' import * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles' @@ -126,7 +135,6 @@ import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/ import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen' import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' import * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions' -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' @@ -437,6 +445,17 @@ export class ComAtprotoAdminNS { return this._server.xrpc.method(nsid, cfg) } + updateAccountPassword( + cfg: ConfigOf< + AV, + ComAtprotoAdminUpdateAccountPassword.Handler>, + ComAtprotoAdminUpdateAccountPassword.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.admin.updateAccountPassword' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + updateCommunicationTemplate( cfg: ConfigOf< AV, @@ -467,6 +486,32 @@ export class ComAtprotoIdentityNS { this._server = server } + getRecommendedDidCredentials( + cfg: ConfigOf< + AV, + ComAtprotoIdentityGetRecommendedDidCredentials.Handler>, + ComAtprotoIdentityGetRecommendedDidCredentials.HandlerReqCtx< + ExtractAuth + > + >, + ) { + const nsid = 'com.atproto.identity.getRecommendedDidCredentials' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + requestPlcOperationSignature( + cfg: ConfigOf< + AV, + ComAtprotoIdentityRequestPlcOperationSignature.Handler>, + ComAtprotoIdentityRequestPlcOperationSignature.HandlerReqCtx< + ExtractAuth + > + >, + ) { + const nsid = 'com.atproto.identity.requestPlcOperationSignature' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + resolveHandle( cfg: ConfigOf< AV, @@ -478,6 +523,28 @@ export class ComAtprotoIdentityNS { return this._server.xrpc.method(nsid, cfg) } + signPlcOperation( + cfg: ConfigOf< + AV, + ComAtprotoIdentitySignPlcOperation.Handler>, + ComAtprotoIdentitySignPlcOperation.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.identity.signPlcOperation' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + submitPlcOperation( + cfg: ConfigOf< + AV, + ComAtprotoIdentitySubmitPlcOperation.Handler>, + ComAtprotoIdentitySubmitPlcOperation.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.identity.submitPlcOperation' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + updateHandle( cfg: ConfigOf< AV, @@ -601,6 +668,28 @@ export class ComAtprotoRepoNS { return this._server.xrpc.method(nsid, cfg) } + importRepo( + cfg: ConfigOf< + AV, + ComAtprotoRepoImportRepo.Handler>, + ComAtprotoRepoImportRepo.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.repo.importRepo' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + listMissingBlobs( + cfg: ConfigOf< + AV, + ComAtprotoRepoListMissingBlobs.Handler>, + ComAtprotoRepoListMissingBlobs.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.repo.listMissingBlobs' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + listRecords( cfg: ConfigOf< AV, @@ -642,6 +731,28 @@ export class ComAtprotoServerNS { this._server = server } + activateAccount( + cfg: ConfigOf< + AV, + ComAtprotoServerActivateAccount.Handler>, + ComAtprotoServerActivateAccount.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.activateAccount' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + checkAccountStatus( + cfg: ConfigOf< + AV, + ComAtprotoServerCheckAccountStatus.Handler>, + ComAtprotoServerCheckAccountStatus.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.checkAccountStatus' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + confirmEmail( cfg: ConfigOf< AV, @@ -708,6 +819,17 @@ export class ComAtprotoServerNS { return this._server.xrpc.method(nsid, cfg) } + deactivateAccount( + cfg: ConfigOf< + AV, + ComAtprotoServerDeactivateAccount.Handler>, + ComAtprotoServerDeactivateAccount.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.deactivateAccount' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + deleteAccount( cfg: ConfigOf< AV, @@ -752,6 +874,17 @@ export class ComAtprotoServerNS { return this._server.xrpc.method(nsid, cfg) } + getServiceAuth( + cfg: ConfigOf< + AV, + ComAtprotoServerGetServiceAuth.Handler>, + ComAtprotoServerGetServiceAuth.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.getServiceAuth' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getSession( cfg: ConfigOf< AV, @@ -1021,36 +1154,25 @@ export class ComAtprotoTempNS { this._server = server } - fetchLabels( - cfg: ConfigOf< - AV, - ComAtprotoTempFetchLabels.Handler>, - ComAtprotoTempFetchLabels.HandlerReqCtx> - >, - ) { - const nsid = 'com.atproto.temp.fetchLabels' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } - - importRepo( + checkSignupQueue( cfg: ConfigOf< AV, - ComAtprotoTempImportRepo.Handler>, - ComAtprotoTempImportRepo.HandlerReqCtx> + ComAtprotoTempCheckSignupQueue.Handler>, + ComAtprotoTempCheckSignupQueue.HandlerReqCtx> >, ) { - const nsid = 'com.atproto.temp.importRepo' // @ts-ignore + const nsid = 'com.atproto.temp.checkSignupQueue' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - pushBlob( + fetchLabels( cfg: ConfigOf< AV, - ComAtprotoTempPushBlob.Handler>, - ComAtprotoTempPushBlob.HandlerReqCtx> + ComAtprotoTempFetchLabels.Handler>, + ComAtprotoTempFetchLabels.HandlerReqCtx> >, ) { - const nsid = 'com.atproto.temp.pushBlob' // @ts-ignore + const nsid = 'com.atproto.temp.fetchLabels' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } @@ -1064,17 +1186,6 @@ export class ComAtprotoTempNS { const nsid = 'com.atproto.temp.requestPhoneVerification' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - - transferAccount( - cfg: ConfigOf< - AV, - ComAtprotoTempTransferAccount.Handler>, - ComAtprotoTempTransferAccount.HandlerReqCtx> - >, - ) { - const nsid = 'com.atproto.temp.transferAccount' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } } export class AppNS { @@ -1637,17 +1748,6 @@ export class AppBskyUnspeccedNS { return this._server.xrpc.method(nsid, cfg) } - getTimelineSkeleton( - cfg: ConfigOf< - AV, - AppBskyUnspeccedGetTimelineSkeleton.Handler>, - AppBskyUnspeccedGetTimelineSkeleton.HandlerReqCtx> - >, - ) { - const nsid = 'app.bsky.unspecced.getTimelineSkeleton' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } - searchActorsSkeleton( cfg: ConfigOf< AV, diff --git a/packages/ozone/src/lexicon/lexicons.ts b/packages/ozone/src/lexicon/lexicons.ts index fea624e9a04..14e4c1cb81e 100644 --- a/packages/ozone/src/lexicon/lexicons.ts +++ b/packages/ozone/src/lexicon/lexicons.ts @@ -91,6 +91,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, subject: { @@ -147,6 +148,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventAcknowledge', 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', + 'lex:com.atproto.admin.defs#modEventEmail', 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, @@ -301,6 +303,12 @@ export const schemaDict = { type: 'string', format: 'datetime', }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, }, }, reportViewDetail: { @@ -895,6 +903,33 @@ export const schemaDict = { }, }, }, + modEventTag: { + type: 'object', + description: 'Add/Remove a tag on a subject', + required: ['add', 'remove'], + properties: { + add: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be added to the subject. If already exists, won't be duplicated.", + }, + remove: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated.", + }, + comment: { + type: 'string', + description: 'Additional comment about added/removed tags.', + }, + }, + }, communicationTemplateView: { type: 'object', required: [ @@ -1073,6 +1108,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventReverseTakedown', 'lex:com.atproto.admin.defs#modEventUnmute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventTag', ], }, subject: { @@ -1450,6 +1486,16 @@ export const schemaDict = { description: 'Sort direction for the events. Defaults to descending order of created at timestamp.', }, + createdAfter: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created after a given timestamp', + }, + createdBefore: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created before a given timestamp', + }, subject: { type: 'string', format: 'uri', @@ -1466,6 +1512,53 @@ export const schemaDict = { maximum: 100, default: 50, }, + hasComment: { + type: 'boolean', + description: 'If true, only events with comments are returned', + }, + comment: { + type: 'string', + description: + 'If specified, only events with comments containing the keyword are returned', + }, + addedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were added are returned', + }, + removedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were removed are returned', + }, + addedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were added are returned', + }, + removedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were removed are returned', + }, + reportTypes: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1577,6 +1670,18 @@ export const schemaDict = { maximum: 100, default: 50, }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, + excludeTags: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1758,6 +1863,33 @@ export const schemaDict = { }, }, }, + ComAtprotoAdminUpdateAccountPassword: { + lexicon: 1, + id: 'com.atproto.admin.updateAccountPassword', + defs: { + main: { + type: 'procedure', + description: + 'Update the password for a user account as an administrator.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['did', 'password'], + properties: { + did: { + type: 'string', + format: 'did', + }, + password: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoAdminUpdateCommunicationTemplate: { lexicon: 1, id: 'com.atproto.admin.updateCommunicationTemplate', @@ -1863,13 +1995,63 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentityGetRecommendedDidCredentials: { + lexicon: 1, + id: 'com.atproto.identity.getRecommendedDidCredentials', + defs: { + main: { + type: 'query', + description: + 'Describe the credentials that should be included in the DID doc of an account that is migrating to this service.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + rotationKeys: { + description: + 'Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs.', + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentityRequestPlcOperationSignature: { + lexicon: 1, + id: 'com.atproto.identity.requestPlcOperationSignature', + defs: { + main: { + type: 'procedure', + description: + 'Request an email with a code to in order to request a signed PLC operation. Requires Auth.', + }, + }, + }, ComAtprotoIdentityResolveHandle: { lexicon: 1, id: 'com.atproto.identity.resolveHandle', defs: { main: { type: 'query', - description: 'Provides the DID of a repo.', + description: 'Resolves a handle (domain name) to a DID.', parameters: { type: 'params', required: ['handle'], @@ -1897,13 +2079,92 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentitySignPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.signPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Signs a PLC operation to update some value(s) in the requesting DID's document.", + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + token: { + description: + 'A token received through com.atproto.identity.requestPlcOperationSignature', + type: 'string', + }, + rotationKeys: { + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + description: 'A signed DID PLC operation.', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentitySubmitPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.submitPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Validates a PLC operation to ensure that it doesn't violate a service's constraints or get the identity into a bad state, then submits it to the PLC registry", + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, ComAtprotoIdentityUpdateHandle: { lexicon: 1, id: 'com.atproto.identity.updateHandle', defs: { main: { type: 'procedure', - description: 'Updates the handle of the account.', + description: + "Updates the current account's handle. Verifies handle validity, and updates did:plc document if necessary. Implemented by PDS, and requires auth.", input: { encoding: 'application/json', schema: { @@ -1913,6 +2174,7 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'The new handle.', }, }, }, @@ -2003,7 +2265,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find labels relevant to the provided URI patterns.', + description: + 'Find labels relevant to the provided AT-URI patterns. Public endpoint for moderation services, though may return different or additional results with auth.', parameters: { type: 'params', required: ['uriPatterns'], @@ -2064,13 +2327,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to label updates.', + description: + 'Subscribe to stream of labels (and negations). Public endpoint implemented by mod services. Uses same sequencing scheme as repo event stream.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -2126,7 +2390,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Report a repo or a record.', + description: + 'Submit a moderation report regarding an atproto account or record. Implemented by moderation services (with PDS proxying), and requires auth.', input: { encoding: 'application/json', schema: { @@ -2135,10 +2400,14 @@ export const schemaDict = { properties: { reasonType: { type: 'ref', + description: + 'Indicates the broad category of violation the report is for.', ref: 'lex:com.atproto.moderation.defs#reasonType', }, reason: { type: 'string', + description: + 'Additional context about the content and violation.', }, subject: { type: 'union', @@ -2249,7 +2518,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Apply a batch transaction of creates, updates, and deletes.', + 'Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2259,12 +2528,14 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the records.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data, for all operations.", }, writes: { type: 'array', @@ -2280,6 +2551,8 @@ export const schemaDict = { }, swapCommit: { type: 'string', + description: + 'If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.', format: 'cid', }, }, @@ -2288,12 +2561,14 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that the 'swapCommit' parameter did not match current commit.", }, ], }, create: { type: 'object', - description: 'Create a new record.', + description: 'Operation which creates a new record.', required: ['collection', 'value'], properties: { collection: { @@ -2311,7 +2586,7 @@ export const schemaDict = { }, update: { type: 'object', - description: 'Update an existing record.', + description: 'Operation which updates an existing record.', required: ['collection', 'rkey', 'value'], properties: { collection: { @@ -2328,7 +2603,7 @@ export const schemaDict = { }, delete: { type: 'object', - description: 'Delete an existing record.', + description: 'Operation which deletes an existing record.', required: ['collection', 'rkey'], properties: { collection: { @@ -2348,7 +2623,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create a new record.', + description: + 'Create a single new repository record. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2358,7 +2634,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2367,17 +2644,18 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', - description: 'The record to create.', + description: 'The record itself. Must contain a $type field.', }, swapCommit: { type: 'string', @@ -2408,6 +2686,8 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that 'swapCommit' didn't match current repo commit.", }, ], }, @@ -2419,7 +2699,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete a record, or ensure it doesn't exist.", + description: + "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", input: { encoding: 'application/json', schema: { @@ -2429,7 +2710,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2438,7 +2720,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, swapRecord: { type: 'string', @@ -2470,7 +2752,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about the repo, including the list of collections.', + 'Get information about an account and repository, including the list of collections. Does not require auth.', parameters: { type: 'params', required: ['repo'], @@ -2504,9 +2786,12 @@ export const schemaDict = { }, didDoc: { type: 'unknown', + description: 'The complete DID document for this account.', }, collections: { type: 'array', + description: + 'List of all the collections (NSIDs) for which this repo contains at least one record.', items: { type: 'string', format: 'nsid', @@ -2514,6 +2799,8 @@ export const schemaDict = { }, handleIsCorrect: { type: 'boolean', + description: + 'Indicates if handle is currently valid (resolves bi-directionally)', }, }, }, @@ -2527,7 +2814,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a record.', + description: + 'Get a single record from a repository. Does not require auth.', parameters: { type: 'params', required: ['repo', 'collection', 'rkey'], @@ -2544,7 +2832,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, cid: { type: 'string', @@ -2577,39 +2865,112 @@ export const schemaDict = { }, }, }, - ComAtprotoRepoListRecords: { + ComAtprotoRepoImportRepo: { lexicon: 1, - id: 'com.atproto.repo.listRecords', + id: 'com.atproto.repo.importRepo', + defs: { + main: { + type: 'procedure', + description: + 'Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.', + input: { + encoding: 'application/vnd.ipld.car', + }, + }, + }, + }, + ComAtprotoRepoListMissingBlobs: { + lexicon: 1, + id: 'com.atproto.repo.listMissingBlobs', defs: { main: { type: 'query', - description: 'List a range of records in a collection.', + description: + 'Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.', parameters: { type: 'params', - required: ['repo', 'collection'], properties: { - repo: { - type: 'string', - format: 'at-identifier', - description: 'The handle or DID of the repo.', - }, - collection: { - type: 'string', - format: 'nsid', - description: 'The NSID of the record type.', - }, limit: { type: 'integer', minimum: 1, - maximum: 100, - default: 50, - description: 'The number of records to return.', + maximum: 1000, + default: 500, }, cursor: { type: 'string', }, - rkeyStart: { - type: 'string', + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['blobs'], + properties: { + cursor: { + type: 'string', + }, + blobs: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.repo.listMissingBlobs#recordBlob', + }, + }, + }, + }, + }, + }, + recordBlob: { + type: 'object', + required: ['cid', 'recordUri'], + properties: { + cid: { + type: 'string', + format: 'cid', + }, + recordUri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + }, + }, + ComAtprotoRepoListRecords: { + lexicon: 1, + id: 'com.atproto.repo.listRecords', + defs: { + main: { + type: 'query', + description: + 'List a range of records in a repository, matching a specific collection. Does not require auth.', + parameters: { + type: 'params', + required: ['repo', 'collection'], + properties: { + repo: { + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', + }, + collection: { + type: 'string', + format: 'nsid', + description: 'The NSID of the record type.', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + description: 'The number of records to return.', + }, + cursor: { + type: 'string', + }, + rkeyStart: { + type: 'string', description: 'DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)', }, @@ -2669,7 +3030,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Write a record, creating or updating it as needed.', + description: + 'Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2680,7 +3042,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2689,13 +3052,14 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', @@ -2705,7 +3069,7 @@ export const schemaDict = { type: 'string', format: 'cid', description: - 'Compare and swap with the previous record by CID.', + 'Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation', }, swapCommit: { type: 'string', @@ -2769,7 +3133,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Upload a new blob to be added to repo in a later request.', + 'Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.', input: { encoding: '*/*', }, @@ -2788,6 +3152,75 @@ export const schemaDict = { }, }, }, + ComAtprotoServerActivateAccount: { + lexicon: 1, + id: 'com.atproto.server.activateAccount', + defs: { + main: { + type: 'procedure', + description: + "Activates a currently deactivated account. Used to finalize account migration after the account's repo is imported and identity is setup.", + }, + }, + }, + ComAtprotoServerCheckAccountStatus: { + lexicon: 1, + id: 'com.atproto.server.checkAccountStatus', + defs: { + main: { + type: 'query', + description: + 'Returns the status of an account, especially as pertaining to import or recovery. Can be called many times over the course of an account migration. Requires auth and can only be called pertaining to oneself.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: [ + 'activated', + 'validDid', + 'repoCommit', + 'repoRev', + 'repoBlocks', + 'indexedRecords', + 'privateStateValues', + 'expectedBlobs', + 'importedBlobs', + ], + properties: { + activated: { + type: 'boolean', + }, + validDid: { + type: 'boolean', + }, + repoCommit: { + type: 'string', + format: 'cid', + }, + repoRev: { + type: 'string', + }, + repoBlocks: { + type: 'integer', + }, + indexedRecords: { + type: 'integer', + }, + privateStateValues: { + type: 'integer', + }, + expectedBlobs: { + type: 'integer', + }, + importedBlobs: { + type: 'integer', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerConfirmEmail: { lexicon: 1, id: 'com.atproto.server.confirmEmail', @@ -2834,7 +3267,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create an account.', + description: 'Create an account. Implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2847,10 +3280,13 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'Requested handle for the account.', }, did: { type: 'string', format: 'did', + description: + 'Pre-existing atproto DID, being imported to a new account.', }, inviteCode: { type: 'string', @@ -2863,12 +3299,18 @@ export const schemaDict = { }, password: { type: 'string', + description: + 'Initial account password. May need to meet instance-specific password strength requirements.', }, recoveryKey: { type: 'string', + description: + 'DID PLC rotation key (aka, recovery key) to be included in PLC creation operation.', }, plcOp: { type: 'unknown', + description: + 'A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented.', }, }, }, @@ -2877,6 +3319,8 @@ export const schemaDict = { encoding: 'application/json', schema: { type: 'object', + description: + 'Account login session returned on successful account creation.', required: ['accessJwt', 'refreshJwt', 'handle', 'did'], properties: { accessJwt: { @@ -2892,9 +3336,11 @@ export const schemaDict = { did: { type: 'string', format: 'did', + description: 'The DID of the new account.', }, didDoc: { type: 'unknown', + description: 'Complete DID document.', }, }, }, @@ -2940,6 +3386,8 @@ export const schemaDict = { properties: { name: { type: 'string', + description: + 'A short name for the App Password, to help distinguish them.', }, }, }, @@ -3141,6 +3589,31 @@ export const schemaDict = { }, }, }, + ComAtprotoServerDeactivateAccount: { + lexicon: 1, + id: 'com.atproto.server.deactivateAccount', + defs: { + main: { + type: 'procedure', + description: + 'Deactivates a currently active account. Stops serving of repo, and future writes to repo until reactivated. Used to finalize account migration with the old host after the account has been activated on the new host.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + deleteAfter: { + type: 'string', + format: 'datetime', + description: + 'A recommendation to server as to how long they should hold onto the deactivated account before deleting.', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerDefs: { lexicon: 1, id: 'com.atproto.server.defs', @@ -3207,7 +3680,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete an actor's account with a token and password.", + description: + "Delete an actor's account with a token and password. Can only be called after requesting a deletion token. Requires auth.", input: { encoding: 'application/json', schema: { @@ -3244,7 +3718,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Delete the current session.', + description: 'Delete the current session. Requires auth.', }, }, }, @@ -3255,29 +3729,40 @@ export const schemaDict = { main: { type: 'query', description: - "Get a document describing the service's accounts configuration.", + "Describes the server's account creation requirements and capabilities. Implemented by PDS.", output: { encoding: 'application/json', schema: { type: 'object', - required: ['availableUserDomains'], + required: ['did', 'availableUserDomains'], properties: { inviteCodeRequired: { type: 'boolean', + description: + 'If true, an invite code must be supplied to create an account on this instance.', }, phoneVerificationRequired: { type: 'boolean', + description: + 'If true, a phone verification token must be supplied to create an account on this instance.', }, availableUserDomains: { type: 'array', + description: + 'List of domain suffixes that can be used in account handles.', items: { type: 'string', }, }, links: { type: 'ref', + description: 'URLs of service policy documents.', ref: 'lex:com.atproto.server.describeServer#links', }, + did: { + type: 'string', + format: 'did', + }, }, }, }, @@ -3301,7 +3786,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get all invite codes for a given account.', + description: + 'Get all invite codes for the current account. Requires auth.', parameters: { type: 'params', properties: { @@ -3312,6 +3798,8 @@ export const schemaDict = { createAvailable: { type: 'boolean', default: true, + description: + "Controls whether any new 'earned' but not 'created' invites should be created.", }, }, }, @@ -3339,13 +3827,49 @@ export const schemaDict = { }, }, }, + ComAtprotoServerGetServiceAuth: { + lexicon: 1, + id: 'com.atproto.server.getServiceAuth', + defs: { + main: { + type: 'query', + description: + 'Get a signed token on behalf of the requesting DID for the requested service.', + parameters: { + type: 'params', + required: ['aud'], + properties: { + aud: { + type: 'string', + format: 'did', + description: + 'The DID of the service that the token will be used to authenticate with', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['token'], + properties: { + token: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerGetSession: { lexicon: 1, id: 'com.atproto.server.getSession', defs: { main: { type: 'query', - description: 'Get information about the current session.', + description: + 'Get information about the current auth session. Requires auth.', output: { encoding: 'application/json', schema: { @@ -3425,7 +3949,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Refresh an authentication session.', + description: + "Refresh an authentication session. Requires auth using the 'refreshJwt' (not the 'accessJwt').", output: { encoding: 'application/json', schema: { @@ -3531,7 +4056,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Reserve a repo signing key for account creation.', + description: + 'Reserve a repo signing key, for use with account creation. Necessary so that a DID PLC update operation can be constructed during an account migraiton. Public and does not require auth; implemented by PDS. NOTE: this endpoint may change when full account migration is implemented.', input: { encoding: 'application/json', schema: { @@ -3539,7 +4065,8 @@ export const schemaDict = { properties: { did: { type: 'string', - description: 'The did to reserve a new did:key for', + format: 'did', + description: 'The DID to reserve a key for.', }, }, }, @@ -3552,7 +4079,8 @@ export const schemaDict = { properties: { signingKey: { type: 'string', - description: 'Public signing key in the form of a did:key.', + description: + 'The public key for the reserved signing key, in did:key serialization.', }, }, }, @@ -3659,7 +4187,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a blob associated with a given repo.', + description: + 'Get a blob associated with a given account. Returns the full blob as originally uploaded. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cid'], @@ -3667,7 +4196,7 @@ export const schemaDict = { did: { type: 'string', format: 'did', - description: 'The DID of the repo.', + description: 'The DID of the account.', }, cid: { type: 'string', @@ -3688,7 +4217,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get blocks from a given repo.', + description: + 'Get data blocks from a given repo, by CID. For example, intermediate MST nodes, or records. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cids'], @@ -3783,7 +4313,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the current commit CID & revision of the repo.', + description: + 'Get the current commit CID & revision of the specified repo. Does not require auth.', parameters: { type: 'params', required: ['did'], @@ -3826,7 +4357,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get blocks needed for existence or non-existence of record.', + 'Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.', parameters: { type: 'params', required: ['did', 'collection', 'rkey'], @@ -3842,6 +4373,7 @@ export const schemaDict = { }, rkey: { type: 'string', + description: 'Record Key', }, commit: { type: 'string', @@ -3863,7 +4395,7 @@ export const schemaDict = { main: { type: 'query', description: - "Gets the DID's repo, optionally catching up from a specific revision.", + "Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS.", parameters: { type: 'params', required: ['did'], @@ -3875,7 +4407,8 @@ export const schemaDict = { }, since: { type: 'string', - description: 'The revision of the repo to catch up from.', + description: + "The revision ('rev') of the repo to create a diff from.", }, }, }, @@ -3891,7 +4424,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List blob CIDs since some revision.', + description: + 'List blob CIDso for an account, since some repo revision. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did'], @@ -3944,7 +4478,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List DIDs and root CIDs of hosted repos.', + description: + 'Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { @@ -3990,6 +4525,7 @@ export const schemaDict = { head: { type: 'string', format: 'cid', + description: 'Current repo commit CID', }, rev: { type: 'string', @@ -4005,7 +4541,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Notify a crawling service of a recent update; often when a long break between updates causes the connection with the crawling service to break.', + 'Notify a crawling service of a recent update, and that crawling should resume. Intended use is after a gap between repo stream events caused the crawling service to disconnect. Does not require auth; implemented by Relay.', input: { encoding: 'application/json', schema: { @@ -4015,7 +4551,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is notifying of update.', + 'Hostname of the current service (usually a PDS) that is notifying of update.', }, }, }, @@ -4029,7 +4565,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Request a service to persistently crawl hosted repos.', + description: + 'Request a service to persistently crawl hosted repos. Expected use is new PDS instances declaring their existence to Relays. Does not require auth.', input: { encoding: 'application/json', schema: { @@ -4039,7 +4576,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is requesting to be crawled.', + 'Hostname of the current service (eg, PDS) that is requesting to be crawled.', }, }, }, @@ -4053,13 +4590,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to repo updates.', + description: + 'Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -4068,6 +4606,7 @@ export const schemaDict = { type: 'union', refs: [ 'lex:com.atproto.sync.subscribeRepos#commit', + 'lex:com.atproto.sync.subscribeRepos#identity', 'lex:com.atproto.sync.subscribeRepos#handle', 'lex:com.atproto.sync.subscribeRepos#migrate', 'lex:com.atproto.sync.subscribeRepos#tombstone', @@ -4081,11 +4620,15 @@ export const schemaDict = { }, { name: 'ConsumerTooSlow', + description: + 'If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection.', }, ], }, commit: { type: 'object', + description: + 'Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.', required: [ 'seq', 'rebase', @@ -4103,34 +4646,45 @@ export const schemaDict = { properties: { seq: { type: 'integer', + description: 'The stream sequence number of this message.', }, rebase: { type: 'boolean', + description: 'DEPRECATED -- unused', }, tooBig: { type: 'boolean', + description: + 'Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data.', }, repo: { type: 'string', format: 'did', + description: 'The repo this event comes from.', }, commit: { type: 'cid-link', + description: 'Repo commit object CID.', }, prev: { type: 'cid-link', + description: + 'DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability.', }, rev: { type: 'string', - description: 'The rev of the emitted commit.', + description: + 'The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event.', }, since: { type: 'string', - description: 'The rev of the last emitted commit from this repo.', + description: + 'The rev of the last emitted commit from this repo (if any).', }, blocks: { type: 'bytes', - description: 'CAR file containing relevant blocks.', + description: + 'CAR file containing relevant blocks, as a diff since the previous repo state.', maxLength: 1000000, }, ops: { @@ -4138,6 +4692,8 @@ export const schemaDict = { items: { type: 'ref', ref: 'lex:com.atproto.sync.subscribeRepos#repoOp', + description: + 'List of repo mutation operations in this commit (eg, records created, updated, or deleted).', }, maxLength: 200, }, @@ -4145,8 +4701,31 @@ export const schemaDict = { type: 'array', items: { type: 'cid-link', + description: + 'List of new blobs (by CID) referenced by records in this commit.', }, }, + time: { + type: 'string', + format: 'datetime', + description: + 'Timestamp of when this message was originally broadcast.', + }, + }, + }, + identity: { + type: 'object', + description: + "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.", + required: ['seq', 'did', 'time'], + properties: { + seq: { + type: 'integer', + }, + did: { + type: 'string', + format: 'did', + }, time: { type: 'string', format: 'datetime', @@ -4155,6 +4734,8 @@ export const schemaDict = { }, handle: { type: 'object', + description: + "Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity.", required: ['seq', 'did', 'handle', 'time'], properties: { seq: { @@ -4176,6 +4757,8 @@ export const schemaDict = { }, migrate: { type: 'object', + description: + 'Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead', required: ['seq', 'did', 'migrateTo', 'time'], nullable: ['migrateTo'], properties: { @@ -4197,6 +4780,8 @@ export const schemaDict = { }, tombstone: { type: 'object', + description: + 'Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event', required: ['seq', 'did', 'time'], properties: { seq: { @@ -4227,8 +4812,7 @@ export const schemaDict = { }, repoOp: { type: 'object', - description: - "A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null.", + description: 'A repo operation, ie a mutation of a single record.', required: ['action', 'path', 'cid'], nullable: ['cid'], properties: { @@ -4241,45 +4825,34 @@ export const schemaDict = { }, cid: { type: 'cid-link', + description: + 'For creates and updates, the new record CID. For deletions, null.', }, }, }, }, }, - ComAtprotoTempFetchLabels: { + ComAtprotoTempCheckSignupQueue: { lexicon: 1, - id: 'com.atproto.temp.fetchLabels', + id: 'com.atproto.temp.checkSignupQueue', defs: { main: { type: 'query', - description: - 'Fetch all labels from a labeler created after a certain date.', - parameters: { - type: 'params', - properties: { - since: { - type: 'integer', - }, - limit: { - type: 'integer', - minimum: 1, - maximum: 250, - default: 50, - }, - }, - }, + description: 'Check accounts location in signup queue.', output: { encoding: 'application/json', schema: { type: 'object', - required: ['labels'], + required: ['activated'], properties: { - labels: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:com.atproto.label.defs#label', - }, + activated: { + type: 'boolean', + }, + placeInQueue: { + type: 'integer', + }, + estimatedTimeMs: { + type: 'integer', }, }, }, @@ -4287,75 +4860,40 @@ export const schemaDict = { }, }, }, - ComAtprotoTempImportRepo: { - lexicon: 1, - id: 'com.atproto.temp.importRepo', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: 'application/vnd.ipld.car', - }, - output: { - encoding: 'text/plain', - }, - }, - }, - }, - ComAtprotoTempPushBlob: { - lexicon: 1, - id: 'com.atproto.temp.pushBlob', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: '*/*', - }, - }, - }, - }, - ComAtprotoTempRequestPhoneVerification: { + ComAtprotoTempFetchLabels: { lexicon: 1, - id: 'com.atproto.temp.requestPhoneVerification', + id: 'com.atproto.temp.fetchLabels', defs: { main: { - type: 'procedure', + type: 'query', description: - 'Request a verification code to be sent to the supplied phone number', - input: { + 'DEPRECATED: use queryLabels or subscribeLabels instead -- Fetch all labels from a labeler created after a certain date.', + parameters: { + type: 'params', + properties: { + since: { + type: 'integer', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 250, + default: 50, + }, + }, + }, + output: { encoding: 'application/json', schema: { type: 'object', - required: ['phoneNumber'], + required: ['labels'], properties: { - phoneNumber: { - type: 'string', + labels: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.label.defs#label', + }, }, }, }, @@ -4363,86 +4901,32 @@ export const schemaDict = { }, }, }, - ComAtprotoTempTransferAccount: { + ComAtprotoTempRequestPhoneVerification: { lexicon: 1, - id: 'com.atproto.temp.transferAccount', + id: 'com.atproto.temp.requestPhoneVerification', defs: { main: { type: 'procedure', - description: 'Transfer an account.', + description: + 'Request a verification code to be sent to the supplied phone number', input: { encoding: 'application/json', schema: { type: 'object', - required: ['handle', 'did', 'plcOp'], - properties: { - handle: { - type: 'string', - format: 'handle', - }, - did: { - type: 'string', - format: 'did', - }, - plcOp: { - type: 'unknown', - }, - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['accessJwt', 'refreshJwt', 'handle', 'did'], + required: ['phoneNumber'], properties: { - accessJwt: { - type: 'string', - }, - refreshJwt: { - type: 'string', - }, - handle: { - type: 'string', - format: 'handle', - }, - did: { + phoneNumber: { type: 'string', - format: 'did', }, }, }, }, - errors: [ - { - name: 'InvalidHandle', - }, - { - name: 'InvalidPassword', - }, - { - name: 'InvalidInviteCode', - }, - { - name: 'HandleNotAvailable', - }, - { - name: 'UnsupportedDomain', - }, - { - name: 'UnresolvableDid', - }, - { - name: 'IncompatibleDidDoc', - }, - ], }, }, }, AppBskyActorDefs: { lexicon: 1, id: 'app.bsky.actor.defs', - description: 'A reference to an actor in the network.', defs: { profileViewBasic: { type: 'object', @@ -4575,6 +5059,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests.", properties: { muted: { type: 'boolean', @@ -4615,6 +5101,9 @@ export const schemaDict = { 'lex:app.bsky.actor.defs#personalDetailsPref', 'lex:app.bsky.actor.defs#feedViewPref', 'lex:app.bsky.actor.defs#threadViewPref', + 'lex:app.bsky.actor.defs#interestsPref', + 'lex:app.bsky.actor.defs#mutedWordsPref', + 'lex:app.bsky.actor.defs#hiddenPostsPref', ], }, }, @@ -4659,6 +5148,9 @@ export const schemaDict = { format: 'at-uri', }, }, + timelineIndex: { + type: 'integer', + }, }, }, personalDetailsPref: { @@ -4718,6 +5210,79 @@ export const schemaDict = { }, }, }, + interestsPref: { + type: 'object', + required: ['tags'], + properties: { + tags: { + type: 'array', + maxLength: 100, + items: { + type: 'string', + maxLength: 640, + maxGraphemes: 64, + }, + description: + "A list of tags which describe the account owner's interests gathered during onboarding.", + }, + }, + }, + mutedWordTarget: { + type: 'string', + knownValues: ['content', 'tag'], + maxLength: 640, + maxGraphemes: 64, + }, + mutedWord: { + type: 'object', + description: 'A word that the account owner has muted.', + required: ['value', 'targets'], + properties: { + value: { + type: 'string', + description: 'The muted word itself.', + maxLength: 10000, + maxGraphemes: 1000, + }, + targets: { + type: 'array', + description: 'The intended targets of the muted word.', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWordTarget', + }, + }, + }, + }, + mutedWordsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWord', + }, + description: 'A list of words the account owner has muted.', + }, + }, + }, + hiddenPostsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'string', + format: 'at-uri', + }, + description: + 'A list of URIs of posts the account owner has hidden.', + }, + }, + }, }, }, AppBskyActorGetPreferences: { @@ -4726,7 +5291,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get private preferences attached to the account.', + description: + 'Get private preferences attached to the current account. Expected use is synchronization between multiple devices, and import/export during account migration. Requires auth.', parameters: { type: 'params', properties: {}, @@ -4753,7 +5319,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get detailed profile view of an actor.', + description: + 'Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.', parameters: { type: 'params', required: ['actor'], @@ -4761,6 +5328,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Handle or DID of account to fetch profile of.', }, }, }, @@ -4820,7 +5388,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested actors, used for discovery.', + description: + 'Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding.', parameters: { type: 'params', properties: { @@ -4863,7 +5432,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a profile.', + description: 'A declaration of a Bluesky account profile.', key: 'literal:self', record: { type: 'object', @@ -4875,21 +5444,28 @@ export const schemaDict = { }, description: { type: 'string', + description: 'Free-form profile description text.', maxGraphemes: 256, maxLength: 2560, }, avatar: { type: 'blob', + description: + "Small image to be displayed next to posts from account. AKA, 'profile picture'", accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, banner: { type: 'blob', + description: + 'Larger horizontal image to display behind profile view.', accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, labels: { type: 'union', + description: + 'Self-label values, specific to the Bluesky application, on the overall account.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, }, @@ -4926,7 +5502,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actors (profiles) matching search criteria.', + description: + 'Find actors (profiles) matching search criteria. Does not require auth.', parameters: { type: 'params', properties: { @@ -4978,7 +5555,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actor suggestions for a prefix search term.', + description: + 'Find actor suggestions for a prefix search term. Expected use is for auto-completion during text field entry. Does not require auth.', parameters: { type: 'params', properties: { @@ -5020,11 +5598,11 @@ export const schemaDict = { AppBskyEmbedExternal: { lexicon: 1, id: 'app.bsky.embed.external', - description: - 'A representation of some externally linked content, embedded in another form of content.', defs: { main: { type: 'object', + description: + "A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post).", required: ['external'], properties: { external: { @@ -5088,7 +5666,7 @@ export const schemaDict = { AppBskyEmbedImages: { lexicon: 1, id: 'app.bsky.embed.images', - description: 'A set of images embedded in some other form of content.', + description: 'A set of images embedded in a Bluesky record (eg, a post).', defs: { main: { type: 'object', @@ -5115,6 +5693,8 @@ export const schemaDict = { }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5158,12 +5738,18 @@ export const schemaDict = { properties: { thumb: { type: 'string', + description: + 'Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View.', }, fullsize: { type: 'string', + description: + 'Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View.', }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5177,7 +5763,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.record', description: - 'A representation of a record embedded in another form of content.', + 'A representation of a record embedded in a Bluesky record (eg, a post). For example, a quote-post, or sharing a feed generator record.', defs: { main: { type: 'object', @@ -5223,6 +5809,7 @@ export const schemaDict = { }, value: { type: 'unknown', + description: 'The record data itself.', }, labels: { type: 'array', @@ -5287,7 +5874,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.recordWithMedia', description: - 'A representation of a record embedded in another form of content, alongside other compatible embeds.', + 'A representation of a record embedded in a Bluesky record (eg, a post), alongside other compatible embeds. For example, a quote post and image, or a quote post and external URL card.', defs: { main: { type: 'object', @@ -5386,6 +5973,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests.", properties: { repost: { type: 'string', @@ -5646,7 +6235,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about a feed generator, including policies and offered feed URIs.', + 'Get information about a feed generator, including policies and offered feed URIs. Does not require auth; implemented by Feed Generator services (not App View).', output: { encoding: 'application/json', schema: { @@ -5701,7 +6290,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of the existence of a feed generator.', + description: + 'Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.', key: 'any', record: { type: 'object', @@ -5735,6 +6325,7 @@ export const schemaDict = { }, labels: { type: 'union', + description: 'Self-label values', refs: ['lex:com.atproto.label.defs#selfLabels'], }, createdAt: { @@ -5752,7 +6343,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of feeds created by the actor.', + description: + "Get a list of feeds (feed generator records) created by the actor (in the actor's repo).", parameters: { type: 'params', required: ['actor'], @@ -5800,7 +6392,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of posts liked by an actor.', + description: + 'Get a list of posts liked by an actor. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -5856,7 +6449,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth.", parameters: { type: 'params', required: ['actor'], @@ -5876,6 +6470,8 @@ export const schemaDict = { }, filter: { type: 'string', + description: + 'Combinations of post/repost types to include in response.', knownValues: [ 'posts_with_replies', 'posts_no_replies', @@ -5923,7 +6519,7 @@ export const schemaDict = { main: { type: 'query', description: - "Get a hydrated feed from an actor's selected feed generator.", + "Get a hydrated feed from an actor's selected feed generator. Implemented by App View.", parameters: { type: 'params', required: ['feed'], @@ -5976,7 +6572,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get information about a feed generator.', + description: + 'Get information about a feed generator. Implemented by AppView.', parameters: { type: 'params', required: ['feed'], @@ -5984,6 +6581,7 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: 'AT-URI of the feed generator record.', }, }, }, @@ -5999,9 +6597,13 @@ export const schemaDict = { }, isOnline: { type: 'boolean', + description: + 'Indicates whether the feed generator service has been online recently, or else seems to be inactive.', }, isValid: { type: 'boolean', + description: + 'Indicates whether the feed generator service is compatible with the record declaration.', }, }, }, @@ -6054,7 +6656,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a skeleton of a feed provided by a feed generator.', + description: + 'Get a skeleton of a feed provided by a feed generator. Auth is optional, depending on provider requirements, and provides the DID of the requester. Implemented by Feed Generator Service.', parameters: { type: 'params', required: ['feed'], @@ -6062,6 +6665,8 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: + 'Reference to feed generator record describing the specific feed being requested.', }, limit: { type: 'integer', @@ -6107,7 +6712,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the list of likes.', + description: + 'Get like records which reference a subject (by AT-URI and CID).', parameters: { type: 'params', required: ['uri'], @@ -6115,10 +6721,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'AT-URI of the subject (eg, a post record).', }, cid: { type: 'string', format: 'cid', + description: + 'CID of the subject record (aka, specific version of record), to filter likes.', }, limit: { type: 'integer', @@ -6185,7 +6794,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a view of a recent posts from actors in a list.', + description: + 'Get a feed of recent posts from a list (posts and reposts from any actors on the list). Does not require auth.', parameters: { type: 'params', required: ['list'], @@ -6193,6 +6803,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the list record.', }, limit: { type: 'integer', @@ -6238,7 +6849,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get posts in a thread.', + description: + 'Get posts in a thread. Does not require auth, but additional metadata and filtering will be applied for authed requests.', parameters: { type: 'params', required: ['uri'], @@ -6246,15 +6858,20 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to post record.', }, depth: { type: 'integer', + description: + 'How many levels of reply depth should be included in response.', default: 6, minimum: 0, maximum: 1000, }, parentHeight: { type: 'integer', + description: + 'How many levels of parent (and grandparent, etc) post to include.', default: 80, minimum: 0, maximum: 1000, @@ -6292,13 +6909,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Gets post views for a specified list of posts (by AT-URI). This is sometimes referred to as 'hydrating' a 'feed skeleton'.", parameters: { type: 'params', required: ['uris'], properties: { uris: { type: 'array', + description: 'List of post AT-URIs to return hydrated views for.', items: { type: 'string', format: 'at-uri', @@ -6332,7 +6951,7 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of reposts.', + description: 'Get a list of reposts for a given post.', parameters: { type: 'params', required: ['uri'], @@ -6340,10 +6959,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of post record', }, cid: { type: 'string', format: 'cid', + description: + 'If supplied, filters to reposts of specific version (by CID) of the post record.', }, limit: { type: 'integer', @@ -6392,7 +7014,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested feeds for the viewer.', + description: + 'Get a list of suggested feeds (feed generators) for the requesting account.', parameters: { type: 'params', properties: { @@ -6435,12 +7058,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of the actor's home timeline.", + description: + "Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed.", parameters: { type: 'params', properties: { algorithm: { type: 'string', + description: + "Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism.", }, limit: { type: 'integer', @@ -6481,7 +7107,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a like.', + description: "Record declaring a 'like' of a piece of subject content.", key: 'tid', record: { type: 'object', @@ -6506,7 +7132,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a post.', + description: 'Record containing a Bluesky post.', key: 'tid', record: { type: 'object', @@ -6516,10 +7142,12 @@ export const schemaDict = { type: 'string', maxLength: 3000, maxGraphemes: 300, + description: + 'The primary post content. May be an empty string, if there are embeds.', }, entities: { type: 'array', - description: 'Deprecated: replaced by app.bsky.richtext.facet.', + description: 'DEPRECATED: replaced by app.bsky.richtext.facet.', items: { type: 'ref', ref: 'lex:app.bsky.feed.post#entity', @@ -6527,6 +7155,8 @@ export const schemaDict = { }, facets: { type: 'array', + description: + 'Annotations of text (mentions, URLs, hashtags, etc)', items: { type: 'ref', ref: 'lex:app.bsky.richtext.facet', @@ -6547,6 +7177,8 @@ export const schemaDict = { }, langs: { type: 'array', + description: + 'Indicates human language of post primary text content.', maxLength: 3, items: { type: 'string', @@ -6555,21 +7187,26 @@ export const schemaDict = { }, labels: { type: 'union', + description: + 'Self-label values for this post. Effectively content warnings.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, tags: { type: 'array', + description: + 'Additional hashtags, in addition to any included in post text and facets.', maxLength: 8, items: { type: 'string', maxLength: 640, maxGraphemes: 64, }, - description: 'Additional non-inline tags describing this post.', }, createdAt: { type: 'string', format: 'datetime', + description: + 'Client-declared timestamp when this post was originally created.', }, }, }, @@ -6629,7 +7266,8 @@ export const schemaDict = { id: 'app.bsky.feed.repost', defs: { main: { - description: 'A declaration of a repost.', + description: + "Record representing a 'repost' of an existing Bluesky post.", type: 'record', key: 'tid', record: { @@ -6655,7 +7293,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find posts matching search criteria.', + description: + 'Find posts matching search criteria, returning views of those posts.', parameters: { type: 'params', required: ['q'], @@ -6718,7 +7357,7 @@ export const schemaDict = { type: 'record', key: 'tid', description: - "Defines interaction gating rules for a thread. The rkey of the threadgate record should match the rkey of the thread's root post.", + "Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository..", record: { type: 'object', required: ['post', 'createdAt'], @@ -6726,6 +7365,7 @@ export const schemaDict = { post: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the post record.', }, allow: { type: 'array', @@ -6775,7 +7415,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a block.', + description: + "Record declaring a 'block' relationship against another account. NOTE: blocks are public in Bluesky; see blog posts for details.", key: 'tid', record: { type: 'object', @@ -6784,6 +7425,7 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'DID of the account to be blocked.', }, createdAt: { type: 'string', @@ -6972,7 +7614,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a social follow.', + description: + "Record declaring a social 'follow' relationship of another account. Duplicate follows will be ignored by the AppView.", key: 'tid', record: { type: 'object', @@ -6997,7 +7640,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor is blocking.', + description: + 'Enumerates which accounts the requesting account is currently blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7040,7 +7684,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a list of an actor's followers.", + description: + 'Enumerates accounts which follow a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7092,7 +7737,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor follows.', + description: + 'Enumerates accounts which a specified account (actor) follows.', parameters: { type: 'params', required: ['actor'], @@ -7144,7 +7790,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of actors.', + description: + "Gets a 'view' (with additional context) of a specified list.", parameters: { type: 'params', required: ['list'], @@ -7152,6 +7799,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of the list record to hydrate.', }, limit: { type: 'integer', @@ -7196,7 +7844,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is blocking.', + description: + 'Get mod lists that the requesting account (actor) is blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7239,7 +7888,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is muting.', + description: + 'Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7282,7 +7932,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of lists that belong to an actor.', + description: + 'Enumerates the lists created by a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7290,6 +7941,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'The account (actor) to enumerate lists from.', }, limit: { type: 'integer', @@ -7330,7 +7982,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor mutes.', + description: + 'Enumerates accounts that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7374,7 +8027,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Enumerates public relationships between one account, and a list of other accounts', + 'Enumerates public relationships between one account, and a list of other accounts. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -7382,9 +8035,12 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Primary account requesting relationships for.', }, others: { type: 'array', + description: + "List of 'other' accounts to be related back to the primary.", maxLength: 30, items: { type: 'string', @@ -7432,7 +8088,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get suggested follows related to a given actor.', + description: + 'Enumerates follows similar to a given account (actor). Expected use is to recommend additional accounts immediately after following one account.', parameters: { type: 'params', required: ['actor'], @@ -7468,7 +8125,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a list of actors.', + description: + 'Record representing a list of accounts (actors). Scope includes both moderation-oriented lists and curration-oriented lists.', key: 'tid', record: { type: 'object', @@ -7476,12 +8134,15 @@ export const schemaDict = { properties: { purpose: { type: 'ref', + description: + 'Defines the purpose of the list (aka, moderation-oriented or curration-oriented)', ref: 'lex:app.bsky.graph.defs#listPurpose', }, name: { type: 'string', maxLength: 64, minLength: 1, + description: 'Display name for list; can not be empty.', }, description: { type: 'string', @@ -7519,7 +8180,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A block of an entire list of actors.', + description: + 'Record representing a block relationship against an entire an entire list of accounts (actors).', key: 'tid', record: { type: 'object', @@ -7528,6 +8190,7 @@ export const schemaDict = { subject: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the mod list record.', }, createdAt: { type: 'string', @@ -7544,7 +8207,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'An item under a declared list of actors.', + description: + "Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records.", key: 'tid', record: { type: 'object', @@ -7553,10 +8217,13 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'The account which is included on the list.', }, list: { type: 'string', format: 'at-uri', + description: + 'Reference (AT-URI) to the list record (app.bsky.graph.list).', }, createdAt: { type: 'string', @@ -7573,7 +8240,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute an actor by DID or handle.', + description: + 'Creates a mute relationship for the specified account. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7596,7 +8264,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute a list of actors.', + description: + 'Creates a mute relationship for the specified list of accounts. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7619,7 +8288,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute an actor by DID or handle.', + description: 'Unmutes the specified account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7642,7 +8311,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute a list of actors.', + description: 'Unmutes the specified list of accounts. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7665,7 +8334,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the count of unread notifications.', + description: + 'Count the number of unread notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7696,7 +8366,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of notifications.', + description: + 'Enumerate notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7807,7 +8478,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Register for push notifications with a service.', + description: + 'Register to receive push notifications, via a specified service, for the requesting account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7840,7 +8512,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Notify server that the user has seen notifications.', + description: + 'Notify server that the requesting account has seen notifications. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7863,6 +8536,7 @@ export const schemaDict = { defs: { main: { type: 'object', + description: 'Annotation of a sub-string within rich text.', required: ['index', 'features'], properties: { index: { @@ -7884,7 +8558,8 @@ export const schemaDict = { }, mention: { type: 'object', - description: 'A facet feature for actor mentions.', + description: + "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID.", required: ['did'], properties: { did: { @@ -7895,7 +8570,8 @@ export const schemaDict = { }, link: { type: 'object', - description: 'A facet feature for links.', + description: + 'Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.', required: ['uri'], properties: { uri: { @@ -7906,7 +8582,8 @@ export const schemaDict = { }, tag: { type: 'object', - description: 'A hashtag.', + description: + "Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags').", required: ['tag'], properties: { tag: { @@ -7919,7 +8596,7 @@ export const schemaDict = { byteSlice: { type: 'object', description: - 'A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings.', + 'Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.', required: ['byteStart', 'byteEnd'], properties: { byteStart: { @@ -8054,55 +8731,6 @@ export const schemaDict = { }, }, }, - AppBskyUnspeccedGetTimelineSkeleton: { - lexicon: 1, - id: 'app.bsky.unspecced.getTimelineSkeleton', - defs: { - main: { - type: 'query', - description: - 'DEPRECATED: a skeleton of a timeline. Unspecced and will be unavailable soon.', - parameters: { - type: 'params', - properties: { - limit: { - type: 'integer', - minimum: 1, - maximum: 100, - default: 50, - }, - cursor: { - type: 'string', - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['feed'], - properties: { - cursor: { - type: 'string', - }, - feed: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:app.bsky.feed.defs#skeletonFeedPost', - }, - }, - }, - }, - }, - errors: [ - { - name: 'UnknownFeed', - }, - ], - }, - }, - }, AppBskyUnspeccedSearchActorsSkeleton: { lexicon: 1, id: 'app.bsky.unspecced.searchActorsSkeleton', @@ -8261,10 +8889,19 @@ export const ids = { ComAtprotoAdminSendEmail: 'com.atproto.admin.sendEmail', ComAtprotoAdminUpdateAccountEmail: 'com.atproto.admin.updateAccountEmail', ComAtprotoAdminUpdateAccountHandle: 'com.atproto.admin.updateAccountHandle', + ComAtprotoAdminUpdateAccountPassword: + 'com.atproto.admin.updateAccountPassword', ComAtprotoAdminUpdateCommunicationTemplate: 'com.atproto.admin.updateCommunicationTemplate', ComAtprotoAdminUpdateSubjectStatus: 'com.atproto.admin.updateSubjectStatus', + ComAtprotoIdentityGetRecommendedDidCredentials: + 'com.atproto.identity.getRecommendedDidCredentials', + ComAtprotoIdentityRequestPlcOperationSignature: + 'com.atproto.identity.requestPlcOperationSignature', ComAtprotoIdentityResolveHandle: 'com.atproto.identity.resolveHandle', + ComAtprotoIdentitySignPlcOperation: 'com.atproto.identity.signPlcOperation', + ComAtprotoIdentitySubmitPlcOperation: + 'com.atproto.identity.submitPlcOperation', ComAtprotoIdentityUpdateHandle: 'com.atproto.identity.updateHandle', ComAtprotoLabelDefs: 'com.atproto.label.defs', ComAtprotoLabelQueryLabels: 'com.atproto.label.queryLabels', @@ -8276,22 +8913,28 @@ export const ids = { ComAtprotoRepoDeleteRecord: 'com.atproto.repo.deleteRecord', ComAtprotoRepoDescribeRepo: 'com.atproto.repo.describeRepo', ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord', + ComAtprotoRepoImportRepo: 'com.atproto.repo.importRepo', + ComAtprotoRepoListMissingBlobs: 'com.atproto.repo.listMissingBlobs', ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords', ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord', ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob', + ComAtprotoServerActivateAccount: 'com.atproto.server.activateAccount', + ComAtprotoServerCheckAccountStatus: 'com.atproto.server.checkAccountStatus', ComAtprotoServerConfirmEmail: 'com.atproto.server.confirmEmail', ComAtprotoServerCreateAccount: 'com.atproto.server.createAccount', ComAtprotoServerCreateAppPassword: 'com.atproto.server.createAppPassword', ComAtprotoServerCreateInviteCode: 'com.atproto.server.createInviteCode', ComAtprotoServerCreateInviteCodes: 'com.atproto.server.createInviteCodes', ComAtprotoServerCreateSession: 'com.atproto.server.createSession', + ComAtprotoServerDeactivateAccount: 'com.atproto.server.deactivateAccount', ComAtprotoServerDefs: 'com.atproto.server.defs', ComAtprotoServerDeleteAccount: 'com.atproto.server.deleteAccount', ComAtprotoServerDeleteSession: 'com.atproto.server.deleteSession', ComAtprotoServerDescribeServer: 'com.atproto.server.describeServer', ComAtprotoServerGetAccountInviteCodes: 'com.atproto.server.getAccountInviteCodes', + ComAtprotoServerGetServiceAuth: 'com.atproto.server.getServiceAuth', ComAtprotoServerGetSession: 'com.atproto.server.getSession', ComAtprotoServerListAppPasswords: 'com.atproto.server.listAppPasswords', ComAtprotoServerRefreshSession: 'com.atproto.server.refreshSession', @@ -8318,12 +8961,10 @@ export const ids = { ComAtprotoSyncNotifyOfUpdate: 'com.atproto.sync.notifyOfUpdate', ComAtprotoSyncRequestCrawl: 'com.atproto.sync.requestCrawl', ComAtprotoSyncSubscribeRepos: 'com.atproto.sync.subscribeRepos', + ComAtprotoTempCheckSignupQueue: 'com.atproto.temp.checkSignupQueue', ComAtprotoTempFetchLabels: 'com.atproto.temp.fetchLabels', - ComAtprotoTempImportRepo: 'com.atproto.temp.importRepo', - ComAtprotoTempPushBlob: 'com.atproto.temp.pushBlob', ComAtprotoTempRequestPhoneVerification: 'com.atproto.temp.requestPhoneVerification', - ComAtprotoTempTransferAccount: 'com.atproto.temp.transferAccount', AppBskyActorDefs: 'app.bsky.actor.defs', AppBskyActorGetPreferences: 'app.bsky.actor.getPreferences', AppBskyActorGetProfile: 'app.bsky.actor.getProfile', @@ -8391,7 +9032,6 @@ export const ids = { 'app.bsky.unspecced.getPopularFeedGenerators', AppBskyUnspeccedGetTaggedSuggestions: 'app.bsky.unspecced.getTaggedSuggestions', - AppBskyUnspeccedGetTimelineSkeleton: 'app.bsky.unspecced.getTimelineSkeleton', AppBskyUnspeccedSearchActorsSkeleton: 'app.bsky.unspecced.searchActorsSkeleton', AppBskyUnspeccedSearchPostsSkeleton: 'app.bsky.unspecced.searchPostsSkeleton', diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/defs.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/defs.ts index c20177ca50e..6836fa7e516 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/defs.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/defs.ts @@ -82,6 +82,7 @@ export function validateProfileViewDetailed(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#profileViewDetailed', v) } +/** Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests. */ export interface ViewerState { muted?: boolean mutedByList?: AppBskyGraphDefs.ListViewBasic @@ -112,6 +113,9 @@ export type Preferences = ( | PersonalDetailsPref | FeedViewPref | ThreadViewPref + | InterestsPref + | MutedWordsPref + | HiddenPostsPref | { $type: string; [k: string]: unknown } )[] @@ -153,6 +157,7 @@ export function validateContentLabelPref(v: unknown): ValidationResult { export interface SavedFeedsPref { pinned: string[] saved: string[] + timelineIndex?: number [k: string]: unknown } @@ -233,3 +238,80 @@ export function isThreadViewPref(v: unknown): v is ThreadViewPref { export function validateThreadViewPref(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#threadViewPref', v) } + +export interface InterestsPref { + /** A list of tags which describe the account owner's interests gathered during onboarding. */ + tags: string[] + [k: string]: unknown +} + +export function isInterestsPref(v: unknown): v is InterestsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#interestsPref' + ) +} + +export function validateInterestsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#interestsPref', v) +} + +export type MutedWordTarget = 'content' | 'tag' | (string & {}) + +/** A word that the account owner has muted. */ +export interface MutedWord { + /** The muted word itself. */ + value: string + /** The intended targets of the muted word. */ + targets: MutedWordTarget[] + [k: string]: unknown +} + +export function isMutedWord(v: unknown): v is MutedWord { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWord' + ) +} + +export function validateMutedWord(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWord', v) +} + +export interface MutedWordsPref { + /** A list of words the account owner has muted. */ + items: MutedWord[] + [k: string]: unknown +} + +export function isMutedWordsPref(v: unknown): v is MutedWordsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWordsPref' + ) +} + +export function validateMutedWordsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWordsPref', v) +} + +export interface HiddenPostsPref { + /** A list of URIs of posts the account owner has hidden. */ + items: string[] + [k: string]: unknown +} + +export function isHiddenPostsPref(v: unknown): v is HiddenPostsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#hiddenPostsPref' + ) +} + +export function validateHiddenPostsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#hiddenPostsPref', v) +} diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/getPreferences.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/getPreferences.ts index 88d78a57cba..305e80484be 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/getPreferences.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/getPreferences.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/getProfile.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/getProfile.ts index 802afda5361..5a7b1f25bfc 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/getProfile.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/getProfile.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** Handle or DID of account to fetch profile of. */ actor: string } @@ -28,7 +29,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/getProfiles.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/getProfiles.ts index 2549b264e33..16438505654 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/getProfiles.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/getProfiles.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/getSuggestions.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/getSuggestions.ts index a6d4d6102af..33b89a18bfa 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/getSuggestions.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/getSuggestions.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/profile.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/profile.ts index 7dbc4c1ccec..8810ce7bed9 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/profile.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/profile.ts @@ -9,8 +9,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { displayName?: string + /** Free-form profile description text. */ description?: string + /** Small image to be displayed next to posts from account. AKA, 'profile picture' */ avatar?: BlobRef + /** Larger horizontal image to display behind profile view. */ banner?: BlobRef labels?: | ComAtprotoLabelDefs.SelfLabels diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/putPreferences.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/putPreferences.ts index 1e5ee2d834e..670e752fea3 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/putPreferences.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/putPreferences.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/searchActors.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/searchActors.ts index f072b8a4d04..dcda0c41854 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/searchActors.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/searchActors.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -39,7 +39,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts b/packages/ozone/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts index 0cf56753db2..0198b23d790 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/embed/external.ts b/packages/ozone/src/lexicon/types/app/bsky/embed/external.ts index f42a6cfd95c..b137ee4b6f5 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/embed/external.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/embed/external.ts @@ -6,6 +6,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' +/** A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). */ export interface Main { external: External [k: string]: unknown diff --git a/packages/ozone/src/lexicon/types/app/bsky/embed/images.ts b/packages/ozone/src/lexicon/types/app/bsky/embed/images.ts index 4864fad3dea..96399867a1a 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/embed/images.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/embed/images.ts @@ -26,6 +26,7 @@ export function validateMain(v: unknown): ValidationResult { export interface Image { image: BlobRef + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown @@ -76,8 +77,11 @@ export function validateView(v: unknown): ValidationResult { } export interface ViewImage { + /** Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. */ thumb: string + /** Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. */ fullsize: string + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown diff --git a/packages/ozone/src/lexicon/types/app/bsky/embed/record.ts b/packages/ozone/src/lexicon/types/app/bsky/embed/record.ts index cea5742a45e..dbe7f13152b 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/embed/record.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/embed/record.ts @@ -57,6 +57,7 @@ export interface ViewRecord { uri: string cid: string author: AppBskyActorDefs.ProfileViewBasic + /** The record data itself. */ value: {} labels?: ComAtprotoLabelDefs.Label[] embeds?: ( diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/defs.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/defs.ts index 382d3f58ecf..261d8a622ec 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/defs.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/defs.ts @@ -45,6 +45,7 @@ export function validatePostView(v: unknown): ValidationResult { return lexicons.validate('app.bsky.feed.defs#postView', v) } +/** Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests. */ export interface ViewerState { repost?: string like?: string diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts index d329bf20a5a..5bf8699a3ca 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -32,7 +32,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getActorFeeds.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getActorFeeds.ts index 3e930cbe201..0b8afff4ec8 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getActorFeeds.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getActorFeeds.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getActorLikes.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getActorLikes.ts index df2f291e1a7..da315ae33c7 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getActorLikes.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getActorLikes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { error?: 'BlockedActor' | 'BlockedByActor' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts index 25f51f6fe5f..017c7a6a2d4 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts @@ -6,13 +6,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { actor: string limit: number cursor?: string + /** Combinations of post/repost types to include in response. */ filter: | 'posts_with_replies' | 'posts_no_replies' @@ -43,7 +44,7 @@ export interface HandlerError { error?: 'BlockedActor' | 'BlockedByActor' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeed.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeed.ts index e72b1010aea..e03913a6fb3 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeed.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeed.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts index fab3b30c316..7ab89057a8c 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** AT-URI of the feed generator record. */ feed: string } @@ -17,7 +18,9 @@ export type InputSchema = undefined export interface OutputSchema { view: AppBskyFeedDefs.GeneratorView + /** Indicates whether the feed generator service has been online recently, or else seems to be inactive. */ isOnline: boolean + /** Indicates whether the feed generator service is compatible with the record declaration. */ isValid: boolean [k: string]: unknown } @@ -35,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts index d7e082f2362..21963a91e2e 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts index 1c8f349b42b..ca1cef20f08 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference to feed generator record describing the specific feed being requested. */ feed: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getLikes.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getLikes.ts index d581f5bfa9c..275d99bba3d 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getLikes.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getLikes.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** AT-URI of the subject (eg, a post record). */ uri: string + /** CID of the subject record (aka, specific version of record), to filter likes. */ cid?: string limit: number cursor?: string @@ -39,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getListFeed.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getListFeed.ts index e24c3f8ed22..84e12deaa92 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getListFeed.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getListFeed.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to the list record. */ list: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { error?: 'UnknownList' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts index 61de94b729d..ae232fd91a2 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts @@ -6,12 +6,15 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to post record. */ uri: string + /** How many levels of reply depth should be included in response. */ depth: number + /** How many levels of parent (and grandparent, etc) post to include. */ parentHeight: number } @@ -40,7 +43,7 @@ export interface HandlerError { error?: 'NotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getPosts.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getPosts.ts index 4282f5d349f..85000c74787 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getPosts.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getPosts.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** List of post AT-URIs to return hydrated views for. */ uris: string[] } @@ -33,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getRepostedBy.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getRepostedBy.ts index 0b9c1a6f68b..40e008815d9 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getRepostedBy.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getRepostedBy.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** Reference (AT-URI) of post record */ uri: string + /** If supplied, filters to reposts of specific version (by CID) of the post record. */ cid?: string limit: number cursor?: string @@ -39,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts index 9b271335466..d1ec590f33d 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getTimeline.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getTimeline.ts index 832caf5c6f7..5202c9eb6e3 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getTimeline.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getTimeline.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. */ algorithm?: string limit: number cursor?: string @@ -36,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/post.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/post.ts index 93870b4452d..881e3d199aa 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/post.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/post.ts @@ -14,9 +14,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' import * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef' export interface Record { + /** The primary post content. May be an empty string, if there are embeds. */ text: string - /** Deprecated: replaced by app.bsky.richtext.facet. */ + /** DEPRECATED: replaced by app.bsky.richtext.facet. */ entities?: Entity[] + /** Annotations of text (mentions, URLs, hashtags, etc) */ facets?: AppBskyRichtextFacet.Main[] reply?: ReplyRef embed?: @@ -25,12 +27,14 @@ export interface Record { | AppBskyEmbedRecord.Main | AppBskyEmbedRecordWithMedia.Main | { $type: string; [k: string]: unknown } + /** Indicates human language of post primary text content. */ langs?: string[] labels?: | ComAtprotoLabelDefs.SelfLabels | { $type: string; [k: string]: unknown } - /** Additional non-inline tags describing this post. */ + /** Additional hashtags, in addition to any included in post text and facets. */ tags?: string[] + /** Client-declared timestamp when this post was originally created. */ createdAt: string [k: string]: unknown } diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/searchPosts.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/searchPosts.ts index 36ac7cbb67d..9dae079c226 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/searchPosts.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/searchPosts.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -41,7 +41,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/threadgate.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/threadgate.ts index 6a190d6e98a..e14140d5609 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/threadgate.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/threadgate.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the post record. */ post: string allow?: ( | MentionRule diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/block.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/block.ts index 947463af422..b7f19f126b7 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/block.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/block.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** DID of the account to be blocked. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getBlocks.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getBlocks.ts index d380a14880a..1fc9cd8ce37 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getBlocks.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getBlocks.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getFollowers.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getFollowers.ts index b337be52c1b..f5645eaef29 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getFollowers.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getFollowers.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getFollows.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getFollows.ts index 71e9ca0270c..b9bd249da45 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getFollows.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getFollows.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getList.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getList.ts index fc45dd20985..864a81b3833 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getList.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getList.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) of the list record to hydrate. */ list: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getListBlocks.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getListBlocks.ts index 04cca70b44d..7399a14fadc 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getListBlocks.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getListBlocks.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getListMutes.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getListMutes.ts index 04cca70b44d..7399a14fadc 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getListMutes.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getListMutes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getLists.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getLists.ts index 8acf9362c00..dc0c4f18bea 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getLists.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getLists.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** The account (actor) to enumerate lists from. */ actor: string limit: number cursor?: string @@ -36,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getMutes.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getMutes.ts index 0034095b975..f450393522d 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getMutes.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getMutes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getRelationships.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getRelationships.ts index 32a27434782..bd6b6e765ed 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getRelationships.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getRelationships.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Primary account requesting relationships for. */ actor: string + /** List of 'other' accounts to be related back to the primary. */ others?: string[] } @@ -40,7 +42,7 @@ export interface HandlerError { error?: 'ActorNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts index a2245846fd2..8f310334d0a 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/list.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/list.ts index 36a7fb17a3f..91c8ccee5bb 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/list.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/list.ts @@ -11,6 +11,7 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { purpose: AppBskyGraphDefs.ListPurpose + /** Display name for list; can not be empty. */ name: string description?: string descriptionFacets?: AppBskyRichtextFacet.Main[] diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/listblock.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/listblock.ts index 59f2e057eb5..592778c7a51 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/listblock.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/listblock.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the mod list record. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/listitem.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/listitem.ts index 69eff329ed4..5e93b34a111 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/listitem.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/listitem.ts @@ -7,7 +7,9 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** The account which is included on the list. */ subject: string + /** Reference (AT-URI) to the list record (app.bsky.graph.list). */ list: string createdAt: string [k: string]: unknown diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/muteActor.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/muteActor.ts index 52d1b864989..baa9844046a 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/muteActor.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/muteActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/muteActorList.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/muteActorList.ts index bf803f388af..6a68f680a1c 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/muteActorList.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/muteActorList.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActor.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActor.ts index 52d1b864989..baa9844046a 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActor.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActorList.ts b/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActorList.ts index bf803f388af..6a68f680a1c 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActorList.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/graph/unmuteActorList.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/app/bsky/notification/getUnreadCount.ts b/packages/ozone/src/lexicon/types/app/bsky/notification/getUnreadCount.ts index 6cf3c84beb5..eae30df7c1b 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/notification/getUnreadCount.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/notification/getUnreadCount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { seenAt?: string @@ -32,7 +32,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/notification/listNotifications.ts b/packages/ozone/src/lexicon/types/app/bsky/notification/listNotifications.ts index b50d6e8282e..d494494e569 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/notification/listNotifications.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/notification/listNotifications.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/notification/registerPush.ts b/packages/ozone/src/lexicon/types/app/bsky/notification/registerPush.ts index 9923aeb058e..cce8f95839d 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/notification/registerPush.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/notification/registerPush.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/app/bsky/notification/updateSeen.ts b/packages/ozone/src/lexicon/types/app/bsky/notification/updateSeen.ts index 136191edc40..93db017a152 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/notification/updateSeen.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/notification/updateSeen.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/app/bsky/richtext/facet.ts b/packages/ozone/src/lexicon/types/app/bsky/richtext/facet.ts index 2c5b2d723a9..139b5382caf 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/richtext/facet.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/richtext/facet.ts @@ -6,6 +6,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' +/** Annotation of a sub-string within rich text. */ export interface Main { index: ByteSlice features: (Mention | Link | Tag | { $type: string; [k: string]: unknown })[] @@ -25,7 +26,7 @@ export function validateMain(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#main', v) } -/** A facet feature for actor mentions. */ +/** Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID. */ export interface Mention { did: string [k: string]: unknown @@ -43,7 +44,7 @@ export function validateMention(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#mention', v) } -/** A facet feature for links. */ +/** Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. */ export interface Link { uri: string [k: string]: unknown @@ -61,7 +62,7 @@ export function validateLink(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#link', v) } -/** A hashtag. */ +/** Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). */ export interface Tag { tag: string [k: string]: unknown @@ -77,7 +78,7 @@ export function validateTag(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#tag', v) } -/** A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings. */ +/** Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. */ export interface ByteSlice { byteStart: number byteEnd: number diff --git a/packages/ozone/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts b/packages/ozone/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts index 97937e926c2..02f19f3cc6a 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from '../feed/defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts b/packages/ozone/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts index e6319c54b4e..a03f442140d 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts b/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts index 5c45b9fb622..4634407b890 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyUnspeccedDefs from './defs' export interface QueryParams { @@ -43,7 +43,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts b/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts index 15532087b82..860d4e8407c 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyUnspeccedDefs from './defs' export interface QueryParams { @@ -41,7 +41,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts index d42a8f2ef1d..b910b7987b4 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/defs.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/defs.ts index 41be2ad96e7..a713a635635 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/defs.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/defs.ts @@ -40,6 +40,7 @@ export interface ModEventView { | ModEventEscalate | ModEventMute | ModEventEmail + | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: | RepoRef @@ -76,6 +77,7 @@ export interface ModEventViewDetail { | ModEventAcknowledge | ModEventEscalate | ModEventMute + | ModEventEmail | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: @@ -154,6 +156,7 @@ export interface SubjectStatusView { /** True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators. */ appealed?: boolean suspendUntil?: string + tags?: string[] [k: string]: unknown } @@ -718,6 +721,29 @@ export function validateModEventEmail(v: unknown): ValidationResult { return lexicons.validate('com.atproto.admin.defs#modEventEmail', v) } +/** Add/Remove a tag on a subject */ +export interface ModEventTag { + /** Tags to be added to the subject. If already exists, won't be duplicated. */ + add: string[] + /** Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated. */ + remove: string[] + /** Additional comment about added/removed tags. */ + comment?: string + [k: string]: unknown +} + +export function isModEventTag(v: unknown): v is ModEventTag { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.admin.defs#modEventTag' + ) +} + +export function validateModEventTag(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.admin.defs#modEventTag', v) +} + export interface CommunicationTemplateView { id: string /** Name of the template. */ diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/deleteAccount.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/deleteAccount.ts index 13e68eb5c7d..003c1b5ebcd 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/deleteAccount.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/deleteAccount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts index 4bc6ec86fe4..c5ae5cd469f 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts index 62864923dfd..68c6503d95e 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts index 2b64371f1ed..2bf8de35583 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts index df44702b51c..99d08c7f1b7 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -24,6 +24,7 @@ export interface InputSchema { | ComAtprotoAdminDefs.ModEventReverseTakedown | ComAtprotoAdminDefs.ModEventUnmute | ComAtprotoAdminDefs.ModEventEmail + | ComAtprotoAdminDefs.ModEventTag | { $type: string; [k: string]: unknown } subject: | ComAtprotoAdminDefs.RepoRef @@ -53,7 +54,7 @@ export interface HandlerError { error?: 'SubjectHasAction' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts index fb3aa8b8375..3f2836e7142 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfo.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfo.ts index 88a2b17a4b8..c7b840a153d 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfo.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfos.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfos.ts index 46d917293a8..99ef44a99f5 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfos.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/getAccountInfos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/getInviteCodes.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/getInviteCodes.ts index 1eb099aae66..d68b97d775a 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/getInviteCodes.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/getInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoServerDefs from '../server/defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/getModerationEvent.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/getModerationEvent.ts index 7de567a73db..99c8bbe20ef 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/getModerationEvent.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/getModerationEvent.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/getRecord.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/getRecord.ts index 48222d9d819..557945e2fbd 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/getRecord.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/getRecord.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -30,7 +30,7 @@ export interface HandlerError { error?: 'RecordNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/getRepo.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/getRepo.ts index 19911baa90a..ede9fcf3ce8 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/getRepo.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/getRepo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -29,7 +29,7 @@ export interface HandlerError { error?: 'RepoNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts index 7315e51e8c2..d5976db70b1 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts index cb479533d39..843c228e6f9 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts index f3c4f1fbb95..9f4738578aa 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -15,10 +15,27 @@ export interface QueryParams { createdBy?: string /** Sort direction for the events. Defaults to descending order of created at timestamp. */ sortDirection: 'asc' | 'desc' + /** Retrieve events created after a given timestamp */ + createdAfter?: string + /** Retrieve events created before a given timestamp */ + createdBefore?: string subject?: string /** If true, events on all record types (posts, lists, profile etc.) owned by the did are returned */ includeAllUserRecords: boolean limit: number + /** If true, only events with comments are returned */ + hasComment?: boolean + /** If specified, only events with comments containing the keyword are returned */ + comment?: string + /** If specified, only events where all of these labels were added are returned */ + addedLabels?: string[] + /** If specified, only events where all of these labels were removed are returned */ + removedLabels?: string[] + /** If specified, only events where all of these tags were added are returned */ + addedTags?: string[] + /** If specified, only events where all of these tags were removed are returned */ + removedTags?: string[] + reportTypes?: string[] cursor?: string } @@ -43,7 +60,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts index 6e1aea1f679..f5031d25117 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -35,6 +35,8 @@ export interface QueryParams { /** Get subjects in unresolved appealed status */ appealed?: boolean limit: number + tags?: string[] + excludeTags?: string[] cursor?: string } @@ -59,7 +61,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/searchRepos.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/searchRepos.ts index 1e7e1a36bb6..d1529956c17 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/searchRepos.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/searchRepos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/sendEmail.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/sendEmail.ts index f94cfb3a083..836fba39f79 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/sendEmail.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/sendEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts index 9e6140256ef..ebabffbccdb 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts index c378f421926..d6dc4a2dc25 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts new file mode 100644 index 00000000000..948568f0d3d --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts @@ -0,0 +1,39 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + did: string + password: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/ozone/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts index 5dc5cecda4a..73e079cfe58 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -44,7 +44,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts b/packages/ozone/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts index 559ee948380..94df3041cf3 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -48,7 +48,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts b/packages/ozone/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts new file mode 100644 index 00000000000..5fa374de737 --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts @@ -0,0 +1,47 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + /** Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs. */ + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/ozone/src/lexicon/types/com/atproto/identity/requestPlcOperationSignature.ts b/packages/ozone/src/lexicon/types/com/atproto/identity/requestPlcOperationSignature.ts new file mode 100644 index 00000000000..82672f1d1c7 --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/identity/requestPlcOperationSignature.ts @@ -0,0 +1,31 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined +export type HandlerInput = undefined + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/ozone/src/lexicon/types/com/atproto/identity/resolveHandle.ts b/packages/ozone/src/lexicon/types/com/atproto/identity/resolveHandle.ts index ef90e99bb30..05019df6166 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/identity/resolveHandle.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/identity/resolveHandle.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle to resolve. */ @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/temp/transferAccount.ts b/packages/ozone/src/lexicon/types/com/atproto/identity/signPlcOperation.ts similarity index 70% rename from packages/bsky/src/lexicon/types/com/atproto/temp/transferAccount.ts rename to packages/ozone/src/lexicon/types/com/atproto/identity/signPlcOperation.ts index 86c1d750e07..3c908c049f2 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/temp/transferAccount.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/identity/signPlcOperation.ts @@ -6,22 +6,23 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - handle: string - did: string - plcOp: {} + /** A token received through com.atproto.identity.requestPlcOperationSignature */ + token?: string + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} [k: string]: unknown } export interface OutputSchema { - accessJwt: string - refreshJwt: string - handle: string - did: string + /** A signed DID PLC operation. */ + operation: {} [k: string]: unknown } @@ -39,17 +40,9 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string - error?: - | 'InvalidHandle' - | 'InvalidPassword' - | 'InvalidInviteCode' - | 'HandleNotAvailable' - | 'UnsupportedDomain' - | 'UnresolvableDid' - | 'IncompatibleDidDoc' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts b/packages/ozone/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts new file mode 100644 index 00000000000..5290b55d023 --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts @@ -0,0 +1,38 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + operation: {} + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/ozone/src/lexicon/types/com/atproto/identity/updateHandle.ts b/packages/ozone/src/lexicon/types/com/atproto/identity/updateHandle.ts index 1f639c344e9..f451d1f57c7 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/identity/updateHandle.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/identity/updateHandle.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { + /** The new handle. */ handle: string [k: string]: unknown } diff --git a/packages/ozone/src/lexicon/types/com/atproto/label/queryLabels.ts b/packages/ozone/src/lexicon/types/com/atproto/label/queryLabels.ts index 1d7f8a4def5..0c9d55a6961 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/label/queryLabels.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/label/queryLabels.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoLabelDefs from './defs' export interface QueryParams { @@ -39,7 +39,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/label/subscribeLabels.ts b/packages/ozone/src/lexicon/types/com/atproto/label/subscribeLabels.ts index 9d4b4441ae0..6034b35d895 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/label/subscribeLabels.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/label/subscribeLabels.ts @@ -10,7 +10,7 @@ import { IncomingMessage } from 'http' import * as ComAtprotoLabelDefs from './defs' export interface QueryParams { - /** The last known event to backfill from. */ + /** The last known event seq number to backfill from. */ cursor?: number } diff --git a/packages/ozone/src/lexicon/types/com/atproto/moderation/createReport.ts b/packages/ozone/src/lexicon/types/com/atproto/moderation/createReport.ts index 96aaf4a9c29..aa3f810a91c 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/moderation/createReport.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/moderation/createReport.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoModerationDefs from './defs' import * as ComAtprotoAdminDefs from '../admin/defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -15,6 +15,7 @@ export interface QueryParams {} export interface InputSchema { reasonType: ComAtprotoModerationDefs.ReasonType + /** Additional context about the content and violation. */ reason?: string subject: | ComAtprotoAdminDefs.RepoRef @@ -52,7 +53,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/applyWrites.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/applyWrites.ts index 61d1e7c28e4..3956d7c3048 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/applyWrites.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/applyWrites.ts @@ -6,16 +6,17 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string - /** Flag for validating the records. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data, for all operations. */ validate: boolean writes: (Create | Update | Delete)[] + /** If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations. */ swapCommit?: string [k: string]: unknown } @@ -43,7 +44,7 @@ export type Handler = ( ctx: HandlerReqCtx, ) => Promise | HandlerOutput -/** Create a new record. */ +/** Operation which creates a new record. */ export interface Create { collection: string rkey?: string @@ -63,7 +64,7 @@ export function validateCreate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#create', v) } -/** Update an existing record. */ +/** Operation which updates an existing record. */ export interface Update { collection: string rkey: string @@ -83,7 +84,7 @@ export function validateUpdate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#update', v) } -/** Delete an existing record. */ +/** Operation which deletes an existing record. */ export interface Delete { collection: string rkey: string diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/createRecord.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/createRecord.ts index df8c5d9e600..55cc95d0ad7 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/createRecord.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/createRecord.ts @@ -6,20 +6,20 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey?: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate: boolean - /** The record to create. */ + /** The record itself. Must contain a $type field. */ record: {} /** Compare and swap with the previous commit by CID. */ swapCommit?: string @@ -49,7 +49,7 @@ export interface HandlerError { error?: 'InvalidSwap' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/deleteRecord.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/deleteRecord.ts index f45118a3769..3bb97be0aad 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/deleteRecord.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/deleteRecord.ts @@ -6,16 +6,16 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** Compare and swap with the previous record by CID. */ swapRecord?: string diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/describeRepo.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/describeRepo.ts index 7b8a2b995eb..749bedcfeb7 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/describeRepo.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/describeRepo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ @@ -18,8 +18,11 @@ export type InputSchema = undefined export interface OutputSchema { handle: string did: string + /** The complete DID document for this account. */ didDoc: {} + /** List of all the collections (NSIDs) for which this repo contains at least one record. */ collections: string[] + /** Indicates if handle is currently valid (resolves bi-directionally) */ handleIsCorrect: boolean [k: string]: unknown } @@ -37,7 +40,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/getRecord.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/getRecord.ts index 35c9b4b7166..1a737a848be 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/getRecord.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/getRecord.ts @@ -6,14 +6,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** The CID of the version of the record. If not specified, then return the most recent version. */ cid?: string @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/com/atproto/temp/pushBlob.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/importRepo.ts similarity index 84% rename from packages/bsky/src/lexicon/types/com/atproto/temp/pushBlob.ts rename to packages/ozone/src/lexicon/types/com/atproto/repo/importRepo.ts index 97e890dbb14..921798c0ded 100644 --- a/packages/bsky/src/lexicon/types/com/atproto/temp/pushBlob.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/importRepo.ts @@ -7,17 +7,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' -export interface QueryParams { - /** The DID of the repo. */ - did: string -} +export interface QueryParams {} export type InputSchema = string | Uint8Array export interface HandlerInput { - encoding: '*/*' + encoding: 'application/vnd.ipld.car' body: stream.Readable } diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts new file mode 100644 index 00000000000..40f4d385e47 --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts @@ -0,0 +1,65 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams { + limit: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + blobs: RecordBlob[] + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput + +export interface RecordBlob { + cid: string + recordUri: string + [k: string]: unknown +} + +export function isRecordBlob(v: unknown): v is RecordBlob { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.repo.listMissingBlobs#recordBlob' + ) +} + +export function validateRecordBlob(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.repo.listMissingBlobs#recordBlob', v) +} diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/listRecords.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/listRecords.ts index a6cf6abd1f3..f46f6eb0f7f 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/listRecords.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/listRecords.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ @@ -45,7 +45,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/putRecord.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/putRecord.ts index f10f773c1c4..193841a2294 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/putRecord.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/putRecord.ts @@ -6,22 +6,22 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate: boolean /** The record to write. */ record: {} - /** Compare and swap with the previous record by CID. */ + /** Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation */ swapRecord?: string | null /** Compare and swap with the previous commit by CID. */ swapCommit?: string @@ -51,7 +51,7 @@ export interface HandlerError { error?: 'InvalidSwap' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/repo/uploadBlob.ts b/packages/ozone/src/lexicon/types/com/atproto/repo/uploadBlob.ts index ad6002df925..febbbff9d16 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/repo/uploadBlob.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/repo/uploadBlob.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/activateAccount.ts b/packages/ozone/src/lexicon/types/com/atproto/server/activateAccount.ts new file mode 100644 index 00000000000..82672f1d1c7 --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/server/activateAccount.ts @@ -0,0 +1,31 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined +export type HandlerInput = undefined + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/ozone/src/lexicon/types/com/atproto/server/checkAccountStatus.ts b/packages/ozone/src/lexicon/types/com/atproto/server/checkAccountStatus.ts new file mode 100644 index 00000000000..f17182a8dce --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/server/checkAccountStatus.ts @@ -0,0 +1,51 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + activated: boolean + validDid: boolean + repoCommit: string + repoRev: string + repoBlocks: number + indexedRecords: number + privateStateValues: number + expectedBlobs: number + importedBlobs: number + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/ozone/src/lexicon/types/com/atproto/server/confirmEmail.ts b/packages/ozone/src/lexicon/types/com/atproto/server/confirmEmail.ts index ffaeeb8fe75..b667a04b996 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/confirmEmail.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/confirmEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/createAccount.ts b/packages/ozone/src/lexicon/types/com/atproto/server/createAccount.ts index bbf2c009bf5..6e9b2f9f3c2 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/createAccount.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/createAccount.ts @@ -6,28 +6,36 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { email?: string + /** Requested handle for the account. */ handle: string + /** Pre-existing atproto DID, being imported to a new account. */ did?: string inviteCode?: string verificationCode?: string verificationPhone?: string + /** Initial account password. May need to meet instance-specific password strength requirements. */ password?: string + /** DID PLC rotation key (aka, recovery key) to be included in PLC creation operation. */ recoveryKey?: string + /** A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented. */ plcOp?: {} [k: string]: unknown } +/** Account login session returned on successful account creation. */ export interface OutputSchema { accessJwt: string refreshJwt: string handle: string + /** The DID of the new account. */ did: string + /** Complete DID document. */ didDoc?: {} [k: string]: unknown } @@ -56,7 +64,7 @@ export interface HandlerError { | 'IncompatibleDidDoc' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/createAppPassword.ts b/packages/ozone/src/lexicon/types/com/atproto/server/createAppPassword.ts index 8e4a0a519e0..dcc5178ecfa 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/createAppPassword.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/createAppPassword.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { + /** A short name for the App Password, to help distinguish them. */ name: string [k: string]: unknown } @@ -34,7 +35,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCode.ts b/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCode.ts index acfac56ba76..9cfeacc7e28 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCode.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCode.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCodes.ts b/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCodes.ts index 5887d77fada..eb6cd2bb1b1 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCodes.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/createInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/createSession.ts b/packages/ozone/src/lexicon/types/com/atproto/server/createSession.ts index 2cd448703a6..3952959fe5e 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/createSession.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/createSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -45,7 +45,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/deactivateAccount.ts b/packages/ozone/src/lexicon/types/com/atproto/server/deactivateAccount.ts new file mode 100644 index 00000000000..b3793d6b2e0 --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/server/deactivateAccount.ts @@ -0,0 +1,39 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + /** A recommendation to server as to how long they should hold onto the deactivated account before deleting. */ + deleteAfter?: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/ozone/src/lexicon/types/com/atproto/server/deleteAccount.ts b/packages/ozone/src/lexicon/types/com/atproto/server/deleteAccount.ts index 37ddbba13e0..4fcec360a11 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/deleteAccount.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/deleteAccount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/deleteSession.ts b/packages/ozone/src/lexicon/types/com/atproto/server/deleteSession.ts index e4244870425..82672f1d1c7 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/deleteSession.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/deleteSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/describeServer.ts b/packages/ozone/src/lexicon/types/com/atproto/server/describeServer.ts index bb574dba9ff..c2625347f20 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/describeServer.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/describeServer.ts @@ -6,17 +6,21 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export type InputSchema = undefined export interface OutputSchema { + /** If true, an invite code must be supplied to create an account on this instance. */ inviteCodeRequired?: boolean + /** If true, a phone verification token must be supplied to create an account on this instance. */ phoneVerificationRequired?: boolean + /** List of domain suffixes that can be used in account handles. */ availableUserDomains: string[] links?: Links + did: string [k: string]: unknown } @@ -33,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts b/packages/ozone/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts index e387a5e38e4..82c3ffa8c31 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoServerDefs from './defs' export interface QueryParams { includeUsed: boolean + /** Controls whether any new 'earned' but not 'created' invites should be created. */ createAvailable: boolean } @@ -35,7 +36,7 @@ export interface HandlerError { error?: 'DuplicateCreate' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/bsky/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts b/packages/ozone/src/lexicon/types/com/atproto/server/getServiceAuth.ts similarity index 77% rename from packages/bsky/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts rename to packages/ozone/src/lexicon/types/com/atproto/server/getServiceAuth.ts index 4ccad20c902..73efe2313a9 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/getServiceAuth.ts @@ -6,19 +6,17 @@ 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 '../feed/defs' +import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { - limit: number - cursor?: string + /** The DID of the service that the token will be used to authenticate with */ + aud: string } export type InputSchema = undefined export interface OutputSchema { - cursor?: string - feed: AppBskyFeedDefs.SkeletonFeedPost[] + token: string [k: string]: unknown } @@ -33,10 +31,9 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string - error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/getSession.ts b/packages/ozone/src/lexicon/types/com/atproto/server/getSession.ts index 4f95acf523d..5a8c40b947e 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/getSession.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/getSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/listAppPasswords.ts b/packages/ozone/src/lexicon/types/com/atproto/server/listAppPasswords.ts index ebd74da9d39..241418d932d 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/listAppPasswords.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/listAppPasswords.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/refreshSession.ts b/packages/ozone/src/lexicon/types/com/atproto/server/refreshSession.ts index 35874f78a69..3adeb7fc20e 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/refreshSession.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/refreshSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -35,7 +35,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/requestAccountDelete.ts b/packages/ozone/src/lexicon/types/com/atproto/server/requestAccountDelete.ts index e4244870425..82672f1d1c7 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/requestAccountDelete.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/requestAccountDelete.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts b/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts index e4244870425..82672f1d1c7 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts b/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts index 6876d44ca46..24dce3e12af 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/requestPasswordReset.ts b/packages/ozone/src/lexicon/types/com/atproto/server/requestPasswordReset.ts index 47fb4bb62f3..d0f3f2ad769 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/requestPasswordReset.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/requestPasswordReset.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/reserveSigningKey.ts b/packages/ozone/src/lexicon/types/com/atproto/server/reserveSigningKey.ts index ad5a5a8758c..0ec1e80c77c 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/reserveSigningKey.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/reserveSigningKey.ts @@ -6,18 +6,18 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The did to reserve a new did:key for */ + /** The DID to reserve a key for. */ did?: string [k: string]: unknown } export interface OutputSchema { - /** Public signing key in the form of a did:key. */ + /** The public key for the reserved signing key, in did:key serialization. */ signingKey: string [k: string]: unknown } @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/resetPassword.ts b/packages/ozone/src/lexicon/types/com/atproto/server/resetPassword.ts index 9e6ece3e4c4..38f63382cf0 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/resetPassword.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/resetPassword.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/revokeAppPassword.ts b/packages/ozone/src/lexicon/types/com/atproto/server/revokeAppPassword.ts index 4627f68eaa2..769ad6aa521 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/revokeAppPassword.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/revokeAppPassword.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/server/updateEmail.ts b/packages/ozone/src/lexicon/types/com/atproto/server/updateEmail.ts index c88bd3021b2..5473d7571e9 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/server/updateEmail.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/server/updateEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/getBlob.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/getBlob.ts index 60750902472..93e50403f20 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/getBlob.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/getBlob.ts @@ -7,10 +7,10 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { - /** The DID of the repo. */ + /** The DID of the account. */ did: string /** The CID of the blob to fetch */ cid: string @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/getBlocks.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/getBlocks.ts index e73410efb41..f1b8ebe5db1 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/getBlocks.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/getBlocks.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -29,7 +29,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/getCheckout.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/getCheckout.ts index 63a657e56b9..51856b9088d 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/getCheckout.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/getCheckout.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/getHead.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/getHead.ts index 586ae1a4189..adedd4cf211 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/getHead.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/getHead.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -34,7 +34,7 @@ export interface HandlerError { error?: 'HeadNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/getLatestCommit.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/getLatestCommit.ts index 9b91e878724..bbae68bbe76 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/getLatestCommit.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/getLatestCommit.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -35,7 +35,7 @@ export interface HandlerError { error?: 'RepoNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/getRecord.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/getRecord.ts index 297f0ac7794..c78ff8c2089 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/getRecord.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/getRecord.ts @@ -7,12 +7,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ did: string collection: string + /** Record Key */ rkey: string /** An optional past commit CID. */ commit?: string @@ -32,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/getRepo.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/getRepo.ts index 495d31a1a22..0d426557c5f 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/getRepo.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/getRepo.ts @@ -7,12 +7,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ did: string - /** The revision of the repo to catch up from. */ + /** The revision ('rev') of the repo to create a diff from. */ since?: string } @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/listBlobs.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/listBlobs.ts index b397bb3b3df..67a66577809 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/listBlobs.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/listBlobs.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/listRepos.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/listRepos.ts index 783a8e314c2..e5a8e2ca9d6 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/listRepos.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/listRepos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { limit: number @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams @@ -48,6 +48,7 @@ export type Handler = ( export interface Repo { did: string + /** Current repo commit CID */ head: string rev: string [k: string]: unknown diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts index 3d310c1139a..8a0af577c7c 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts @@ -6,12 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is notifying of update. */ + /** Hostname of the current service (usually a PDS) that is notifying of update. */ hostname: string [k: string]: unknown } diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/requestCrawl.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/requestCrawl.ts index 87ef20d7297..31180aabf58 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/requestCrawl.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/requestCrawl.ts @@ -6,12 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is requesting to be crawled. */ + /** Hostname of the current service (eg, PDS) that is requesting to be crawled. */ hostname: string [k: string]: unknown } diff --git a/packages/ozone/src/lexicon/types/com/atproto/sync/subscribeRepos.ts b/packages/ozone/src/lexicon/types/com/atproto/sync/subscribeRepos.ts index fb334778bf6..19874b06083 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/sync/subscribeRepos.ts @@ -9,12 +9,13 @@ import { HandlerAuth, ErrorFrame } from '@atproto/xrpc-server' import { IncomingMessage } from 'http' export interface QueryParams { - /** The last known event to backfill from. */ + /** The last known event seq number to backfill from. */ cursor?: number } export type OutputSchema = | Commit + | Identity | Handle | Migrate | Tombstone @@ -32,21 +33,29 @@ export type Handler = ( ctx: HandlerReqCtx, ) => AsyncIterable +/** Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature. */ export interface Commit { + /** The stream sequence number of this message. */ seq: number + /** DEPRECATED -- unused */ rebase: boolean + /** Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data. */ tooBig: boolean + /** The repo this event comes from. */ repo: string + /** Repo commit object CID. */ commit: CID + /** DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability. */ prev?: CID | null - /** The rev of the emitted commit. */ + /** The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event. */ rev: string - /** The rev of the last emitted commit from this repo. */ + /** The rev of the last emitted commit from this repo (if any). */ since: string | null - /** CAR file containing relevant blocks. */ + /** CAR file containing relevant blocks, as a diff since the previous repo state. */ blocks: Uint8Array ops: RepoOp[] blobs: CID[] + /** Timestamp of when this message was originally broadcast. */ time: string [k: string]: unknown } @@ -63,6 +72,27 @@ export function validateCommit(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#commit', v) } +/** Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache. */ +export interface Identity { + seq: number + did: string + time: string + [k: string]: unknown +} + +export function isIdentity(v: unknown): v is Identity { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.sync.subscribeRepos#identity' + ) +} + +export function validateIdentity(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.sync.subscribeRepos#identity', v) +} + +/** Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity. */ export interface Handle { seq: number did: string @@ -83,6 +113,7 @@ export function validateHandle(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#handle', v) } +/** Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead */ export interface Migrate { seq: number did: string @@ -103,6 +134,7 @@ export function validateMigrate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#migrate', v) } +/** Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event */ export interface Tombstone { seq: number did: string @@ -140,10 +172,11 @@ export function validateInfo(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#info', v) } -/** A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null. */ +/** A repo operation, ie a mutation of a single record. */ export interface RepoOp { action: 'create' | 'update' | 'delete' | (string & {}) path: string + /** For creates and updates, the new record CID. For deletions, null. */ cid: CID | null [k: string]: unknown } diff --git a/packages/ozone/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts b/packages/ozone/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts new file mode 100644 index 00000000000..9486bce2b2b --- /dev/null +++ b/packages/ozone/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts @@ -0,0 +1,45 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + activated: boolean + placeInQueue?: number + estimatedTimeMs?: number + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/ozone/src/lexicon/types/com/atproto/temp/fetchLabels.ts b/packages/ozone/src/lexicon/types/com/atproto/temp/fetchLabels.ts index 39341fd3a0e..0fbdeed1196 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/temp/fetchLabels.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/temp/fetchLabels.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoLabelDefs from '../label/defs' export interface QueryParams { @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts b/packages/ozone/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts index 5a295f701eb..c977500fc33 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts +++ b/packages/ozone/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/ozone/src/logger.ts b/packages/ozone/src/logger.ts index 42b0a78b2a4..0b3e5acf52c 100644 --- a/packages/ozone/src/logger.ts +++ b/packages/ozone/src/logger.ts @@ -5,6 +5,8 @@ export const dbLogger: ReturnType = subsystemLogger('ozone:db') export const httpLogger: ReturnType = subsystemLogger('ozone') +export const langLogger: ReturnType = + subsystemLogger('ozone:lang') export const loggerMiddleware = pinoHttp({ logger: httpLogger, diff --git a/packages/ozone/src/mod-service/index.ts b/packages/ozone/src/mod-service/index.ts index 4c1c84e55dc..7f06272d55d 100644 --- a/packages/ozone/src/mod-service/index.ts +++ b/packages/ozone/src/mod-service/index.ts @@ -12,6 +12,7 @@ import { isModEventReport, isModEventTakedown, isModEventEmail, + isModEventTag, RepoRef, RepoBlobRef, } from '../lexicon/types/com/atproto/admin/defs' @@ -24,6 +25,8 @@ import { ModerationEventRow, ModerationSubjectStatusRow, ReversibleModerationEvent, + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + UNSPECCED_TAKEDOWN_LABEL, } from './types' import { ModerationEvent } from '../db/schema/moderation_event' import { StatusKeyset, TimeIdKeyset, paginate } from '../db/pagination' @@ -39,6 +42,7 @@ import { import { BlobPushEvent } from '../db/schema/blob_push_event' import { BackgroundQueue } from '../background' import { EventPusher } from '../daemon' +import { jsonb } from '../db/types' export type ModerationServiceCreator = (db: Database) => ModerationService @@ -49,6 +53,7 @@ export class ModerationService { public eventPusher: EventPusher, public appviewAgent: AtpAgent, private appviewAuth: AppviewAuth, + public serverDid: string, ) {} static creator( @@ -56,6 +61,7 @@ export class ModerationService { eventPusher: EventPusher, appviewAgent: AtpAgent, appviewAuth: AppviewAuth, + serverDid: string, ) { return (db: Database) => new ModerationService( @@ -64,6 +70,7 @@ export class ModerationService { eventPusher, appviewAgent, appviewAuth, + serverDid, ) } @@ -91,6 +98,15 @@ export class ModerationService { includeAllUserRecords: boolean types: ModerationEvent['action'][] sortDirection?: 'asc' | 'desc' + hasComment?: boolean + comment?: string + createdAfter?: string + createdBefore?: string + addedLabels: string[] + removedLabels: string[] + addedTags: string[] + removedTags: string[] + reportTypes?: string[] }): Promise<{ cursor?: string; events: ModerationEventRow[] }> { const { subject, @@ -100,7 +116,17 @@ export class ModerationService { includeAllUserRecords, sortDirection = 'desc', types, + hasComment, + comment, + createdAfter, + createdBefore, + addedLabels, + removedLabels, + addedTags, + removedTags, + reportTypes, } = opts + const { ref } = this.db.db.dynamic let builder = this.db.db.selectFrom('moderation_event').selectAll() if (subject) { builder = builder.where((qb) => { @@ -134,8 +160,42 @@ export class ModerationService { if (createdBy) { builder = builder.where('createdBy', '=', createdBy) } + if (createdAfter) { + builder = builder.where('createdAt', '>=', createdAfter) + } + if (createdBefore) { + builder = builder.where('createdAt', '<=', createdBefore) + } + if (comment) { + builder = builder.where('comment', 'ilike', `%${comment}%`) + } + if (hasComment) { + builder = builder.where('comment', 'is not', null) + } + + // If multiple labels are passed, then only retrieve events where all those labels exist + if (addedLabels.length) { + addedLabels.forEach((label) => { + builder = builder.where('createLabelVals', 'ilike', `%${label}%`) + }) + } + if (removedLabels.length) { + removedLabels.forEach((label) => { + builder = builder.where('negateLabelVals', 'ilike', `%${label}%`) + }) + } + if (addedTags.length) { + builder = builder.where(sql`${ref('addedTags')} @> ${jsonb(addedTags)}`) + } + if (removedTags.length) { + builder = builder.where( + sql`${ref('removedTags')} @> ${jsonb(removedTags)}`, + ) + } + if (reportTypes?.length) { + builder = builder.where(sql`meta->>'reportType'`, 'in', reportTypes) + } - const { ref } = this.db.db.dynamic const keyset = new TimeIdKeyset( ref(`moderation_event.createdAt`), ref('moderation_event.id'), @@ -191,7 +251,10 @@ export class ModerationService { subject: ModSubject createdBy: string createdAt?: Date - }): Promise { + }): Promise<{ + event: ModerationEventRow + subjectStatus: ModerationSubjectStatusRow | null + }> { this.db.assertTransaction() const { event, subject, createdBy, createdAt = new Date() } = info @@ -206,6 +269,9 @@ export class ModerationService { const meta: Record = {} + const addedTags = isModEventTag(event) ? jsonb(event.add) : null + const removedTags = isModEventTag(event) ? jsonb(event.remove) : null + if (isModEventReport(event)) { meta.reportType = event.reportType } @@ -218,6 +284,8 @@ export class ModerationService { meta.subjectLine = event.subjectLine } + const subjectInfo = subject.info() + const modEvent = await this.db.db .insertInto('moderation_event') .values({ @@ -227,6 +295,8 @@ export class ModerationService { createdBy, createLabelVals, negateLabelVals, + addedTags, + removedTags, durationInHours: event.durationInHours ? Number(event.durationInHours) : null, @@ -236,14 +306,22 @@ export class ModerationService { event.durationInHours ? addHoursToDate(event.durationInHours, createdAt).toISOString() : undefined, - ...subject.info(), + subjectType: subjectInfo.subjectType, + subjectDid: subjectInfo.subjectDid, + subjectUri: subjectInfo.subjectUri, + subjectCid: subjectInfo.subjectCid, + subjectBlobCids: jsonb(subjectInfo.subjectBlobCids), }) .returningAll() .executeTakeFirstOrThrow() - await adjustModerationSubjectStatus(this.db, modEvent, subject.blobCids) + const subjectStatus = await adjustModerationSubjectStatus( + this.db, + modEvent, + subject.blobCids, + ) - return modEvent + return { event: modEvent, subjectStatus } } async getLastReversibleEventForSubject(subject: ReversalSubject) { @@ -323,7 +401,7 @@ export class ModerationService { const isRevertingTakedown = action === 'com.atproto.admin.defs#modEventTakedown' this.db.assertTransaction() - const result = await this.logEvent({ + const { event } = await this.logEvent({ event: { $type: isRevertingTakedown ? 'com.atproto.admin.defs#modEventReverseTakedown' @@ -343,7 +421,7 @@ export class ModerationService { } } - return result + return event } async takedownRepo( @@ -359,19 +437,25 @@ export class ModerationService { subjectDid: subject.did, takedownRef, })) - const repoEvts = await this.db.db - .insertInto('repo_push_event') - .values(values) - .onConflict((oc) => - oc.columns(['subjectDid', 'eventType']).doUpdateSet({ - takedownRef, - confirmedAt: null, - attempts: 0, - lastAttempted: null, - }), - ) - .returning('id') - .execute() + + const [repoEvts] = await Promise.all([ + this.db.db + .insertInto('repo_push_event') + .values(values) + .onConflict((oc) => + oc.columns(['subjectDid', 'eventType']).doUpdateSet({ + takedownRef, + confirmedAt: null, + attempts: 0, + lastAttempted: null, + }), + ) + .returning('id') + .execute(), + this.formatAndCreateLabels(subject.did, null, { + create: [UNSPECCED_TAKEDOWN_LABEL], + }), + ]) this.db.onCommit(() => { this.backgroundQueue.add(async () => { @@ -383,18 +467,23 @@ export class ModerationService { } async reverseTakedownRepo(subject: RepoSubject) { - const repoEvts = await this.db.db - .updateTable('repo_push_event') - .where('eventType', 'in', TAKEDOWNS) - .where('subjectDid', '=', subject.did) - .set({ - takedownRef: null, - confirmedAt: null, - attempts: 0, - lastAttempted: null, - }) - .returning('id') - .execute() + const [repoEvts] = await Promise.all([ + this.db.db + .updateTable('repo_push_event') + .where('eventType', 'in', TAKEDOWNS) + .where('subjectDid', '=', subject.did) + .set({ + takedownRef: null, + confirmedAt: null, + attempts: 0, + lastAttempted: null, + }) + .returning('id') + .execute(), + this.formatAndCreateLabels(subject.did, null, { + negate: [UNSPECCED_TAKEDOWN_LABEL], + }), + ]) this.db.onCommit(() => { this.backgroundQueue.add(async () => { @@ -415,19 +504,27 @@ export class ModerationService { subjectCid: subject.cid, takedownRef, })) - const recordEvts = await this.db.db - .insertInto('record_push_event') - .values(values) - .onConflict((oc) => - oc.columns(['subjectUri', 'eventType']).doUpdateSet({ - takedownRef, - confirmedAt: null, - attempts: 0, - lastAttempted: null, - }), - ) - .returning('id') - .execute() + const blobCids = subject.blobCids + const labels: string[] = [UNSPECCED_TAKEDOWN_LABEL] + if (blobCids && blobCids.length > 0) { + labels.push(UNSPECCED_TAKEDOWN_BLOBS_LABEL) + } + const [recordEvts] = await Promise.all([ + this.db.db + .insertInto('record_push_event') + .values(values) + .onConflict((oc) => + oc.columns(['subjectUri', 'eventType']).doUpdateSet({ + takedownRef, + confirmedAt: null, + attempts: 0, + lastAttempted: null, + }), + ) + .returning('id') + .execute(), + this.formatAndCreateLabels(subject.uri, subject.cid, { create: labels }), + ]) this.db.onCommit(() => { this.backgroundQueue.add(async () => { @@ -437,7 +534,6 @@ export class ModerationService { }) }) - const blobCids = subject.blobCids if (blobCids && blobCids.length > 0) { const blobValues: Insertable[] = [] for (const eventType of TAKEDOWNS) { @@ -478,19 +574,27 @@ export class ModerationService { async reverseTakedownRecord(subject: RecordSubject) { this.db.assertTransaction() - const recordEvts = await this.db.db - .updateTable('record_push_event') - .where('eventType', 'in', TAKEDOWNS) - .where('subjectDid', '=', subject.did) - .where('subjectUri', '=', subject.uri) - .set({ - takedownRef: null, - confirmedAt: null, - attempts: 0, - lastAttempted: null, - }) - .returning('id') - .execute() + const labels: string[] = [UNSPECCED_TAKEDOWN_LABEL] + const blobCids = subject.blobCids + if (blobCids && blobCids.length > 0) { + labels.push(UNSPECCED_TAKEDOWN_BLOBS_LABEL) + } + const [recordEvts] = await Promise.all([ + this.db.db + .updateTable('record_push_event') + .where('eventType', 'in', TAKEDOWNS) + .where('subjectDid', '=', subject.did) + .where('subjectUri', '=', subject.uri) + .set({ + takedownRef: null, + confirmedAt: null, + attempts: 0, + lastAttempted: null, + }) + .returning('id') + .execute(), + this.formatAndCreateLabels(subject.uri, subject.cid, { negate: labels }), + ]) this.db.onCommit(() => { this.backgroundQueue.add(async () => { await Promise.all( @@ -499,7 +603,6 @@ export class ModerationService { }) }) - const blobCids = subject.blobCids if (blobCids && blobCids.length > 0) { const blobEvts = await this.db.db .updateTable('blob_push_event') @@ -535,7 +638,10 @@ export class ModerationService { subject: ModSubject reportedBy: string createdAt?: Date - }): Promise { + }): Promise<{ + event: ModerationEventRow + subjectStatus: ModerationSubjectStatusRow | null + }> { const { reasonType, reason, @@ -544,7 +650,7 @@ export class ModerationService { subject, } = info - const event = await this.logEvent({ + const result = await this.logEvent({ event: { $type: 'com.atproto.admin.defs#modEventReport', reportType: reasonType, @@ -555,7 +661,7 @@ export class ModerationService { createdAt, }) - return event + return result } async getSubjectStatuses({ @@ -574,6 +680,8 @@ export class ModerationService { lastReviewedBy, sortField, subject, + tags, + excludeTags, }: { cursor?: string limit?: number @@ -590,8 +698,11 @@ export class ModerationService { sortDirection: 'asc' | 'desc' lastReviewedBy?: string sortField: 'lastReviewedAt' | 'lastReportedAt' + tags: string[] + excludeTags: string[] }) { let builder = this.db.db.selectFrom('moderation_subject_status').selectAll() + const { ref } = this.db.db.dynamic if (subject) { const subjectInfo = getStatusIdentifierFromSubject(subject) @@ -653,7 +764,24 @@ export class ModerationService { ) } - const { ref } = this.db.db.dynamic + if (tags.length) { + builder = builder.where( + sql`${ref('moderation_subject_status.tags')} @> ${jsonb(tags)}`, + ) + } + + if (excludeTags.length) { + builder = builder.where((qb) => + qb + .where( + sql`NOT(${ref('moderation_subject_status.tags')} @> ${jsonb( + excludeTags, + )})`, + ) + .orWhere('tags', 'is', null), + ) + } + const keyset = new StatusKeyset( ref(`moderation_subject_status.${sortField}`), ref('moderation_subject_status.id'), @@ -683,26 +811,26 @@ export class ModerationService { } } - async isSubjectTakendown(subject: ModSubject): Promise { - const builder = this.db.db + async getStatus( + subject: ModSubject, + ): Promise { + const result = await this.db.db .selectFrom('moderation_subject_status') .where('did', '=', subject.did) - .where('recordPath', '=', subject.recordPath || '') - - const result = await builder.select('takendown').executeTakeFirst() - - return !!result?.takendown + .where('recordPath', '=', subject.recordPath ?? '') + .selectAll() + .executeTakeFirst() + return result ?? null } async formatAndCreateLabels( - src: string, uri: string, cid: string | null, labels: { create?: string[]; negate?: string[] }, ): Promise { const { create = [], negate = [] } = labels const toCreate = create.map((val) => ({ - src, + src: this.serverDid, uri, cid: cid ?? undefined, val, @@ -710,7 +838,7 @@ export class ModerationService { cts: new Date().toISOString(), })) const toNegate = negate.map((val) => ({ - src, + src: this.serverDid, uri, cid: cid ?? undefined, val, diff --git a/packages/ozone/src/mod-service/lang.ts b/packages/ozone/src/mod-service/lang.ts new file mode 100644 index 00000000000..91d3d12d5ce --- /dev/null +++ b/packages/ozone/src/mod-service/lang.ts @@ -0,0 +1,82 @@ +import { ModerationService } from '.' +import { ModSubject } from './subject' +import { ModerationSubjectStatusRow } from './types' +import { langLogger as log } from '../logger' + +export class ModerationLangService { + constructor(private moderationService: ModerationService) {} + + async tagSubjectWithLang({ + subject, + subjectStatus, + createdBy, + }: { + subject: ModSubject + createdBy: string + subjectStatus: ModerationSubjectStatusRow | null + }) { + if ( + subjectStatus && + !subjectStatus.tags?.find((tag) => tag.includes('lang:')) + ) { + try { + const recordLangs = await this.getRecordLang({ + subject, + }) + await this.moderationService.logEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventTag', + add: recordLangs + ? recordLangs.map((lang) => `lang:${lang}`) + : ['lang:und'], + remove: [], + }, + subject, + createdBy, + }) + } catch (err) { + log.error({ subject, err }, 'Error getting record langs') + } + } + } + + async getRecordLang({ + subject, + }: { + subject: ModSubject + }): Promise { + const isRecord = subject.isRecord() + const langs = new Set() + + if ( + subject.isRepo() || + (isRecord && subject.uri.endsWith('/app.bsky.actor.profile/self')) + ) { + const feed = await this.moderationService.views.fetchAuthorFeed( + subject.did, + ) + feed.forEach((item) => { + const itemLangs = item.post.record['langs'] as string[] | null + if (itemLangs?.length) { + // Pick the first fragment of the lang code so that instead of `en-US` and `en-GB` we get `en` + itemLangs.forEach((lang) => langs.add(lang.split('-')[0])) + } + }) + } + + if (isRecord) { + const recordByUri = await this.moderationService.views.fetchRecords([ + subject, + ]) + const record = recordByUri.get(subject.uri) + const recordLang = record?.value.langs as string[] | null + if (recordLang?.length) { + recordLang + .map((lang) => lang.split('-')[0]) + .forEach((lang) => langs.add(lang)) + } + } + + return langs.size > 0 ? Array.from(langs) : null + } +} diff --git a/packages/ozone/src/mod-service/status.ts b/packages/ozone/src/mod-service/status.ts index 598ebe20712..2edba64282f 100644 --- a/packages/ozone/src/mod-service/status.ts +++ b/packages/ozone/src/mod-service/status.ts @@ -10,8 +10,8 @@ import { } from '../lexicon/types/com/atproto/admin/defs' import { ModerationEventRow, ModerationSubjectStatusRow } from './types' import { HOUR } from '@atproto/common' -import { sql } from 'kysely' import { REASONAPPEAL } from '../lexicon/types/com/atproto/moderation/defs' +import { jsonb } from '../db/types' const getSubjectStatusForModerationEvent = ({ action, @@ -82,6 +82,8 @@ const getSubjectStatusForModerationEvent = ({ lastReviewedBy: createdBy, lastReviewedAt: createdAt, } + case 'com.atproto.admin.defs#modEventTag': + return { tags: [] } case 'com.atproto.admin.defs#modEventResolveAppeal': return { appealed: false, @@ -106,6 +108,8 @@ export const adjustModerationSubjectStatus = async ( subjectCid, createdBy, meta, + addedTags, + removedTags, comment, createdAt, } = moderationEvent @@ -190,10 +194,22 @@ export const adjustModerationSubjectStatus = async ( subjectStatus.comment = comment } + if (action === 'com.atproto.admin.defs#modEventTag') { + let tags = currentStatus?.tags || [] + if (addedTags?.length) { + tags = tags.concat(addedTags) + } + if (removedTags?.length) { + tags = tags.filter((tag) => !removedTags.includes(tag)) + } + newStatus.tags = jsonb([...new Set(tags)]) as unknown as string[] + subjectStatus.tags = newStatus.tags + } + if (blobCids?.length) { - const newBlobCids = sql`${JSON.stringify( + const newBlobCids = jsonb( blobCids, - )}` as unknown as ModerationSubjectStatusRow['blobCids'] + ) as unknown as ModerationSubjectStatusRow['blobCids'] newStatus.blobCids = newBlobCids subjectStatus.blobCids = newBlobCids } @@ -205,7 +221,6 @@ export const adjustModerationSubjectStatus = async ( ...newStatus, createdAt: now, updatedAt: now, - // TODO: Need to get the types right here. } as ModerationSubjectStatusRow) .onConflict((oc) => oc.constraint('moderation_status_unique_idx').doUpdateSet({ @@ -214,8 +229,8 @@ export const adjustModerationSubjectStatus = async ( }), ) - const status = await insertQuery.executeTakeFirst() - return status + const status = await insertQuery.returningAll().executeTakeFirst() + return status || null } type ModerationSubjectStatusFilter = diff --git a/packages/ozone/src/mod-service/subject.ts b/packages/ozone/src/mod-service/subject.ts index 2ea41eed42e..82c8f15f1d5 100644 --- a/packages/ozone/src/mod-service/subject.ts +++ b/packages/ozone/src/mod-service/subject.ts @@ -37,7 +37,11 @@ export const subjectFromEventRow = (row: ModerationEventRow): ModSubject => { row.subjectUri && row.subjectCid ) { - return new RecordSubject(row.subjectUri, row.subjectCid) + return new RecordSubject( + row.subjectUri, + row.subjectCid, + row.subjectBlobCids ?? [], + ) } else { return new RepoSubject(row.subjectDid) } @@ -50,7 +54,7 @@ export const subjectFromStatusRow = ( // Not too intuitive but the recordpath is basically / // which is what the last 2 params of .make() arguments are const uri = AtUri.make(row.did, ...row.recordPath.split('/')).toString() - return new RecordSubject(uri.toString(), row.recordCid) + return new RecordSubject(uri.toString(), row.recordCid, row.blobCids ?? []) } else { return new RepoSubject(row.did) } @@ -61,6 +65,7 @@ type SubjectInfo = { subjectDid: string subjectUri: string | null subjectCid: string | null + subjectBlobCids: string[] | null } export interface ModSubject { @@ -89,6 +94,7 @@ export class RepoSubject implements ModSubject { subjectDid: this.did, subjectUri: null, subjectCid: null, + subjectBlobCids: null, } } lex(): RepoRef { @@ -124,6 +130,7 @@ export class RecordSubject implements ModSubject { subjectDid: this.did, subjectUri: this.uri, subjectCid: this.cid, + subjectBlobCids: this.blobCids ?? [], } } lex(): StrongRef { diff --git a/packages/ozone/src/mod-service/types.ts b/packages/ozone/src/mod-service/types.ts index 94fc58a8d33..6099384a3cd 100644 --- a/packages/ozone/src/mod-service/types.ts +++ b/packages/ozone/src/mod-service/types.ts @@ -30,3 +30,8 @@ export type ModEventType = | ComAtprotoAdminDefs.ModEventReport | ComAtprotoAdminDefs.ModEventMute | ComAtprotoAdminDefs.ModEventReverseTakedown + | ComAtprotoAdminDefs.ModEventTag + +export const UNSPECCED_TAKEDOWN_LABEL = '!unspecced-takedown' + +export const UNSPECCED_TAKEDOWN_BLOBS_LABEL = '!unspecced-takedown-blobs' diff --git a/packages/ozone/src/mod-service/views.ts b/packages/ozone/src/mod-service/views.ts index 1ae32126b8f..e21d2a46f5c 100644 --- a/packages/ozone/src/mod-service/views.ts +++ b/packages/ozone/src/mod-service/views.ts @@ -1,6 +1,6 @@ import { sql } from 'kysely' import { AtUri, INVALID_HANDLE, normalizeDatetimeAlways } from '@atproto/syntax' -import AtpAgent from '@atproto/api' +import AtpAgent, { AppBskyFeedDefs } from '@atproto/api' import { dedupeStrs } from '@atproto/common' import { BlobRef } from '@atproto/lexicon' import { Database } from '../db' @@ -88,7 +88,7 @@ export class ModerationViews { comment: event.comment ?? undefined, }, subject: subjectFromEventRow(event).lex(), - subjectBlobCids: [], + subjectBlobCids: event.subjectBlobCids ?? [], createdBy: event.createdBy, createdAt: event.createdAt, subjectHandle: event.subjectHandle ?? undefined, @@ -163,6 +163,11 @@ export class ModerationViews { eventView.event.sticky = true } + if (event.action === 'com.atproto.admin.defs#modEventTag') { + eventView.event.add = event.addedTags || [] + eventView.event.remove = event.removedTags || [] + } + return eventView } @@ -217,7 +222,7 @@ export class ModerationViews { subjects.map(async (subject) => { const uri = new AtUri(subject.uri) try { - return await this.appviewAgent.api.com.atproto.repo.getRecord( + const record = await this.appviewAgent.api.com.atproto.repo.getRecord( { repo: uri.hostname, collection: uri.collection, @@ -226,6 +231,7 @@ export class ModerationViews { }, auth, ) + return record } catch { return null } @@ -473,9 +479,22 @@ export class ModerationViews { appealed: status.appealed ?? undefined, subjectRepoHandle: status.handle ?? undefined, subjectBlobCids: status.blobCids || [], + tags: status.tags || [], subject: subjectFromStatusRow(status).lex(), } } + + async fetchAuthorFeed( + actor: string, + ): Promise { + const auth = await this.appviewAuth() + if (!auth) return [] + const { + data: { feed }, + } = await this.appviewAgent.api.app.bsky.feed.getAuthorFeed({ actor }, auth) + + return feed + } } type RecordSubject = { uri: string; cid?: string } diff --git a/packages/ozone/tests/__snapshots__/get-record.test.ts.snap b/packages/ozone/tests/__snapshots__/get-record.test.ts.snap index 14a83f9dfda..decfb8f4ba4 100644 --- a/packages/ozone/tests/__snapshots__/get-record.test.ts.snap +++ b/packages/ozone/tests/__snapshots__/get-record.test.ts.snap @@ -7,6 +7,14 @@ Object { "cid": "cids(0)", "indexedAt": "1970-01-01T00:00:00.000Z", "labels": Array [ + Object { + "cid": "cids(0)", + "cts": "1970-01-01T00:00:00.000Z", + "neg": false, + "src": "user(1)", + "uri": "record(0)", + "val": "!unspecced-takedown", + }, Object { "cid": "cids(0)", "cts": "1970-01-01T00:00:00.000Z", @@ -31,6 +39,9 @@ Object { }, "subjectBlobCids": Array [], "subjectRepoHandle": "alice.test", + "tags": Array [ + "lang:und", + ], "takendown": true, "updatedAt": "1970-01-01T00:00:00.000Z", }, @@ -93,6 +104,14 @@ Object { "cid": "cids(0)", "indexedAt": "1970-01-01T00:00:00.000Z", "labels": Array [ + Object { + "cid": "cids(0)", + "cts": "1970-01-01T00:00:00.000Z", + "neg": false, + "src": "user(1)", + "uri": "record(0)", + "val": "!unspecced-takedown", + }, Object { "cid": "cids(0)", "cts": "1970-01-01T00:00:00.000Z", @@ -117,6 +136,9 @@ Object { }, "subjectBlobCids": Array [], "subjectRepoHandle": "alice.test", + "tags": Array [ + "lang:und", + ], "takendown": true, "updatedAt": "1970-01-01T00:00:00.000Z", }, diff --git a/packages/ozone/tests/__snapshots__/get-repo.test.ts.snap b/packages/ozone/tests/__snapshots__/get-repo.test.ts.snap index 4ffd7e3564a..67404b88362 100644 --- a/packages/ozone/tests/__snapshots__/get-repo.test.ts.snap +++ b/packages/ozone/tests/__snapshots__/get-repo.test.ts.snap @@ -8,7 +8,15 @@ Object { "indexedAt": "1970-01-01T00:00:00.000Z", "invites": Array [], "invitesDisabled": false, - "labels": Array [], + "labels": Array [ + Object { + "cts": "1970-01-01T00:00:00.000Z", + "neg": false, + "src": "user(1)", + "uri": "user(0)", + "val": "!unspecced-takedown", + }, + ], "moderation": Object { "subjectStatus": Object { "createdAt": "1970-01-01T00:00:00.000Z", @@ -23,6 +31,9 @@ Object { }, "subjectBlobCids": Array [], "subjectRepoHandle": "alice.test", + "tags": Array [ + "lang:und", + ], "takendown": true, "updatedAt": "1970-01-01T00:00:00.000Z", }, diff --git a/packages/ozone/tests/__snapshots__/moderation-events.test.ts.snap b/packages/ozone/tests/__snapshots__/moderation-events.test.ts.snap index 8fa16b311f2..fcb73413622 100644 --- a/packages/ozone/tests/__snapshots__/moderation-events.test.ts.snap +++ b/packages/ozone/tests/__snapshots__/moderation-events.test.ts.snap @@ -29,6 +29,9 @@ Object { }, "subjectBlobCids": Array [], "subjectRepoHandle": "alice.test", + "tags": Array [ + "lang:und", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, @@ -76,7 +79,26 @@ Array [ "comment": "X", "reportType": "com.atproto.moderation.defs#reasonSpam", }, - "id": 7, + "id": 11, + "subject": Object { + "$type": "com.atproto.admin.defs#repoRef", + "did": "user(0)", + }, + "subjectBlobCids": Array [], + "subjectHandle": "bob.test", + }, + Object { + "createdAt": "1970-01-01T00:00:00.000Z", + "createdBy": "user(2)", + "event": Object { + "$type": "com.atproto.admin.defs#modEventTag", + "add": Array [ + "lang:en", + "lang:i", + ], + "remove": Array [], + }, + "id": 6, "subject": Object { "$type": "com.atproto.admin.defs#repoRef", "did": "user(0)", @@ -93,7 +115,7 @@ Array [ "comment": "X", "reportType": "com.atproto.moderation.defs#reasonSpam", }, - "id": 3, + "id": 5, "subject": Object { "$type": "com.atproto.admin.defs#repoRef", "did": "user(0)", @@ -115,7 +137,26 @@ Array [ "comment": "X", "reportType": "com.atproto.moderation.defs#reasonSpam", }, - "id": 6, + "id": 10, + "subject": Object { + "$type": "com.atproto.repo.strongRef", + "cid": "cids(0)", + "uri": "record(0)", + }, + "subjectBlobCids": Array [], + "subjectHandle": "alice.test", + }, + Object { + "createdAt": "1970-01-01T00:00:00.000Z", + "createdBy": "user(1)", + "event": Object { + "$type": "com.atproto.admin.defs#modEventTag", + "add": Array [ + "lang:und", + ], + "remove": Array [], + }, + "id": 4, "subject": Object { "$type": "com.atproto.repo.strongRef", "cid": "cids(0)", @@ -133,7 +174,7 @@ Array [ "comment": "X", "reportType": "com.atproto.moderation.defs#reasonSpam", }, - "id": 2, + "id": 3, "subject": Object { "$type": "com.atproto.repo.strongRef", "cid": "cids(0)", diff --git a/packages/ozone/tests/__snapshots__/moderation-statuses.test.ts.snap b/packages/ozone/tests/__snapshots__/moderation-statuses.test.ts.snap index a4939733d1a..cf361739a6c 100644 --- a/packages/ozone/tests/__snapshots__/moderation-statuses.test.ts.snap +++ b/packages/ozone/tests/__snapshots__/moderation-statuses.test.ts.snap @@ -1,10 +1,52 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`moderation-statuses query statuses returns statuses filtered by subject language 1`] = ` +Array [ + Object { + "createdAt": "1970-01-01T00:00:00.000Z", + "id": 7, + "lastReportedAt": "1970-01-01T00:00:00.000Z", + "reviewState": "com.atproto.admin.defs#reviewOpen", + "subject": Object { + "$type": "com.atproto.repo.strongRef", + "cid": "cids(0)", + "uri": "record(0)", + }, + "subjectBlobCids": Array [], + "subjectRepoHandle": "bob.test", + "tags": Array [ + "lang:en", + "lang:i", + ], + "takendown": false, + "updatedAt": "1970-01-01T00:00:00.000Z", + }, + Object { + "createdAt": "1970-01-01T00:00:00.000Z", + "id": 5, + "lastReportedAt": "1970-01-01T00:00:00.000Z", + "reviewState": "com.atproto.admin.defs#reviewOpen", + "subject": Object { + "$type": "com.atproto.admin.defs#repoRef", + "did": "user(0)", + }, + "subjectBlobCids": Array [], + "subjectRepoHandle": "bob.test", + "tags": Array [ + "lang:en", + "lang:i", + ], + "takendown": false, + "updatedAt": "1970-01-01T00:00:00.000Z", + }, +] +`; + exports[`moderation-statuses query statuses returns statuses for subjects that received moderation events 1`] = ` Array [ Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 4, + "id": 7, "lastReportedAt": "1970-01-01T00:00:00.000Z", "reviewState": "com.atproto.admin.defs#reviewOpen", "subject": Object { @@ -14,12 +56,16 @@ Array [ }, "subjectBlobCids": Array [], "subjectRepoHandle": "bob.test", + "tags": Array [ + "lang:en", + "lang:i", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 3, + "id": 5, "lastReportedAt": "1970-01-01T00:00:00.000Z", "reviewState": "com.atproto.admin.defs#reviewOpen", "subject": Object { @@ -28,12 +74,16 @@ Array [ }, "subjectBlobCids": Array [], "subjectRepoHandle": "bob.test", + "tags": Array [ + "lang:en", + "lang:i", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 2, + "id": 3, "lastReportedAt": "1970-01-01T00:00:00.000Z", "reviewState": "com.atproto.admin.defs#reviewOpen", "subject": Object { @@ -43,6 +93,9 @@ Array [ }, "subjectBlobCids": Array [], "subjectRepoHandle": "alice.test", + "tags": Array [ + "lang:und", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, @@ -57,6 +110,9 @@ Array [ }, "subjectBlobCids": Array [], "subjectRepoHandle": "alice.test", + "tags": Array [ + "lang:und", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, diff --git a/packages/ozone/tests/__snapshots__/moderation.test.ts.snap b/packages/ozone/tests/__snapshots__/moderation.test.ts.snap index 33a973e714f..39d2b6d4890 100644 --- a/packages/ozone/tests/__snapshots__/moderation.test.ts.snap +++ b/packages/ozone/tests/__snapshots__/moderation.test.ts.snap @@ -4,7 +4,7 @@ exports[`moderation reporting creates reports of a record. 1`] = ` Array [ Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 4, + "id": 5, "reasonType": "com.atproto.moderation.defs#reasonSpam", "reportedBy": "user(0)", "subject": Object { @@ -15,7 +15,7 @@ Array [ }, Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 5, + "id": 7, "reason": "defamation", "reasonType": "com.atproto.moderation.defs#reasonOther", "reportedBy": "user(1)", @@ -42,7 +42,7 @@ Array [ }, Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 2, + "id": 3, "reason": "impersonation", "reasonType": "com.atproto.moderation.defs#reasonOther", "reportedBy": "user(2)", diff --git a/packages/ozone/tests/get-record.test.ts b/packages/ozone/tests/get-record.test.ts index 303e0f054d0..735f4725f11 100644 --- a/packages/ozone/tests/get-record.test.ts +++ b/packages/ozone/tests/get-record.test.ts @@ -27,14 +27,6 @@ describe('admin get record view', () => { }) beforeAll(async () => { - await sc.emitModerationEvent({ - event: { $type: 'com.atproto.admin.defs#modEventFlag' }, - subject: { - $type: 'com.atproto.repo.strongRef', - uri: sc.posts[sc.dids.alice][0].ref.uriStr, - cid: sc.posts[sc.dids.alice][0].ref.cidStr, - }, - }) await sc.createReport({ reportedBy: sc.dids.bob, reasonType: REASONSPAM, diff --git a/packages/ozone/tests/moderation-events.test.ts b/packages/ozone/tests/moderation-events.test.ts index 670fa4beaa6..fbe571a8172 100644 --- a/packages/ozone/tests/moderation-events.test.ts +++ b/packages/ozone/tests/moderation-events.test.ts @@ -1,7 +1,12 @@ +import assert from 'node:assert' import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env' -import AtpAgent, { ComAtprotoAdminDefs } from '@atproto/api' +import AtpAgent, { + ComAtprotoAdminDefs, + ComAtprotoAdminEmitModerationEvent, +} from '@atproto/api' import { forSnapshot } from './_util' import { + REASONAPPEAL, REASONMISLEADING, REASONSPAM, } from '../src/lexicon/types/com/atproto/moderation/defs' @@ -12,7 +17,9 @@ describe('moderation-events', () => { let pdsAgent: AtpAgent let sc: SeedClient - const emitModerationEvent = async (eventData) => { + const emitModerationEvent = async ( + eventData: ComAtprotoAdminEmitModerationEvent.InputSchema, + ) => { return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, { encoding: 'application/json', headers: network.ozone.adminAuthHeaders('moderator'), @@ -141,7 +148,7 @@ describe('moderation-events', () => { expect( [...new Set(allEvents.data.events.map((e) => e.event.$type))].length, - ).toEqual(3) + ).toEqual(4) }) it('returns events for all content by user', async () => { @@ -196,25 +203,223 @@ describe('moderation-events', () => { const defaultEvents = await getPaginatedEvents() const reversedEvents = await getPaginatedEvents('asc') - expect(allEvents.data.events.length).toEqual(4) + expect(allEvents.data.events.length).toEqual(6) expect(defaultEvents.length).toEqual(allEvents.data.events.length) expect(reversedEvents.length).toEqual(allEvents.data.events.length) - expect(reversedEvents[0].id).toEqual(defaultEvents[3].id) + // First event in the reversed list is the last item in the default list + expect(reversedEvents[0].id).toEqual(defaultEvents[5].id) + }) + + it('returns report events matching reportType filters', async () => { + const [spamEvents, misleadingEvents] = await Promise.all([ + queryModerationEvents({ + reportTypes: [REASONSPAM], + }), + queryModerationEvents({ + reportTypes: [REASONMISLEADING, REASONAPPEAL], + }), + ]) + + expect(misleadingEvents.data.events.length).toEqual(2) + expect(spamEvents.data.events.length).toEqual(6) + }) + + it('returns events matching keyword in comment', async () => { + const [eventsWithX, eventsWithTest, eventsWithComment] = + await Promise.all([ + queryModerationEvents({ + comment: 'X', + }), + queryModerationEvents({ + comment: 'test', + }), + queryModerationEvents({ + hasComment: true, + }), + ]) + + expect(eventsWithX.data.events.length).toEqual(10) + expect(eventsWithTest.data.events.length).toEqual(0) + expect(eventsWithComment.data.events.length).toEqual(10) + }) + + it('returns events matching filter params for labels', async () => { + const [negatedLabelEvent, createdLabelEvent] = await Promise.all([ + emitModerationEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventLabel', + comment: 'X', + negateLabelVals: ['L1', 'L2'], + createLabelVals: [], + }, + // Report bob's account by alice and vice versa + subject: { + $type: 'com.atproto.admin.defs#repoRef', + did: sc.dids.alice, + }, + createdBy: sc.dids.bob, + }), + emitModerationEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventLabel', + comment: 'X', + createLabelVals: ['L1', 'L2'], + negateLabelVals: [], + }, + // Report bob's account by alice and vice versa + subject: { + $type: 'com.atproto.admin.defs#repoRef', + did: sc.dids.bob, + }, + createdBy: sc.dids.alice, + }), + ]) + const [withTwoLabels, withoutTwoLabels, withOneLabel, withoutOneLabel] = + await Promise.all([ + queryModerationEvents({ + addedLabels: ['L1', 'L3'], + }), + queryModerationEvents({ + removedLabels: ['L1', 'L2'], + }), + queryModerationEvents({ + addedLabels: ['L1'], + }), + queryModerationEvents({ + removedLabels: ['L2'], + }), + ]) + + // Verify that when querying for events where 2 different labels were added + // events where all of the labels from the list was added are returned + expect(withTwoLabels.data.events.length).toEqual(0) + expect(negatedLabelEvent.data.id).toEqual( + withoutTwoLabels.data.events[0].id, + ) + + expect(createdLabelEvent.data.id).toEqual(withOneLabel.data.events[0].id) + expect(negatedLabelEvent.data.id).toEqual( + withoutOneLabel.data.events[0].id, + ) + }) + it('returns events matching filter params for tags', async () => { + const tagEvent = async ({ + add, + remove, + }: { + add: string[] + remove: string[] + }) => + emitModerationEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventTag', + comment: 'X', + add, + remove, + }, + subject: { + $type: 'com.atproto.admin.defs#repoRef', + did: sc.dids.carol, + }, + createdBy: sc.dids.bob, + }) + const addEvent = await tagEvent({ add: ['L1', 'L2'], remove: [] }) + const addAndRemoveEvent = await tagEvent({ add: ['L3'], remove: ['L2'] }) + const [addFinder, addAndRemoveFinder, _removeFinder] = await Promise.all([ + queryModerationEvents({ + addedTags: ['L1'], + }), + queryModerationEvents({ + addedTags: ['L3'], + removedTags: ['L2'], + }), + queryModerationEvents({ + removedTags: ['L2'], + }), + ]) + + expect(addFinder.data.events.length).toEqual(1) + expect(addEvent.data.id).toEqual(addFinder.data.events[0].id) + + expect(addAndRemoveEvent.data.id).toEqual( + addAndRemoveFinder.data.events[0].id, + ) + expect(addAndRemoveEvent.data.id).toEqual( + addAndRemoveFinder.data.events[0].id, + ) + expect(addAndRemoveEvent.data.event.add).toEqual(['L3']) + expect(addAndRemoveEvent.data.event.remove).toEqual(['L2']) }) }) describe('get event', () => { it('gets an event by specific id', async () => { const { data } = await pdsAgent.api.com.atproto.admin.getModerationEvent( - { - id: 1, + { id: 1 }, + { headers: network.ozone.adminAuthHeaders('moderator') }, + ) + expect(forSnapshot(data)).toMatchSnapshot() + }) + }) + + describe('blobs', () => { + it('are tracked on takedown event', async () => { + const post = sc.posts[sc.dids.carol][0] + assert(post.images.length > 1) + await emitModerationEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventTakedown', }, - { - headers: network.ozone.adminAuthHeaders('moderator'), + subject: { + $type: 'com.atproto.repo.strongRef', + uri: post.ref.uriStr, + cid: post.ref.cidStr, }, - ) + subjectBlobCids: [post.images[0].image.ref.toString()], + createdBy: sc.dids.alice, + }) + const { data: result } = + await pdsAgent.api.com.atproto.admin.queryModerationEvents( + { + subject: post.ref.uriStr, + types: ['com.atproto.admin.defs#modEventTakedown'], + }, + { headers: network.ozone.adminAuthHeaders('moderator') }, + ) + expect(result.events[0]).toMatchObject({ + createdBy: sc.dids.alice, + event: { + $type: 'com.atproto.admin.defs#modEventTakedown', + }, + subjectBlobCids: [post.images[0].image.ref.toString()], + }) + }) - expect(forSnapshot(data)).toMatchSnapshot() + it("are tracked on reverse-takedown event even if they aren't specified", async () => { + const post = sc.posts[sc.dids.carol][0] + await emitModerationEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventReverseTakedown', + }, + subject: { + $type: 'com.atproto.repo.strongRef', + uri: post.ref.uriStr, + cid: post.ref.cidStr, + }, + createdBy: sc.dids.alice, + }) + const { data: result } = + await pdsAgent.api.com.atproto.admin.queryModerationEvents( + { subject: post.ref.uriStr }, + { headers: network.ozone.adminAuthHeaders('moderator') }, + ) + expect(result.events[0]).toMatchObject({ + createdBy: sc.dids.alice, + event: { + $type: 'com.atproto.admin.defs#modEventReverseTakedown', + }, + subjectBlobCids: [post.images[0].image.ref.toString()], + }) }) }) }) diff --git a/packages/ozone/tests/moderation-status-tags.test.ts b/packages/ozone/tests/moderation-status-tags.test.ts new file mode 100644 index 00000000000..eedac64ca39 --- /dev/null +++ b/packages/ozone/tests/moderation-status-tags.test.ts @@ -0,0 +1,92 @@ +import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env' +import AtpAgent from '@atproto/api' +import { REASONSPAM } from '../src/lexicon/types/com/atproto/moderation/defs' + +describe('moderation-status-tags', () => { + let network: TestNetwork + let agent: AtpAgent + let pdsAgent: AtpAgent + let sc: SeedClient + + const emitModerationEvent = async (eventData) => { + return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, { + encoding: 'application/json', + headers: network.bsky.adminAuthHeaders('moderator'), + }) + } + + const queryModerationStatuses = (statusQuery) => + agent.api.com.atproto.admin.queryModerationStatuses(statusQuery, { + headers: network.bsky.adminAuthHeaders('moderator'), + }) + + beforeAll(async () => { + network = await TestNetwork.create({ + dbPostgresSchema: 'ozone_moderation_status_tags', + }) + agent = network.ozone.getClient() + pdsAgent = network.pds.getClient() + sc = network.getSeedClient() + await basicSeed(sc) + await network.processAll() + }) + + afterAll(async () => { + await network.close() + }) + + describe('manage tags on subject status', () => { + it('adds and removes tags on a subject', async () => { + const bobsAccount = { + $type: 'com.atproto.admin.defs#repoRef', + did: sc.dids.bob, + } + await emitModerationEvent({ + subject: bobsAccount, + event: { + $type: 'com.atproto.admin.defs#modEventReport', + comment: 'X', + reportType: REASONSPAM, + }, + createdBy: sc.dids.alice, + }) + await emitModerationEvent({ + subject: bobsAccount, + event: { + $type: 'com.atproto.admin.defs#modEventTag', + add: ['interaction-churn'], + remove: [], + }, + createdBy: sc.dids.alice, + }) + const { data: statusAfterInteractionTag } = await queryModerationStatuses( + { + subject: bobsAccount.did, + }, + ) + expect(statusAfterInteractionTag.subjectStatuses[0].tags).toContain( + 'interaction-churn', + ) + + await emitModerationEvent({ + subject: bobsAccount, + event: { + $type: 'com.atproto.admin.defs#modEventTag', + remove: ['interaction-churn'], + add: ['follow-churn'], + }, + createdBy: sc.dids.alice, + }) + const { data: statusAfterFollowTag } = await queryModerationStatuses({ + subject: bobsAccount.did, + }) + + expect(statusAfterFollowTag.subjectStatuses[0].tags).not.toContain( + 'interaction-churn', + ) + expect(statusAfterFollowTag.subjectStatuses[0].tags).toContain( + 'follow-churn', + ) + }) + }) +}) diff --git a/packages/ozone/tests/moderation-statuses.test.ts b/packages/ozone/tests/moderation-statuses.test.ts index b1a1ed95c77..527611d5313 100644 --- a/packages/ozone/tests/moderation-statuses.test.ts +++ b/packages/ozone/tests/moderation-statuses.test.ts @@ -1,3 +1,4 @@ +import assert from 'node:assert' import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env' import AtpAgent, { ComAtprotoAdminDefs, @@ -38,8 +39,8 @@ describe('moderation-statuses', () => { } const bobsPost = { $type: 'com.atproto.repo.strongRef', - uri: sc.posts[sc.dids.bob][1].ref.uriStr, - cid: sc.posts[sc.dids.bob][1].ref.cidStr, + uri: sc.posts[sc.dids.bob][0].ref.uriStr, + cid: sc.posts[sc.dids.bob][0].ref.cidStr, } const alicesPost = { $type: 'com.atproto.repo.strongRef', @@ -94,6 +95,23 @@ describe('moderation-statuses', () => { expect(forSnapshot(response.data.subjectStatuses)).toMatchSnapshot() }) + it('returns statuses filtered by subject language', async () => { + const klingonQueue = await queryModerationStatuses({ + tags: ['lang:i'], + }) + + expect(forSnapshot(klingonQueue.data.subjectStatuses)).toMatchSnapshot() + + const nonKlingonQueue = await queryModerationStatuses({ + excludeTags: ['lang:i'], + }) + + // Verify that the klingon tagged subject is not returned when excluding klingon + expect( + nonKlingonQueue.data.subjectStatuses.map((s) => s.id), + ).not.toContain(klingonQueue.data.subjectStatuses[0].id) + }) + it('returns paginated statuses', async () => { // We know there will be exactly 4 statuses in db const getPaginatedStatuses = async ( @@ -118,7 +136,7 @@ describe('moderation-statuses', () => { } const list = await getPaginatedStatuses({}) - expect(list[0].id).toEqual(4) + expect(list[0].id).toEqual(7) expect(list[list.length - 1].id).toEqual(1) await emitModerationEvent({ @@ -141,4 +159,58 @@ describe('moderation-statuses', () => { expect(listReviewedFirst.length).toEqual(list.length) }) }) + + describe('blobs', () => { + it('are tracked on takendown subject', async () => { + const post = sc.posts[sc.dids.carol][0] + assert(post.images.length > 1) + await emitModerationEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventTakedown', + }, + subject: { + $type: 'com.atproto.repo.strongRef', + uri: post.ref.uriStr, + cid: post.ref.cidStr, + }, + subjectBlobCids: [post.images[0].image.ref.toString()], + createdBy: sc.dids.alice, + }) + const { data: result } = + await pdsAgent.api.com.atproto.admin.queryModerationStatuses( + { subject: post.ref.uriStr }, + { headers: network.ozone.adminAuthHeaders('moderator') }, + ) + expect(result.subjectStatuses.length).toBe(1) + expect(result.subjectStatuses[0]).toMatchObject({ + takendown: true, + subjectBlobCids: [post.images[0].image.ref.toString()], + }) + }) + + it('are tracked on reverse-takendown subject based on previous status', async () => { + const post = sc.posts[sc.dids.carol][0] + await emitModerationEvent({ + event: { + $type: 'com.atproto.admin.defs#modEventReverseTakedown', + }, + subject: { + $type: 'com.atproto.repo.strongRef', + uri: post.ref.uriStr, + cid: post.ref.cidStr, + }, + createdBy: sc.dids.alice, + }) + const { data: result } = + await pdsAgent.api.com.atproto.admin.queryModerationStatuses( + { subject: post.ref.uriStr }, + { headers: network.ozone.adminAuthHeaders('moderator') }, + ) + expect(result.subjectStatuses.length).toBe(1) + expect(result.subjectStatuses[0]).toMatchObject({ + takendown: false, + subjectBlobCids: [post.images[0].image.ref.toString()], + }) + }) + }) }) diff --git a/packages/ozone/tests/moderation.test.ts b/packages/ozone/tests/moderation.test.ts index c2f8df0ae12..79aae3938c9 100644 --- a/packages/ozone/tests/moderation.test.ts +++ b/packages/ozone/tests/moderation.test.ts @@ -25,6 +25,10 @@ import { } from '../src/lexicon/types/com/atproto/admin/defs' import { EventReverser } from '../src' import { TestOzone } from '@atproto/dev-env/src/ozone' +import { + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + UNSPECCED_TAKEDOWN_LABEL, +} from '../src/mod-service/types' type BaseCreateReportParams = | { account: string } @@ -40,6 +44,7 @@ describe('moderation', () => { let network: TestNetwork let ozone: TestOzone let agent: AtpAgent + let bskyAgent: AtpAgent let pdsAgent: AtpAgent let sc: SeedClient @@ -139,12 +144,23 @@ describe('moderation', () => { return data } + const getLabel = async (uri: string, val: string, neg = false) => { + return ozone.ctx.db.db + .selectFrom('label') + .selectAll() + .where('uri', '=', uri) + .where('val', '=', val) + .where('neg', '=', neg) + .executeTakeFirst() + } + beforeAll(async () => { network = await TestNetwork.create({ dbPostgresSchema: 'ozone_moderation', }) ozone = network.ozone agent = network.ozone.getClient() + bskyAgent = network.bsky.getClient() pdsAgent = network.pds.getClient() sc = network.getSeedClient() await basicSeed(sc) @@ -444,12 +460,9 @@ describe('moderation', () => { cid: post.cidStr, } const modService = ctx.modService(ctx.db) - await modService.formatAndCreateLabels( - ctx.cfg.service.did, - post.uriStr, - post.cidStr, - { create: ['kittens'] }, - ) + await modService.formatAndCreateLabels(post.uriStr, post.cidStr, { + create: ['kittens'], + }) await emitLabelEvent({ negateLabelVals: ['kittens'], createLabelVals: [], @@ -464,12 +477,9 @@ describe('moderation', () => { }) await expect(getRecordLabels(post.uriStr)).resolves.toEqual(['kittens']) // Cleanup - await modService.formatAndCreateLabels( - ctx.cfg.service.did, - post.uriStr, - post.cidStr, - { negate: ['kittens'] }, - ) + await modService.formatAndCreateLabels(post.uriStr, post.cidStr, { + negate: ['kittens'], + }) }) it('no-ops when negating an already-negated label and reverses.', async () => { @@ -497,12 +507,9 @@ describe('moderation', () => { }) await expect(getRecordLabels(post.uriStr)).resolves.toEqual(['bears']) // Cleanup - await modService.formatAndCreateLabels( - ctx.cfg.service.did, - post.uriStr, - post.cidStr, - { negate: ['bears'] }, - ) + await modService.formatAndCreateLabels(post.uriStr, post.cidStr, { + negate: ['bears'], + }) }) it('creates non-existing labels and reverses.', async () => { @@ -559,12 +566,9 @@ describe('moderation', () => { it('creates and negates labels on a repo and reverses.', async () => { const { ctx } = ozone const modService = ctx.modService(ctx.db) - await modService.formatAndCreateLabels( - ctx.cfg.service.did, - sc.dids.bob, - null, - { create: ['kittens'] }, - ) + await modService.formatAndCreateLabels(sc.dids.bob, null, { + create: ['kittens'], + }) await emitLabelEvent({ createLabelVals: ['puppies'], negateLabelVals: ['kittens'], @@ -632,34 +636,62 @@ describe('moderation', () => { ).rejects.toThrow('Subject is not taken down') }) - it('fans out repo takedowns to pds', async () => { + it('fans out repo takedowns', async () => { await performTakedown({ account: sc.dids.bob, }) await ozone.processAll() - const res1 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( + const pdsRes1 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( + { + did: sc.dids.bob, + }, + { headers: network.pds.adminAuthHeaders() }, + ) + expect(pdsRes1.data.takedown?.applied).toBe(true) + + const bskyRes1 = await bskyAgent.api.com.atproto.admin.getSubjectStatus( { did: sc.dids.bob, }, { headers: network.pds.adminAuthHeaders() }, ) - expect(res1.data.takedown?.applied).toBe(true) + expect(bskyRes1.data.takedown?.applied).toBe(true) + + const takedownLabel1 = await getLabel( + sc.dids.bob, + UNSPECCED_TAKEDOWN_LABEL, + ) + expect(takedownLabel1).toBeDefined() // cleanup await performReverseTakedown({ account: sc.dids.bob }) await ozone.processAll() - const res2 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( + const pdsRes2 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( { did: sc.dids.bob, }, { headers: network.pds.adminAuthHeaders() }, ) - expect(res2.data.takedown?.applied).toBe(false) + expect(pdsRes2.data.takedown?.applied).toBe(false) + + const bskyRes2 = await bskyAgent.api.com.atproto.admin.getSubjectStatus( + { + did: sc.dids.bob, + }, + { headers: network.bsky.adminAuthHeaders() }, + ) + expect(bskyRes2.data.takedown?.applied).toBe(false) + + const takedownLabel2 = await getLabel( + sc.dids.bob, + UNSPECCED_TAKEDOWN_LABEL, + ) + expect(takedownLabel2).toBeUndefined() }) - it('fans out record takedowns to pds', async () => { + it('fans out record takedowns', async () => { const post = sc.posts[sc.dids.bob][0] const uri = post.ref.uriStr const cid = post.ref.cidStr @@ -667,21 +699,39 @@ describe('moderation', () => { content: { uri, cid }, }) await ozone.processAll() - const res1 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( + + const pdsRes1 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( { uri }, { headers: network.pds.adminAuthHeaders() }, ) - expect(res1.data.takedown?.applied).toBe(true) + expect(pdsRes1.data.takedown?.applied).toBe(true) + + const bskyRes1 = await bskyAgent.api.com.atproto.admin.getSubjectStatus( + { uri }, + { headers: network.bsky.adminAuthHeaders() }, + ) + expect(bskyRes1.data.takedown?.applied).toBe(true) + + const takedownLabel1 = await getLabel(uri, UNSPECCED_TAKEDOWN_LABEL) + expect(takedownLabel1).toBeDefined() // cleanup await performReverseTakedown({ content: { uri, cid } }) await ozone.processAll() - const res2 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( + const pdsRes2 = await pdsAgent.api.com.atproto.admin.getSubjectStatus( { uri }, { headers: network.pds.adminAuthHeaders() }, ) - expect(res2.data.takedown?.applied).toBe(false) + expect(pdsRes2.data.takedown?.applied).toBe(false) + const bskyRes2 = await bskyAgent.api.com.atproto.admin.getSubjectStatus( + { uri }, + { headers: network.bsky.adminAuthHeaders() }, + ) + expect(bskyRes2.data.takedown?.applied).toBe(false) + + const takedownLabel2 = await getLabel(uri, UNSPECCED_TAKEDOWN_LABEL) + expect(takedownLabel2).toBeUndefined() }) it('allows full moderators to takedown.', async () => { @@ -732,6 +782,7 @@ describe('moderation', () => { 'Must be a full moderator to perform an account takedown', ) }) + it('automatically reverses actions marked with duration', async () => { await createReport({ reasonType: REASONSPAM, @@ -791,6 +842,22 @@ describe('moderation', () => { }) }) + it('serves label when authed', async () => { + const { data: unauthed } = await agent.api.com.atproto.temp.fetchLabels( + {}, + ) + expect(unauthed.labels.map((l) => l.val)).not.toContain( + UNSPECCED_TAKEDOWN_LABEL, + ) + const { data: authed } = await agent.api.com.atproto.temp.fetchLabels( + {}, + { headers: network.bsky.adminAuthHeaders() }, + ) + expect(authed.labels.map((l) => l.val)).toContain( + UNSPECCED_TAKEDOWN_LABEL, + ) + }) + async function emitLabelEvent( opts: Partial & { subject: ComAtprotoAdminEmitModerationEvent.InputSchema['subject'] @@ -925,6 +992,14 @@ describe('moderation', () => { expect(res.data.takedown?.applied).toBe(true) }) + it('creates a takedown blobs label', async () => { + const label = await getLabel( + post.ref.uriStr, + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + ) + expect(label).toBeDefined() + }) + it('restores blob when action is reversed.', async () => { await performReverseTakedown({ content: { @@ -958,5 +1033,29 @@ describe('moderation', () => { ) expect(res.data.takedown?.applied).toBe(false) }) + + it('serves label when authed', async () => { + const { data: unauthed } = await agent.api.com.atproto.temp.fetchLabels( + {}, + ) + expect(unauthed.labels.map((l) => l.val)).not.toContain( + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + ) + const { data: authed } = await agent.api.com.atproto.temp.fetchLabels( + {}, + { headers: network.bsky.adminAuthHeaders() }, + ) + expect(authed.labels.map((l) => l.val)).toContain( + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + ) + }) + + it('negates takedown blobs label on reversal', async () => { + const label = await getLabel( + post.ref.uriStr, + UNSPECCED_TAKEDOWN_BLOBS_LABEL, + ) + expect(label).toBeUndefined() + }) }) }) diff --git a/packages/pds/CHANGELOG.md b/packages/pds/CHANGELOG.md index 2d43ef15468..8d2e19210b8 100644 --- a/packages/pds/CHANGELOG.md +++ b/packages/pds/CHANGELOG.md @@ -1,5 +1,56 @@ # @atproto/pds +## 0.4.1 + +### Patch Changes + +- Updated dependencies [[`514aab92d`](https://github.com/bluesky-social/atproto/commit/514aab92d26acd43859285f46318e386846522b1)]: + - @atproto/api@0.10.1 + +## 0.4.0 + +### Patch Changes + +- Updated dependencies [[`b60719480`](https://github.com/bluesky-social/atproto/commit/b60719480f5f00bffd074a40e8ddc03aa93d137d), [`4c511b3d9`](https://github.com/bluesky-social/atproto/commit/4c511b3d9de41ffeae3fc11db941e7df04f4468a)]: + - @atproto/api@0.10.0 + +## 0.3.19 + +### Patch Changes + +- Updated dependencies [[`f79cc6339`](https://github.com/bluesky-social/atproto/commit/f79cc63390ae9dbd47a4ff5d694eec25b78b788e)]: + - @atproto/api@0.9.8 + +## 0.3.18 + +### Patch Changes + +- Updated dependencies [[`fcf8e3faf`](https://github.com/bluesky-social/atproto/commit/fcf8e3faf311559162c3aa0d9af36f84951914bc), [`8c94979f7`](https://github.com/bluesky-social/atproto/commit/8c94979f73fc5057449e24e66ef2e09b0e17e55b)]: + - @atproto/repo@0.3.7 + - @atproto/api@0.9.7 + - @atproto/aws@0.1.7 + +## 0.3.17 + +### Patch Changes + +- Updated dependencies [[`e4ec7af03`](https://github.com/bluesky-social/atproto/commit/e4ec7af03608949fc3b00a845f547a77599b5ad0)]: + - @atproto/api@0.9.6 + +## 0.3.16 + +### Patch Changes + +- Updated dependencies [[`8994d363`](https://github.com/bluesky-social/atproto/commit/8994d3633adad1c02569d6d44ae896e18195e8e2)]: + - @atproto/api@0.9.5 + +## 0.3.15 + +### Patch Changes + +- Updated dependencies [[`4171c04a`](https://github.com/bluesky-social/atproto/commit/4171c04ad81c5734a4558bc41fa1c4f3a1aba18c)]: + - @atproto/api@0.9.4 + ## 0.3.14 ### Patch Changes diff --git a/packages/pds/package.json b/packages/pds/package.json index dc208213816..74935d75057 100644 --- a/packages/pds/package.json +++ b/packages/pds/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/pds", - "version": "0.3.14", + "version": "0.4.1", "license": "MIT", "description": "Reference implementation of atproto Personal Data Server (PDS)", "keywords": [ @@ -44,7 +44,7 @@ "@atproto/xrpc": "workspace:^", "@atproto/xrpc-server": "workspace:^", "@did-plc/lib": "^0.0.4", - "better-sqlite3": "^7.6.2", + "better-sqlite3": "^9.4.0", "bytes": "^3.1.2", "compression": "^1.7.4", "cors": "^2.8.5", @@ -77,7 +77,7 @@ "@atproto/bsky": "workspace:^", "@atproto/dev-env": "workspace:^", "@atproto/lex-cli": "workspace:^", - "@atproto/pds-entryway": "npm:@atproto/pds@0.3.0-entryway.2", + "@atproto/pds-entryway": "npm:@atproto/pds@0.3.0-entryway.3", "@did-plc/server": "^0.0.1", "@types/cors": "^2.8.12", "@types/disposable-email": "^0.2.0", diff --git a/packages/pds/src/account-manager/db/migrations/002-account-deactivation.ts b/packages/pds/src/account-manager/db/migrations/002-account-deactivation.ts new file mode 100644 index 00000000000..fad3c21d230 --- /dev/null +++ b/packages/pds/src/account-manager/db/migrations/002-account-deactivation.ts @@ -0,0 +1,17 @@ +import { Kysely } from 'kysely' + +export async function up(db: Kysely): Promise { + await db.schema + .alterTable('actor') + .addColumn('deactivatedAt', 'varchar') + .execute() + await db.schema + .alterTable('actor') + .addColumn('deleteAfter', 'varchar') + .execute() +} + +export async function down(db: Kysely): Promise { + await db.schema.alterTable('actor').dropColumn('deactivatedAt').execute() + await db.schema.alterTable('actor').dropColumn('deleteAfter').execute() +} diff --git a/packages/pds/src/account-manager/db/migrations/index.ts b/packages/pds/src/account-manager/db/migrations/index.ts index 4b694f0f0f4..154dcd3ea9a 100644 --- a/packages/pds/src/account-manager/db/migrations/index.ts +++ b/packages/pds/src/account-manager/db/migrations/index.ts @@ -1,5 +1,7 @@ -import * as init from './001-init' +import * as mig001 from './001-init' +import * as mig002 from './002-account-deactivation' export default { - '001': init, + '001': mig001, + '002': mig002, } diff --git a/packages/pds/src/account-manager/db/schema/actor.ts b/packages/pds/src/account-manager/db/schema/actor.ts index cfb3fcbe66b..999add6b966 100644 --- a/packages/pds/src/account-manager/db/schema/actor.ts +++ b/packages/pds/src/account-manager/db/schema/actor.ts @@ -5,6 +5,8 @@ export interface Actor { handle: string | null createdAt: string takedownRef: string | null + deactivatedAt: string | null + deleteAfter: string | null } export type ActorEntry = Selectable diff --git a/packages/pds/src/account-manager/db/schema/email-token.ts b/packages/pds/src/account-manager/db/schema/email-token.ts index c544a95ce54..c69a57a0a29 100644 --- a/packages/pds/src/account-manager/db/schema/email-token.ts +++ b/packages/pds/src/account-manager/db/schema/email-token.ts @@ -3,6 +3,7 @@ export type EmailTokenPurpose = | 'update_email' | 'reset_password' | 'delete_account' + | 'plc_operation' export interface EmailToken { purpose: EmailTokenPurpose diff --git a/packages/pds/src/account-manager/helpers/account.ts b/packages/pds/src/account-manager/helpers/account.ts index f0e87c6d0ed..344c06a3778 100644 --- a/packages/pds/src/account-manager/helpers/account.ts +++ b/packages/pds/src/account-manager/helpers/account.ts @@ -1,6 +1,7 @@ import { isErrUniqueViolation, notSoftDeletedClause } from '../../db' import { AccountDb, ActorEntry } from '../db' import { StatusAttr } from '../../lexicon/types/com/atproto/admin/defs' +import { DAY } from '@atproto/common' export class UserAlreadyExistsError extends Error {} @@ -10,19 +11,28 @@ export type ActorAccount = ActorEntry & { invitesDisabled: 0 | 1 | null } -const selectAccountQB = (db: AccountDb, includeSoftDeleted: boolean) => { +export type AvailabilityFlags = { + includeTakenDown?: boolean + includeDeactivated?: boolean +} + +const selectAccountQB = (db: AccountDb, flags?: AvailabilityFlags) => { + const { includeTakenDown = false, includeDeactivated = false } = flags ?? {} const { ref } = db.db.dynamic return db.db .selectFrom('actor') .leftJoin('account', 'actor.did', 'account.did') - .if(!includeSoftDeleted, (qb) => - qb.where(notSoftDeletedClause(ref('actor'))), + .if(!includeTakenDown, (qb) => qb.where(notSoftDeletedClause(ref('actor')))) + .if(!includeDeactivated, (qb) => + qb.where('actor.deactivatedAt', 'is', null), ) .select([ 'actor.did', 'actor.handle', 'actor.createdAt', 'actor.takedownRef', + 'actor.deactivatedAt', + 'actor.deleteAfter', 'account.email', 'account.emailConfirmedAt', 'account.invitesDisabled', @@ -32,9 +42,9 @@ const selectAccountQB = (db: AccountDb, includeSoftDeleted: boolean) => { export const getAccount = async ( db: AccountDb, handleOrDid: string, - includeSoftDeleted = false, + flags?: AvailabilityFlags, ): Promise => { - const found = await selectAccountQB(db, includeSoftDeleted) + const found = await selectAccountQB(db, flags) .where((qb) => { if (handleOrDid.startsWith('did:')) { return qb.where('actor.did', '=', handleOrDid) @@ -49,9 +59,9 @@ export const getAccount = async ( export const getAccountByEmail = async ( db: AccountDb, email: string, - includeSoftDeleted = false, + flags?: AvailabilityFlags, ): Promise => { - const found = await selectAccountQB(db, includeSoftDeleted) + const found = await selectAccountQB(db, flags) .where('email', '=', email.toLowerCase()) .executeTakeFirst() return found || null @@ -62,16 +72,21 @@ export const registerActor = async ( opts: { did: string handle: string + deactivated?: boolean }, ) => { - const { did, handle } = opts + const { did, handle, deactivated } = opts + const now = Date.now() + const createdAt = new Date(now).toISOString() const [registered] = await db.executeWithRetry( db.db .insertInto('actor') .values({ did, handle, - createdAt: new Date().toISOString(), + createdAt, + deactivatedAt: deactivated ? createdAt : null, + deleteAfter: deactivated ? new Date(now + 3 * DAY).toISOString() : null, }) .onConflict((oc) => oc.doNothing()) .returning('did'), @@ -208,3 +223,31 @@ export const updateAccountTakedownStatus = async ( db.db.updateTable('actor').set({ takedownRef }).where('did', '=', did), ) } + +export const deactivateAccount = async ( + db: AccountDb, + did: string, + deleteAfter: string | null, +) => { + await db.executeWithRetry( + db.db + .updateTable('actor') + .set({ + deactivatedAt: new Date().toISOString(), + deleteAfter, + }) + .where('did', '=', did), + ) +} + +export const activateAccount = async (db: AccountDb, did: string) => { + await db.executeWithRetry( + db.db + .updateTable('actor') + .set({ + deactivatedAt: null, + deleteAfter: null, + }) + .where('did', '=', did), + ) +} diff --git a/packages/pds/src/account-manager/helpers/email-token.ts b/packages/pds/src/account-manager/helpers/email-token.ts index 85be5d4b6d0..7d3690ad0e9 100644 --- a/packages/pds/src/account-manager/helpers/email-token.ts +++ b/packages/pds/src/account-manager/helpers/email-token.ts @@ -34,6 +34,12 @@ export const deleteEmailToken = async ( ) } +export const deleteAllEmailTokens = async (db: AccountDb, did: string) => { + await db.executeWithRetry( + db.db.deleteFrom('email_token').where('did', '=', did), + ) +} + export const assertValidToken = async ( db: AccountDb, did: string, diff --git a/packages/pds/src/account-manager/index.ts b/packages/pds/src/account-manager/index.ts index 1a6a2493fb9..89fb4ac00b1 100644 --- a/packages/pds/src/account-manager/index.ts +++ b/packages/pds/src/account-manager/index.ts @@ -39,16 +39,16 @@ export class AccountManager { async getAccount( handleOrDid: string, - includeSoftDeleted = false, + flags?: account.AvailabilityFlags, ): Promise { - return account.getAccount(this.db, handleOrDid, includeSoftDeleted) + return account.getAccount(this.db, handleOrDid, flags) } async getAccountByEmail( email: string, - includeSoftDeleted = false, + flags?: account.AvailabilityFlags, ): Promise { - return account.getAccountByEmail(this.db, email, includeSoftDeleted) + return account.getAccountByEmail(this.db, email, flags) } // Repo exists and is not taken-down @@ -57,11 +57,17 @@ export class AccountManager { return !!got } + async isAccountActivated(did: string): Promise { + const account = await this.getAccount(did, { includeDeactivated: true }) + if (!account) return false + return !account.deactivatedAt + } + async getDidForActor( handleOrDid: string, - includeSoftDeleted = false, + flags?: account.AvailabilityFlags, ): Promise { - const got = await this.getAccount(handleOrDid, includeSoftDeleted) + const got = await this.getAccount(handleOrDid, flags) return got?.did ?? null } @@ -73,8 +79,18 @@ export class AccountManager { repoCid: CID repoRev: string inviteCode?: string + deactivated?: boolean }) { - const { did, handle, email, password, repoCid, repoRev, inviteCode } = opts + const { + did, + handle, + email, + password, + repoCid, + repoRev, + inviteCode, + deactivated, + } = opts const passwordScrypt = password ? await scrypt.genSaltAndHash(password) : undefined @@ -92,7 +108,7 @@ export class AccountManager { await invite.ensureInviteIsAvailable(dbTxn, inviteCode) } await Promise.all([ - account.registerActor(dbTxn, { did, handle }), + account.registerActor(dbTxn, { did, handle, deactivated }), email && passwordScrypt ? account.registerAccount(dbTxn, { did, email, passwordScrypt }) : Promise.resolve(), @@ -135,6 +151,14 @@ export class AccountManager { return repo.updateRoot(this.db, did, cid, rev) } + async deactivateAccount(did: string, deleteAfter: string | null) { + return account.deactivateAccount(this.db, did, deleteAfter) + } + + async activateAccount(did: string) { + return account.activateAccount(this.db, did) + } + // Auth // ---------- @@ -309,6 +333,15 @@ export class AccountManager { return emailToken.assertValidToken(this.db, did, purpose, token) } + async assertValidEmailTokenAndCleanup( + did: string, + purpose: EmailTokenPurpose, + token: string, + ) { + await emailToken.assertValidToken(this.db, did, purpose, token) + await emailToken.deleteEmailToken(this.db, did, purpose) + } + async confirmEmail(opts: { did: string; token: string }) { const { did, token } = opts await emailToken.assertValidToken(this.db, did, 'confirm_email', token) @@ -321,18 +354,14 @@ export class AccountManager { ) } - async updateEmail(opts: { did: string; email: string; token?: string }) { - const { did, email, token } = opts - if (token) { - await this.db.transaction((dbTxn) => - Promise.all([ - account.updateEmail(dbTxn, did, email), - emailToken.deleteEmailToken(dbTxn, did, 'update_email'), - ]), - ) - } else { - return account.updateEmail(this.db, did, email) - } + async updateEmail(opts: { did: string; email: string }) { + const { did, email } = opts + await this.db.transaction((dbTxn) => + Promise.all([ + account.updateEmail(dbTxn, did, email), + emailToken.deleteAllEmailTokens(dbTxn, did), + ]), + ) } async resetPassword(opts: { password: string; token: string }) { @@ -341,6 +370,11 @@ export class AccountManager { 'reset_password', opts.token, ) + await this.updateAccountPassword({ did, password: opts.password }) + } + + async updateAccountPassword(opts: { did: string; password: string }) { + const { did } = opts const passwordScrypt = await scrypt.genSaltAndHash(opts.password) await this.db.transaction(async (dbTxn) => Promise.all([ diff --git a/packages/pds/src/actor-store/blob/reader.ts b/packages/pds/src/actor-store/blob/reader.ts index bb38ed92e69..299358b1119 100644 --- a/packages/pds/src/actor-store/blob/reader.ts +++ b/packages/pds/src/actor-store/blob/reader.ts @@ -3,7 +3,7 @@ import { CID } from 'multiformats/cid' import { BlobNotFoundError, BlobStore } from '@atproto/repo' import { InvalidRequestError } from '@atproto/xrpc-server' import { ActorDb } from '../db' -import { notSoftDeletedClause } from '../../db/util' +import { countAll, countDistinct, notSoftDeletedClause } from '../../db/util' import { StatusAttr } from '../../lexicon/types/com/atproto/admin/defs' export class BlobReader { @@ -73,4 +73,57 @@ export class BlobReader { ? { applied: true, ref: res.takedownRef } : { applied: false } } + + async getRecordsForBlob(cid: CID): Promise { + const res = await this.db.db + .selectFrom('record_blob') + .where('blobCid', '=', cid.toString()) + .selectAll() + .execute() + return res.map((row) => row.recordUri) + } + + async blobCount(): Promise { + const res = await this.db.db + .selectFrom('blob') + .select(countAll.as('count')) + .executeTakeFirst() + return res?.count ?? 0 + } + + async recordBlobCount(): Promise { + const { ref } = this.db.db.dynamic + const res = await this.db.db + .selectFrom('record_blob') + .select(countDistinct(ref('blobCid')).as('count')) + .executeTakeFirst() + return res?.count ?? 0 + } + + async listMissingBlobs(opts: { + cursor?: string + limit: number + }): Promise<{ cid: string; recordUri: string }[]> { + const { cursor, limit } = opts + let builder = this.db.db + .selectFrom('record_blob') + .whereNotExists((qb) => + qb + .selectFrom('blob') + .selectAll() + .whereRef('blob.cid', '=', 'record_blob.blobCid'), + ) + .selectAll() + .orderBy('blobCid', 'asc') + .groupBy('blobCid') + .limit(limit) + if (cursor) { + builder = builder.where('blobCid', '>', cursor) + } + const res = await builder.execute() + return res.map((row) => ({ + cid: row.blobCid, + recordUri: row.recordUri, + })) + } } diff --git a/packages/pds/src/actor-store/blob/transactor.ts b/packages/pds/src/actor-store/blob/transactor.ts index 013235639a0..fa937e6bec6 100644 --- a/packages/pds/src/actor-store/blob/transactor.ts +++ b/packages/pds/src/actor-store/blob/transactor.ts @@ -20,6 +20,15 @@ import { BackgroundQueue } from '../../background' import { BlobReader } from './reader' import { StatusAttr } from '../../lexicon/types/com/atproto/admin/defs' +export type BlobMetadata = { + tempKey: string + size: number + cid: CID + mimeType: string + width: number | null + height: number | null +} + export class BlobTransactor extends BlobReader { constructor( public db: ActorDb, @@ -29,10 +38,10 @@ export class BlobTransactor extends BlobReader { super(db, blobstore) } - async addUntetheredBlob( + async uploadBlobAndGetMetadata( userSuggestedMime: string, blobStream: stream.Readable, - ): Promise { + ): Promise { const [tempKey, size, sha256, imgInfo, sniffedMime] = await Promise.all([ this.blobstore.putTemp(cloneStream(blobStream)), streamSize(cloneStream(blobStream)), @@ -44,6 +53,27 @@ export class BlobTransactor extends BlobReader { const cid = sha256RawToCid(sha256) const mimeType = sniffedMime || userSuggestedMime + return { + tempKey, + size, + cid, + mimeType, + width: imgInfo?.width ?? null, + height: imgInfo?.height ?? null, + } + } + + async trackUntetheredBlob(metadata: BlobMetadata) { + const { tempKey, size, cid, mimeType, width, height } = metadata + const found = await this.db.db + .selectFrom('blob') + .selectAll() + .where('cid', '=', cid.toString()) + .executeTakeFirst() + if (found?.takedownRef) { + throw new InvalidRequestError('Blob has been takendown, cannot re-upload') + } + await this.db.db .insertInto('blob') .values({ @@ -51,8 +81,8 @@ export class BlobTransactor extends BlobReader { mimeType, size, tempKey, - width: imgInfo?.width || null, - height: imgInfo?.height || null, + width, + height, createdAt: new Date().toISOString(), }) .onConflict((oc) => diff --git a/packages/pds/src/actor-store/index.ts b/packages/pds/src/actor-store/index.ts index b18716380e6..698956b65f5 100644 --- a/packages/pds/src/actor-store/index.ts +++ b/packages/pds/src/actor-store/index.ts @@ -1,4 +1,5 @@ import path from 'path' +import assert from 'assert' import fs from 'fs/promises' import * as crypto from '@atproto/crypto' import { Keypair, ExportableKeypair } from '@atproto/crypto' @@ -106,6 +107,30 @@ export class ActorStore { } } + async writeNoTransaction(did: string, fn: ActorStoreWriterFn) { + const keypair = await this.keypair(did) + const db = await this.openDb(did) + try { + const writer = createActorTransactor(did, db, keypair, this.resources) + return await fn({ + ...writer, + transact: async (fn: ActorStoreTransactFn): Promise => { + return db.transaction((dbTxn) => { + const transactor = createActorTransactor( + did, + dbTxn, + keypair, + this.resources, + ) + return fn(transactor) + }) + }, + }) + } finally { + db.close() + } + } + async create(did: string, keypair: ExportableKeypair) { const { directory, dbLocation, keyLocation } = await this.getLocation(did) // ensure subdir exists @@ -148,6 +173,7 @@ export class ActorStore { async reserveKeypair(did?: string): Promise { let keyLoc: string | undefined if (did) { + assertSafePathPart(did) keyLoc = path.join(this.reservedKeyDir, did) const maybeKey = await loadKey(keyLoc) if (maybeKey) { @@ -242,6 +268,7 @@ const createActorReader = ( export type ActorStoreReadFn = (fn: ActorStoreReader) => Promise export type ActorStoreTransactFn = (fn: ActorStoreTransactor) => Promise +export type ActorStoreWriterFn = (fn: ActorStoreWriter) => Promise export type ActorStoreReader = { did: string @@ -259,3 +286,18 @@ export type ActorStoreTransactor = { record: RecordTransactor pref: PreferenceTransactor } + +export type ActorStoreWriter = ActorStoreTransactor & { + transact: (fn: ActorStoreTransactFn) => Promise +} + +function assertSafePathPart(part: string) { + const normalized = path.normalize(part) + assert( + part === normalized && + !part.startsWith('.') && + !part.includes('/') && + !part.includes('\\'), + `unsafe path part: ${part}`, + ) +} diff --git a/packages/pds/src/actor-store/record/reader.ts b/packages/pds/src/actor-store/record/reader.ts index ed8d231f3cf..7c7b3383439 100644 --- a/packages/pds/src/actor-store/record/reader.ts +++ b/packages/pds/src/actor-store/record/reader.ts @@ -2,7 +2,7 @@ import * as syntax from '@atproto/syntax' import { AtUri, ensureValidAtUri } from '@atproto/syntax' import { cborToLexRecord } from '@atproto/repo' import { CID } from 'multiformats/cid' -import { notSoftDeletedClause } from '../../db/util' +import { countAll, notSoftDeletedClause } from '../../db/util' import { ids } from '../../lexicon/lexicons' import { ActorDb, Backlink } from '../db' import { StatusAttr } from '../../lexicon/types/com/atproto/admin/defs' @@ -11,6 +11,14 @@ import { RepoRecord } from '@atproto/lexicon' export class RecordReader { constructor(public db: ActorDb) {} + async recordCount(): Promise { + const res = await this.db.db + .selectFrom('record') + .select(countAll.as('count')) + .executeTakeFirst() + return res?.count ?? 0 + } + async listCollections(): Promise { const collections = await this.db.db .selectFrom('record') diff --git a/packages/pds/src/actor-store/repo/sql-repo-reader.ts b/packages/pds/src/actor-store/repo/sql-repo-reader.ts index 90b61b08e68..30f994031c4 100644 --- a/packages/pds/src/actor-store/repo/sql-repo-reader.ts +++ b/packages/pds/src/actor-store/repo/sql-repo-reader.ts @@ -8,6 +8,7 @@ import { chunkArray } from '@atproto/common' import { CID } from 'multiformats/cid' import { ActorDb } from '../db' import { sql } from 'kysely' +import { countAll } from '../../db' export class SqlRepoReader extends ReadableBlockstore { cache: BlockMap = new BlockMap() @@ -136,6 +137,14 @@ export class SqlRepoReader extends ReadableBlockstore { return builder.execute() } + async countBlocks(): Promise { + const res = await this.db.db + .selectFrom('repo_block') + .select(countAll.as('count')) + .executeTakeFirst() + return res?.count ?? 0 + } + async destroy(): Promise { throw new Error('Destruction of SQL repo storage not allowed at runtime') } diff --git a/packages/pds/src/api/app/bsky/actor/getPreferences.ts b/packages/pds/src/api/app/bsky/actor/getPreferences.ts index d89666358ae..0068281a2dc 100644 --- a/packages/pds/src/api/app/bsky/actor/getPreferences.ts +++ b/packages/pds/src/api/app/bsky/actor/getPreferences.ts @@ -3,6 +3,7 @@ import AppContext from '../../../../context' import { AuthScope } from '../../../../auth-verifier' export default function (server: Server, ctx: AppContext) { + if (!ctx.cfg.bskyAppView) return server.app.bsky.actor.getPreferences({ auth: ctx.authVerifier.access, handler: async ({ auth }) => { diff --git a/packages/pds/src/api/app/bsky/actor/getProfile.ts b/packages/pds/src/api/app/bsky/actor/getProfile.ts index 732c7babe1a..74de7f3af6d 100644 --- a/packages/pds/src/api/app/bsky/actor/getProfile.ts +++ b/packages/pds/src/api/app/bsky/actor/getProfile.ts @@ -4,27 +4,37 @@ import { authPassthru } from '../../../proxy' import { OutputSchema } from '../../../../lexicon/types/app/bsky/actor/getProfile' import { LocalViewer, - handleReadAfterWrite, LocalRecords, + handleReadAfterWrite, } from '../../../../read-after-write' +import { pipethrough } from '../../../../pipethrough' + +const METHOD_NSID = 'app.bsky.actor.getProfile' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.getProfile({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, auth, params }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null - const res = await ctx.appViewAgent.api.app.bsky.actor.getProfile( + const res = await pipethrough( + bskyAppView.url, + METHOD_NSID, params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), ) - if (res.data.did === requester) { - return await handleReadAfterWrite(ctx, requester, res, getProfileMunge) - } - return { - encoding: 'application/json', - body: res.data, + if (!requester) { + return res } + return handleReadAfterWrite( + ctx, + METHOD_NSID, + requester, + res, + getProfileMunge, + ) }, }) } @@ -33,7 +43,9 @@ const getProfileMunge = async ( localViewer: LocalViewer, original: OutputSchema, local: LocalRecords, + requester: string, ): Promise => { if (!local.profile) return original + if (original.did !== requester) return original return localViewer.updateProfileDetailed(original, local.profile.record) } diff --git a/packages/pds/src/api/app/bsky/actor/getProfiles.ts b/packages/pds/src/api/app/bsky/actor/getProfiles.ts index 2f0f1405378..3ab9338c7c5 100644 --- a/packages/pds/src/api/app/bsky/actor/getProfiles.ts +++ b/packages/pds/src/api/app/bsky/actor/getProfiles.ts @@ -1,29 +1,36 @@ import AppContext from '../../../../context' import { Server } from '../../../../lexicon' import { OutputSchema } from '../../../../lexicon/types/app/bsky/actor/getProfiles' +import { pipethrough } from '../../../../pipethrough' import { LocalViewer, handleReadAfterWrite, LocalRecords, } from '../../../../read-after-write' +const METHOD_NSID = 'app.bsky.actor.getProfiles' + export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.getProfiles({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.actor.getProfiles( + + const res = await pipethrough( + bskyAppView.url, + METHOD_NSID, params, await ctx.appviewAuthHeaders(requester), ) - const hasSelf = res.data.profiles.some((prof) => prof.did === requester) - if (hasSelf) { - return await handleReadAfterWrite(ctx, requester, res, getProfilesMunge) - } - return { - encoding: 'application/json', - body: res.data, - } + return handleReadAfterWrite( + ctx, + METHOD_NSID, + requester, + res, + getProfilesMunge, + ) }, }) } @@ -36,6 +43,7 @@ const getProfilesMunge = async ( ): Promise => { const localProf = local.profile if (!localProf) return original + const profiles = original.profiles.map((prof) => { if (prof.did !== requester) return prof return localViewer.updateProfileDetailed(prof, localProf.record) diff --git a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts index 5fd8b260276..6bfd65adf74 100644 --- a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts +++ b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.getSuggestions({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.actor.getSuggestions( + return pipethrough( + bskyAppView.url, + 'app.bsky.actor.getSuggestions', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/actor/putPreferences.ts b/packages/pds/src/api/app/bsky/actor/putPreferences.ts index f6274d42278..7b3755f891e 100644 --- a/packages/pds/src/api/app/bsky/actor/putPreferences.ts +++ b/packages/pds/src/api/app/bsky/actor/putPreferences.ts @@ -4,6 +4,7 @@ import AppContext from '../../../../context' import { AccountPreference } from '../../../../actor-store/preference/reader' export default function (server: Server, ctx: AppContext) { + if (!ctx.cfg.bskyAppView) return server.app.bsky.actor.putPreferences({ auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, input }) => { diff --git a/packages/pds/src/api/app/bsky/actor/searchActors.ts b/packages/pds/src/api/app/bsky/actor/searchActors.ts index 7c184de1116..53c97566818 100644 --- a/packages/pds/src/api/app/bsky/actor/searchActors.ts +++ b/packages/pds/src/api/app/bsky/actor/searchActors.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.searchActors({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.actor.searchActors( + return pipethrough( + bskyAppView.url, + 'app.bsky.actor.searchActors', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts b/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts index c1a8738488d..51e778b24ee 100644 --- a/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/pds/src/api/app/bsky/actor/searchActorsTypeahead.ts @@ -1,20 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.actor.searchActorsTypeahead({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = - await ctx.appViewAgent.api.app.bsky.actor.searchActorsTypeahead( - params, - await ctx.appviewAuthHeaders(requester), - ) - return { - encoding: 'application/json', - body: res.data, - } + return pipethrough( + bskyAppView.url, + 'app.bsky.actor.searchActorsTypeahead', + params, + await ctx.appviewAuthHeaders(requester), + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts b/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts index 384d68500d4..123bce1785b 100644 --- a/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts +++ b/packages/pds/src/api/app/bsky/feed/getActorFeeds.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getActorFeeds({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getActorFeeds( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getActorFeeds', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getActorLikes.ts b/packages/pds/src/api/app/bsky/feed/getActorLikes.ts index 07fb66fd828..d8e2f839904 100644 --- a/packages/pds/src/api/app/bsky/feed/getActorLikes.ts +++ b/packages/pds/src/api/app/bsky/feed/getActorLikes.ts @@ -7,25 +7,36 @@ import { handleReadAfterWrite, LocalRecords, } from '../../../../read-after-write' +import { pipethrough } from '../../../../pipethrough' + +const METHOD_NSID = 'app.bsky.feed.getActorLikes' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getActorLikes({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null - - const res = await ctx.appViewAgent.api.app.bsky.feed.getActorLikes( + const res = await pipethrough( + bskyAppView.url, + METHOD_NSID, params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), ) - if (requester) { - return await handleReadAfterWrite(ctx, requester, res, getAuthorMunge) - } - return { - encoding: 'application/json', - body: res.data, + + if (!requester) { + return res } + + return await handleReadAfterWrite( + ctx, + METHOD_NSID, + requester, + res, + getAuthorMunge, + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts b/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts index 17ae8f0ac10..c90760bbfd9 100644 --- a/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getAuthorFeed.ts @@ -8,24 +8,34 @@ import { handleReadAfterWrite, LocalRecords, } from '../../../../read-after-write' +import { pipethrough } from '../../../../pipethrough' + +const METHOD_NSID = 'app.bsky.feed.getAuthorFeed' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getAuthorFeed({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null - const res = await ctx.appViewAgent.api.app.bsky.feed.getAuthorFeed( + const res = await pipethrough( + bskyAppView.url, + METHOD_NSID, params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), ) - if (requester) { - return await handleReadAfterWrite(ctx, requester, res, getAuthorMunge) - } - return { - encoding: 'application/json', - body: res.data, + if (!requester) { + return res } + return await handleReadAfterWrite( + ctx, + METHOD_NSID, + requester, + res, + getAuthorMunge, + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getFeed.ts b/packages/pds/src/api/app/bsky/feed/getFeed.ts index dd42e81fb94..89c84b18ba8 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeed.ts @@ -1,15 +1,18 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' -import { noUndefinedVals } from '@atproto/common' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + const { bskyAppView } = ctx.cfg + if (!appViewAgent || !bskyAppView) return server.app.bsky.feed.getFeed({ auth: ctx.authVerifier.access, handler: async ({ req, params, auth }) => { const requester = auth.credentials.did const { data: feed } = - await ctx.appViewAgent.api.app.bsky.feed.getFeedGenerator( + await appViewAgent.api.app.bsky.feed.getFeedGenerator( { feed: params.feed }, await ctx.appviewAuthHeaders(requester), ) @@ -20,18 +23,12 @@ export default function (server: Server, ctx: AppContext) { // forward accept-language header to upstream services serviceAuthHeaders.headers['accept-language'] = req.headers['accept-language'] - const res = await ctx.appViewAgent.api.app.bsky.feed.getFeed( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getFeed', params, serviceAuthHeaders, ) - - return { - encoding: 'application/json', - body: res.data, - headers: noUndefinedVals({ - 'content-language': res.headers['content-language'], - }), - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts b/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts index 57c4731db53..f71ea74117f 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeedGenerator.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getFeedGenerator({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getFeedGenerator( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getFeedGenerator', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts b/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts index 1370fbbd6f3..c07c3dac228 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeedGenerators.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getFeedGenerators({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getFeedGenerators( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getFeedGenerators', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getLikes.ts b/packages/pds/src/api/app/bsky/feed/getLikes.ts index ad656dfbd4c..90a96681c85 100644 --- a/packages/pds/src/api/app/bsky/feed/getLikes.ts +++ b/packages/pds/src/api/app/bsky/feed/getLikes.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getLikes({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getLikes( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getLikes', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getListFeed.ts b/packages/pds/src/api/app/bsky/feed/getListFeed.ts index 06e2abcbfe5..3447a721904 100644 --- a/packages/pds/src/api/app/bsky/feed/getListFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getListFeed.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getListFeed({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getListFeed( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getListFeed', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getPostThread.ts b/packages/pds/src/api/app/bsky/feed/getPostThread.ts index 00bf0b01d82..da09523875b 100644 --- a/packages/pds/src/api/app/bsky/feed/getPostThread.ts +++ b/packages/pds/src/api/app/bsky/feed/getPostThread.ts @@ -1,6 +1,6 @@ +import assert from 'node:assert' import { AtUri } from '@atproto/syntax' -import { AppBskyFeedGetPostThread } from '@atproto/api' -import { Headers } from '@atproto/xrpc' +import { Headers, XRPCError } from '@atproto/xrpc' import { Server } from '../../../../lexicon' import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' @@ -17,12 +17,18 @@ import { LocalViewer, getLocalLag, getRepoRev, - handleReadAfterWrite, LocalRecords, RecordDescript, + handleReadAfterWrite, + formatMungedResponse, } from '../../../../read-after-write' +import { pipethrough } from '../../../../pipethrough' + +const METHOD_NSID = 'app.bsky.feed.getPostThread' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getPostThread({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { @@ -30,31 +36,31 @@ export default function (server: Server, ctx: AppContext) { auth.credentials.type === 'access' ? auth.credentials.did : null if (!requester) { - const res = await ctx.appViewAgent.api.app.bsky.feed.getPostThread( + return pipethrough( + bskyAppView.url, + METHOD_NSID, params, authPassthru(req), ) - - return { - encoding: 'application/json', - body: res.data, - } } try { - const res = await ctx.appViewAgent.api.app.bsky.feed.getPostThread( + const res = await pipethrough( + bskyAppView.url, + METHOD_NSID, params, await ctx.appviewAuthHeaders(requester), ) return await handleReadAfterWrite( ctx, + METHOD_NSID, requester, res, getPostThreadMunge, ) } catch (err) { - if (err instanceof AppBskyFeedGetPostThread.NotFoundError) { + if (err instanceof XRPCError && err.error === 'NotFound') { const headers = err.headers const keypair = await ctx.actorStore.keypair(requester) const local = await ctx.actorStore.read(requester, (store) => { @@ -70,15 +76,7 @@ export default function (server: Server, ctx: AppContext) { if (local === null) { throw err } else { - return { - encoding: 'application/json', - body: local.data, - headers: local.lag - ? { - 'Atproto-Upstream-Lag': local.lag.toString(10), - } - : undefined, - } + return formatMungedResponse(local.data, local.lag) } } else { throw err @@ -205,6 +203,7 @@ const readAfterWriteNotFound = async ( const highestParent = getHighestParent(thread) if (highestParent) { try { + assert(ctx.appViewAgent) const parentsRes = await ctx.appViewAgent.api.app.bsky.feed.getPostThread( { uri: highestParent, parentHeight: params.parentHeight, depth: 0 }, await ctx.appviewAuthHeaders(requester), diff --git a/packages/pds/src/api/app/bsky/feed/getPosts.ts b/packages/pds/src/api/app/bsky/feed/getPosts.ts index f04927a4997..89d0d08587d 100644 --- a/packages/pds/src/api/app/bsky/feed/getPosts.ts +++ b/packages/pds/src/api/app/bsky/feed/getPosts.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getPosts({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getPosts( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getPosts', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts b/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts index e797967fc2a..971d150824c 100644 --- a/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts +++ b/packages/pds/src/api/app/bsky/feed/getRepostedBy.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getRepostedBy({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getRepostedBy( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getRepostedBy', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts b/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts index 17fbf947471..6da81787533 100644 --- a/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts +++ b/packages/pds/src/api/app/bsky/feed/getSuggestedFeeds.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getSuggestedFeeds({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getSuggestedFeeds( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.getSuggestedFeeds', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getTimeline.ts b/packages/pds/src/api/app/bsky/feed/getTimeline.ts index 6139432580a..90fc5bac42f 100644 --- a/packages/pds/src/api/app/bsky/feed/getTimeline.ts +++ b/packages/pds/src/api/app/bsky/feed/getTimeline.ts @@ -6,17 +6,30 @@ import { handleReadAfterWrite, LocalRecords, } from '../../../../read-after-write' +import { pipethrough } from '../../../../pipethrough' + +const METHOD_NSID = 'app.bsky.feed.getTimeline' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.getTimeline({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.getTimeline( + const res = await pipethrough( + bskyAppView.url, + METHOD_NSID, params, await ctx.appviewAuthHeaders(requester), ) - return await handleReadAfterWrite(ctx, requester, res, getTimelineMunge) + return await handleReadAfterWrite( + ctx, + METHOD_NSID, + requester, + res, + getTimelineMunge, + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/searchPosts.ts b/packages/pds/src/api/app/bsky/feed/searchPosts.ts index e9942432fde..7cc09c864e5 100644 --- a/packages/pds/src/api/app/bsky/feed/searchPosts.ts +++ b/packages/pds/src/api/app/bsky/feed/searchPosts.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.feed.searchPosts({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.feed.searchPosts( + return pipethrough( + bskyAppView.url, + 'app.bsky.feed.searchPosts', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getBlocks.ts b/packages/pds/src/api/app/bsky/graph/getBlocks.ts index ff1f299f43f..1b29f9b62d2 100644 --- a/packages/pds/src/api/app/bsky/graph/getBlocks.ts +++ b/packages/pds/src/api/app/bsky/graph/getBlocks.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getBlocks({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.graph.getBlocks( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getBlocks', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getFollowers.ts b/packages/pds/src/api/app/bsky/graph/getFollowers.ts index 18f1e0df397..0a158f2bbe5 100644 --- a/packages/pds/src/api/app/bsky/graph/getFollowers.ts +++ b/packages/pds/src/api/app/bsky/graph/getFollowers.ts @@ -1,21 +1,22 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getFollowers({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null - const res = await ctx.appViewAgent.api.app.bsky.graph.getFollowers( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getFollowers', params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getFollows.ts b/packages/pds/src/api/app/bsky/graph/getFollows.ts index 91955965ed6..6802acda888 100644 --- a/packages/pds/src/api/app/bsky/graph/getFollows.ts +++ b/packages/pds/src/api/app/bsky/graph/getFollows.ts @@ -1,21 +1,22 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getFollows({ auth: ctx.authVerifier.accessOrRole, handler: async ({ req, params, auth }) => { const requester = auth.credentials.type === 'access' ? auth.credentials.did : null - const res = await ctx.appViewAgent.api.app.bsky.graph.getFollows( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getFollows', params, requester ? await ctx.appviewAuthHeaders(requester) : authPassthru(req), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getList.ts b/packages/pds/src/api/app/bsky/graph/getList.ts index fb5776f5df2..6ef1dbf7ee0 100644 --- a/packages/pds/src/api/app/bsky/graph/getList.ts +++ b/packages/pds/src/api/app/bsky/graph/getList.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getList({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.graph.getList( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getList', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getListBlocks.ts b/packages/pds/src/api/app/bsky/graph/getListBlocks.ts index 376de0ba914..d9aed6e7cd6 100644 --- a/packages/pds/src/api/app/bsky/graph/getListBlocks.ts +++ b/packages/pds/src/api/app/bsky/graph/getListBlocks.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getListBlocks({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.graph.getListBlocks( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getListBlocks', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getListMutes.ts b/packages/pds/src/api/app/bsky/graph/getListMutes.ts index c489124642c..575c09d5b1a 100644 --- a/packages/pds/src/api/app/bsky/graph/getListMutes.ts +++ b/packages/pds/src/api/app/bsky/graph/getListMutes.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getListMutes({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.graph.getListMutes( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getListMutes', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getLists.ts b/packages/pds/src/api/app/bsky/graph/getLists.ts index 61a1cb89079..c824c9cdb4b 100644 --- a/packages/pds/src/api/app/bsky/graph/getLists.ts +++ b/packages/pds/src/api/app/bsky/graph/getLists.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getLists({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.graph.getLists( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getLists', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getMutes.ts b/packages/pds/src/api/app/bsky/graph/getMutes.ts index 0dc0e72412c..d422237dd0f 100644 --- a/packages/pds/src/api/app/bsky/graph/getMutes.ts +++ b/packages/pds/src/api/app/bsky/graph/getMutes.ts @@ -1,19 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getMutes({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = await ctx.appViewAgent.api.app.bsky.graph.getMutes( + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getMutes', params, await ctx.appviewAuthHeaders(requester), ) - return { - encoding: 'application/json', - body: res.data, - } }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts b/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts index 0a11361f05c..dfe453be8f6 100644 --- a/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +++ b/packages/pds/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts @@ -1,20 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.graph.getSuggestedFollowsByActor({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = - await ctx.appViewAgent.api.app.bsky.graph.getSuggestedFollowsByActor( - params, - await ctx.appviewAuthHeaders(requester), - ) - return { - encoding: 'application/json', - body: res.data, - } + return pipethrough( + bskyAppView.url, + 'app.bsky.graph.getSuggestedFollowsByActor', + params, + await ctx.appviewAuthHeaders(requester), + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/graph/muteActor.ts b/packages/pds/src/api/app/bsky/graph/muteActor.ts index 2b2f218b44d..c88a05b9eaf 100644 --- a/packages/pds/src/api/app/bsky/graph/muteActor.ts +++ b/packages/pds/src/api/app/bsky/graph/muteActor.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.muteActor({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.muteActor(input.body, { + await appViewAgent.api.app.bsky.graph.muteActor(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/graph/muteActorList.ts b/packages/pds/src/api/app/bsky/graph/muteActorList.ts index 97d524900f7..74c2357d3d9 100644 --- a/packages/pds/src/api/app/bsky/graph/muteActorList.ts +++ b/packages/pds/src/api/app/bsky/graph/muteActorList.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.muteActorList({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.muteActorList(input.body, { + await appViewAgent.api.app.bsky.graph.muteActorList(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/graph/unmuteActor.ts b/packages/pds/src/api/app/bsky/graph/unmuteActor.ts index 0f7a1610321..e73c5d08e5a 100644 --- a/packages/pds/src/api/app/bsky/graph/unmuteActor.ts +++ b/packages/pds/src/api/app/bsky/graph/unmuteActor.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.unmuteActor({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.unmuteActor(input.body, { + await appViewAgent.api.app.bsky.graph.unmuteActor(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts b/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts index aaf5225bded..e36afeaf0a3 100644 --- a/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts +++ b/packages/pds/src/api/app/bsky/graph/unmuteActorList.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.graph.unmuteActorList({ auth: ctx.authVerifier.access, handler: async ({ auth, input }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.graph.unmuteActorList(input.body, { + await appViewAgent.api.app.bsky.graph.unmuteActorList(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts b/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts index bca4bf3d46f..d6b8a235ba3 100644 --- a/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts +++ b/packages/pds/src/api/app/bsky/notification/getUnreadCount.ts @@ -1,20 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.notification.getUnreadCount({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = - await ctx.appViewAgent.api.app.bsky.notification.getUnreadCount( - params, - await ctx.appviewAuthHeaders(requester), - ) - return { - encoding: 'application/json', - body: res.data, - } + return pipethrough( + bskyAppView.url, + 'app.bsky.notification.getUnreadCount', + params, + await ctx.appviewAuthHeaders(requester), + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/notification/listNotifications.ts b/packages/pds/src/api/app/bsky/notification/listNotifications.ts index 4a514ae03f4..005473eb6f4 100644 --- a/packages/pds/src/api/app/bsky/notification/listNotifications.ts +++ b/packages/pds/src/api/app/bsky/notification/listNotifications.ts @@ -1,20 +1,20 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.notification.listNotifications({ auth: ctx.authVerifier.access, handler: async ({ params, auth }) => { const requester = auth.credentials.did - const res = - await ctx.appViewAgent.api.app.bsky.notification.listNotifications( - params, - await ctx.appviewAuthHeaders(requester), - ) - return { - encoding: 'application/json', - body: res.data, - } + return pipethrough( + bskyAppView.url, + 'app.bsky.notification.listNotifications', + params, + await ctx.appviewAuthHeaders(requester), + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/notification/registerPush.ts b/packages/pds/src/api/app/bsky/notification/registerPush.ts index e6a5bf1b14f..ec6084c41aa 100644 --- a/packages/pds/src/api/app/bsky/notification/registerPush.ts +++ b/packages/pds/src/api/app/bsky/notification/registerPush.ts @@ -6,8 +6,10 @@ import { AtpAgent } from '@atproto/api' import { getDidDoc } from '../util/resolver' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.notification.registerPush({ - auth: ctx.authVerifier.access, + auth: ctx.authVerifier.accessDeactived, handler: async ({ auth, input }) => { const { serviceDid } = input.body const { @@ -16,14 +18,11 @@ export default function (server: Server, ctx: AppContext) { const authHeaders = await ctx.serviceAuthHeaders(did, serviceDid) - if (ctx.cfg.bskyAppView.did === serviceDid) { - await ctx.appViewAgent.api.app.bsky.notification.registerPush( - input.body, - { - ...authHeaders, - encoding: 'application/json', - }, - ) + if (ctx.cfg.bskyAppView?.did === serviceDid) { + await appViewAgent.api.app.bsky.notification.registerPush(input.body, { + ...authHeaders, + encoding: 'application/json', + }) return } diff --git a/packages/pds/src/api/app/bsky/notification/updateSeen.ts b/packages/pds/src/api/app/bsky/notification/updateSeen.ts index dc0217ffb67..18a0ea3fa11 100644 --- a/packages/pds/src/api/app/bsky/notification/updateSeen.ts +++ b/packages/pds/src/api/app/bsky/notification/updateSeen.ts @@ -2,12 +2,14 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' export default function (server: Server, ctx: AppContext) { + const { appViewAgent } = ctx + if (!appViewAgent) return server.app.bsky.notification.updateSeen({ auth: ctx.authVerifier.access, handler: async ({ input, auth }) => { const requester = auth.credentials.did - await ctx.appViewAgent.api.app.bsky.notification.updateSeen(input.body, { + await appViewAgent.api.app.bsky.notification.updateSeen(input.body, { ...(await ctx.appviewAuthHeaders(requester)), encoding: 'application/json', }) diff --git a/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts b/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts index 08466ed9f5c..da7be6fb649 100644 --- a/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +++ b/packages/pds/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts @@ -1,21 +1,21 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' // THIS IS A TEMPORARY UNSPECCED ROUTE export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.unspecced.getPopularFeedGenerators({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = - await ctx.appViewAgent.api.app.bsky.unspecced.getPopularFeedGenerators( - params, - await ctx.appviewAuthHeaders(requester), - ) - return { - encoding: 'application/json', - body: res.data, - } + return pipethrough( + bskyAppView.url, + 'app.bsky.unspecced.getPopularFeedGenerators', + params, + await ctx.appviewAuthHeaders(requester), + ) }, }) } diff --git a/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts b/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts index cd43177b83d..68e84985441 100644 --- a/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts +++ b/packages/pds/src/api/app/bsky/unspecced/getTaggedSuggestions.ts @@ -1,21 +1,21 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { pipethrough } from '../../../../pipethrough' // THIS IS A TEMPORARY UNSPECCED ROUTE export default function (server: Server, ctx: AppContext) { + const { bskyAppView } = ctx.cfg + if (!bskyAppView) return server.app.bsky.unspecced.getTaggedSuggestions({ auth: ctx.authVerifier.access, handler: async ({ auth, params }) => { const requester = auth.credentials.did - const res = - await ctx.appViewAgent.api.app.bsky.unspecced.getTaggedSuggestions( - params, - await ctx.appviewAuthHeaders(requester), - ) - return { - encoding: 'application/json', - body: res.data, - } + return pipethrough( + bskyAppView.url, + 'app.bsky.unspecced.getTaggedSuggestions', + params, + await ctx.appviewAuthHeaders(requester), + ) }, }) } diff --git a/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts b/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts index 5d1c9bf1ee1..7b6939270a2 100644 --- a/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts +++ b/packages/pds/src/api/com/atproto/admin/createCommunicationTemplate.ts @@ -3,15 +3,16 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.createCommunicationTemplate({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.createCommunicationTemplate( + await moderationAgent.com.atproto.admin.createCommunicationTemplate( input.body, authPassthru(req, true), ) - return { encoding: 'application/json', body: result, diff --git a/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts b/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts index 2f497f9089e..d10c2564571 100644 --- a/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts +++ b/packages/pds/src/api/com/atproto/admin/deleteCommunicationTemplate.ts @@ -3,10 +3,12 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.deleteCommunicationTemplate({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { - await ctx.moderationAgent.com.atproto.admin.deleteCommunicationTemplate( + await moderationAgent.com.atproto.admin.deleteCommunicationTemplate( input.body, authPassthru(req, true), ) diff --git a/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts b/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts index b2befdd53cc..65bb4c36d0e 100644 --- a/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts +++ b/packages/pds/src/api/com/atproto/admin/emitModerationEvent.ts @@ -3,15 +3,16 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.emitModerationEvent({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.emitModerationEvent( + await moderationAgent.com.atproto.admin.emitModerationEvent( input.body, authPassthru(req, true), ) - return { encoding: 'application/json', body: result, diff --git a/packages/pds/src/api/com/atproto/admin/getAccountInfo.ts b/packages/pds/src/api/com/atproto/admin/getAccountInfo.ts index 7b94a8c57d8..e258f9714b2 100644 --- a/packages/pds/src/api/com/atproto/admin/getAccountInfo.ts +++ b/packages/pds/src/api/com/atproto/admin/getAccountInfo.ts @@ -8,7 +8,10 @@ export default function (server: Server, ctx: AppContext) { auth: ctx.authVerifier.roleOrAdminService, handler: async ({ params }) => { const [account, invites, invitedBy] = await Promise.all([ - ctx.accountManager.getAccount(params.did, true), + ctx.accountManager.getAccount(params.did, { + includeDeactivated: true, + includeTakenDown: true, + }), ctx.accountManager.getAccountInvitesCodes(params.did), ctx.accountManager.getInvitedByForAccounts([params.did]), ]) diff --git a/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts b/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts index d368c3bfd72..a5e579baa58 100644 --- a/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts +++ b/packages/pds/src/api/com/atproto/admin/getModerationEvent.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.getModerationEvent({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data } = - await ctx.moderationAgent.com.atproto.admin.getModerationEvent( + await moderationAgent.com.atproto.admin.getModerationEvent( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/getRecord.ts b/packages/pds/src/api/com/atproto/admin/getRecord.ts index 90575354028..3cff5508683 100644 --- a/packages/pds/src/api/com/atproto/admin/getRecord.ts +++ b/packages/pds/src/api/com/atproto/admin/getRecord.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.getRecord({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data: recordDetailAppview } = - await ctx.moderationAgent.com.atproto.admin.getRecord( + await moderationAgent.com.atproto.admin.getRecord( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/getRepo.ts b/packages/pds/src/api/com/atproto/admin/getRepo.ts index 85592c52b14..880b407ce79 100644 --- a/packages/pds/src/api/com/atproto/admin/getRepo.ts +++ b/packages/pds/src/api/com/atproto/admin/getRepo.ts @@ -3,10 +3,12 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.getRepo({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { - const res = await ctx.moderationAgent.com.atproto.admin.getRepo( + const res = await moderationAgent.com.atproto.admin.getRepo( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/index.ts b/packages/pds/src/api/com/atproto/admin/index.ts index cca12226f4b..b0911afa66c 100644 --- a/packages/pds/src/api/com/atproto/admin/index.ts +++ b/packages/pds/src/api/com/atproto/admin/index.ts @@ -15,6 +15,7 @@ import disableInviteCodes from './disableInviteCodes' import getInviteCodes from './getInviteCodes' import updateAccountHandle from './updateAccountHandle' import updateAccountEmail from './updateAccountEmail' +import updateAccountPassword from './updateAccountPassword' import sendEmail from './sendEmail' import deleteAccount from './deleteAccount' import queryModerationStatuses from './queryModerationStatuses' @@ -40,6 +41,7 @@ export default function (server: Server, ctx: AppContext) { getInviteCodes(server, ctx) updateAccountHandle(server, ctx) updateAccountEmail(server, ctx) + updateAccountPassword(server, ctx) sendEmail(server, ctx) deleteAccount(server, ctx) listCommunicationTemplates(server, ctx) diff --git a/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts b/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts index 41e5d025522..dfe3a74bce8 100644 --- a/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts +++ b/packages/pds/src/api/com/atproto/admin/listCommunicationTemplates.ts @@ -3,15 +3,16 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.listCommunicationTemplates({ auth: ctx.authVerifier.role, handler: async ({ req }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.listCommunicationTemplates( + await moderationAgent.com.atproto.admin.listCommunicationTemplates( {}, authPassthru(req, true), ) - return { encoding: 'application/json', body: result, diff --git a/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts b/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts index 00e12439649..2d33ca6d466 100644 --- a/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts +++ b/packages/pds/src/api/com/atproto/admin/queryModerationEvents.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.queryModerationEvents({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.queryModerationEvents( + await moderationAgent.com.atproto.admin.queryModerationEvents( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts b/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts index d2b2f36a1fe..c31125ce114 100644 --- a/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts +++ b/packages/pds/src/api/com/atproto/admin/queryModerationStatuses.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.queryModerationStatuses({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data } = - await ctx.moderationAgent.com.atproto.admin.queryModerationStatuses( + await moderationAgent.com.atproto.admin.queryModerationStatuses( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/searchRepos.ts b/packages/pds/src/api/com/atproto/admin/searchRepos.ts index 5e21b2ab894..d09ff7b2327 100644 --- a/packages/pds/src/api/com/atproto/admin/searchRepos.ts +++ b/packages/pds/src/api/com/atproto/admin/searchRepos.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.searchRepos({ auth: ctx.authVerifier.role, handler: async ({ req, params }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.searchRepos( + await moderationAgent.com.atproto.admin.searchRepos( params, authPassthru(req), ) diff --git a/packages/pds/src/api/com/atproto/admin/sendEmail.ts b/packages/pds/src/api/com/atproto/admin/sendEmail.ts index c632e87ce59..e23d6bea5c1 100644 --- a/packages/pds/src/api/com/atproto/admin/sendEmail.ts +++ b/packages/pds/src/api/com/atproto/admin/sendEmail.ts @@ -18,7 +18,10 @@ export default function (server: Server, ctx: AppContext) { subject = 'Message from Bluesky moderator', comment, } = input.body - const account = await ctx.accountManager.getAccount(recipientDid) + const account = await ctx.accountManager.getAccount(recipientDid, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!account) { throw new InvalidRequestError('Recipient not found') } @@ -40,21 +43,25 @@ export default function (server: Server, ctx: AppContext) { { content }, { subject, to: account.email }, ) - await ctx.appViewAgent.api.com.atproto.admin.emitModerationEvent( - { - event: { - $type: 'com.atproto.admin.defs#modEventEmail', - subjectLine: subject, - comment, - }, - subject: { - $type: 'com.atproto.admin.defs#repoRef', - did: recipientDid, + + if (ctx.moderationAgent) { + await ctx.moderationAgent.api.com.atproto.admin.emitModerationEvent( + { + event: { + $type: 'com.atproto.admin.defs#modEventEmail', + subjectLine: subject, + comment, + }, + subject: { + $type: 'com.atproto.admin.defs#repoRef', + did: recipientDid, + }, + createdBy: senderDid, }, - createdBy: senderDid, - }, - { ...authPassthru(req), encoding: 'application/json' }, - ) + { ...authPassthru(req), encoding: 'application/json' }, + ) + } + return { encoding: 'application/json', body: { sent: true }, diff --git a/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts b/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts index 6e42905b83d..c2f266d716d 100644 --- a/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts +++ b/packages/pds/src/api/com/atproto/admin/updateAccountEmail.ts @@ -10,7 +10,10 @@ export default function (server: Server, ctx: AppContext) { if (!auth.credentials.admin) { throw new AuthRequiredError('Insufficient privileges') } - const account = await ctx.accountManager.getAccount(input.body.account) + const account = await ctx.accountManager.getAccount(input.body.account, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!account) { throw new InvalidRequestError( `Account does not exist: ${input.body.account}`, diff --git a/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts b/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts index b13d1ee54aa..1d4e1189c83 100644 --- a/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts +++ b/packages/pds/src/api/com/atproto/admin/updateAccountHandle.ts @@ -21,7 +21,10 @@ export default function (server: Server, ctx: AppContext) { }) // Pessimistic check to handle spam: also enforced by updateHandle() and the db. - const account = await ctx.accountManager.getAccount(handle) + const account = await ctx.accountManager.getAccount(handle, { + includeDeactivated: true, + includeTakenDown: true, + }) if (account) { if (account.did !== did) { @@ -46,6 +49,7 @@ export default function (server: Server, ctx: AppContext) { try { await ctx.sequencer.sequenceHandleUpdate(did, handle) + await ctx.sequencer.sequenceIdentityEvt(did) } catch (err) { httpLogger.error( { err, did, handle }, diff --git a/packages/pds/src/api/com/atproto/admin/updateAccountPassword.ts b/packages/pds/src/api/com/atproto/admin/updateAccountPassword.ts new file mode 100644 index 00000000000..294286c3873 --- /dev/null +++ b/packages/pds/src/api/com/atproto/admin/updateAccountPassword.ts @@ -0,0 +1,28 @@ +import { AuthRequiredError } from '@atproto/xrpc-server' +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import { authPassthru } from '../../../proxy' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.admin.updateAccountPassword({ + auth: ctx.authVerifier.role, + handler: async ({ input, auth, req }) => { + if (!auth.credentials.admin) { + throw new AuthRequiredError( + 'Must be an admin to update an account password', + ) + } + + if (ctx.entrywayAgent) { + await ctx.entrywayAgent.com.atproto.admin.updateAccountPassword( + input.body, + authPassthru(req, true), + ) + return + } + + const { did, password } = input.body + await ctx.accountManager.updateAccountPassword({ did, password }) + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts b/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts index abec4b275e6..c548a83bf03 100644 --- a/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts +++ b/packages/pds/src/api/com/atproto/admin/updateCommunicationTemplate.ts @@ -3,11 +3,13 @@ import AppContext from '../../../../context' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { + const { moderationAgent } = ctx + if (!moderationAgent) return server.com.atproto.admin.updateCommunicationTemplate({ auth: ctx.authVerifier.role, handler: async ({ req, input }) => { const { data: result } = - await ctx.moderationAgent.com.atproto.admin.updateCommunicationTemplate( + await moderationAgent.com.atproto.admin.updateCommunicationTemplate( input.body, authPassthru(req, true), ) diff --git a/packages/pds/src/api/com/atproto/identity/getRecommendedDidCredentials.ts b/packages/pds/src/api/com/atproto/identity/getRecommendedDidCredentials.ts new file mode 100644 index 00000000000..cd163f16566 --- /dev/null +++ b/packages/pds/src/api/com/atproto/identity/getRecommendedDidCredentials.ts @@ -0,0 +1,45 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.identity.getRecommendedDidCredentials({ + auth: ctx.authVerifier.access, + handler: async ({ auth }) => { + const requester = auth.credentials.did + const signingKey = await ctx.actorStore.keypair(requester) + const verificationMethods = { + atproto: signingKey.did(), + } + const account = await ctx.accountManager.getAccount(requester, { + includeDeactivated: true, + }) + const alsoKnownAs = account?.handle + ? [`at://${account.handle}`] + : undefined + + const plcRotationKey = + ctx.cfg.entryway?.plcRotationKey ?? ctx.plcRotationKey.did() + const rotationKeys = [plcRotationKey] + if (ctx.cfg.identity.recoveryDidKey) { + rotationKeys.unshift(ctx.cfg.identity.recoveryDidKey) + } + + const services = { + atproto_pds: { + type: 'AtprotoPersonalDataServer', + endpoint: ctx.cfg.service.publicUrl, + }, + } + + return { + encoding: 'application/json', + body: { + alsoKnownAs, + verificationMethods, + rotationKeys, + services, + }, + } + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/identity/index.ts b/packages/pds/src/api/com/atproto/identity/index.ts index 724b82de197..0a1d72a919b 100644 --- a/packages/pds/src/api/com/atproto/identity/index.ts +++ b/packages/pds/src/api/com/atproto/identity/index.ts @@ -2,8 +2,16 @@ import AppContext from '../../../../context' import { Server } from '../../../../lexicon' import resolveHandle from './resolveHandle' import updateHandle from './updateHandle' +import getRecommendedDidCredentials from './getRecommendedDidCredentials' +import requestPlcOperationSignature from './requestPlcOperationSignature' +import signPlcOperation from './signPlcOperation' +import submitPlcOperation from './submitPlcOperation' export default function (server: Server, ctx: AppContext) { resolveHandle(server, ctx) updateHandle(server, ctx) + getRecommendedDidCredentials(server, ctx) + requestPlcOperationSignature(server, ctx) + signPlcOperation(server, ctx) + submitPlcOperation(server, ctx) } diff --git a/packages/pds/src/api/com/atproto/identity/requestPlcOperationSignature.ts b/packages/pds/src/api/com/atproto/identity/requestPlcOperationSignature.ts new file mode 100644 index 00000000000..2c49a4b983b --- /dev/null +++ b/packages/pds/src/api/com/atproto/identity/requestPlcOperationSignature.ts @@ -0,0 +1,35 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import { InvalidRequestError } from '@atproto/xrpc-server' +import { authPassthru } from '../../../proxy' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.identity.requestPlcOperationSignature({ + auth: ctx.authVerifier.accessNotAppPassword, + handler: async ({ auth, req }) => { + if (ctx.entrywayAgent) { + await ctx.entrywayAgent.com.atproto.identity.requestPlcOperationSignature( + undefined, + authPassthru(req), + ) + return + } + + const did = auth.credentials.did + const account = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + includeTakenDown: true, + }) + if (!account) { + throw new InvalidRequestError('account not found') + } else if (!account.email) { + throw new InvalidRequestError('account does not have an email address') + } + const token = await ctx.accountManager.createEmailToken( + did, + 'plc_operation', + ) + await ctx.mailer.sendPlcOperation({ token }, { to: account.email }) + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/identity/resolveHandle.ts b/packages/pds/src/api/com/atproto/identity/resolveHandle.ts index 472d7ccb234..40122e2f3b6 100644 --- a/packages/pds/src/api/com/atproto/identity/resolveHandle.ts +++ b/packages/pds/src/api/com/atproto/identity/resolveHandle.ts @@ -18,7 +18,7 @@ export default function (server: Server, ctx: AppContext) { } let did: string | undefined - const user = await ctx.accountManager.getAccount(handle, true) + const user = await ctx.accountManager.getAccount(handle) if (user) { did = user.did @@ -33,7 +33,7 @@ export default function (server: Server, ctx: AppContext) { } // this is not someone on our server, but we help with resolving anyway - if (!did) { + if (!did && ctx.appViewAgent) { did = await tryResolveFromAppView(ctx.appViewAgent, handle) } diff --git a/packages/pds/src/api/com/atproto/identity/signPlcOperation.ts b/packages/pds/src/api/com/atproto/identity/signPlcOperation.ts new file mode 100644 index 00000000000..95381aa8588 --- /dev/null +++ b/packages/pds/src/api/com/atproto/identity/signPlcOperation.ts @@ -0,0 +1,58 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import * as plc from '@did-plc/lib' +import { check } from '@atproto/common' +import { InvalidRequestError } from '@atproto/xrpc-server' +import { authPassthru, resultPassthru } from '../../../proxy' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.identity.signPlcOperation({ + auth: ctx.authVerifier.accessNotAppPassword, + handler: async ({ auth, input, req }) => { + if (ctx.entrywayAgent) { + return resultPassthru( + await ctx.entrywayAgent.com.atproto.identity.signPlcOperation( + input.body, + authPassthru(req, true), + ), + ) + } + + const did = auth.credentials.did + const { token } = input.body + if (!token) { + throw new InvalidRequestError( + 'email confirmation token required to sign PLC operations', + ) + } + await ctx.accountManager.assertValidEmailTokenAndCleanup( + did, + 'plc_operation', + token, + ) + + const lastOp = await ctx.plcClient.getLastOp(did) + if (check.is(lastOp, plc.def.tombstone)) { + throw new InvalidRequestError('Did is tombstoned') + } + const operation = await plc.createUpdateOp( + lastOp, + ctx.plcRotationKey, + (lastOp) => ({ + ...lastOp, + rotationKeys: input.body.rotationKeys ?? lastOp.rotationKeys, + alsoKnownAs: input.body.alsoKnownAs ?? lastOp.alsoKnownAs, + verificationMethods: + input.body.verificationMethods ?? lastOp.verificationMethods, + services: input.body.services ?? lastOp.services, + }), + ) + return { + encoding: 'application/json', + body: { + operation, + }, + } + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/identity/submitPlcOperation.ts b/packages/pds/src/api/com/atproto/identity/submitPlcOperation.ts new file mode 100644 index 00000000000..66db47fe482 --- /dev/null +++ b/packages/pds/src/api/com/atproto/identity/submitPlcOperation.ts @@ -0,0 +1,48 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import * as plc from '@did-plc/lib' +import { check } from '@atproto/common' +import { InvalidRequestError } from '@atproto/xrpc-server' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.identity.submitPlcOperation({ + auth: ctx.authVerifier.access, + handler: async ({ auth, input }) => { + const requester = auth.credentials.did + const op = input.body.operation + + if (!check.is(op, plc.def.operation)) { + throw new InvalidRequestError('Invalid operation') + } + + if (!op.rotationKeys.includes(ctx.plcRotationKey.did())) { + throw new InvalidRequestError( + "Rotation keys do not include server's rotation key", + ) + } + if (op.services['atproto_pds']?.type !== 'AtprotoPersonalDataServer') { + throw new InvalidRequestError('Incorrect type on atproto_pds service') + } + if (op.services['atproto_pds']?.endpoint !== ctx.cfg.service.publicUrl) { + throw new InvalidRequestError( + 'Incorrect endpoint on atproto_pds service', + ) + } + const signingKey = await ctx.actorStore.keypair(requester) + if (op.verificationMethods['atproto'] !== signingKey.did()) { + throw new InvalidRequestError('Incorrect signing key') + } + const account = await ctx.accountManager.getAccount(requester, { + includeDeactivated: true, + }) + if ( + account?.handle && + op.alsoKnownAs.at(0) !== `at://${account.handle}` + ) { + throw new InvalidRequestError('Incorrect handle in alsoKnownAs') + } + + await ctx.plcClient.sendOperation(requester, op) + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/identity/updateHandle.ts b/packages/pds/src/api/com/atproto/identity/updateHandle.ts index 32018601756..06f836a83ff 100644 --- a/packages/pds/src/api/com/atproto/identity/updateHandle.ts +++ b/packages/pds/src/api/com/atproto/identity/updateHandle.ts @@ -42,7 +42,9 @@ export default function (server: Server, ctx: AppContext) { }) // Pessimistic check to handle spam: also enforced by updateHandle() and the db. - const account = await ctx.accountManager.getAccount(handle) + const account = await ctx.accountManager.getAccount(handle, { + includeDeactivated: true, + }) if (account) { if (account.did !== requester) { @@ -55,6 +57,7 @@ export default function (server: Server, ctx: AppContext) { try { await ctx.sequencer.sequenceHandleUpdate(requester, handle) + await ctx.sequencer.sequenceIdentityEvt(requester) } catch (err) { httpLogger.error( { err, did: requester, handle }, diff --git a/packages/pds/src/api/com/atproto/moderation/createReport.ts b/packages/pds/src/api/com/atproto/moderation/createReport.ts index 7b3cc998e22..64ed5c20005 100644 --- a/packages/pds/src/api/com/atproto/moderation/createReport.ts +++ b/packages/pds/src/api/com/atproto/moderation/createReport.ts @@ -1,16 +1,22 @@ import { Server } from '../../../../lexicon' import AppContext from '../../../../context' +import { InvalidRequestError } from '@atproto/xrpc-server' export default function (server: Server, ctx: AppContext) { server.com.atproto.moderation.createReport({ auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ input, auth }) => { const requester = auth.credentials.did + if (!ctx.reportingAgent) { + throw new InvalidRequestError( + 'Your hosting service is not configured with a moderation provider. If this seems in error, reach out to your hosting provider.', + ) + } const { data: result } = - await ctx.moderationAgent.com.atproto.moderation.createReport( + await ctx.reportingAgent.com.atproto.moderation.createReport( input.body, { - ...(await ctx.moderationAuthHeaders(requester)), + ...(await ctx.reportingAuthHeaders(requester)), encoding: 'application/json', }, ) diff --git a/packages/pds/src/api/com/atproto/repo/applyWrites.ts b/packages/pds/src/api/com/atproto/repo/applyWrites.ts index 1fd1bbb531e..d93c29fa32f 100644 --- a/packages/pds/src/api/com/atproto/repo/applyWrites.ts +++ b/packages/pds/src/api/com/atproto/repo/applyWrites.ts @@ -48,19 +48,20 @@ export default function (server: Server, ctx: AppContext) { handler: async ({ input, auth }) => { const tx = input.body const { repo, validate, swapCommit } = tx - const did = await ctx.accountManager.getDidForActor(repo) + const account = await ctx.accountManager.getAccount(repo, { + includeDeactivated: true, + }) - if (!did) { + if (!account) { throw new InvalidRequestError(`Could not find repo: ${repo}`) + } else if (account.deactivatedAt) { + throw new InvalidRequestError('Account is deactivated') } + + const did = account.did if (did !== auth.credentials.did) { throw new AuthRequiredError() } - if (validate === false) { - throw new InvalidRequestError( - 'Unvalidated writes are not yet supported.', - ) - } if (tx.writes.length > 200) { throw new InvalidRequestError('Too many writes. Max: 200') } diff --git a/packages/pds/src/api/com/atproto/repo/createRecord.ts b/packages/pds/src/api/com/atproto/repo/createRecord.ts index 8d7aaedd11c..88d3b910d41 100644 --- a/packages/pds/src/api/com/atproto/repo/createRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/createRecord.ts @@ -28,19 +28,19 @@ export default function (server: Server, ctx: AppContext) { handler: async ({ input, auth }) => { const { repo, collection, rkey, record, swapCommit, validate } = input.body - const did = await ctx.accountManager.getDidForActor(repo) + const account = await ctx.accountManager.getAccount(repo, { + includeDeactivated: true, + }) - if (!did) { + if (!account) { throw new InvalidRequestError(`Could not find repo: ${repo}`) + } else if (account.deactivatedAt) { + throw new InvalidRequestError('Account is deactivated') } + const did = account.did if (did !== auth.credentials.did) { throw new AuthRequiredError() } - if (validate === false) { - throw new InvalidRequestError( - 'Unvalidated writes are not yet supported.', - ) - } const swapCommitCid = swapCommit ? CID.parse(swapCommit) : undefined let write: PreparedCreate diff --git a/packages/pds/src/api/com/atproto/repo/deleteRecord.ts b/packages/pds/src/api/com/atproto/repo/deleteRecord.ts index 5a98c0d9963..51589e9d2bc 100644 --- a/packages/pds/src/api/com/atproto/repo/deleteRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/deleteRecord.ts @@ -22,11 +22,16 @@ export default function (server: Server, ctx: AppContext) { ], handler: async ({ input, auth }) => { const { repo, collection, rkey, swapCommit, swapRecord } = input.body - const did = await ctx.accountManager.getDidForActor(repo) + const account = await ctx.accountManager.getAccount(repo, { + includeDeactivated: true, + }) - if (!did) { + if (!account) { throw new InvalidRequestError(`Could not find repo: ${repo}`) + } else if (account.deactivatedAt) { + throw new InvalidRequestError('Account is deactivated') } + const did = account.did if (did !== auth.credentials.did) { throw new AuthRequiredError() } diff --git a/packages/pds/src/api/com/atproto/repo/getRecord.ts b/packages/pds/src/api/com/atproto/repo/getRecord.ts index 68f73d38b12..3d8b44099d4 100644 --- a/packages/pds/src/api/com/atproto/repo/getRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/getRecord.ts @@ -2,6 +2,7 @@ import { AtUri } from '@atproto/syntax' import { Server } from '../../../../lexicon' import AppContext from '../../../../context' import { InvalidRequestError } from '@atproto/xrpc-server' +import { pipethrough } from '../../../../pipethrough' export default function (server: Server, ctx: AppContext) { server.com.atproto.repo.getRecord(async ({ params }) => { @@ -27,10 +28,14 @@ export default function (server: Server, ctx: AppContext) { } } - const res = await ctx.appViewAgent.api.com.atproto.repo.getRecord(params) - return { - encoding: 'application/json', - body: res.data, + if (!ctx.cfg.bskyAppView) { + throw new InvalidRequestError(`Could not locate record`) } + + return await pipethrough( + ctx.cfg.bskyAppView.url, + 'com.atproto.repo.getRecord', + params, + ) }) } diff --git a/packages/pds/src/api/com/atproto/repo/importRepo.ts b/packages/pds/src/api/com/atproto/repo/importRepo.ts new file mode 100644 index 00000000000..1e320c99088 --- /dev/null +++ b/packages/pds/src/api/com/atproto/repo/importRepo.ts @@ -0,0 +1,135 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import { ActorStoreTransactor } from '../../../../actor-store' +import { TID } from '@atproto/common' +import { + Repo, + WriteOpAction, + getAndParseRecord, + readCarStream, + verifyDiff, +} from '@atproto/repo' +import { InvalidRequestError } from '@atproto/xrpc-server' +import { CID } from 'multiformats/cid' +import PQueue from 'p-queue' +import { AtUri } from '@atproto/syntax' +import { BlobRef, LexValue, RepoRecord } from '@atproto/lexicon' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.repo.importRepo({ + auth: ctx.authVerifier.accessNotAppPassword, + handler: async ({ input, auth }) => { + const did = auth.credentials.did + if (!ctx.cfg.service.acceptingImports) { + throw new InvalidRequestError('Service is not accepting repo imports') + } + await ctx.actorStore.transact(did, (store) => + importRepo(store, input.body), + ) + }, + }) +} + +const importRepo = async ( + actorStore: ActorStoreTransactor, + incomingCar: AsyncIterable, +) => { + const now = new Date().toISOString() + const rev = TID.nextStr() + const did = actorStore.repo.did + + const { roots, blocks } = await readCarStream(incomingCar) + if (roots.length !== 1) { + throw new InvalidRequestError('expected one root') + } + const currRoot = await actorStore.db.db + .selectFrom('repo_root') + .selectAll() + .executeTakeFirst() + const currRepo = currRoot + ? await Repo.load(actorStore.repo.storage, CID.parse(currRoot.cid)) + : null + const diff = await verifyDiff( + currRepo, + blocks, + roots[0], + undefined, + undefined, + { ensureLeaves: false }, + ) + diff.commit.rev = rev + await actorStore.repo.storage.applyCommit(diff.commit, currRepo === null) + const recordQueue = new PQueue({ concurrency: 50 }) + const controller = new AbortController() + for (const write of diff.writes) { + recordQueue + .add( + async () => { + const uri = AtUri.make(did, write.collection, write.rkey) + if (write.action === WriteOpAction.Delete) { + await actorStore.record.deleteRecord(uri) + } else { + let parsedRecord: RepoRecord + try { + const parsed = await getAndParseRecord(blocks, write.cid) + parsedRecord = parsed.record + } catch { + throw new InvalidRequestError( + `Could not parse record at '${write.collection}/${write.rkey}'`, + ) + } + const indexRecord = actorStore.record.indexRecord( + uri, + write.cid, + parsedRecord, + write.action, + rev, + now, + ) + const recordBlobs = findBlobRefs(parsedRecord) + const blobValues = recordBlobs.map((cid) => ({ + recordUri: uri.toString(), + blobCid: cid.ref.toString(), + })) + const indexRecordBlobs = + blobValues.length > 0 + ? actorStore.db.db + .insertInto('record_blob') + .values(blobValues) + .onConflict((oc) => oc.doNothing()) + .execute() + : Promise.resolve() + await Promise.all([indexRecord, indexRecordBlobs]) + } + }, + { signal: controller.signal }, + ) + .catch((err) => controller.abort(err)) + } + await recordQueue.onIdle() + controller.signal.throwIfAborted() +} + +export const findBlobRefs = (val: LexValue, layer = 0): BlobRef[] => { + if (layer > 32) { + return [] + } + // walk arrays + if (Array.isArray(val)) { + return val.flatMap((item) => findBlobRefs(item, layer + 1)) + } + // objects + if (val && typeof val === 'object') { + // convert blobs, leaving the original encoding so that we don't change CIDs on re-encode + if (val instanceof BlobRef) { + return [val] + } + // retain cids & bytes + if (CID.asCID(val) || val instanceof Uint8Array) { + return [] + } + return Object.values(val).flatMap((item) => findBlobRefs(item, layer + 1)) + } + // pass through + return [] +} diff --git a/packages/pds/src/api/com/atproto/repo/index.ts b/packages/pds/src/api/com/atproto/repo/index.ts index ce13a10fe15..5c754064e95 100644 --- a/packages/pds/src/api/com/atproto/repo/index.ts +++ b/packages/pds/src/api/com/atproto/repo/index.ts @@ -8,6 +8,8 @@ import getRecord from './getRecord' import listRecords from './listRecords' import putRecord from './putRecord' import uploadBlob from './uploadBlob' +import listMissingBlobs from './listMissingBlobs' +import importRepo from './importRepo' export default function (server: Server, ctx: AppContext) { applyWrites(server, ctx) @@ -18,4 +20,6 @@ export default function (server: Server, ctx: AppContext) { listRecords(server, ctx) putRecord(server, ctx) uploadBlob(server, ctx) + listMissingBlobs(server, ctx) + importRepo(server, ctx) } diff --git a/packages/pds/src/api/com/atproto/repo/listMissingBlobs.ts b/packages/pds/src/api/com/atproto/repo/listMissingBlobs.ts new file mode 100644 index 00000000000..8bb01cd5585 --- /dev/null +++ b/packages/pds/src/api/com/atproto/repo/listMissingBlobs.ts @@ -0,0 +1,23 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.repo.listMissingBlobs({ + auth: ctx.authVerifier.access, + handler: async ({ auth, params }) => { + const did = auth.credentials.did + const { limit, cursor } = params + const blobs = await ctx.actorStore.read(did, (store) => + store.repo.blob.listMissingBlobs({ limit, cursor }), + ) + + return { + encoding: 'application/json', + body: { + blobs, + cursor: blobs.at(-1)?.cid, + }, + } + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/repo/putRecord.ts b/packages/pds/src/api/com/atproto/repo/putRecord.ts index a0cc047e4ee..4e930365ff4 100644 --- a/packages/pds/src/api/com/atproto/repo/putRecord.ts +++ b/packages/pds/src/api/com/atproto/repo/putRecord.ts @@ -38,19 +38,19 @@ export default function (server: Server, ctx: AppContext) { swapCommit, swapRecord, } = input.body - const did = await ctx.accountManager.getDidForActor(repo) + const account = await ctx.accountManager.getAccount(repo, { + includeDeactivated: true, + }) - if (!did) { + if (!account) { throw new InvalidRequestError(`Could not find repo: ${repo}`) + } else if (account.deactivatedAt) { + throw new InvalidRequestError('Account is deactivated') } + const did = account.did if (did !== auth.credentials.did) { throw new AuthRequiredError() } - if (validate === false) { - throw new InvalidRequestError( - 'Unvalidated writes are not yet supported.', - ) - } const uri = AtUri.make(did, collection, rkey) const swapCommitCid = swapCommit ? CID.parse(swapCommit) : undefined diff --git a/packages/pds/src/api/com/atproto/repo/uploadBlob.ts b/packages/pds/src/api/com/atproto/repo/uploadBlob.ts index 4bb536f804e..ca610f79d9d 100644 --- a/packages/pds/src/api/com/atproto/repo/uploadBlob.ts +++ b/packages/pds/src/api/com/atproto/repo/uploadBlob.ts @@ -12,9 +12,35 @@ export default function (server: Server, ctx: AppContext) { handler: async ({ auth, input }) => { const requester = auth.credentials.did - const blob = await ctx.actorStore.transact(requester, (actorTxn) => { - return actorTxn.repo.blob.addUntetheredBlob(input.encoding, input.body) - }) + const blob = await ctx.actorStore.writeNoTransaction( + requester, + async (store) => { + const metadata = await store.repo.blob.uploadBlobAndGetMetadata( + input.encoding, + input.body, + ) + + return store.transact(async (actorTxn) => { + const blobRef = await actorTxn.repo.blob.trackUntetheredBlob( + metadata, + ) + + // make the blob permanent if an associated record is already indexed + const recordsForBlob = await actorTxn.repo.blob.getRecordsForBlob( + blobRef.ref, + ) + if (recordsForBlob.length > 0) { + await actorTxn.repo.blob.verifyBlobAndMakePermanent({ + cid: blobRef.ref, + mimeType: blobRef.mimeType, + constraints: {}, + }) + } + + return blobRef + }) + }, + ) return { encoding: 'application/json', diff --git a/packages/pds/src/api/com/atproto/server/activateAccount.ts b/packages/pds/src/api/com/atproto/server/activateAccount.ts new file mode 100644 index 00000000000..c666fd865eb --- /dev/null +++ b/packages/pds/src/api/com/atproto/server/activateAccount.ts @@ -0,0 +1,47 @@ +import { CidSet } from '@atproto/repo' +import { InvalidRequestError } from '@atproto/xrpc-server' +import { INVALID_HANDLE } from '@atproto/syntax' +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import { assertValidDidDocumentForService } from './util' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.server.activateAccount({ + auth: ctx.authVerifier.accessNotAppPassword, + handler: async ({ auth }) => { + const requester = auth.credentials.did + + await assertValidDidDocumentForService(ctx, requester) + + const account = await ctx.accountManager.getAccount(requester, { + includeDeactivated: true, + }) + if (!account) { + throw new InvalidRequestError('user not found', 'AccountNotFound') + } + + await ctx.accountManager.activateAccount(requester) + + const commitData = await ctx.actorStore.read(requester, async (store) => { + const root = await store.repo.storage.getRootDetailed() + const blocks = await store.repo.storage.getBlocks([root.cid]) + return { + cid: root.cid, + rev: root.rev, + since: null, + prev: null, + newBlocks: blocks.blocks, + removedCids: new CidSet(), + } + }) + + // @NOTE: we're over-emitting for now for backwards compatibility, can reduce this in the future + await ctx.sequencer.sequenceIdentityEvt(requester) + await ctx.sequencer.sequenceHandleUpdate( + requester, + account.handle ?? INVALID_HANDLE, + ) + await ctx.sequencer.sequenceCommit(requester, commitData, []) + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/server/checkAccountStatus.ts b/packages/pds/src/api/com/atproto/server/checkAccountStatus.ts new file mode 100644 index 00000000000..9ceb7dbcbe9 --- /dev/null +++ b/packages/pds/src/api/com/atproto/server/checkAccountStatus.ts @@ -0,0 +1,46 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import { isValidDidDocForService } from './util' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.server.checkAccountStatus({ + auth: ctx.authVerifier.access, + handler: async ({ auth }) => { + const requester = auth.credentials.did + const [ + repoRoot, + repoBlocks, + indexedRecords, + importedBlobs, + expectedBlobs, + ] = await ctx.actorStore.read(requester, async (store) => { + return await Promise.all([ + store.repo.storage.getRootDetailed(), + store.repo.storage.countBlocks(), + store.record.recordCount(), + store.repo.blob.blobCount(), + store.repo.blob.recordBlobCount(), + ]) + }) + const [activated, validDid] = await Promise.all([ + ctx.accountManager.isAccountActivated(requester), + isValidDidDocForService(ctx, requester), + ]) + + return { + encoding: 'application/json', + body: { + activated, + validDid, + repoCommit: repoRoot.cid.toString(), + repoRev: repoRoot.rev, + repoBlocks, + indexedRecords, + privateStateValues: 0, + expectedBlobs, + importedBlobs, + }, + } + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/server/confirmEmail.ts b/packages/pds/src/api/com/atproto/server/confirmEmail.ts index cbe7e5a0f74..b48165b4f70 100644 --- a/packages/pds/src/api/com/atproto/server/confirmEmail.ts +++ b/packages/pds/src/api/com/atproto/server/confirmEmail.ts @@ -9,7 +9,9 @@ export default function (server: Server, ctx: AppContext) { handler: async ({ auth, input, req }) => { const did = auth.credentials.did - const user = await ctx.accountManager.getAccount(did) + const user = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + }) if (!user) { throw new InvalidRequestError('user not found', 'AccountNotFound') } diff --git a/packages/pds/src/api/com/atproto/server/createAccount.ts b/packages/pds/src/api/com/atproto/server/createAccount.ts index c8f47a0d432..b6758b8c614 100644 --- a/packages/pds/src/api/com/atproto/server/createAccount.ts +++ b/packages/pds/src/api/com/atproto/server/createAccount.ts @@ -1,6 +1,6 @@ import { DidDocument, MINUTE, check } from '@atproto/common' import { AtprotoData, ensureAtpDocument } from '@atproto/identity' -import { InvalidRequestError } from '@atproto/xrpc-server' +import { AuthRequiredError, InvalidRequestError } from '@atproto/xrpc-server' import { ExportableKeypair, Keypair, Secp256k1Keypair } from '@atproto/crypto' import * as plc from '@did-plc/lib' import disposable from 'disposable-email' @@ -19,11 +19,21 @@ export default function (server: Server, ctx: AppContext) { durationMs: 5 * MINUTE, points: 100, }, - handler: async ({ input, req }) => { - const { did, handle, email, password, inviteCode, signingKey, plcOp } = - ctx.entrywayAgent - ? await validateInputsForEntrywayPds(ctx, input.body) - : await validateInputsForLocalPds(ctx, input.body) + auth: ctx.authVerifier.userDidAuthOptional, + handler: async ({ input, auth, req }) => { + const requester = auth.credentials?.iss ?? null + const { + did, + handle, + email, + password, + inviteCode, + signingKey, + plcOp, + deactivated, + } = ctx.entrywayAgent + ? await validateInputsForEntrywayPds(ctx, input.body) + : await validateInputsForLocalPds(ctx, input.body, requester) let didDoc: DidDocument | undefined let creds: { accessJwt: string; refreshJwt: string } @@ -54,9 +64,13 @@ export default function (server: Server, ctx: AppContext) { repoCid: commit.cid, repoRev: commit.rev, inviteCode, + deactivated, }) - await ctx.sequencer.sequenceCommit(did, commit, []) + if (!deactivated) { + await ctx.sequencer.sequenceCommit(did, commit, []) + await ctx.sequencer.sequenceIdentityEvt(did) + } await ctx.accountManager.updateRepoRoot(did, commit.cid, commit.rev) didDoc = await didDocForSession(ctx, did, true) await ctx.actorStore.clearReservedKeypair(signingKey.did(), did) @@ -135,12 +149,14 @@ const validateInputsForEntrywayPds = async ( inviteCode: undefined, signingKey, plcOp, + deactivated: false, } } const validateInputsForLocalPds = async ( ctx: AppContext, input: CreateAccountInput, + requester: string | null, ) => { const { email, password, inviteCode } = input if (input.plcOp) { @@ -188,14 +204,38 @@ const validateInputsForLocalPds = async ( // determine the did & any plc ops we need to send // if the provided did document is poorly setup, we throw const signingKey = await Secp256k1Keypair.create({ exportable: true }) - const { did, plcOp } = input.did - ? await validateExistingDid(ctx, handle, input.did, signingKey) - : await createDidAndPlcOp(ctx, handle, input, signingKey) - return { did, handle, email, password, inviteCode, signingKey, plcOp } + let did: string + let plcOp: plc.Operation | null + let deactivated = false + if (input.did) { + if (input.did !== requester) { + throw new AuthRequiredError( + `Missing auth to create account with did: ${input.did}`, + ) + } + did = input.did + plcOp = null + deactivated = true + } else { + const formatted = await formatDidAndPlcOp(ctx, handle, input, signingKey) + did = formatted.did + plcOp = formatted.plcOp + } + + return { + did, + handle, + email, + password, + inviteCode, + signingKey, + plcOp, + deactivated, + } } -const createDidAndPlcOp = async ( +const formatDidAndPlcOp = async ( ctx: AppContext, handle: string, input: CreateAccountInput, @@ -224,47 +264,6 @@ const createDidAndPlcOp = async ( plcOp: plcCreate.op, } } - -const validateExistingDid = async ( - ctx: AppContext, - handle: string, - did: string, - signingKey: Keypair, -): Promise<{ - did: string - plcOp: plc.Operation | null -}> => { - // if the user is bringing their own did: - // resolve the user's did doc data, including rotationKeys if did:plc - // determine if we have the capability to make changes to their DID - let atpData: AtprotoData - try { - atpData = await ctx.idResolver.did.resolveAtprotoData(did) - } catch (err) { - throw new InvalidRequestError( - `could not resolve valid DID document :${did}`, - 'UnresolvableDid', - ) - } - validateAtprotoData(atpData, { - handle, - pds: ctx.cfg.service.publicUrl, - signingKey: signingKey.did(), - }) - - if (did.startsWith('did:plc')) { - const data = await ctx.plcClient.getDocumentData(did) - if (!data.rotationKeys.includes(ctx.plcRotationKey.did())) { - throw new InvalidRequestError( - 'PLC DID does not include service rotation key', - 'IncompatibleDidDoc', - ) - } - } - - return { did: did, plcOp: null } -} - const validateAtprotoData = ( data: AtprotoData, expected: { diff --git a/packages/pds/src/api/com/atproto/server/createSession.ts b/packages/pds/src/api/com/atproto/server/createSession.ts index 70e42fdde62..c315f726f3a 100644 --- a/packages/pds/src/api/com/atproto/server/createSession.ts +++ b/packages/pds/src/api/com/atproto/server/createSession.ts @@ -35,8 +35,14 @@ export default function (server: Server, ctx: AppContext) { const identifier = input.body.identifier.toLowerCase() const user = identifier.includes('@') - ? await ctx.accountManager.getAccountByEmail(identifier, true) - : await ctx.accountManager.getAccount(identifier, true) + ? await ctx.accountManager.getAccountByEmail(identifier, { + includeDeactivated: true, + includeTakenDown: true, + }) + : await ctx.accountManager.getAccount(identifier, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!user) { throw new AuthRequiredError('Invalid identifier or password') diff --git a/packages/pds/src/api/com/atproto/server/deactivateAccount.ts b/packages/pds/src/api/com/atproto/server/deactivateAccount.ts new file mode 100644 index 00000000000..1b7b9179d9a --- /dev/null +++ b/packages/pds/src/api/com/atproto/server/deactivateAccount.ts @@ -0,0 +1,15 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.server.deactivateAccount({ + auth: ctx.authVerifier.accessNotAppPassword, + handler: async ({ auth, input }) => { + const requester = auth.credentials.did + await ctx.accountManager.deactivateAccount( + requester, + input.body.deleteAfter ?? null, + ) + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/server/deleteAccount.ts b/packages/pds/src/api/com/atproto/server/deleteAccount.ts index 9dc1de0df07..c42810ede40 100644 --- a/packages/pds/src/api/com/atproto/server/deleteAccount.ts +++ b/packages/pds/src/api/com/atproto/server/deleteAccount.ts @@ -13,7 +13,10 @@ export default function (server: Server, ctx: AppContext) { handler: async ({ input, req }) => { const { did, password, token } = input.body - const account = await ctx.accountManager.getAccount(did, true) + const account = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!account) { throw new InvalidRequestError('account not found') } @@ -41,6 +44,7 @@ export default function (server: Server, ctx: AppContext) { ) await ctx.actorStore.destroy(did) await ctx.accountManager.deleteAccount(did) + await ctx.sequencer.sequenceIdentityEvt(did) await ctx.sequencer.sequenceTombstone(did) await ctx.sequencer.deleteAllForUser(did) }, diff --git a/packages/pds/src/api/com/atproto/server/describeServer.ts b/packages/pds/src/api/com/atproto/server/describeServer.ts index 0ad3b2d66eb..28037ba8a55 100644 --- a/packages/pds/src/api/com/atproto/server/describeServer.ts +++ b/packages/pds/src/api/com/atproto/server/describeServer.ts @@ -11,6 +11,7 @@ export default function (server: Server, ctx: AppContext) { return { encoding: 'application/json', body: { + did: ctx.cfg.service.did, availableUserDomains, inviteCodeRequired, links: { privacyPolicy, termsOfService }, diff --git a/packages/pds/src/api/com/atproto/server/getServiceAuth.ts b/packages/pds/src/api/com/atproto/server/getServiceAuth.ts new file mode 100644 index 00000000000..52bb0ff5ae9 --- /dev/null +++ b/packages/pds/src/api/com/atproto/server/getServiceAuth.ts @@ -0,0 +1,24 @@ +import { createServiceJwt } from '@atproto/xrpc-server' +import AppContext from '../../../../context' +import { Server } from '../../../../lexicon' + +export default function (server: Server, ctx: AppContext) { + server.com.atproto.server.getServiceAuth({ + auth: ctx.authVerifier.access, + handler: async ({ params, auth }) => { + const did = auth.credentials.did + const keypair = await ctx.actorStore.keypair(did) + const token = await createServiceJwt({ + iss: did, + aud: params.aud, + keypair, + }) + return { + encoding: 'application/json', + body: { + token, + }, + } + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/server/getSession.ts b/packages/pds/src/api/com/atproto/server/getSession.ts index 8b81068a147..542677a2808 100644 --- a/packages/pds/src/api/com/atproto/server/getSession.ts +++ b/packages/pds/src/api/com/atproto/server/getSession.ts @@ -7,7 +7,7 @@ import { didDocForSession } from './util' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.getSession({ - auth: ctx.authVerifier.access, + auth: ctx.authVerifier.accessDeactived, handler: async ({ auth, req }) => { if (ctx.entrywayAgent) { return resultPassthru( diff --git a/packages/pds/src/api/com/atproto/server/index.ts b/packages/pds/src/api/com/atproto/server/index.ts index f5ab1245c1c..7208f106b17 100644 --- a/packages/pds/src/api/com/atproto/server/index.ts +++ b/packages/pds/src/api/com/atproto/server/index.ts @@ -30,6 +30,11 @@ import createAppPassword from './createAppPassword' import listAppPasswords from './listAppPasswords' import revokeAppPassword from './revokeAppPassword' +import getServiceAuth from './getServiceAuth' +import checkAccountStatus from './checkAccountStatus' +import activateAccount from './activateAccount' +import deactivateAccount from './deactivateAccount' + export default function (server: Server, ctx: AppContext) { describeServer(server, ctx) createAccount(server, ctx) @@ -52,4 +57,8 @@ export default function (server: Server, ctx: AppContext) { createAppPassword(server, ctx) listAppPasswords(server, ctx) revokeAppPassword(server, ctx) + getServiceAuth(server, ctx) + checkAccountStatus(server, ctx) + activateAccount(server, ctx) + deactivateAccount(server, ctx) } diff --git a/packages/pds/src/api/com/atproto/server/refreshSession.ts b/packages/pds/src/api/com/atproto/server/refreshSession.ts index 9b9d4f6a5fd..c33059c44e2 100644 --- a/packages/pds/src/api/com/atproto/server/refreshSession.ts +++ b/packages/pds/src/api/com/atproto/server/refreshSession.ts @@ -11,7 +11,10 @@ export default function (server: Server, ctx: AppContext) { auth: ctx.authVerifier.refresh, handler: async ({ auth, req }) => { const did = auth.credentials.did - const user = await ctx.accountManager.getAccount(did, true) + const user = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!user) { throw new InvalidRequestError( `Could not find user info for account: ${did}`, diff --git a/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts b/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts index 2566682d244..5572c4c70d4 100644 --- a/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts +++ b/packages/pds/src/api/com/atproto/server/requestAccountDelete.ts @@ -1,3 +1,4 @@ +import { DAY, HOUR } from '@atproto/common' import { InvalidRequestError } from '@atproto/xrpc-server' import { Server } from '../../../../lexicon' import AppContext from '../../../../context' @@ -5,10 +6,25 @@ import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.requestAccountDelete({ + rateLimit: [ + { + durationMs: DAY, + points: 15, + calcKey: ({ auth }) => auth.credentials.did, + }, + { + durationMs: HOUR, + points: 5, + calcKey: ({ auth }) => auth.credentials.did, + }, + ], auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, req }) => { const did = auth.credentials.did - const account = await ctx.accountManager.getAccount(did) + const account = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!account) { throw new InvalidRequestError('account not found') } diff --git a/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts b/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts index 76703d0d6d2..1840f09c740 100644 --- a/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts +++ b/packages/pds/src/api/com/atproto/server/requestEmailConfirmation.ts @@ -1,3 +1,4 @@ +import { DAY, HOUR } from '@atproto/common' import { InvalidRequestError } from '@atproto/xrpc-server' import { Server } from '../../../../lexicon' import AppContext from '../../../../context' @@ -5,10 +6,25 @@ import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.requestEmailConfirmation({ + rateLimit: [ + { + durationMs: DAY, + points: 15, + calcKey: ({ auth }) => auth.credentials.did, + }, + { + durationMs: HOUR, + points: 5, + calcKey: ({ auth }) => auth.credentials.did, + }, + ], auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, req }) => { const did = auth.credentials.did - const account = await ctx.accountManager.getAccount(did) + const account = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!account) { throw new InvalidRequestError('account not found') } diff --git a/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts b/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts index 696a7d2c018..0972df7b77e 100644 --- a/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts +++ b/packages/pds/src/api/com/atproto/server/requestEmailUpdate.ts @@ -1,3 +1,4 @@ +import { DAY, HOUR } from '@atproto/common' import { InvalidRequestError } from '@atproto/xrpc-server' import { Server } from '../../../../lexicon' import AppContext from '../../../../context' @@ -5,10 +6,25 @@ import { authPassthru, resultPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { server.com.atproto.server.requestEmailUpdate({ + rateLimit: [ + { + durationMs: DAY, + points: 15, + calcKey: ({ auth }) => auth.credentials.did, + }, + { + durationMs: HOUR, + points: 5, + calcKey: ({ auth }) => auth.credentials.did, + }, + ], auth: ctx.authVerifier.accessCheckTakedown, handler: async ({ auth, req }) => { const did = auth.credentials.did - const account = await ctx.accountManager.getAccount(did) + const account = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + includeTakenDown: true, + }) if (!account) { throw new InvalidRequestError('account not found') } diff --git a/packages/pds/src/api/com/atproto/server/requestPasswordReset.ts b/packages/pds/src/api/com/atproto/server/requestPasswordReset.ts index 4afdb0add83..d7684742ba8 100644 --- a/packages/pds/src/api/com/atproto/server/requestPasswordReset.ts +++ b/packages/pds/src/api/com/atproto/server/requestPasswordReset.ts @@ -1,32 +1,48 @@ +import { DAY, HOUR } from '@atproto/common' import { InvalidRequestError } from '@atproto/xrpc-server' import AppContext from '../../../../context' import { Server } from '../../../../lexicon' import { authPassthru } from '../../../proxy' export default function (server: Server, ctx: AppContext) { - server.com.atproto.server.requestPasswordReset(async ({ input, req }) => { - const email = input.body.email.toLowerCase() + server.com.atproto.server.requestPasswordReset({ + rateLimit: [ + { + durationMs: DAY, + points: 50, + }, + { + durationMs: HOUR, + points: 15, + }, + ], + handler: async ({ input, req }) => { + const email = input.body.email.toLowerCase() - const account = await ctx.accountManager.getAccountByEmail(email) + const account = await ctx.accountManager.getAccountByEmail(email, { + includeDeactivated: true, + includeTakenDown: true, + }) - if (!account?.email) { - if (ctx.entrywayAgent) { - await ctx.entrywayAgent.com.atproto.server.requestPasswordReset( - input.body, - authPassthru(req, true), - ) - return + if (!account?.email) { + if (ctx.entrywayAgent) { + await ctx.entrywayAgent.com.atproto.server.requestPasswordReset( + input.body, + authPassthru(req, true), + ) + return + } + throw new InvalidRequestError('account does not have an email address') } - throw new InvalidRequestError('account does not have an email address') - } - const token = await ctx.accountManager.createEmailToken( - account.did, - 'reset_password', - ) - await ctx.mailer.sendResetPassword( - { identifier: account.handle ?? account.email, token }, - { to: account.email }, - ) + const token = await ctx.accountManager.createEmailToken( + account.did, + 'reset_password', + ) + await ctx.mailer.sendResetPassword( + { identifier: account.handle ?? account.email, token }, + { to: account.email }, + ) + }, }) } diff --git a/packages/pds/src/api/com/atproto/server/updateEmail.ts b/packages/pds/src/api/com/atproto/server/updateEmail.ts index 52d27a64ae4..33de0ca6f61 100644 --- a/packages/pds/src/api/com/atproto/server/updateEmail.ts +++ b/packages/pds/src/api/com/atproto/server/updateEmail.ts @@ -16,7 +16,9 @@ export default function (server: Server, ctx: AppContext) { 'This email address is not supported, please use a different email.', ) } - const account = await ctx.accountManager.getAccount(did) + const account = await ctx.accountManager.getAccount(did, { + includeDeactivated: true, + }) if (!account) { throw new InvalidRequestError('account not found') } @@ -45,7 +47,7 @@ export default function (server: Server, ctx: AppContext) { } try { - await ctx.accountManager.updateEmail({ did, email, token }) + await ctx.accountManager.updateEmail({ did, email }) } catch (err) { if (err instanceof UserAlreadyExistsError) { throw new InvalidRequestError( diff --git a/packages/pds/src/api/com/atproto/server/util.ts b/packages/pds/src/api/com/atproto/server/util.ts index fc3bfae8e05..43ec0398531 100644 --- a/packages/pds/src/api/com/atproto/server/util.ts +++ b/packages/pds/src/api/com/atproto/server/util.ts @@ -3,6 +3,8 @@ import { DidDocument } from '@atproto/identity' import { ServerConfig } from '../../../../config' import AppContext from '../../../../context' import { dbLogger } from '../../../../logger' +import { InvalidRequestError } from '@atproto/xrpc-server' +import { getPdsEndpoint, getSigningDidKey } from '@atproto/common' // generate an invite code preceded by the hostname // with '.'s replaced by '-'s so it is not mistakable for a link @@ -40,3 +42,71 @@ export const didDocForSession = async ( dbLogger.warn({ err, did }, 'failed to resolve did doc') } } + +export const isValidDidDocForService = async ( + ctx: AppContext, + did: string, +): Promise => { + try { + await assertValidDidDocumentForService(ctx, did) + return true + } catch { + return false + } +} + +export const assertValidDidDocumentForService = async ( + ctx: AppContext, + did: string, +) => { + if (did.startsWith('did:plc')) { + const resolved = await ctx.plcClient.getDocumentData(did) + await assertValidDocContents(ctx, did, { + pdsEndpoint: resolved.services['atproto_pds']?.endpoint, + signingKey: resolved.verificationMethods['atproto'], + rotationKeys: resolved.rotationKeys, + }) + } else { + const resolved = await ctx.idResolver.did.resolve(did, true) + if (!resolved) { + throw new InvalidRequestError('Could not resolve DID') + } + await assertValidDocContents(ctx, did, { + pdsEndpoint: getPdsEndpoint(resolved), + signingKey: getSigningDidKey(resolved), + }) + } +} + +const assertValidDocContents = async ( + ctx: AppContext, + did: string, + contents: { + signingKey?: string + pdsEndpoint?: string + rotationKeys?: string[] + }, +) => { + const { signingKey, pdsEndpoint, rotationKeys } = contents + + const plcRotationKey = + ctx.cfg.entryway?.plcRotationKey ?? ctx.plcRotationKey.did() + if (rotationKeys !== undefined && !rotationKeys.includes(plcRotationKey)) { + throw new InvalidRequestError( + 'Server rotation key not included in PLC DID data', + ) + } + + if (!pdsEndpoint || pdsEndpoint !== ctx.cfg.service.publicUrl) { + throw new InvalidRequestError( + 'DID document atproto_pds service endpoint does not match PDS public url', + ) + } + + const keypair = await ctx.actorStore.keypair(did) + if (!signingKey || signingKey !== keypair.did()) { + throw new InvalidRequestError( + 'DID document verification method does not match expected signing key', + ) + } +} diff --git a/packages/pds/src/api/com/atproto/sync/listRepos.ts b/packages/pds/src/api/com/atproto/sync/listRepos.ts index 8a9fe8170a4..5641c8cfa68 100644 --- a/packages/pds/src/api/com/atproto/sync/listRepos.ts +++ b/packages/pds/src/api/com/atproto/sync/listRepos.ts @@ -13,6 +13,7 @@ export default function (server: Server, ctx: AppContext) { .selectFrom('actor') .innerJoin('repo_root', 'repo_root.did', 'actor.did') .where(notSoftDeletedClause(ref('actor'))) + .where('actor.deactivatedAt', 'is', null) .select([ 'actor.did as did', 'repo_root.cid as head', diff --git a/packages/pds/src/api/com/atproto/sync/subscribeRepos.ts b/packages/pds/src/api/com/atproto/sync/subscribeRepos.ts index 8302760a75f..1b9c16354f0 100644 --- a/packages/pds/src/api/com/atproto/sync/subscribeRepos.ts +++ b/packages/pds/src/api/com/atproto/sync/subscribeRepos.ts @@ -52,6 +52,13 @@ export default function (server: Server, ctx: AppContext) { time: evt.time, ...evt.evt, } + } else if (evt.type === 'identity') { + yield { + $type: '#identity', + seq: evt.seq, + time: evt.time, + ...evt.evt, + } } else if (evt.type === 'tombstone') { yield { $type: '#tombstone', diff --git a/packages/pds/src/api/com/atproto/temp/checkSignupQueue.ts b/packages/pds/src/api/com/atproto/temp/checkSignupQueue.ts new file mode 100644 index 00000000000..2ca11d29bfa --- /dev/null +++ b/packages/pds/src/api/com/atproto/temp/checkSignupQueue.ts @@ -0,0 +1,26 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import { authPassthru, resultPassthru } from '../../../proxy' + +// THIS IS A TEMPORARY UNSPECCED ROUTE +export default function (server: Server, ctx: AppContext) { + server.com.atproto.temp.checkSignupQueue({ + auth: ctx.authVerifier.accessDeactived, + handler: async ({ req }) => { + if (!ctx.entrywayAgent) { + return { + encoding: 'application/json', + body: { + activated: true, + }, + } + } + return resultPassthru( + await ctx.entrywayAgent.com.atproto.temp.checkSignupQueue( + undefined, + authPassthru(req), + ), + ) + }, + }) +} diff --git a/packages/pds/src/api/com/atproto/temp/importRepo.ts b/packages/pds/src/api/com/atproto/temp/importRepo.ts deleted file mode 100644 index ff11dd5f6d1..00000000000 --- a/packages/pds/src/api/com/atproto/temp/importRepo.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { Readable } from 'stream' -import assert from 'assert' -import PQueue from 'p-queue' -import axios from 'axios' -import { CID } from 'multiformats/cid' -import { InvalidRequestError } from '@atproto/xrpc-server' -import { AsyncBuffer, TID, wait } from '@atproto/common' -import { AtUri } from '@atproto/syntax' -import { - Repo, - WriteOpAction, - getAndParseRecord, - readCarStream, - verifyDiff, -} from '@atproto/repo' -import { BlobRef, LexValue, RepoRecord } from '@atproto/lexicon' -import { Server } from '../../../../lexicon' -import AppContext from '../../../../context' -import { ActorStoreTransactor } from '../../../../actor-store' -import { AtprotoData } from '@atproto/identity' - -export default function (server: Server, ctx: AppContext) { - server.com.atproto.temp.importRepo({ - opts: { - blobLimit: 5 * 1024 * 1024 * 1024, // 5GB - }, - auth: ctx.authVerifier.role, - handler: async ({ params, input, req }) => { - const { did } = params - const outBuffer = new AsyncBuffer() - sendTicks(outBuffer).catch((err) => { - req.log.error({ err }, 'failed to send ticks') - }) - processImport(ctx, did, input.body, outBuffer).catch(async (err) => { - req.log.error({ did, err }, 'failed import') - try { - await ctx.actorStore.destroy(did) - } catch (err) { - req.log.error({ did, err }, 'failed to clean up actor store') - } - outBuffer.throw(err) - }) - - return { - encoding: 'text/plain', - body: Readable.from(outBuffer.events()), - } - }, - }) -} - -const sendTicks = async (outBuffer: AsyncBuffer) => { - while (!outBuffer.isClosed) { - outBuffer.push('tick\n') - await wait(1000) - } -} - -const processImport = async ( - ctx: AppContext, - did: string, - incomingCar: AsyncIterable, - outBuffer: AsyncBuffer, -) => { - const didData = await ctx.idResolver.did.resolveAtprotoData(did) - const alreadyExists = await ctx.actorStore.exists(did) - if (!alreadyExists) { - const keypair = await ctx.actorStore.getReservedKeypair(did) - if (!keypair) { - throw new InvalidRequestError('No signing key reserved') - } - await ctx.actorStore.create(did, keypair) - } - await ctx.actorStore.transact(did, async (actorStore) => { - const blobRefs = await importRepo(actorStore, incomingCar, outBuffer) - await importBlobs(actorStore, didData, blobRefs, outBuffer) - }) - outBuffer.close() -} - -const importRepo = async ( - actorStore: ActorStoreTransactor, - incomingCar: AsyncIterable, - outBuffer: AsyncBuffer, -) => { - const now = new Date().toISOString() - const rev = TID.nextStr() - const did = actorStore.repo.did - - const { roots, blocks } = await readCarStream(incomingCar) - if (roots.length !== 1) { - throw new InvalidRequestError('expected one root') - } - outBuffer.push(`read ${blocks.size} blocks\n`) - const currRoot = await actorStore.db.db - .selectFrom('repo_root') - .selectAll() - .executeTakeFirst() - const currRepo = currRoot - ? await Repo.load(actorStore.repo.storage, CID.parse(currRoot.cid)) - : null - const diff = await verifyDiff( - currRepo, - blocks, - roots[0], - undefined, - undefined, - { ensureLeaves: false }, - ) - outBuffer.push(`diffed repo and found ${diff.writes.length} writes\n`) - diff.commit.rev = rev - await actorStore.repo.storage.applyCommit(diff.commit, currRepo === null) - const recordQueue = new PQueue({ concurrency: 50 }) - let blobRefs: BlobRef[] = [] - let count = 0 - for (const write of diff.writes) { - recordQueue.add(async () => { - const uri = AtUri.make(did, write.collection, write.rkey) - if (write.action === WriteOpAction.Delete) { - await actorStore.record.deleteRecord(uri) - } else { - let parsedRecord: RepoRecord | null - try { - const parsed = await getAndParseRecord(blocks, write.cid) - parsedRecord = parsed.record - } catch { - parsedRecord = null - } - const indexRecord = actorStore.record.indexRecord( - uri, - write.cid, - parsedRecord, - write.action, - rev, - now, - ) - const recordBlobs = findBlobRefs(parsedRecord) - blobRefs = blobRefs.concat(recordBlobs) - const blobValues = recordBlobs.map((cid) => ({ - recordUri: uri.toString(), - blobCid: cid.ref.toString(), - })) - const indexRecordBlobs = - blobValues.length > 0 - ? actorStore.db.db - .insertInto('record_blob') - .values(blobValues) - .onConflict((oc) => oc.doNothing()) - .execute() - : Promise.resolve() - await Promise.all([indexRecord, indexRecordBlobs]) - } - count++ - if (count % 50 === 0) { - outBuffer.push(`indexed ${count}/${diff.writes.length} writes\n`) - } - }) - } - outBuffer.push(`indexed ${count}/${diff.writes.length} writes\n`) - await recordQueue.onIdle() - return blobRefs -} - -const importBlobs = async ( - actorStore: ActorStoreTransactor, - didData: AtprotoData, - blobRefs: BlobRef[], - outBuffer: AsyncBuffer, -) => { - let blobCount = 0 - const blobQueue = new PQueue({ concurrency: 10 }) - outBuffer.push(`fetching ${blobRefs.length} blobs\n`) - const endpoint = `${didData.pds}/xrpc/com.atproto.sync.getBlob` - for (const ref of blobRefs) { - blobQueue.add(async () => { - try { - await importBlob(actorStore, endpoint, ref) - blobCount++ - outBuffer.push(`imported ${blobCount}/${blobRefs.length} blobs\n`) - } catch (err) { - outBuffer.push(`failed to import blob: ${ref.ref.toString()}\n`) - } - }) - } - await blobQueue.onIdle() - outBuffer.push(`finished importing all blobs\n`) -} - -const importBlob = async ( - actorStore: ActorStoreTransactor, - endpoint: string, - blob: BlobRef, -) => { - const hasBlob = await actorStore.db.db - .selectFrom('blob') - .selectAll() - .where('cid', '=', blob.ref.toString()) - .executeTakeFirst() - if (hasBlob) { - return - } - const res = await axios.get(endpoint, { - params: { did: actorStore.repo.did, cid: blob.ref.toString() }, - decompress: true, - responseType: 'stream', - timeout: 5000, - }) - const mimeType = res.headers['content-type'] ?? 'application/octet-stream' - const importedRef = await actorStore.repo.blob.addUntetheredBlob( - mimeType, - res.data, - ) - assert(blob.ref.equals(importedRef.ref)) - await actorStore.repo.blob.verifyBlobAndMakePermanent({ - mimeType: blob.mimeType, - cid: blob.ref, - constraints: {}, - }) -} - -export const findBlobRefs = (val: LexValue, layer = 0): BlobRef[] => { - if (layer > 10) { - return [] - } - // walk arrays - if (Array.isArray(val)) { - return val.flatMap((item) => findBlobRefs(item, layer + 1)) - } - // objects - if (val && typeof val === 'object') { - // convert blobs, leaving the original encoding so that we don't change CIDs on re-encode - if (val instanceof BlobRef) { - return [val] - } - // retain cids & bytes - if (CID.asCID(val) || val instanceof Uint8Array) { - return [] - } - return Object.values(val).flatMap((item) => findBlobRefs(item, layer + 1)) - } - // pass through - return [] -} diff --git a/packages/pds/src/api/com/atproto/temp/index.ts b/packages/pds/src/api/com/atproto/temp/index.ts index 8209dfe49f6..a39aef98fe9 100644 --- a/packages/pds/src/api/com/atproto/temp/index.ts +++ b/packages/pds/src/api/com/atproto/temp/index.ts @@ -1,11 +1,7 @@ import AppContext from '../../../../context' import { Server } from '../../../../lexicon' -import importRepo from './importRepo' -import pushBlob from './pushBlob' -import transferAccount from './transferAccount' +import checkSignupQueue from './checkSignupQueue' export default function (server: Server, ctx: AppContext) { - importRepo(server, ctx) - pushBlob(server, ctx) - transferAccount(server, ctx) + checkSignupQueue(server, ctx) } diff --git a/packages/pds/src/api/com/atproto/temp/pushBlob.ts b/packages/pds/src/api/com/atproto/temp/pushBlob.ts deleted file mode 100644 index 74ef80e42c0..00000000000 --- a/packages/pds/src/api/com/atproto/temp/pushBlob.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Server } from '../../../../lexicon' -import AppContext from '../../../../context' - -export default function (server: Server, ctx: AppContext) { - server.com.atproto.temp.pushBlob({ - auth: ctx.authVerifier.role, - handler: async ({ params, input }) => { - const { did } = params - - await ctx.actorStore.transact(did, async (actorTxn) => { - const blob = await actorTxn.repo.blob.addUntetheredBlob( - input.encoding, - input.body, - ) - await actorTxn.repo.blob.verifyBlobAndMakePermanent({ - mimeType: blob.mimeType, - cid: blob.ref, - constraints: {}, - }) - }) - }, - }) -} diff --git a/packages/pds/src/api/com/atproto/temp/transferAccount.ts b/packages/pds/src/api/com/atproto/temp/transferAccount.ts deleted file mode 100644 index 0b1b765089c..00000000000 --- a/packages/pds/src/api/com/atproto/temp/transferAccount.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { ensureAtpDocument } from '@atproto/identity' -import * as plc from '@did-plc/lib' -import { Server } from '../../../../lexicon' -import AppContext from '../../../../context' -import { check, cidForCbor } from '@atproto/common' -import { InvalidRequestError } from '@atproto/xrpc-server' -import { BlockMap, CidSet } from '@atproto/repo' - -export default function (server: Server, ctx: AppContext) { - server.com.atproto.temp.transferAccount({ - auth: ctx.authVerifier.role, - handler: async ({ input }) => { - const { did, handle } = input.body - - const signingKey = await ctx.actorStore.keypair(did) - const currRoot = await ctx.actorStore.read(did, (store) => - store.repo.storage.getRootDetailed(), - ) - - const plcOp = did.startsWith('did:plc') - ? await verifyDidAndPlcOp( - ctx, - did, - handle, - signingKey.did(), - input.body.plcOp, - ) - : null - - const { accessJwt, refreshJwt } = await ctx.accountManager.createAccount({ - did, - handle, - repoCid: currRoot.cid, - repoRev: currRoot.rev, - }) - - if (plcOp) { - try { - await ctx.plcClient.sendOperation(did, plcOp) - } catch (err) { - await ctx.accountManager.deleteAccount(did) - throw err - } - } - - await ctx.sequencer.sequenceCommit( - did, - { - cid: currRoot.cid, - rev: currRoot.rev, - since: null, - prev: null, - newBlocks: new BlockMap(), - removedCids: new CidSet(), - }, - [], - ) - - return { - encoding: 'application/json', - body: { - handle, - did: did, - accessJwt: accessJwt, - refreshJwt: refreshJwt, - }, - } - }, - }) -} - -const verifyDidAndPlcOp = async ( - ctx: AppContext, - did: string, - handle: string, - signingKey: string, - plcOp: unknown, -): Promise => { - if (!check.is(plcOp, plc.def.operation)) { - throw new InvalidRequestError('invalid plc operation', 'IncompatibleDidDoc') - } - await plc.assureValidOp(plcOp) - const prev = await ctx.plcClient.getLastOp(did) - if (!prev || prev.type === 'plc_tombstone') { - throw new InvalidRequestError( - 'no accessible prev for did', - 'IncompatibleDidDoc', - ) - } - const prevCid = await cidForCbor(prev) - if (plcOp.prev?.toString() !== prevCid.toString()) { - throw new InvalidRequestError( - 'invalid prev on plc operation', - 'IncompatibleDidDoc', - ) - } - const normalizedPrev = plc.normalizeOp(prev) - await plc.assureValidSig(normalizedPrev.rotationKeys, plcOp) - const doc = plc.formatDidDoc({ did, ...plcOp }) - const data = ensureAtpDocument(doc) - if (handle !== data.handle) { - throw new InvalidRequestError( - 'invalid handle on plc operation', - 'IncompatibleDidDoc', - ) - } else if (data.pds !== ctx.cfg.service.publicUrl) { - throw new InvalidRequestError( - 'invalid service on plc operation', - 'IncompatibleDidDoc', - ) - } else if (data.signingKey !== signingKey) { - throw new InvalidRequestError( - 'invalid signing key on plc operation', - 'IncompatibleDidDoc', - ) - } - return plcOp -} diff --git a/packages/pds/src/auth-verifier.ts b/packages/pds/src/auth-verifier.ts index dc5f0bc29d5..668791c187f 100644 --- a/packages/pds/src/auth-verifier.ts +++ b/packages/pds/src/auth-verifier.ts @@ -22,6 +22,7 @@ export enum AuthScope { Access = 'com.atproto.access', Refresh = 'com.atproto.refresh', AppPass = 'com.atproto.appPass', + Deactivated = 'com.atproto.deactivated', } export enum RoleStatus { @@ -72,6 +73,14 @@ type RefreshOutput = { artifacts: string } +type UserDidOutput = { + credentials: { + type: 'user_did' + aud: string + iss: string + } +} + type ValidatedBearer = { did: string scope: AuthScope @@ -88,7 +97,7 @@ export type AuthVerifierOpts = { dids: { pds: string entryway?: string - admin: string + admin?: string } } @@ -125,7 +134,9 @@ export class AuthVerifier { AuthScope.Access, AuthScope.AppPass, ]) - const found = await this.accountManager.getAccount(result.credentials.did) + const found = await this.accountManager.getAccount(result.credentials.did, { + includeDeactivated: true, + }) if (!found) { // will be turned into ExpiredToken for the client if proxied by entryway throw new ForbiddenError('Account not found', 'AccountNotFound') @@ -143,6 +154,14 @@ export class AuthVerifier { return this.validateAccessToken(ctx.req, [AuthScope.Access]) } + accessDeactived = (ctx: ReqCtx): Promise => { + return this.validateAccessToken(ctx.req, [ + AuthScope.Access, + AuthScope.AppPass, + AuthScope.Deactivated, + ]) + } + refresh = async (ctx: ReqCtx): Promise => { const { did, scope, token, audience, payload } = await this.validateBearerToken(ctx.req, [AuthScope.Refresh], { @@ -210,24 +229,38 @@ export class AuthVerifier { } } + userDidAuth = async (reqCtx: ReqCtx): Promise => { + const payload = await this.verifyServiceJwt(reqCtx, { + aud: this.dids.entryway ?? this.dids.pds, + iss: null, + }) + return { + credentials: { + type: 'user_did', + aud: payload.aud, + iss: payload.iss, + }, + } + } + + userDidAuthOptional = async ( + reqCtx: ReqCtx, + ): Promise => { + if (isBearerToken(reqCtx.req)) { + return await this.userDidAuth(reqCtx) + } else { + return { credentials: null } + } + } + adminService = async (reqCtx: ReqCtx): Promise => { - const jwtStr = bearerTokenFromReq(reqCtx.req) - if (!jwtStr) { - throw new AuthRequiredError('missing jwt', 'MissingJwt') + if (!this.dids.admin) { + throw new AuthRequiredError('Untrusted issuer', 'UntrustedIss') } - const payload = await verifyServiceJwt( - jwtStr, - this.dids.entryway ?? this.dids.pds, - async (did, forceRefresh) => { - if (did !== this.dids.admin) { - throw new AuthRequiredError( - 'Untrusted issuer for admin actions', - 'UntrustedIss', - ) - } - return this.idResolver.did.resolveAtprotoKey(did, forceRefresh) - }, - ) + const payload = await this.verifyServiceJwt(reqCtx, { + aud: this.dids.entryway ?? this.dids.pds, + iss: [this.dids.admin], + }) return { credentials: { type: 'service', @@ -299,6 +332,28 @@ export class AuthVerifier { } } + async verifyServiceJwt( + reqCtx: ReqCtx, + opts: { aud: string | null; iss: string[] | null }, + ) { + const getSigningKey = async ( + did: string, + forceRefresh: boolean, + ): Promise => { + if (opts.iss !== null && !opts.iss.includes(did)) { + throw new AuthRequiredError('Untrusted issuer', 'UntrustedIss') + } + return this.idResolver.did.resolveAtprotoKey(did, forceRefresh) + } + + const jwtStr = bearerTokenFromReq(reqCtx.req) + if (!jwtStr) { + throw new AuthRequiredError('missing jwt', 'MissingJwt') + } + const payload = await verifyServiceJwt(jwtStr, opts.aud, getSigningKey) + return { iss: payload.iss, aud: payload.aud } + } + parseRoleCreds(req: express.Request) { const parsed = parseBasicAuth(req.headers.authorization || '') const { Missing, Valid, Invalid } = RoleStatus diff --git a/packages/pds/src/config/config.ts b/packages/pds/src/config/config.ts index 2f8f295b2b0..8ca807d39b5 100644 --- a/packages/pds/src/config/config.ts +++ b/packages/pds/src/config/config.ts @@ -22,6 +22,8 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { version: env.version, // default? privacyPolicyUrl: env.privacyPolicyUrl, termsOfServiceUrl: env.termsOfServiceUrl, + acceptingImports: env.acceptingImports ?? true, + blobUploadLimit: env.blobUploadLimit ?? 5 * 1024 * 1024, // 5mb } const dbLoc = (name: string) => { @@ -167,19 +169,46 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { repoBackfillLimitMs: env.repoBackfillLimitMs ?? DAY, } - assert(env.bskyAppViewUrl) - assert(env.bskyAppViewDid) - const bskyAppViewCfg: ServerConfig['bskyAppView'] = { - url: env.bskyAppViewUrl, - did: env.bskyAppViewDid, - cdnUrlPattern: env.bskyAppViewCdnUrlPattern, + let bskyAppViewCfg: ServerConfig['bskyAppView'] = null + if (env.bskyAppViewUrl) { + assert( + env.bskyAppViewDid, + 'if bsky appview service url is configured, must configure its did as well.', + ) + bskyAppViewCfg = { + url: env.bskyAppViewUrl, + did: env.bskyAppViewDid, + cdnUrlPattern: env.bskyAppViewCdnUrlPattern, + } } - assert(env.modServiceUrl) - assert(env.modServiceDid) - const modServiceCfg: ServerConfig['modService'] = { - url: env.modServiceUrl, - did: env.modServiceDid, + let modServiceCfg: ServerConfig['modService'] = null + if (env.modServiceUrl) { + assert( + env.modServiceDid, + 'if mod service url is configured, must configure its did as well.', + ) + modServiceCfg = { + url: env.modServiceUrl, + did: env.modServiceDid, + } + } + + let reportServiceCfg: ServerConfig['reportService'] = null + if (env.reportServiceUrl) { + assert( + env.reportServiceDid, + 'if report service url is configured, must configure its did as well.', + ) + reportServiceCfg = { + url: env.reportServiceUrl, + did: env.reportServiceDid, + } + } + + // if there's a mod service, default report service into it + if (modServiceCfg && !reportServiceCfg) { + reportServiceCfg = modServiceCfg } const redisCfg: ServerConfig['redis'] = env.redisScratchAddress @@ -215,6 +244,7 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { subscription: subscriptionCfg, bskyAppView: bskyAppViewCfg, modService: modServiceCfg, + reportService: reportServiceCfg, redis: redisCfg, rateLimits: rateLimitsCfg, crawlers: crawlersCfg, @@ -232,8 +262,9 @@ export type ServerConfig = { email: EmailConfig | null moderationEmail: EmailConfig | null subscription: SubscriptionConfig - bskyAppView: BksyAppViewConfig - modService: ModServiceConfig + bskyAppView: BksyAppViewConfig | null + modService: ModServiceConfig | null + reportService: ReportServiceConfig | null redis: RedisScratchConfig | null rateLimits: RateLimitsConfig crawlers: string[] @@ -247,6 +278,8 @@ export type ServiceConfig = { version?: string privacyPolicyUrl?: string termsOfServiceUrl?: string + acceptingImports: boolean + blobUploadLimit: number } export type DatabaseConfig = { @@ -342,3 +375,8 @@ export type ModServiceConfig = { url: string did: string } + +export type ReportServiceConfig = { + url: string + did: string +} diff --git a/packages/pds/src/config/env.ts b/packages/pds/src/config/env.ts index cc5f698fa80..fb5aed8232f 100644 --- a/packages/pds/src/config/env.ts +++ b/packages/pds/src/config/env.ts @@ -9,6 +9,8 @@ export const readEnv = (): ServerEnvironment => { version: envStr('PDS_VERSION'), privacyPolicyUrl: envStr('PDS_PRIVACY_POLICY_URL'), termsOfServiceUrl: envStr('PDS_TERMS_OF_SERVICE_URL'), + acceptingImports: envBool('PDS_ACCEPTING_REPO_IMPORTS'), + blobUploadLimit: envInt('PDS_BLOB_UPLOAD_LIMIT'), // database dataDirectory: envStr('PDS_DATA_DIRECTORY'), @@ -75,6 +77,10 @@ export const readEnv = (): ServerEnvironment => { modServiceUrl: envStr('PDS_MOD_SERVICE_URL'), modServiceDid: envStr('PDS_MOD_SERVICE_DID'), + // report service + reportServiceUrl: envStr('PDS_REPORT_SERVICE_URL'), + reportServiceDid: envStr('PDS_REPORT_SERVICE_DID'), + // rate limits rateLimitsEnabled: envBool('PDS_RATE_LIMITS_ENABLED'), rateLimitBypassKey: envStr('PDS_RATE_LIMIT_BYPASS_KEY'), @@ -110,6 +116,8 @@ export type ServerEnvironment = { version?: string privacyPolicyUrl?: string termsOfServiceUrl?: string + acceptingImports?: boolean + blobUploadLimit?: number // database dataDirectory?: string @@ -174,6 +182,10 @@ export type ServerEnvironment = { modServiceUrl?: string modServiceDid?: string + // report service + reportServiceUrl?: string + reportServiceDid?: string + // rate limits rateLimitsEnabled?: boolean rateLimitBypassKey?: string diff --git a/packages/pds/src/context.ts b/packages/pds/src/context.ts index 6a5b2927df1..a9fe996056f 100644 --- a/packages/pds/src/context.ts +++ b/packages/pds/src/context.ts @@ -1,3 +1,4 @@ +import assert from 'node:assert' import * as nodemailer from 'nodemailer' import { Redis } from 'ioredis' import * as plc from '@did-plc/lib' @@ -42,8 +43,9 @@ export type AppContextOptions = { backgroundQueue: BackgroundQueue redisScratch?: Redis crawlers: Crawlers - appViewAgent: AtpAgent - moderationAgent: AtpAgent + appViewAgent?: AtpAgent + moderationAgent?: AtpAgent + reportingAgent?: AtpAgent entrywayAgent?: AtpAgent authVerifier: AuthVerifier plcRotationKey: crypto.Keypair @@ -67,8 +69,9 @@ export class AppContext { public backgroundQueue: BackgroundQueue public redisScratch?: Redis public crawlers: Crawlers - public appViewAgent: AtpAgent - public moderationAgent: AtpAgent + public appViewAgent: AtpAgent | undefined + public moderationAgent: AtpAgent | undefined + public reportingAgent: AtpAgent | undefined public entrywayAgent: AtpAgent | undefined public authVerifier: AuthVerifier public plcRotationKey: crypto.Keypair @@ -90,6 +93,7 @@ export class AppContext { this.crawlers = opts.crawlers this.appViewAgent = opts.appViewAgent this.moderationAgent = opts.moderationAgent + this.reportingAgent = opts.reportingAgent this.entrywayAgent = opts.entrywayAgent this.authVerifier = opts.authVerifier this.plcRotationKey = opts.plcRotationKey @@ -161,9 +165,15 @@ export class AppContext { ? getRedisClient(cfg.redis.address, cfg.redis.password) : undefined - const appViewAgent = new AtpAgent({ service: cfg.bskyAppView.url }) - const moderationAgent = new AtpAgent({ service: cfg.modService.url }) - + const appViewAgent = cfg.bskyAppView + ? new AtpAgent({ service: cfg.bskyAppView.url }) + : undefined + const moderationAgent = cfg.modService + ? new AtpAgent({ service: cfg.modService.url }) + : undefined + const reportingAgent = cfg.reportService + ? new AtpAgent({ service: cfg.reportService.url }) + : undefined const entrywayAgent = cfg.entryway ? new AtpAgent({ service: cfg.entryway.url }) : undefined @@ -189,7 +199,7 @@ export class AppContext { dids: { pds: cfg.service.did, entryway: cfg.entryway?.did, - admin: cfg.modService.did, + admin: cfg.modService?.did, }, }) @@ -211,8 +221,8 @@ export class AppContext { accountManager, appViewAgent, pdsHostname: cfg.service.hostname, - appviewDid: cfg.bskyAppView.did, - appviewCdnUrlPattern: cfg.bskyAppView.cdnUrlPattern, + appviewDid: cfg.bskyAppView?.did, + appviewCdnUrlPattern: cfg.bskyAppView?.cdnUrlPattern, }) return new AppContext({ @@ -231,6 +241,7 @@ export class AppContext { crawlers, appViewAgent, moderationAgent, + reportingAgent, entrywayAgent, authVerifier, plcRotationKey, @@ -240,13 +251,20 @@ export class AppContext { } async appviewAuthHeaders(did: string) { + assert(this.cfg.bskyAppView) return this.serviceAuthHeaders(did, this.cfg.bskyAppView.did) } async moderationAuthHeaders(did: string) { + assert(this.cfg.modService) return this.serviceAuthHeaders(did, this.cfg.modService.did) } + async reportingAuthHeaders(did: string) { + assert(this.cfg.reportService) + return this.serviceAuthHeaders(did, this.cfg.reportService.did) + } + async serviceAuthHeaders(did: string, aud: string) { const keypair = await this.actorStore.keypair(did) return createServiceAuthHeaders({ diff --git a/packages/pds/src/db/util.ts b/packages/pds/src/db/util.ts index 17b84822753..519921c70dc 100644 --- a/packages/pds/src/db/util.ts +++ b/packages/pds/src/db/util.ts @@ -22,6 +22,7 @@ export const softDeleted = (repoOrRecord: { takedownRef: string | null }) => { } export const countAll = sql`count(*)` +export const countDistinct = (ref: DbRef) => sql`count(distinct ${ref})` // For use with doUpdateSet() export const excluded = (db: Kysely, col) => { diff --git a/packages/pds/src/index.ts b/packages/pds/src/index.ts index 77f5948e8aa..ea7c7aa53ee 100644 --- a/packages/pds/src/index.ts +++ b/packages/pds/src/index.ts @@ -63,7 +63,7 @@ export class PDS { payload: { jsonLimit: 100 * 1024, // 100kb textLimit: 100 * 1024, // 100kb - blobLimit: 5 * 1024 * 1024, // 5mb + blobLimit: cfg.service.blobUploadLimit, }, } if (cfg.rateLimits.enabled) { diff --git a/packages/pds/src/lexicon/index.ts b/packages/pds/src/lexicon/index.ts index 0e30f4d172c..cf2c613e686 100644 --- a/packages/pds/src/lexicon/index.ts +++ b/packages/pds/src/lexicon/index.ts @@ -30,9 +30,14 @@ import * as ComAtprotoAdminSearchRepos from './types/com/atproto/admin/searchRep import * as ComAtprotoAdminSendEmail from './types/com/atproto/admin/sendEmail' import * as ComAtprotoAdminUpdateAccountEmail from './types/com/atproto/admin/updateAccountEmail' import * as ComAtprotoAdminUpdateAccountHandle from './types/com/atproto/admin/updateAccountHandle' +import * as ComAtprotoAdminUpdateAccountPassword from './types/com/atproto/admin/updateAccountPassword' import * as ComAtprotoAdminUpdateCommunicationTemplate from './types/com/atproto/admin/updateCommunicationTemplate' import * as ComAtprotoAdminUpdateSubjectStatus from './types/com/atproto/admin/updateSubjectStatus' +import * as ComAtprotoIdentityGetRecommendedDidCredentials from './types/com/atproto/identity/getRecommendedDidCredentials' +import * as ComAtprotoIdentityRequestPlcOperationSignature from './types/com/atproto/identity/requestPlcOperationSignature' import * as ComAtprotoIdentityResolveHandle from './types/com/atproto/identity/resolveHandle' +import * as ComAtprotoIdentitySignPlcOperation from './types/com/atproto/identity/signPlcOperation' +import * as ComAtprotoIdentitySubmitPlcOperation from './types/com/atproto/identity/submitPlcOperation' import * as ComAtprotoIdentityUpdateHandle from './types/com/atproto/identity/updateHandle' import * as ComAtprotoLabelQueryLabels from './types/com/atproto/label/queryLabels' import * as ComAtprotoLabelSubscribeLabels from './types/com/atproto/label/subscribeLabels' @@ -42,19 +47,25 @@ import * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createReco import * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord' import * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo' import * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord' +import * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo' +import * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs' import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords' import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord' import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob' +import * as ComAtprotoServerActivateAccount from './types/com/atproto/server/activateAccount' +import * as ComAtprotoServerCheckAccountStatus from './types/com/atproto/server/checkAccountStatus' import * as ComAtprotoServerConfirmEmail from './types/com/atproto/server/confirmEmail' import * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount' import * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword' import * as ComAtprotoServerCreateInviteCode from './types/com/atproto/server/createInviteCode' import * as ComAtprotoServerCreateInviteCodes from './types/com/atproto/server/createInviteCodes' import * as ComAtprotoServerCreateSession from './types/com/atproto/server/createSession' +import * as ComAtprotoServerDeactivateAccount from './types/com/atproto/server/deactivateAccount' import * as ComAtprotoServerDeleteAccount from './types/com/atproto/server/deleteAccount' import * as ComAtprotoServerDeleteSession from './types/com/atproto/server/deleteSession' import * as ComAtprotoServerDescribeServer from './types/com/atproto/server/describeServer' import * as ComAtprotoServerGetAccountInviteCodes from './types/com/atproto/server/getAccountInviteCodes' +import * as ComAtprotoServerGetServiceAuth from './types/com/atproto/server/getServiceAuth' import * as ComAtprotoServerGetSession from './types/com/atproto/server/getSession' import * as ComAtprotoServerListAppPasswords from './types/com/atproto/server/listAppPasswords' import * as ComAtprotoServerRefreshSession from './types/com/atproto/server/refreshSession' @@ -78,11 +89,9 @@ import * as ComAtprotoSyncListRepos from './types/com/atproto/sync/listRepos' import * as ComAtprotoSyncNotifyOfUpdate from './types/com/atproto/sync/notifyOfUpdate' import * as ComAtprotoSyncRequestCrawl from './types/com/atproto/sync/requestCrawl' import * as ComAtprotoSyncSubscribeRepos from './types/com/atproto/sync/subscribeRepos' +import * as ComAtprotoTempCheckSignupQueue from './types/com/atproto/temp/checkSignupQueue' import * as ComAtprotoTempFetchLabels from './types/com/atproto/temp/fetchLabels' -import * as ComAtprotoTempImportRepo from './types/com/atproto/temp/importRepo' -import * as ComAtprotoTempPushBlob from './types/com/atproto/temp/pushBlob' import * as ComAtprotoTempRequestPhoneVerification from './types/com/atproto/temp/requestPhoneVerification' -import * as ComAtprotoTempTransferAccount from './types/com/atproto/temp/transferAccount' import * as AppBskyActorGetPreferences from './types/app/bsky/actor/getPreferences' import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile' import * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles' @@ -126,7 +135,6 @@ import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/ import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen' import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators' import * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions' -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' @@ -437,6 +445,17 @@ export class ComAtprotoAdminNS { return this._server.xrpc.method(nsid, cfg) } + updateAccountPassword( + cfg: ConfigOf< + AV, + ComAtprotoAdminUpdateAccountPassword.Handler>, + ComAtprotoAdminUpdateAccountPassword.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.admin.updateAccountPassword' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + updateCommunicationTemplate( cfg: ConfigOf< AV, @@ -467,6 +486,32 @@ export class ComAtprotoIdentityNS { this._server = server } + getRecommendedDidCredentials( + cfg: ConfigOf< + AV, + ComAtprotoIdentityGetRecommendedDidCredentials.Handler>, + ComAtprotoIdentityGetRecommendedDidCredentials.HandlerReqCtx< + ExtractAuth + > + >, + ) { + const nsid = 'com.atproto.identity.getRecommendedDidCredentials' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + requestPlcOperationSignature( + cfg: ConfigOf< + AV, + ComAtprotoIdentityRequestPlcOperationSignature.Handler>, + ComAtprotoIdentityRequestPlcOperationSignature.HandlerReqCtx< + ExtractAuth + > + >, + ) { + const nsid = 'com.atproto.identity.requestPlcOperationSignature' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + resolveHandle( cfg: ConfigOf< AV, @@ -478,6 +523,28 @@ export class ComAtprotoIdentityNS { return this._server.xrpc.method(nsid, cfg) } + signPlcOperation( + cfg: ConfigOf< + AV, + ComAtprotoIdentitySignPlcOperation.Handler>, + ComAtprotoIdentitySignPlcOperation.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.identity.signPlcOperation' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + submitPlcOperation( + cfg: ConfigOf< + AV, + ComAtprotoIdentitySubmitPlcOperation.Handler>, + ComAtprotoIdentitySubmitPlcOperation.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.identity.submitPlcOperation' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + updateHandle( cfg: ConfigOf< AV, @@ -601,6 +668,28 @@ export class ComAtprotoRepoNS { return this._server.xrpc.method(nsid, cfg) } + importRepo( + cfg: ConfigOf< + AV, + ComAtprotoRepoImportRepo.Handler>, + ComAtprotoRepoImportRepo.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.repo.importRepo' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + listMissingBlobs( + cfg: ConfigOf< + AV, + ComAtprotoRepoListMissingBlobs.Handler>, + ComAtprotoRepoListMissingBlobs.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.repo.listMissingBlobs' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + listRecords( cfg: ConfigOf< AV, @@ -642,6 +731,28 @@ export class ComAtprotoServerNS { this._server = server } + activateAccount( + cfg: ConfigOf< + AV, + ComAtprotoServerActivateAccount.Handler>, + ComAtprotoServerActivateAccount.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.activateAccount' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + + checkAccountStatus( + cfg: ConfigOf< + AV, + ComAtprotoServerCheckAccountStatus.Handler>, + ComAtprotoServerCheckAccountStatus.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.checkAccountStatus' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + confirmEmail( cfg: ConfigOf< AV, @@ -708,6 +819,17 @@ export class ComAtprotoServerNS { return this._server.xrpc.method(nsid, cfg) } + deactivateAccount( + cfg: ConfigOf< + AV, + ComAtprotoServerDeactivateAccount.Handler>, + ComAtprotoServerDeactivateAccount.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.deactivateAccount' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + deleteAccount( cfg: ConfigOf< AV, @@ -752,6 +874,17 @@ export class ComAtprotoServerNS { return this._server.xrpc.method(nsid, cfg) } + getServiceAuth( + cfg: ConfigOf< + AV, + ComAtprotoServerGetServiceAuth.Handler>, + ComAtprotoServerGetServiceAuth.HandlerReqCtx> + >, + ) { + const nsid = 'com.atproto.server.getServiceAuth' // @ts-ignore + return this._server.xrpc.method(nsid, cfg) + } + getSession( cfg: ConfigOf< AV, @@ -1021,36 +1154,25 @@ export class ComAtprotoTempNS { this._server = server } - fetchLabels( - cfg: ConfigOf< - AV, - ComAtprotoTempFetchLabels.Handler>, - ComAtprotoTempFetchLabels.HandlerReqCtx> - >, - ) { - const nsid = 'com.atproto.temp.fetchLabels' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } - - importRepo( + checkSignupQueue( cfg: ConfigOf< AV, - ComAtprotoTempImportRepo.Handler>, - ComAtprotoTempImportRepo.HandlerReqCtx> + ComAtprotoTempCheckSignupQueue.Handler>, + ComAtprotoTempCheckSignupQueue.HandlerReqCtx> >, ) { - const nsid = 'com.atproto.temp.importRepo' // @ts-ignore + const nsid = 'com.atproto.temp.checkSignupQueue' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - pushBlob( + fetchLabels( cfg: ConfigOf< AV, - ComAtprotoTempPushBlob.Handler>, - ComAtprotoTempPushBlob.HandlerReqCtx> + ComAtprotoTempFetchLabels.Handler>, + ComAtprotoTempFetchLabels.HandlerReqCtx> >, ) { - const nsid = 'com.atproto.temp.pushBlob' // @ts-ignore + const nsid = 'com.atproto.temp.fetchLabels' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } @@ -1064,17 +1186,6 @@ export class ComAtprotoTempNS { const nsid = 'com.atproto.temp.requestPhoneVerification' // @ts-ignore return this._server.xrpc.method(nsid, cfg) } - - transferAccount( - cfg: ConfigOf< - AV, - ComAtprotoTempTransferAccount.Handler>, - ComAtprotoTempTransferAccount.HandlerReqCtx> - >, - ) { - const nsid = 'com.atproto.temp.transferAccount' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } } export class AppNS { @@ -1637,17 +1748,6 @@ export class AppBskyUnspeccedNS { return this._server.xrpc.method(nsid, cfg) } - getTimelineSkeleton( - cfg: ConfigOf< - AV, - AppBskyUnspeccedGetTimelineSkeleton.Handler>, - AppBskyUnspeccedGetTimelineSkeleton.HandlerReqCtx> - >, - ) { - const nsid = 'app.bsky.unspecced.getTimelineSkeleton' // @ts-ignore - return this._server.xrpc.method(nsid, cfg) - } - searchActorsSkeleton( cfg: ConfigOf< AV, diff --git a/packages/pds/src/lexicon/lexicons.ts b/packages/pds/src/lexicon/lexicons.ts index fea624e9a04..14e4c1cb81e 100644 --- a/packages/pds/src/lexicon/lexicons.ts +++ b/packages/pds/src/lexicon/lexicons.ts @@ -91,6 +91,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, subject: { @@ -147,6 +148,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventAcknowledge', 'lex:com.atproto.admin.defs#modEventEscalate', 'lex:com.atproto.admin.defs#modEventMute', + 'lex:com.atproto.admin.defs#modEventEmail', 'lex:com.atproto.admin.defs#modEventResolveAppeal', ], }, @@ -301,6 +303,12 @@ export const schemaDict = { type: 'string', format: 'datetime', }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, }, }, reportViewDetail: { @@ -895,6 +903,33 @@ export const schemaDict = { }, }, }, + modEventTag: { + type: 'object', + description: 'Add/Remove a tag on a subject', + required: ['add', 'remove'], + properties: { + add: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be added to the subject. If already exists, won't be duplicated.", + }, + remove: { + type: 'array', + items: { + type: 'string', + }, + description: + "Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated.", + }, + comment: { + type: 'string', + description: 'Additional comment about added/removed tags.', + }, + }, + }, communicationTemplateView: { type: 'object', required: [ @@ -1073,6 +1108,7 @@ export const schemaDict = { 'lex:com.atproto.admin.defs#modEventReverseTakedown', 'lex:com.atproto.admin.defs#modEventUnmute', 'lex:com.atproto.admin.defs#modEventEmail', + 'lex:com.atproto.admin.defs#modEventTag', ], }, subject: { @@ -1450,6 +1486,16 @@ export const schemaDict = { description: 'Sort direction for the events. Defaults to descending order of created at timestamp.', }, + createdAfter: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created after a given timestamp', + }, + createdBefore: { + type: 'string', + format: 'datetime', + description: 'Retrieve events created before a given timestamp', + }, subject: { type: 'string', format: 'uri', @@ -1466,6 +1512,53 @@ export const schemaDict = { maximum: 100, default: 50, }, + hasComment: { + type: 'boolean', + description: 'If true, only events with comments are returned', + }, + comment: { + type: 'string', + description: + 'If specified, only events with comments containing the keyword are returned', + }, + addedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were added are returned', + }, + removedLabels: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these labels were removed are returned', + }, + addedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were added are returned', + }, + removedTags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'If specified, only events where all of these tags were removed are returned', + }, + reportTypes: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1577,6 +1670,18 @@ export const schemaDict = { maximum: 100, default: 50, }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, + excludeTags: { + type: 'array', + items: { + type: 'string', + }, + }, cursor: { type: 'string', }, @@ -1758,6 +1863,33 @@ export const schemaDict = { }, }, }, + ComAtprotoAdminUpdateAccountPassword: { + lexicon: 1, + id: 'com.atproto.admin.updateAccountPassword', + defs: { + main: { + type: 'procedure', + description: + 'Update the password for a user account as an administrator.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['did', 'password'], + properties: { + did: { + type: 'string', + format: 'did', + }, + password: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoAdminUpdateCommunicationTemplate: { lexicon: 1, id: 'com.atproto.admin.updateCommunicationTemplate', @@ -1863,13 +1995,63 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentityGetRecommendedDidCredentials: { + lexicon: 1, + id: 'com.atproto.identity.getRecommendedDidCredentials', + defs: { + main: { + type: 'query', + description: + 'Describe the credentials that should be included in the DID doc of an account that is migrating to this service.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + rotationKeys: { + description: + 'Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs.', + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentityRequestPlcOperationSignature: { + lexicon: 1, + id: 'com.atproto.identity.requestPlcOperationSignature', + defs: { + main: { + type: 'procedure', + description: + 'Request an email with a code to in order to request a signed PLC operation. Requires Auth.', + }, + }, + }, ComAtprotoIdentityResolveHandle: { lexicon: 1, id: 'com.atproto.identity.resolveHandle', defs: { main: { type: 'query', - description: 'Provides the DID of a repo.', + description: 'Resolves a handle (domain name) to a DID.', parameters: { type: 'params', required: ['handle'], @@ -1897,13 +2079,92 @@ export const schemaDict = { }, }, }, + ComAtprotoIdentitySignPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.signPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Signs a PLC operation to update some value(s) in the requesting DID's document.", + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + token: { + description: + 'A token received through com.atproto.identity.requestPlcOperationSignature', + type: 'string', + }, + rotationKeys: { + type: 'array', + items: { + type: 'string', + }, + }, + alsoKnownAs: { + type: 'array', + items: { + type: 'string', + }, + }, + verificationMethods: { + type: 'unknown', + }, + services: { + type: 'unknown', + }, + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + description: 'A signed DID PLC operation.', + }, + }, + }, + }, + }, + }, + }, + ComAtprotoIdentitySubmitPlcOperation: { + lexicon: 1, + id: 'com.atproto.identity.submitPlcOperation', + defs: { + main: { + type: 'procedure', + description: + "Validates a PLC operation to ensure that it doesn't violate a service's constraints or get the identity into a bad state, then submits it to the PLC registry", + input: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['operation'], + properties: { + operation: { + type: 'unknown', + }, + }, + }, + }, + }, + }, + }, ComAtprotoIdentityUpdateHandle: { lexicon: 1, id: 'com.atproto.identity.updateHandle', defs: { main: { type: 'procedure', - description: 'Updates the handle of the account.', + description: + "Updates the current account's handle. Verifies handle validity, and updates did:plc document if necessary. Implemented by PDS, and requires auth.", input: { encoding: 'application/json', schema: { @@ -1913,6 +2174,7 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'The new handle.', }, }, }, @@ -2003,7 +2265,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find labels relevant to the provided URI patterns.', + description: + 'Find labels relevant to the provided AT-URI patterns. Public endpoint for moderation services, though may return different or additional results with auth.', parameters: { type: 'params', required: ['uriPatterns'], @@ -2064,13 +2327,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to label updates.', + description: + 'Subscribe to stream of labels (and negations). Public endpoint implemented by mod services. Uses same sequencing scheme as repo event stream.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -2126,7 +2390,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Report a repo or a record.', + description: + 'Submit a moderation report regarding an atproto account or record. Implemented by moderation services (with PDS proxying), and requires auth.', input: { encoding: 'application/json', schema: { @@ -2135,10 +2400,14 @@ export const schemaDict = { properties: { reasonType: { type: 'ref', + description: + 'Indicates the broad category of violation the report is for.', ref: 'lex:com.atproto.moderation.defs#reasonType', }, reason: { type: 'string', + description: + 'Additional context about the content and violation.', }, subject: { type: 'union', @@ -2249,7 +2518,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Apply a batch transaction of creates, updates, and deletes.', + 'Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2259,12 +2528,14 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the records.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data, for all operations.", }, writes: { type: 'array', @@ -2280,6 +2551,8 @@ export const schemaDict = { }, swapCommit: { type: 'string', + description: + 'If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.', format: 'cid', }, }, @@ -2288,12 +2561,14 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that the 'swapCommit' parameter did not match current commit.", }, ], }, create: { type: 'object', - description: 'Create a new record.', + description: 'Operation which creates a new record.', required: ['collection', 'value'], properties: { collection: { @@ -2311,7 +2586,7 @@ export const schemaDict = { }, update: { type: 'object', - description: 'Update an existing record.', + description: 'Operation which updates an existing record.', required: ['collection', 'rkey', 'value'], properties: { collection: { @@ -2328,7 +2603,7 @@ export const schemaDict = { }, delete: { type: 'object', - description: 'Delete an existing record.', + description: 'Operation which deletes an existing record.', required: ['collection', 'rkey'], properties: { collection: { @@ -2348,7 +2623,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create a new record.', + description: + 'Create a single new repository record. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2358,7 +2634,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2367,17 +2644,18 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', - description: 'The record to create.', + description: 'The record itself. Must contain a $type field.', }, swapCommit: { type: 'string', @@ -2408,6 +2686,8 @@ export const schemaDict = { errors: [ { name: 'InvalidSwap', + description: + "Indicates that 'swapCommit' didn't match current repo commit.", }, ], }, @@ -2419,7 +2699,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete a record, or ensure it doesn't exist.", + description: + "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", input: { encoding: 'application/json', schema: { @@ -2429,7 +2710,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2438,7 +2720,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, swapRecord: { type: 'string', @@ -2470,7 +2752,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about the repo, including the list of collections.', + 'Get information about an account and repository, including the list of collections. Does not require auth.', parameters: { type: 'params', required: ['repo'], @@ -2504,9 +2786,12 @@ export const schemaDict = { }, didDoc: { type: 'unknown', + description: 'The complete DID document for this account.', }, collections: { type: 'array', + description: + 'List of all the collections (NSIDs) for which this repo contains at least one record.', items: { type: 'string', format: 'nsid', @@ -2514,6 +2799,8 @@ export const schemaDict = { }, handleIsCorrect: { type: 'boolean', + description: + 'Indicates if handle is currently valid (resolves bi-directionally)', }, }, }, @@ -2527,7 +2814,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a record.', + description: + 'Get a single record from a repository. Does not require auth.', parameters: { type: 'params', required: ['repo', 'collection', 'rkey'], @@ -2544,7 +2832,7 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', }, cid: { type: 'string', @@ -2577,39 +2865,112 @@ export const schemaDict = { }, }, }, - ComAtprotoRepoListRecords: { + ComAtprotoRepoImportRepo: { lexicon: 1, - id: 'com.atproto.repo.listRecords', + id: 'com.atproto.repo.importRepo', + defs: { + main: { + type: 'procedure', + description: + 'Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.', + input: { + encoding: 'application/vnd.ipld.car', + }, + }, + }, + }, + ComAtprotoRepoListMissingBlobs: { + lexicon: 1, + id: 'com.atproto.repo.listMissingBlobs', defs: { main: { type: 'query', - description: 'List a range of records in a collection.', + description: + 'Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.', parameters: { type: 'params', - required: ['repo', 'collection'], properties: { - repo: { - type: 'string', - format: 'at-identifier', - description: 'The handle or DID of the repo.', - }, - collection: { - type: 'string', - format: 'nsid', - description: 'The NSID of the record type.', - }, limit: { type: 'integer', minimum: 1, - maximum: 100, - default: 50, - description: 'The number of records to return.', + maximum: 1000, + default: 500, }, cursor: { type: 'string', }, - rkeyStart: { - type: 'string', + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['blobs'], + properties: { + cursor: { + type: 'string', + }, + blobs: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.repo.listMissingBlobs#recordBlob', + }, + }, + }, + }, + }, + }, + recordBlob: { + type: 'object', + required: ['cid', 'recordUri'], + properties: { + cid: { + type: 'string', + format: 'cid', + }, + recordUri: { + type: 'string', + format: 'at-uri', + }, + }, + }, + }, + }, + ComAtprotoRepoListRecords: { + lexicon: 1, + id: 'com.atproto.repo.listRecords', + defs: { + main: { + type: 'query', + description: + 'List a range of records in a repository, matching a specific collection. Does not require auth.', + parameters: { + type: 'params', + required: ['repo', 'collection'], + properties: { + repo: { + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', + }, + collection: { + type: 'string', + format: 'nsid', + description: 'The NSID of the record type.', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 100, + default: 50, + description: 'The number of records to return.', + }, + cursor: { + type: 'string', + }, + rkeyStart: { + type: 'string', description: 'DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)', }, @@ -2669,7 +3030,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Write a record, creating or updating it as needed.', + description: + 'Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2680,7 +3042,8 @@ export const schemaDict = { repo: { type: 'string', format: 'at-identifier', - description: 'The handle or DID of the repo.', + description: + 'The handle or DID of the repo (aka, current account).', }, collection: { type: 'string', @@ -2689,13 +3052,14 @@ export const schemaDict = { }, rkey: { type: 'string', - description: 'The key of the record.', + description: 'The Record Key.', maxLength: 15, }, validate: { type: 'boolean', default: true, - description: 'Flag for validating the record.', + description: + "Can be set to 'false' to skip Lexicon schema validation of record data.", }, record: { type: 'unknown', @@ -2705,7 +3069,7 @@ export const schemaDict = { type: 'string', format: 'cid', description: - 'Compare and swap with the previous record by CID.', + 'Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation', }, swapCommit: { type: 'string', @@ -2769,7 +3133,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Upload a new blob to be added to repo in a later request.', + 'Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.', input: { encoding: '*/*', }, @@ -2788,6 +3152,75 @@ export const schemaDict = { }, }, }, + ComAtprotoServerActivateAccount: { + lexicon: 1, + id: 'com.atproto.server.activateAccount', + defs: { + main: { + type: 'procedure', + description: + "Activates a currently deactivated account. Used to finalize account migration after the account's repo is imported and identity is setup.", + }, + }, + }, + ComAtprotoServerCheckAccountStatus: { + lexicon: 1, + id: 'com.atproto.server.checkAccountStatus', + defs: { + main: { + type: 'query', + description: + 'Returns the status of an account, especially as pertaining to import or recovery. Can be called many times over the course of an account migration. Requires auth and can only be called pertaining to oneself.', + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: [ + 'activated', + 'validDid', + 'repoCommit', + 'repoRev', + 'repoBlocks', + 'indexedRecords', + 'privateStateValues', + 'expectedBlobs', + 'importedBlobs', + ], + properties: { + activated: { + type: 'boolean', + }, + validDid: { + type: 'boolean', + }, + repoCommit: { + type: 'string', + format: 'cid', + }, + repoRev: { + type: 'string', + }, + repoBlocks: { + type: 'integer', + }, + indexedRecords: { + type: 'integer', + }, + privateStateValues: { + type: 'integer', + }, + expectedBlobs: { + type: 'integer', + }, + importedBlobs: { + type: 'integer', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerConfirmEmail: { lexicon: 1, id: 'com.atproto.server.confirmEmail', @@ -2834,7 +3267,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Create an account.', + description: 'Create an account. Implemented by PDS.', input: { encoding: 'application/json', schema: { @@ -2847,10 +3280,13 @@ export const schemaDict = { handle: { type: 'string', format: 'handle', + description: 'Requested handle for the account.', }, did: { type: 'string', format: 'did', + description: + 'Pre-existing atproto DID, being imported to a new account.', }, inviteCode: { type: 'string', @@ -2863,12 +3299,18 @@ export const schemaDict = { }, password: { type: 'string', + description: + 'Initial account password. May need to meet instance-specific password strength requirements.', }, recoveryKey: { type: 'string', + description: + 'DID PLC rotation key (aka, recovery key) to be included in PLC creation operation.', }, plcOp: { type: 'unknown', + description: + 'A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented.', }, }, }, @@ -2877,6 +3319,8 @@ export const schemaDict = { encoding: 'application/json', schema: { type: 'object', + description: + 'Account login session returned on successful account creation.', required: ['accessJwt', 'refreshJwt', 'handle', 'did'], properties: { accessJwt: { @@ -2892,9 +3336,11 @@ export const schemaDict = { did: { type: 'string', format: 'did', + description: 'The DID of the new account.', }, didDoc: { type: 'unknown', + description: 'Complete DID document.', }, }, }, @@ -2940,6 +3386,8 @@ export const schemaDict = { properties: { name: { type: 'string', + description: + 'A short name for the App Password, to help distinguish them.', }, }, }, @@ -3141,6 +3589,31 @@ export const schemaDict = { }, }, }, + ComAtprotoServerDeactivateAccount: { + lexicon: 1, + id: 'com.atproto.server.deactivateAccount', + defs: { + main: { + type: 'procedure', + description: + 'Deactivates a currently active account. Stops serving of repo, and future writes to repo until reactivated. Used to finalize account migration with the old host after the account has been activated on the new host.', + input: { + encoding: 'application/json', + schema: { + type: 'object', + properties: { + deleteAfter: { + type: 'string', + format: 'datetime', + description: + 'A recommendation to server as to how long they should hold onto the deactivated account before deleting.', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerDefs: { lexicon: 1, id: 'com.atproto.server.defs', @@ -3207,7 +3680,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: "Delete an actor's account with a token and password.", + description: + "Delete an actor's account with a token and password. Can only be called after requesting a deletion token. Requires auth.", input: { encoding: 'application/json', schema: { @@ -3244,7 +3718,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Delete the current session.', + description: 'Delete the current session. Requires auth.', }, }, }, @@ -3255,29 +3729,40 @@ export const schemaDict = { main: { type: 'query', description: - "Get a document describing the service's accounts configuration.", + "Describes the server's account creation requirements and capabilities. Implemented by PDS.", output: { encoding: 'application/json', schema: { type: 'object', - required: ['availableUserDomains'], + required: ['did', 'availableUserDomains'], properties: { inviteCodeRequired: { type: 'boolean', + description: + 'If true, an invite code must be supplied to create an account on this instance.', }, phoneVerificationRequired: { type: 'boolean', + description: + 'If true, a phone verification token must be supplied to create an account on this instance.', }, availableUserDomains: { type: 'array', + description: + 'List of domain suffixes that can be used in account handles.', items: { type: 'string', }, }, links: { type: 'ref', + description: 'URLs of service policy documents.', ref: 'lex:com.atproto.server.describeServer#links', }, + did: { + type: 'string', + format: 'did', + }, }, }, }, @@ -3301,7 +3786,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get all invite codes for a given account.', + description: + 'Get all invite codes for the current account. Requires auth.', parameters: { type: 'params', properties: { @@ -3312,6 +3798,8 @@ export const schemaDict = { createAvailable: { type: 'boolean', default: true, + description: + "Controls whether any new 'earned' but not 'created' invites should be created.", }, }, }, @@ -3339,13 +3827,49 @@ export const schemaDict = { }, }, }, + ComAtprotoServerGetServiceAuth: { + lexicon: 1, + id: 'com.atproto.server.getServiceAuth', + defs: { + main: { + type: 'query', + description: + 'Get a signed token on behalf of the requesting DID for the requested service.', + parameters: { + type: 'params', + required: ['aud'], + properties: { + aud: { + type: 'string', + format: 'did', + description: + 'The DID of the service that the token will be used to authenticate with', + }, + }, + }, + output: { + encoding: 'application/json', + schema: { + type: 'object', + required: ['token'], + properties: { + token: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, ComAtprotoServerGetSession: { lexicon: 1, id: 'com.atproto.server.getSession', defs: { main: { type: 'query', - description: 'Get information about the current session.', + description: + 'Get information about the current auth session. Requires auth.', output: { encoding: 'application/json', schema: { @@ -3425,7 +3949,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Refresh an authentication session.', + description: + "Refresh an authentication session. Requires auth using the 'refreshJwt' (not the 'accessJwt').", output: { encoding: 'application/json', schema: { @@ -3531,7 +4056,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Reserve a repo signing key for account creation.', + description: + 'Reserve a repo signing key, for use with account creation. Necessary so that a DID PLC update operation can be constructed during an account migraiton. Public and does not require auth; implemented by PDS. NOTE: this endpoint may change when full account migration is implemented.', input: { encoding: 'application/json', schema: { @@ -3539,7 +4065,8 @@ export const schemaDict = { properties: { did: { type: 'string', - description: 'The did to reserve a new did:key for', + format: 'did', + description: 'The DID to reserve a key for.', }, }, }, @@ -3552,7 +4079,8 @@ export const schemaDict = { properties: { signingKey: { type: 'string', - description: 'Public signing key in the form of a did:key.', + description: + 'The public key for the reserved signing key, in did:key serialization.', }, }, }, @@ -3659,7 +4187,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a blob associated with a given repo.', + description: + 'Get a blob associated with a given account. Returns the full blob as originally uploaded. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cid'], @@ -3667,7 +4196,7 @@ export const schemaDict = { did: { type: 'string', format: 'did', - description: 'The DID of the repo.', + description: 'The DID of the account.', }, cid: { type: 'string', @@ -3688,7 +4217,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get blocks from a given repo.', + description: + 'Get data blocks from a given repo, by CID. For example, intermediate MST nodes, or records. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did', 'cids'], @@ -3783,7 +4313,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the current commit CID & revision of the repo.', + description: + 'Get the current commit CID & revision of the specified repo. Does not require auth.', parameters: { type: 'params', required: ['did'], @@ -3826,7 +4357,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get blocks needed for existence or non-existence of record.', + 'Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.', parameters: { type: 'params', required: ['did', 'collection', 'rkey'], @@ -3842,6 +4373,7 @@ export const schemaDict = { }, rkey: { type: 'string', + description: 'Record Key', }, commit: { type: 'string', @@ -3863,7 +4395,7 @@ export const schemaDict = { main: { type: 'query', description: - "Gets the DID's repo, optionally catching up from a specific revision.", + "Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS.", parameters: { type: 'params', required: ['did'], @@ -3875,7 +4407,8 @@ export const schemaDict = { }, since: { type: 'string', - description: 'The revision of the repo to catch up from.', + description: + "The revision ('rev') of the repo to create a diff from.", }, }, }, @@ -3891,7 +4424,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List blob CIDs since some revision.', + description: + 'List blob CIDso for an account, since some repo revision. Does not require auth; implemented by PDS.', parameters: { type: 'params', required: ['did'], @@ -3944,7 +4478,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'List DIDs and root CIDs of hosted repos.', + description: + 'Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { @@ -3990,6 +4525,7 @@ export const schemaDict = { head: { type: 'string', format: 'cid', + description: 'Current repo commit CID', }, rev: { type: 'string', @@ -4005,7 +4541,7 @@ export const schemaDict = { main: { type: 'procedure', description: - 'Notify a crawling service of a recent update; often when a long break between updates causes the connection with the crawling service to break.', + 'Notify a crawling service of a recent update, and that crawling should resume. Intended use is after a gap between repo stream events caused the crawling service to disconnect. Does not require auth; implemented by Relay.', input: { encoding: 'application/json', schema: { @@ -4015,7 +4551,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is notifying of update.', + 'Hostname of the current service (usually a PDS) that is notifying of update.', }, }, }, @@ -4029,7 +4565,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Request a service to persistently crawl hosted repos.', + description: + 'Request a service to persistently crawl hosted repos. Expected use is new PDS instances declaring their existence to Relays. Does not require auth.', input: { encoding: 'application/json', schema: { @@ -4039,7 +4576,7 @@ export const schemaDict = { hostname: { type: 'string', description: - 'Hostname of the service that is requesting to be crawled.', + 'Hostname of the current service (eg, PDS) that is requesting to be crawled.', }, }, }, @@ -4053,13 +4590,14 @@ export const schemaDict = { defs: { main: { type: 'subscription', - description: 'Subscribe to repo updates.', + description: + 'Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.', parameters: { type: 'params', properties: { cursor: { type: 'integer', - description: 'The last known event to backfill from.', + description: 'The last known event seq number to backfill from.', }, }, }, @@ -4068,6 +4606,7 @@ export const schemaDict = { type: 'union', refs: [ 'lex:com.atproto.sync.subscribeRepos#commit', + 'lex:com.atproto.sync.subscribeRepos#identity', 'lex:com.atproto.sync.subscribeRepos#handle', 'lex:com.atproto.sync.subscribeRepos#migrate', 'lex:com.atproto.sync.subscribeRepos#tombstone', @@ -4081,11 +4620,15 @@ export const schemaDict = { }, { name: 'ConsumerTooSlow', + description: + 'If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection.', }, ], }, commit: { type: 'object', + description: + 'Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.', required: [ 'seq', 'rebase', @@ -4103,34 +4646,45 @@ export const schemaDict = { properties: { seq: { type: 'integer', + description: 'The stream sequence number of this message.', }, rebase: { type: 'boolean', + description: 'DEPRECATED -- unused', }, tooBig: { type: 'boolean', + description: + 'Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data.', }, repo: { type: 'string', format: 'did', + description: 'The repo this event comes from.', }, commit: { type: 'cid-link', + description: 'Repo commit object CID.', }, prev: { type: 'cid-link', + description: + 'DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability.', }, rev: { type: 'string', - description: 'The rev of the emitted commit.', + description: + 'The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event.', }, since: { type: 'string', - description: 'The rev of the last emitted commit from this repo.', + description: + 'The rev of the last emitted commit from this repo (if any).', }, blocks: { type: 'bytes', - description: 'CAR file containing relevant blocks.', + description: + 'CAR file containing relevant blocks, as a diff since the previous repo state.', maxLength: 1000000, }, ops: { @@ -4138,6 +4692,8 @@ export const schemaDict = { items: { type: 'ref', ref: 'lex:com.atproto.sync.subscribeRepos#repoOp', + description: + 'List of repo mutation operations in this commit (eg, records created, updated, or deleted).', }, maxLength: 200, }, @@ -4145,8 +4701,31 @@ export const schemaDict = { type: 'array', items: { type: 'cid-link', + description: + 'List of new blobs (by CID) referenced by records in this commit.', }, }, + time: { + type: 'string', + format: 'datetime', + description: + 'Timestamp of when this message was originally broadcast.', + }, + }, + }, + identity: { + type: 'object', + description: + "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.", + required: ['seq', 'did', 'time'], + properties: { + seq: { + type: 'integer', + }, + did: { + type: 'string', + format: 'did', + }, time: { type: 'string', format: 'datetime', @@ -4155,6 +4734,8 @@ export const schemaDict = { }, handle: { type: 'object', + description: + "Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity.", required: ['seq', 'did', 'handle', 'time'], properties: { seq: { @@ -4176,6 +4757,8 @@ export const schemaDict = { }, migrate: { type: 'object', + description: + 'Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead', required: ['seq', 'did', 'migrateTo', 'time'], nullable: ['migrateTo'], properties: { @@ -4197,6 +4780,8 @@ export const schemaDict = { }, tombstone: { type: 'object', + description: + 'Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event', required: ['seq', 'did', 'time'], properties: { seq: { @@ -4227,8 +4812,7 @@ export const schemaDict = { }, repoOp: { type: 'object', - description: - "A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null.", + description: 'A repo operation, ie a mutation of a single record.', required: ['action', 'path', 'cid'], nullable: ['cid'], properties: { @@ -4241,45 +4825,34 @@ export const schemaDict = { }, cid: { type: 'cid-link', + description: + 'For creates and updates, the new record CID. For deletions, null.', }, }, }, }, }, - ComAtprotoTempFetchLabels: { + ComAtprotoTempCheckSignupQueue: { lexicon: 1, - id: 'com.atproto.temp.fetchLabels', + id: 'com.atproto.temp.checkSignupQueue', defs: { main: { type: 'query', - description: - 'Fetch all labels from a labeler created after a certain date.', - parameters: { - type: 'params', - properties: { - since: { - type: 'integer', - }, - limit: { - type: 'integer', - minimum: 1, - maximum: 250, - default: 50, - }, - }, - }, + description: 'Check accounts location in signup queue.', output: { encoding: 'application/json', schema: { type: 'object', - required: ['labels'], + required: ['activated'], properties: { - labels: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:com.atproto.label.defs#label', - }, + activated: { + type: 'boolean', + }, + placeInQueue: { + type: 'integer', + }, + estimatedTimeMs: { + type: 'integer', }, }, }, @@ -4287,75 +4860,40 @@ export const schemaDict = { }, }, }, - ComAtprotoTempImportRepo: { - lexicon: 1, - id: 'com.atproto.temp.importRepo', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: 'application/vnd.ipld.car', - }, - output: { - encoding: 'text/plain', - }, - }, - }, - }, - ComAtprotoTempPushBlob: { - lexicon: 1, - id: 'com.atproto.temp.pushBlob', - defs: { - main: { - type: 'procedure', - description: - "Gets the did's repo, optionally catching up from a specific revision.", - parameters: { - type: 'params', - required: ['did'], - properties: { - did: { - type: 'string', - format: 'did', - description: 'The DID of the repo.', - }, - }, - }, - input: { - encoding: '*/*', - }, - }, - }, - }, - ComAtprotoTempRequestPhoneVerification: { + ComAtprotoTempFetchLabels: { lexicon: 1, - id: 'com.atproto.temp.requestPhoneVerification', + id: 'com.atproto.temp.fetchLabels', defs: { main: { - type: 'procedure', + type: 'query', description: - 'Request a verification code to be sent to the supplied phone number', - input: { + 'DEPRECATED: use queryLabels or subscribeLabels instead -- Fetch all labels from a labeler created after a certain date.', + parameters: { + type: 'params', + properties: { + since: { + type: 'integer', + }, + limit: { + type: 'integer', + minimum: 1, + maximum: 250, + default: 50, + }, + }, + }, + output: { encoding: 'application/json', schema: { type: 'object', - required: ['phoneNumber'], + required: ['labels'], properties: { - phoneNumber: { - type: 'string', + labels: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.label.defs#label', + }, }, }, }, @@ -4363,86 +4901,32 @@ export const schemaDict = { }, }, }, - ComAtprotoTempTransferAccount: { + ComAtprotoTempRequestPhoneVerification: { lexicon: 1, - id: 'com.atproto.temp.transferAccount', + id: 'com.atproto.temp.requestPhoneVerification', defs: { main: { type: 'procedure', - description: 'Transfer an account.', + description: + 'Request a verification code to be sent to the supplied phone number', input: { encoding: 'application/json', schema: { type: 'object', - required: ['handle', 'did', 'plcOp'], - properties: { - handle: { - type: 'string', - format: 'handle', - }, - did: { - type: 'string', - format: 'did', - }, - plcOp: { - type: 'unknown', - }, - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['accessJwt', 'refreshJwt', 'handle', 'did'], + required: ['phoneNumber'], properties: { - accessJwt: { - type: 'string', - }, - refreshJwt: { - type: 'string', - }, - handle: { - type: 'string', - format: 'handle', - }, - did: { + phoneNumber: { type: 'string', - format: 'did', }, }, }, }, - errors: [ - { - name: 'InvalidHandle', - }, - { - name: 'InvalidPassword', - }, - { - name: 'InvalidInviteCode', - }, - { - name: 'HandleNotAvailable', - }, - { - name: 'UnsupportedDomain', - }, - { - name: 'UnresolvableDid', - }, - { - name: 'IncompatibleDidDoc', - }, - ], }, }, }, AppBskyActorDefs: { lexicon: 1, id: 'app.bsky.actor.defs', - description: 'A reference to an actor in the network.', defs: { profileViewBasic: { type: 'object', @@ -4575,6 +5059,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests.", properties: { muted: { type: 'boolean', @@ -4615,6 +5101,9 @@ export const schemaDict = { 'lex:app.bsky.actor.defs#personalDetailsPref', 'lex:app.bsky.actor.defs#feedViewPref', 'lex:app.bsky.actor.defs#threadViewPref', + 'lex:app.bsky.actor.defs#interestsPref', + 'lex:app.bsky.actor.defs#mutedWordsPref', + 'lex:app.bsky.actor.defs#hiddenPostsPref', ], }, }, @@ -4659,6 +5148,9 @@ export const schemaDict = { format: 'at-uri', }, }, + timelineIndex: { + type: 'integer', + }, }, }, personalDetailsPref: { @@ -4718,6 +5210,79 @@ export const schemaDict = { }, }, }, + interestsPref: { + type: 'object', + required: ['tags'], + properties: { + tags: { + type: 'array', + maxLength: 100, + items: { + type: 'string', + maxLength: 640, + maxGraphemes: 64, + }, + description: + "A list of tags which describe the account owner's interests gathered during onboarding.", + }, + }, + }, + mutedWordTarget: { + type: 'string', + knownValues: ['content', 'tag'], + maxLength: 640, + maxGraphemes: 64, + }, + mutedWord: { + type: 'object', + description: 'A word that the account owner has muted.', + required: ['value', 'targets'], + properties: { + value: { + type: 'string', + description: 'The muted word itself.', + maxLength: 10000, + maxGraphemes: 1000, + }, + targets: { + type: 'array', + description: 'The intended targets of the muted word.', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWordTarget', + }, + }, + }, + }, + mutedWordsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'ref', + ref: 'lex:app.bsky.actor.defs#mutedWord', + }, + description: 'A list of words the account owner has muted.', + }, + }, + }, + hiddenPostsPref: { + type: 'object', + required: ['items'], + properties: { + items: { + type: 'array', + items: { + type: 'string', + format: 'at-uri', + }, + description: + 'A list of URIs of posts the account owner has hidden.', + }, + }, + }, }, }, AppBskyActorGetPreferences: { @@ -4726,7 +5291,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get private preferences attached to the account.', + description: + 'Get private preferences attached to the current account. Expected use is synchronization between multiple devices, and import/export during account migration. Requires auth.', parameters: { type: 'params', properties: {}, @@ -4753,7 +5319,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get detailed profile view of an actor.', + description: + 'Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.', parameters: { type: 'params', required: ['actor'], @@ -4761,6 +5328,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Handle or DID of account to fetch profile of.', }, }, }, @@ -4820,7 +5388,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested actors, used for discovery.', + description: + 'Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding.', parameters: { type: 'params', properties: { @@ -4863,7 +5432,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a profile.', + description: 'A declaration of a Bluesky account profile.', key: 'literal:self', record: { type: 'object', @@ -4875,21 +5444,28 @@ export const schemaDict = { }, description: { type: 'string', + description: 'Free-form profile description text.', maxGraphemes: 256, maxLength: 2560, }, avatar: { type: 'blob', + description: + "Small image to be displayed next to posts from account. AKA, 'profile picture'", accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, banner: { type: 'blob', + description: + 'Larger horizontal image to display behind profile view.', accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, labels: { type: 'union', + description: + 'Self-label values, specific to the Bluesky application, on the overall account.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, }, @@ -4926,7 +5502,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actors (profiles) matching search criteria.', + description: + 'Find actors (profiles) matching search criteria. Does not require auth.', parameters: { type: 'params', properties: { @@ -4978,7 +5555,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find actor suggestions for a prefix search term.', + description: + 'Find actor suggestions for a prefix search term. Expected use is for auto-completion during text field entry. Does not require auth.', parameters: { type: 'params', properties: { @@ -5020,11 +5598,11 @@ export const schemaDict = { AppBskyEmbedExternal: { lexicon: 1, id: 'app.bsky.embed.external', - description: - 'A representation of some externally linked content, embedded in another form of content.', defs: { main: { type: 'object', + description: + "A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post).", required: ['external'], properties: { external: { @@ -5088,7 +5666,7 @@ export const schemaDict = { AppBskyEmbedImages: { lexicon: 1, id: 'app.bsky.embed.images', - description: 'A set of images embedded in some other form of content.', + description: 'A set of images embedded in a Bluesky record (eg, a post).', defs: { main: { type: 'object', @@ -5115,6 +5693,8 @@ export const schemaDict = { }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5158,12 +5738,18 @@ export const schemaDict = { properties: { thumb: { type: 'string', + description: + 'Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View.', }, fullsize: { type: 'string', + description: + 'Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View.', }, alt: { type: 'string', + description: + 'Alt text description of the image, for accessibility.', }, aspectRatio: { type: 'ref', @@ -5177,7 +5763,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.record', description: - 'A representation of a record embedded in another form of content.', + 'A representation of a record embedded in a Bluesky record (eg, a post). For example, a quote-post, or sharing a feed generator record.', defs: { main: { type: 'object', @@ -5223,6 +5809,7 @@ export const schemaDict = { }, value: { type: 'unknown', + description: 'The record data itself.', }, labels: { type: 'array', @@ -5287,7 +5874,7 @@ export const schemaDict = { lexicon: 1, id: 'app.bsky.embed.recordWithMedia', description: - 'A representation of a record embedded in another form of content, alongside other compatible embeds.', + 'A representation of a record embedded in a Bluesky record (eg, a post), alongside other compatible embeds. For example, a quote post and image, or a quote post and external URL card.', defs: { main: { type: 'object', @@ -5386,6 +5973,8 @@ export const schemaDict = { }, viewerState: { type: 'object', + description: + "Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests.", properties: { repost: { type: 'string', @@ -5646,7 +6235,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Get information about a feed generator, including policies and offered feed URIs.', + 'Get information about a feed generator, including policies and offered feed URIs. Does not require auth; implemented by Feed Generator services (not App View).', output: { encoding: 'application/json', schema: { @@ -5701,7 +6290,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of the existence of a feed generator.', + description: + 'Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.', key: 'any', record: { type: 'object', @@ -5735,6 +6325,7 @@ export const schemaDict = { }, labels: { type: 'union', + description: 'Self-label values', refs: ['lex:com.atproto.label.defs#selfLabels'], }, createdAt: { @@ -5752,7 +6343,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of feeds created by the actor.', + description: + "Get a list of feeds (feed generator records) created by the actor (in the actor's repo).", parameters: { type: 'params', required: ['actor'], @@ -5800,7 +6392,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of posts liked by an actor.', + description: + 'Get a list of posts liked by an actor. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -5856,7 +6449,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth.", parameters: { type: 'params', required: ['actor'], @@ -5876,6 +6470,8 @@ export const schemaDict = { }, filter: { type: 'string', + description: + 'Combinations of post/repost types to include in response.', knownValues: [ 'posts_with_replies', 'posts_no_replies', @@ -5923,7 +6519,7 @@ export const schemaDict = { main: { type: 'query', description: - "Get a hydrated feed from an actor's selected feed generator.", + "Get a hydrated feed from an actor's selected feed generator. Implemented by App View.", parameters: { type: 'params', required: ['feed'], @@ -5976,7 +6572,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get information about a feed generator.', + description: + 'Get information about a feed generator. Implemented by AppView.', parameters: { type: 'params', required: ['feed'], @@ -5984,6 +6581,7 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: 'AT-URI of the feed generator record.', }, }, }, @@ -5999,9 +6597,13 @@ export const schemaDict = { }, isOnline: { type: 'boolean', + description: + 'Indicates whether the feed generator service has been online recently, or else seems to be inactive.', }, isValid: { type: 'boolean', + description: + 'Indicates whether the feed generator service is compatible with the record declaration.', }, }, }, @@ -6054,7 +6656,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a skeleton of a feed provided by a feed generator.', + description: + 'Get a skeleton of a feed provided by a feed generator. Auth is optional, depending on provider requirements, and provides the DID of the requester. Implemented by Feed Generator Service.', parameters: { type: 'params', required: ['feed'], @@ -6062,6 +6665,8 @@ export const schemaDict = { feed: { type: 'string', format: 'at-uri', + description: + 'Reference to feed generator record describing the specific feed being requested.', }, limit: { type: 'integer', @@ -6107,7 +6712,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the list of likes.', + description: + 'Get like records which reference a subject (by AT-URI and CID).', parameters: { type: 'params', required: ['uri'], @@ -6115,10 +6721,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'AT-URI of the subject (eg, a post record).', }, cid: { type: 'string', format: 'cid', + description: + 'CID of the subject record (aka, specific version of record), to filter likes.', }, limit: { type: 'integer', @@ -6185,7 +6794,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a view of a recent posts from actors in a list.', + description: + 'Get a feed of recent posts from a list (posts and reposts from any actors on the list). Does not require auth.', parameters: { type: 'params', required: ['list'], @@ -6193,6 +6803,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the list record.', }, limit: { type: 'integer', @@ -6238,7 +6849,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get posts in a thread.', + description: + 'Get posts in a thread. Does not require auth, but additional metadata and filtering will be applied for authed requests.', parameters: { type: 'params', required: ['uri'], @@ -6246,15 +6858,20 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to post record.', }, depth: { type: 'integer', + description: + 'How many levels of reply depth should be included in response.', default: 6, minimum: 0, maximum: 1000, }, parentHeight: { type: 'integer', + description: + 'How many levels of parent (and grandparent, etc) post to include.', default: 80, minimum: 0, maximum: 1000, @@ -6292,13 +6909,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of an actor's feed.", + description: + "Gets post views for a specified list of posts (by AT-URI). This is sometimes referred to as 'hydrating' a 'feed skeleton'.", parameters: { type: 'params', required: ['uris'], properties: { uris: { type: 'array', + description: 'List of post AT-URIs to return hydrated views for.', items: { type: 'string', format: 'at-uri', @@ -6332,7 +6951,7 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of reposts.', + description: 'Get a list of reposts for a given post.', parameters: { type: 'params', required: ['uri'], @@ -6340,10 +6959,13 @@ export const schemaDict = { uri: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of post record', }, cid: { type: 'string', format: 'cid', + description: + 'If supplied, filters to reposts of specific version (by CID) of the post record.', }, limit: { type: 'integer', @@ -6392,7 +7014,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of suggested feeds for the viewer.', + description: + 'Get a list of suggested feeds (feed generators) for the requesting account.', parameters: { type: 'params', properties: { @@ -6435,12 +7058,15 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a view of the actor's home timeline.", + description: + "Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed.", parameters: { type: 'params', properties: { algorithm: { type: 'string', + description: + "Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism.", }, limit: { type: 'integer', @@ -6481,7 +7107,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a like.', + description: "Record declaring a 'like' of a piece of subject content.", key: 'tid', record: { type: 'object', @@ -6506,7 +7132,7 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a post.', + description: 'Record containing a Bluesky post.', key: 'tid', record: { type: 'object', @@ -6516,10 +7142,12 @@ export const schemaDict = { type: 'string', maxLength: 3000, maxGraphemes: 300, + description: + 'The primary post content. May be an empty string, if there are embeds.', }, entities: { type: 'array', - description: 'Deprecated: replaced by app.bsky.richtext.facet.', + description: 'DEPRECATED: replaced by app.bsky.richtext.facet.', items: { type: 'ref', ref: 'lex:app.bsky.feed.post#entity', @@ -6527,6 +7155,8 @@ export const schemaDict = { }, facets: { type: 'array', + description: + 'Annotations of text (mentions, URLs, hashtags, etc)', items: { type: 'ref', ref: 'lex:app.bsky.richtext.facet', @@ -6547,6 +7177,8 @@ export const schemaDict = { }, langs: { type: 'array', + description: + 'Indicates human language of post primary text content.', maxLength: 3, items: { type: 'string', @@ -6555,21 +7187,26 @@ export const schemaDict = { }, labels: { type: 'union', + description: + 'Self-label values for this post. Effectively content warnings.', refs: ['lex:com.atproto.label.defs#selfLabels'], }, tags: { type: 'array', + description: + 'Additional hashtags, in addition to any included in post text and facets.', maxLength: 8, items: { type: 'string', maxLength: 640, maxGraphemes: 64, }, - description: 'Additional non-inline tags describing this post.', }, createdAt: { type: 'string', format: 'datetime', + description: + 'Client-declared timestamp when this post was originally created.', }, }, }, @@ -6629,7 +7266,8 @@ export const schemaDict = { id: 'app.bsky.feed.repost', defs: { main: { - description: 'A declaration of a repost.', + description: + "Record representing a 'repost' of an existing Bluesky post.", type: 'record', key: 'tid', record: { @@ -6655,7 +7293,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Find posts matching search criteria.', + description: + 'Find posts matching search criteria, returning views of those posts.', parameters: { type: 'params', required: ['q'], @@ -6718,7 +7357,7 @@ export const schemaDict = { type: 'record', key: 'tid', description: - "Defines interaction gating rules for a thread. The rkey of the threadgate record should match the rkey of the thread's root post.", + "Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository..", record: { type: 'object', required: ['post', 'createdAt'], @@ -6726,6 +7365,7 @@ export const schemaDict = { post: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the post record.', }, allow: { type: 'array', @@ -6775,7 +7415,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a block.', + description: + "Record declaring a 'block' relationship against another account. NOTE: blocks are public in Bluesky; see blog posts for details.", key: 'tid', record: { type: 'object', @@ -6784,6 +7425,7 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'DID of the account to be blocked.', }, createdAt: { type: 'string', @@ -6972,7 +7614,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a social follow.', + description: + "Record declaring a social 'follow' relationship of another account. Duplicate follows will be ignored by the AppView.", key: 'tid', record: { type: 'object', @@ -6997,7 +7640,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor is blocking.', + description: + 'Enumerates which accounts the requesting account is currently blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7040,7 +7684,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: "Get a list of an actor's followers.", + description: + 'Enumerates accounts which follow a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7092,7 +7737,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor follows.', + description: + 'Enumerates accounts which a specified account (actor) follows.', parameters: { type: 'params', required: ['actor'], @@ -7144,7 +7790,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of actors.', + description: + "Gets a 'view' (with additional context) of a specified list.", parameters: { type: 'params', required: ['list'], @@ -7152,6 +7799,7 @@ export const schemaDict = { list: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) of the list record to hydrate.', }, limit: { type: 'integer', @@ -7196,7 +7844,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is blocking.', + description: + 'Get mod lists that the requesting account (actor) is blocking. Requires auth.', parameters: { type: 'params', properties: { @@ -7239,7 +7888,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get lists that the actor is muting.', + description: + 'Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7282,7 +7932,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of lists that belong to an actor.', + description: + 'Enumerates the lists created by a specified account (actor).', parameters: { type: 'params', required: ['actor'], @@ -7290,6 +7941,7 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'The account (actor) to enumerate lists from.', }, limit: { type: 'integer', @@ -7330,7 +7982,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of who the actor mutes.', + description: + 'Enumerates accounts that the requesting account (actor) currently has muted. Requires auth.', parameters: { type: 'params', properties: { @@ -7374,7 +8027,7 @@ export const schemaDict = { main: { type: 'query', description: - 'Enumerates public relationships between one account, and a list of other accounts', + 'Enumerates public relationships between one account, and a list of other accounts. Does not require auth.', parameters: { type: 'params', required: ['actor'], @@ -7382,9 +8035,12 @@ export const schemaDict = { actor: { type: 'string', format: 'at-identifier', + description: 'Primary account requesting relationships for.', }, others: { type: 'array', + description: + "List of 'other' accounts to be related back to the primary.", maxLength: 30, items: { type: 'string', @@ -7432,7 +8088,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get suggested follows related to a given actor.', + description: + 'Enumerates follows similar to a given account (actor). Expected use is to recommend additional accounts immediately after following one account.', parameters: { type: 'params', required: ['actor'], @@ -7468,7 +8125,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A declaration of a list of actors.', + description: + 'Record representing a list of accounts (actors). Scope includes both moderation-oriented lists and curration-oriented lists.', key: 'tid', record: { type: 'object', @@ -7476,12 +8134,15 @@ export const schemaDict = { properties: { purpose: { type: 'ref', + description: + 'Defines the purpose of the list (aka, moderation-oriented or curration-oriented)', ref: 'lex:app.bsky.graph.defs#listPurpose', }, name: { type: 'string', maxLength: 64, minLength: 1, + description: 'Display name for list; can not be empty.', }, description: { type: 'string', @@ -7519,7 +8180,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'A block of an entire list of actors.', + description: + 'Record representing a block relationship against an entire an entire list of accounts (actors).', key: 'tid', record: { type: 'object', @@ -7528,6 +8190,7 @@ export const schemaDict = { subject: { type: 'string', format: 'at-uri', + description: 'Reference (AT-URI) to the mod list record.', }, createdAt: { type: 'string', @@ -7544,7 +8207,8 @@ export const schemaDict = { defs: { main: { type: 'record', - description: 'An item under a declared list of actors.', + description: + "Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records.", key: 'tid', record: { type: 'object', @@ -7553,10 +8217,13 @@ export const schemaDict = { subject: { type: 'string', format: 'did', + description: 'The account which is included on the list.', }, list: { type: 'string', format: 'at-uri', + description: + 'Reference (AT-URI) to the list record (app.bsky.graph.list).', }, createdAt: { type: 'string', @@ -7573,7 +8240,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute an actor by DID or handle.', + description: + 'Creates a mute relationship for the specified account. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7596,7 +8264,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Mute a list of actors.', + description: + 'Creates a mute relationship for the specified list of accounts. Mutes are private in Bluesky. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7619,7 +8288,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute an actor by DID or handle.', + description: 'Unmutes the specified account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7642,7 +8311,7 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Unmute a list of actors.', + description: 'Unmutes the specified list of accounts. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7665,7 +8334,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get the count of unread notifications.', + description: + 'Count the number of unread notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7696,7 +8366,8 @@ export const schemaDict = { defs: { main: { type: 'query', - description: 'Get a list of notifications.', + description: + 'Enumerate notifications for the requesting account. Requires auth.', parameters: { type: 'params', properties: { @@ -7807,7 +8478,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Register for push notifications with a service.', + description: + 'Register to receive push notifications, via a specified service, for the requesting account. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7840,7 +8512,8 @@ export const schemaDict = { defs: { main: { type: 'procedure', - description: 'Notify server that the user has seen notifications.', + description: + 'Notify server that the requesting account has seen notifications. Requires auth.', input: { encoding: 'application/json', schema: { @@ -7863,6 +8536,7 @@ export const schemaDict = { defs: { main: { type: 'object', + description: 'Annotation of a sub-string within rich text.', required: ['index', 'features'], properties: { index: { @@ -7884,7 +8558,8 @@ export const schemaDict = { }, mention: { type: 'object', - description: 'A facet feature for actor mentions.', + description: + "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID.", required: ['did'], properties: { did: { @@ -7895,7 +8570,8 @@ export const schemaDict = { }, link: { type: 'object', - description: 'A facet feature for links.', + description: + 'Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.', required: ['uri'], properties: { uri: { @@ -7906,7 +8582,8 @@ export const schemaDict = { }, tag: { type: 'object', - description: 'A hashtag.', + description: + "Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags').", required: ['tag'], properties: { tag: { @@ -7919,7 +8596,7 @@ export const schemaDict = { byteSlice: { type: 'object', description: - 'A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings.', + 'Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.', required: ['byteStart', 'byteEnd'], properties: { byteStart: { @@ -8054,55 +8731,6 @@ export const schemaDict = { }, }, }, - AppBskyUnspeccedGetTimelineSkeleton: { - lexicon: 1, - id: 'app.bsky.unspecced.getTimelineSkeleton', - defs: { - main: { - type: 'query', - description: - 'DEPRECATED: a skeleton of a timeline. Unspecced and will be unavailable soon.', - parameters: { - type: 'params', - properties: { - limit: { - type: 'integer', - minimum: 1, - maximum: 100, - default: 50, - }, - cursor: { - type: 'string', - }, - }, - }, - output: { - encoding: 'application/json', - schema: { - type: 'object', - required: ['feed'], - properties: { - cursor: { - type: 'string', - }, - feed: { - type: 'array', - items: { - type: 'ref', - ref: 'lex:app.bsky.feed.defs#skeletonFeedPost', - }, - }, - }, - }, - }, - errors: [ - { - name: 'UnknownFeed', - }, - ], - }, - }, - }, AppBskyUnspeccedSearchActorsSkeleton: { lexicon: 1, id: 'app.bsky.unspecced.searchActorsSkeleton', @@ -8261,10 +8889,19 @@ export const ids = { ComAtprotoAdminSendEmail: 'com.atproto.admin.sendEmail', ComAtprotoAdminUpdateAccountEmail: 'com.atproto.admin.updateAccountEmail', ComAtprotoAdminUpdateAccountHandle: 'com.atproto.admin.updateAccountHandle', + ComAtprotoAdminUpdateAccountPassword: + 'com.atproto.admin.updateAccountPassword', ComAtprotoAdminUpdateCommunicationTemplate: 'com.atproto.admin.updateCommunicationTemplate', ComAtprotoAdminUpdateSubjectStatus: 'com.atproto.admin.updateSubjectStatus', + ComAtprotoIdentityGetRecommendedDidCredentials: + 'com.atproto.identity.getRecommendedDidCredentials', + ComAtprotoIdentityRequestPlcOperationSignature: + 'com.atproto.identity.requestPlcOperationSignature', ComAtprotoIdentityResolveHandle: 'com.atproto.identity.resolveHandle', + ComAtprotoIdentitySignPlcOperation: 'com.atproto.identity.signPlcOperation', + ComAtprotoIdentitySubmitPlcOperation: + 'com.atproto.identity.submitPlcOperation', ComAtprotoIdentityUpdateHandle: 'com.atproto.identity.updateHandle', ComAtprotoLabelDefs: 'com.atproto.label.defs', ComAtprotoLabelQueryLabels: 'com.atproto.label.queryLabels', @@ -8276,22 +8913,28 @@ export const ids = { ComAtprotoRepoDeleteRecord: 'com.atproto.repo.deleteRecord', ComAtprotoRepoDescribeRepo: 'com.atproto.repo.describeRepo', ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord', + ComAtprotoRepoImportRepo: 'com.atproto.repo.importRepo', + ComAtprotoRepoListMissingBlobs: 'com.atproto.repo.listMissingBlobs', ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords', ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord', ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob', + ComAtprotoServerActivateAccount: 'com.atproto.server.activateAccount', + ComAtprotoServerCheckAccountStatus: 'com.atproto.server.checkAccountStatus', ComAtprotoServerConfirmEmail: 'com.atproto.server.confirmEmail', ComAtprotoServerCreateAccount: 'com.atproto.server.createAccount', ComAtprotoServerCreateAppPassword: 'com.atproto.server.createAppPassword', ComAtprotoServerCreateInviteCode: 'com.atproto.server.createInviteCode', ComAtprotoServerCreateInviteCodes: 'com.atproto.server.createInviteCodes', ComAtprotoServerCreateSession: 'com.atproto.server.createSession', + ComAtprotoServerDeactivateAccount: 'com.atproto.server.deactivateAccount', ComAtprotoServerDefs: 'com.atproto.server.defs', ComAtprotoServerDeleteAccount: 'com.atproto.server.deleteAccount', ComAtprotoServerDeleteSession: 'com.atproto.server.deleteSession', ComAtprotoServerDescribeServer: 'com.atproto.server.describeServer', ComAtprotoServerGetAccountInviteCodes: 'com.atproto.server.getAccountInviteCodes', + ComAtprotoServerGetServiceAuth: 'com.atproto.server.getServiceAuth', ComAtprotoServerGetSession: 'com.atproto.server.getSession', ComAtprotoServerListAppPasswords: 'com.atproto.server.listAppPasswords', ComAtprotoServerRefreshSession: 'com.atproto.server.refreshSession', @@ -8318,12 +8961,10 @@ export const ids = { ComAtprotoSyncNotifyOfUpdate: 'com.atproto.sync.notifyOfUpdate', ComAtprotoSyncRequestCrawl: 'com.atproto.sync.requestCrawl', ComAtprotoSyncSubscribeRepos: 'com.atproto.sync.subscribeRepos', + ComAtprotoTempCheckSignupQueue: 'com.atproto.temp.checkSignupQueue', ComAtprotoTempFetchLabels: 'com.atproto.temp.fetchLabels', - ComAtprotoTempImportRepo: 'com.atproto.temp.importRepo', - ComAtprotoTempPushBlob: 'com.atproto.temp.pushBlob', ComAtprotoTempRequestPhoneVerification: 'com.atproto.temp.requestPhoneVerification', - ComAtprotoTempTransferAccount: 'com.atproto.temp.transferAccount', AppBskyActorDefs: 'app.bsky.actor.defs', AppBskyActorGetPreferences: 'app.bsky.actor.getPreferences', AppBskyActorGetProfile: 'app.bsky.actor.getProfile', @@ -8391,7 +9032,6 @@ export const ids = { 'app.bsky.unspecced.getPopularFeedGenerators', AppBskyUnspeccedGetTaggedSuggestions: 'app.bsky.unspecced.getTaggedSuggestions', - 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/defs.ts b/packages/pds/src/lexicon/types/app/bsky/actor/defs.ts index c20177ca50e..6836fa7e516 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/defs.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/defs.ts @@ -82,6 +82,7 @@ export function validateProfileViewDetailed(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#profileViewDetailed', v) } +/** Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests. */ export interface ViewerState { muted?: boolean mutedByList?: AppBskyGraphDefs.ListViewBasic @@ -112,6 +113,9 @@ export type Preferences = ( | PersonalDetailsPref | FeedViewPref | ThreadViewPref + | InterestsPref + | MutedWordsPref + | HiddenPostsPref | { $type: string; [k: string]: unknown } )[] @@ -153,6 +157,7 @@ export function validateContentLabelPref(v: unknown): ValidationResult { export interface SavedFeedsPref { pinned: string[] saved: string[] + timelineIndex?: number [k: string]: unknown } @@ -233,3 +238,80 @@ export function isThreadViewPref(v: unknown): v is ThreadViewPref { export function validateThreadViewPref(v: unknown): ValidationResult { return lexicons.validate('app.bsky.actor.defs#threadViewPref', v) } + +export interface InterestsPref { + /** A list of tags which describe the account owner's interests gathered during onboarding. */ + tags: string[] + [k: string]: unknown +} + +export function isInterestsPref(v: unknown): v is InterestsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#interestsPref' + ) +} + +export function validateInterestsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#interestsPref', v) +} + +export type MutedWordTarget = 'content' | 'tag' | (string & {}) + +/** A word that the account owner has muted. */ +export interface MutedWord { + /** The muted word itself. */ + value: string + /** The intended targets of the muted word. */ + targets: MutedWordTarget[] + [k: string]: unknown +} + +export function isMutedWord(v: unknown): v is MutedWord { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWord' + ) +} + +export function validateMutedWord(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWord', v) +} + +export interface MutedWordsPref { + /** A list of words the account owner has muted. */ + items: MutedWord[] + [k: string]: unknown +} + +export function isMutedWordsPref(v: unknown): v is MutedWordsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#mutedWordsPref' + ) +} + +export function validateMutedWordsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#mutedWordsPref', v) +} + +export interface HiddenPostsPref { + /** A list of URIs of posts the account owner has hidden. */ + items: string[] + [k: string]: unknown +} + +export function isHiddenPostsPref(v: unknown): v is HiddenPostsPref { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'app.bsky.actor.defs#hiddenPostsPref' + ) +} + +export function validateHiddenPostsPref(v: unknown): ValidationResult { + return lexicons.validate('app.bsky.actor.defs#hiddenPostsPref', v) +} diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/getPreferences.ts b/packages/pds/src/lexicon/types/app/bsky/actor/getPreferences.ts index 88d78a57cba..305e80484be 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/getPreferences.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/getPreferences.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/getProfile.ts b/packages/pds/src/lexicon/types/app/bsky/actor/getProfile.ts index 802afda5361..5a7b1f25bfc 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/getProfile.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/getProfile.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { + /** Handle or DID of account to fetch profile of. */ actor: string } @@ -28,7 +29,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/getProfiles.ts b/packages/pds/src/lexicon/types/app/bsky/actor/getProfiles.ts index 2549b264e33..16438505654 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/getProfiles.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/getProfiles.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/getSuggestions.ts b/packages/pds/src/lexicon/types/app/bsky/actor/getSuggestions.ts index a6d4d6102af..33b89a18bfa 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/getSuggestions.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/getSuggestions.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/profile.ts b/packages/pds/src/lexicon/types/app/bsky/actor/profile.ts index 7dbc4c1ccec..8810ce7bed9 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/profile.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/profile.ts @@ -9,8 +9,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { displayName?: string + /** Free-form profile description text. */ description?: string + /** Small image to be displayed next to posts from account. AKA, 'profile picture' */ avatar?: BlobRef + /** Larger horizontal image to display behind profile view. */ banner?: BlobRef labels?: | ComAtprotoLabelDefs.SelfLabels diff --git a/packages/pds/src/lexicon/types/app/bsky/actor/putPreferences.ts b/packages/pds/src/lexicon/types/app/bsky/actor/putPreferences.ts index 1e5ee2d834e..670e752fea3 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/putPreferences.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/putPreferences.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams {} 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 f072b8a4d04..dcda0c41854 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/searchActors.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/searchActors.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -39,7 +39,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams 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 0cf56753db2..0198b23d790 100644 --- a/packages/pds/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +++ b/packages/pds/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/embed/external.ts b/packages/pds/src/lexicon/types/app/bsky/embed/external.ts index f42a6cfd95c..b137ee4b6f5 100644 --- a/packages/pds/src/lexicon/types/app/bsky/embed/external.ts +++ b/packages/pds/src/lexicon/types/app/bsky/embed/external.ts @@ -6,6 +6,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' +/** A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). */ export interface Main { external: External [k: string]: unknown diff --git a/packages/pds/src/lexicon/types/app/bsky/embed/images.ts b/packages/pds/src/lexicon/types/app/bsky/embed/images.ts index 4864fad3dea..96399867a1a 100644 --- a/packages/pds/src/lexicon/types/app/bsky/embed/images.ts +++ b/packages/pds/src/lexicon/types/app/bsky/embed/images.ts @@ -26,6 +26,7 @@ export function validateMain(v: unknown): ValidationResult { export interface Image { image: BlobRef + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown @@ -76,8 +77,11 @@ export function validateView(v: unknown): ValidationResult { } export interface ViewImage { + /** Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. */ thumb: string + /** Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. */ fullsize: string + /** Alt text description of the image, for accessibility. */ alt: string aspectRatio?: AspectRatio [k: string]: unknown diff --git a/packages/pds/src/lexicon/types/app/bsky/embed/record.ts b/packages/pds/src/lexicon/types/app/bsky/embed/record.ts index cea5742a45e..dbe7f13152b 100644 --- a/packages/pds/src/lexicon/types/app/bsky/embed/record.ts +++ b/packages/pds/src/lexicon/types/app/bsky/embed/record.ts @@ -57,6 +57,7 @@ export interface ViewRecord { uri: string cid: string author: AppBskyActorDefs.ProfileViewBasic + /** The record data itself. */ value: {} labels?: ComAtprotoLabelDefs.Label[] embeds?: ( diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/defs.ts b/packages/pds/src/lexicon/types/app/bsky/feed/defs.ts index 382d3f58ecf..261d8a622ec 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/defs.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/defs.ts @@ -45,6 +45,7 @@ export function validatePostView(v: unknown): ValidationResult { return lexicons.validate('app.bsky.feed.defs#postView', v) } +/** Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests. */ export interface ViewerState { repost?: string like?: string diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts b/packages/pds/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts index d329bf20a5a..5bf8699a3ca 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -32,7 +32,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getActorFeeds.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getActorFeeds.ts index 3e930cbe201..0b8afff4ec8 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getActorFeeds.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getActorFeeds.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getActorLikes.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getActorLikes.ts index df2f291e1a7..da315ae33c7 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getActorLikes.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getActorLikes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { error?: 'BlockedActor' | 'BlockedByActor' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts index 25f51f6fe5f..017c7a6a2d4 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts @@ -6,13 +6,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { actor: string limit: number cursor?: string + /** Combinations of post/repost types to include in response. */ filter: | 'posts_with_replies' | 'posts_no_replies' @@ -43,7 +44,7 @@ export interface HandlerError { error?: 'BlockedActor' | 'BlockedByActor' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getFeed.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getFeed.ts index e72b1010aea..e03913a6fb3 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getFeed.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getFeed.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts index fab3b30c316..7ab89057a8c 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** AT-URI of the feed generator record. */ feed: string } @@ -17,7 +18,9 @@ export type InputSchema = undefined export interface OutputSchema { view: AppBskyFeedDefs.GeneratorView + /** Indicates whether the feed generator service has been online recently, or else seems to be inactive. */ isOnline: boolean + /** Indicates whether the feed generator service is compatible with the record declaration. */ isValid: boolean [k: string]: unknown } @@ -35,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts index d7e082f2362..21963a91e2e 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts index 1c8f349b42b..ca1cef20f08 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference to feed generator record describing the specific feed being requested. */ feed: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getLikes.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getLikes.ts index d581f5bfa9c..275d99bba3d 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getLikes.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getLikes.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** AT-URI of the subject (eg, a post record). */ uri: string + /** CID of the subject record (aka, specific version of record), to filter likes. */ cid?: string limit: number cursor?: string @@ -39,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getListFeed.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getListFeed.ts index e24c3f8ed22..84e12deaa92 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getListFeed.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getListFeed.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to the list record. */ list: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { error?: 'UnknownList' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts index 61de94b729d..ae232fd91a2 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts @@ -6,12 +6,15 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) to post record. */ uri: string + /** How many levels of reply depth should be included in response. */ depth: number + /** How many levels of parent (and grandparent, etc) post to include. */ parentHeight: number } @@ -40,7 +43,7 @@ export interface HandlerError { error?: 'NotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getPosts.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getPosts.ts index 4282f5d349f..85000c74787 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getPosts.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getPosts.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** List of post AT-URIs to return hydrated views for. */ uris: string[] } @@ -33,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getRepostedBy.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getRepostedBy.ts index 0b9c1a6f68b..40e008815d9 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getRepostedBy.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getRepostedBy.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { + /** Reference (AT-URI) of post record */ uri: string + /** If supplied, filters to reposts of specific version (by CID) of the post record. */ cid?: string limit: number cursor?: string @@ -39,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts index 9b271335466..d1ec590f33d 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getTimeline.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getTimeline.ts index 832caf5c6f7..5202c9eb6e3 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getTimeline.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getTimeline.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { + /** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. */ algorithm?: string limit: number cursor?: string @@ -36,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/post.ts b/packages/pds/src/lexicon/types/app/bsky/feed/post.ts index 93870b4452d..881e3d199aa 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/post.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/post.ts @@ -14,9 +14,11 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' import * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef' export interface Record { + /** The primary post content. May be an empty string, if there are embeds. */ text: string - /** Deprecated: replaced by app.bsky.richtext.facet. */ + /** DEPRECATED: replaced by app.bsky.richtext.facet. */ entities?: Entity[] + /** Annotations of text (mentions, URLs, hashtags, etc) */ facets?: AppBskyRichtextFacet.Main[] reply?: ReplyRef embed?: @@ -25,12 +27,14 @@ export interface Record { | AppBskyEmbedRecord.Main | AppBskyEmbedRecordWithMedia.Main | { $type: string; [k: string]: unknown } + /** Indicates human language of post primary text content. */ langs?: string[] labels?: | ComAtprotoLabelDefs.SelfLabels | { $type: string; [k: string]: unknown } - /** Additional non-inline tags describing this post. */ + /** Additional hashtags, in addition to any included in post text and facets. */ tags?: string[] + /** Client-declared timestamp when this post was originally created. */ createdAt: string [k: string]: unknown } diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts b/packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts index 36ac7cbb67d..9dae079c226 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/searchPosts.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from './defs' export interface QueryParams { @@ -41,7 +41,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/threadgate.ts b/packages/pds/src/lexicon/types/app/bsky/feed/threadgate.ts index 6a190d6e98a..e14140d5609 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/threadgate.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/threadgate.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the post record. */ post: string allow?: ( | MentionRule diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/block.ts b/packages/pds/src/lexicon/types/app/bsky/graph/block.ts index 947463af422..b7f19f126b7 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/block.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/block.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** DID of the account to be blocked. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getBlocks.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getBlocks.ts index d380a14880a..1fc9cd8ce37 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getBlocks.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getBlocks.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getFollowers.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getFollowers.ts index b337be52c1b..f5645eaef29 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getFollowers.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getFollowers.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getFollows.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getFollows.ts index 71e9ca0270c..b9bd249da45 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getFollows.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getFollows.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getList.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getList.ts index fc45dd20985..864a81b3833 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getList.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getList.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Reference (AT-URI) of the list record to hydrate. */ list: string limit: number cursor?: string @@ -37,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getListBlocks.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getListBlocks.ts index 04cca70b44d..7399a14fadc 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getListBlocks.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getListBlocks.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getListMutes.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getListMutes.ts index 04cca70b44d..7399a14fadc 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getListMutes.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getListMutes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getLists.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getLists.ts index 8acf9362c00..dc0c4f18bea 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getLists.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getLists.ts @@ -6,10 +6,11 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** The account (actor) to enumerate lists from. */ actor: string limit: number cursor?: string @@ -36,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getMutes.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getMutes.ts index 0034095b975..f450393522d 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getMutes.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getMutes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -35,7 +35,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getRelationships.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getRelationships.ts index 32a27434782..bd6b6e765ed 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getRelationships.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getRelationships.ts @@ -6,11 +6,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyGraphDefs from './defs' export interface QueryParams { + /** Primary account requesting relationships for. */ actor: string + /** List of 'other' accounts to be related back to the primary. */ others?: string[] } @@ -40,7 +42,7 @@ export interface HandlerError { error?: 'ActorNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts b/packages/pds/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts index a2245846fd2..8f310334d0a 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/list.ts b/packages/pds/src/lexicon/types/app/bsky/graph/list.ts index 36a7fb17a3f..91c8ccee5bb 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/list.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/list.ts @@ -11,6 +11,7 @@ import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' export interface Record { purpose: AppBskyGraphDefs.ListPurpose + /** Display name for list; can not be empty. */ name: string description?: string descriptionFacets?: AppBskyRichtextFacet.Main[] diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/listblock.ts b/packages/pds/src/lexicon/types/app/bsky/graph/listblock.ts index 59f2e057eb5..592778c7a51 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/listblock.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/listblock.ts @@ -7,6 +7,7 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** Reference (AT-URI) to the mod list record. */ subject: string createdAt: string [k: string]: unknown diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/listitem.ts b/packages/pds/src/lexicon/types/app/bsky/graph/listitem.ts index 69eff329ed4..5e93b34a111 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/listitem.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/listitem.ts @@ -7,7 +7,9 @@ import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' export interface Record { + /** The account which is included on the list. */ subject: string + /** Reference (AT-URI) to the list record (app.bsky.graph.list). */ list: string createdAt: string [k: string]: unknown diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/muteActor.ts b/packages/pds/src/lexicon/types/app/bsky/graph/muteActor.ts index 52d1b864989..baa9844046a 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/muteActor.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/muteActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/muteActorList.ts b/packages/pds/src/lexicon/types/app/bsky/graph/muteActorList.ts index bf803f388af..6a68f680a1c 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/muteActorList.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/muteActorList.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActor.ts b/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActor.ts index 52d1b864989..baa9844046a 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActor.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActor.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActorList.ts b/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActorList.ts index bf803f388af..6a68f680a1c 100644 --- a/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActorList.ts +++ b/packages/pds/src/lexicon/types/app/bsky/graph/unmuteActorList.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/app/bsky/notification/getUnreadCount.ts b/packages/pds/src/lexicon/types/app/bsky/notification/getUnreadCount.ts index 6cf3c84beb5..eae30df7c1b 100644 --- a/packages/pds/src/lexicon/types/app/bsky/notification/getUnreadCount.ts +++ b/packages/pds/src/lexicon/types/app/bsky/notification/getUnreadCount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { seenAt?: string @@ -32,7 +32,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/notification/listNotifications.ts b/packages/pds/src/lexicon/types/app/bsky/notification/listNotifications.ts index b50d6e8282e..d494494e569 100644 --- a/packages/pds/src/lexicon/types/app/bsky/notification/listNotifications.ts +++ b/packages/pds/src/lexicon/types/app/bsky/notification/listNotifications.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyActorDefs from '../actor/defs' import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs' @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/notification/registerPush.ts b/packages/pds/src/lexicon/types/app/bsky/notification/registerPush.ts index 9923aeb058e..cce8f95839d 100644 --- a/packages/pds/src/lexicon/types/app/bsky/notification/registerPush.ts +++ b/packages/pds/src/lexicon/types/app/bsky/notification/registerPush.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/app/bsky/notification/updateSeen.ts b/packages/pds/src/lexicon/types/app/bsky/notification/updateSeen.ts index 136191edc40..93db017a152 100644 --- a/packages/pds/src/lexicon/types/app/bsky/notification/updateSeen.ts +++ b/packages/pds/src/lexicon/types/app/bsky/notification/updateSeen.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/app/bsky/richtext/facet.ts b/packages/pds/src/lexicon/types/app/bsky/richtext/facet.ts index 2c5b2d723a9..139b5382caf 100644 --- a/packages/pds/src/lexicon/types/app/bsky/richtext/facet.ts +++ b/packages/pds/src/lexicon/types/app/bsky/richtext/facet.ts @@ -6,6 +6,7 @@ import { lexicons } from '../../../../lexicons' import { isObj, hasProp } from '../../../../util' import { CID } from 'multiformats/cid' +/** Annotation of a sub-string within rich text. */ export interface Main { index: ByteSlice features: (Mention | Link | Tag | { $type: string; [k: string]: unknown })[] @@ -25,7 +26,7 @@ export function validateMain(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#main', v) } -/** A facet feature for actor mentions. */ +/** Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID. */ export interface Mention { did: string [k: string]: unknown @@ -43,7 +44,7 @@ export function validateMention(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#mention', v) } -/** A facet feature for links. */ +/** Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. */ export interface Link { uri: string [k: string]: unknown @@ -61,7 +62,7 @@ export function validateLink(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#link', v) } -/** A hashtag. */ +/** Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). */ export interface Tag { tag: string [k: string]: unknown @@ -77,7 +78,7 @@ export function validateTag(v: unknown): ValidationResult { return lexicons.validate('app.bsky.richtext.facet#tag', v) } -/** A text segment. Start is inclusive, end is exclusive. Indices are for utf8-encoded strings. */ +/** Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. */ export interface ByteSlice { byteStart: number byteEnd: number diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts b/packages/pds/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts index 97937e926c2..02f19f3cc6a 100644 --- a/packages/pds/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts +++ b/packages/pds/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyFeedDefs from '../feed/defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts b/packages/pds/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts index e6319c54b4e..a03f442140d 100644 --- a/packages/pds/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts +++ b/packages/pds/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts index 5c45b9fb622..4634407b890 100644 --- a/packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts +++ b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyUnspeccedDefs from './defs' export interface QueryParams { @@ -43,7 +43,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts index 15532087b82..860d4e8407c 100644 --- a/packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts +++ b/packages/pds/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as AppBskyUnspeccedDefs from './defs' export interface QueryParams { @@ -41,7 +41,7 @@ export interface HandlerError { error?: 'BadQueryString' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts b/packages/pds/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts index d42a8f2ef1d..b910b7987b4 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/defs.ts b/packages/pds/src/lexicon/types/com/atproto/admin/defs.ts index 41be2ad96e7..a713a635635 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/defs.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/defs.ts @@ -40,6 +40,7 @@ export interface ModEventView { | ModEventEscalate | ModEventMute | ModEventEmail + | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: | RepoRef @@ -76,6 +77,7 @@ export interface ModEventViewDetail { | ModEventAcknowledge | ModEventEscalate | ModEventMute + | ModEventEmail | ModEventResolveAppeal | { $type: string; [k: string]: unknown } subject: @@ -154,6 +156,7 @@ export interface SubjectStatusView { /** True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators. */ appealed?: boolean suspendUntil?: string + tags?: string[] [k: string]: unknown } @@ -718,6 +721,29 @@ export function validateModEventEmail(v: unknown): ValidationResult { return lexicons.validate('com.atproto.admin.defs#modEventEmail', v) } +/** Add/Remove a tag on a subject */ +export interface ModEventTag { + /** Tags to be added to the subject. If already exists, won't be duplicated. */ + add: string[] + /** Tags to be removed to the subject. Ignores a tag If it doesn't exist, won't be duplicated. */ + remove: string[] + /** Additional comment about added/removed tags. */ + comment?: string + [k: string]: unknown +} + +export function isModEventTag(v: unknown): v is ModEventTag { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.admin.defs#modEventTag' + ) +} + +export function validateModEventTag(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.admin.defs#modEventTag', v) +} + export interface CommunicationTemplateView { id: string /** Name of the template. */ diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/deleteAccount.ts b/packages/pds/src/lexicon/types/com/atproto/admin/deleteAccount.ts index 13e68eb5c7d..003c1b5ebcd 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/deleteAccount.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/deleteAccount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts b/packages/pds/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts index 4bc6ec86fe4..c5ae5cd469f 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts b/packages/pds/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts index 62864923dfd..68c6503d95e 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts b/packages/pds/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts index 2b64371f1ed..2bf8de35583 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts b/packages/pds/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts index df44702b51c..99d08c7f1b7 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -24,6 +24,7 @@ export interface InputSchema { | ComAtprotoAdminDefs.ModEventReverseTakedown | ComAtprotoAdminDefs.ModEventUnmute | ComAtprotoAdminDefs.ModEventEmail + | ComAtprotoAdminDefs.ModEventTag | { $type: string; [k: string]: unknown } subject: | ComAtprotoAdminDefs.RepoRef @@ -53,7 +54,7 @@ export interface HandlerError { error?: 'SubjectHasAction' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts b/packages/pds/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts index fb3aa8b8375..3f2836e7142 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfo.ts b/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfo.ts index 88a2b17a4b8..c7b840a153d 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfo.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfos.ts b/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfos.ts index 46d917293a8..99ef44a99f5 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfos.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/getAccountInfos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/getInviteCodes.ts b/packages/pds/src/lexicon/types/com/atproto/admin/getInviteCodes.ts index 1eb099aae66..d68b97d775a 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/getInviteCodes.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/getInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoServerDefs from '../server/defs' export interface QueryParams { @@ -36,7 +36,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/getModerationEvent.ts b/packages/pds/src/lexicon/types/com/atproto/admin/getModerationEvent.ts index 7de567a73db..99c8bbe20ef 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/getModerationEvent.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/getModerationEvent.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/getRecord.ts b/packages/pds/src/lexicon/types/com/atproto/admin/getRecord.ts index 48222d9d819..557945e2fbd 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/getRecord.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/getRecord.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -30,7 +30,7 @@ export interface HandlerError { error?: 'RecordNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/getRepo.ts b/packages/pds/src/lexicon/types/com/atproto/admin/getRepo.ts index 19911baa90a..ede9fcf3ce8 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/getRepo.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/getRepo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -29,7 +29,7 @@ export interface HandlerError { error?: 'RepoNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts b/packages/pds/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts index 7315e51e8c2..d5976db70b1 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts b/packages/pds/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts index cb479533d39..843c228e6f9 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts b/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts index f3c4f1fbb95..9f4738578aa 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -15,10 +15,27 @@ export interface QueryParams { createdBy?: string /** Sort direction for the events. Defaults to descending order of created at timestamp. */ sortDirection: 'asc' | 'desc' + /** Retrieve events created after a given timestamp */ + createdAfter?: string + /** Retrieve events created before a given timestamp */ + createdBefore?: string subject?: string /** If true, events on all record types (posts, lists, profile etc.) owned by the did are returned */ includeAllUserRecords: boolean limit: number + /** If true, only events with comments are returned */ + hasComment?: boolean + /** If specified, only events with comments containing the keyword are returned */ + comment?: string + /** If specified, only events where all of these labels were added are returned */ + addedLabels?: string[] + /** If specified, only events where all of these labels were removed are returned */ + removedLabels?: string[] + /** If specified, only events where all of these tags were added are returned */ + addedTags?: string[] + /** If specified, only events where all of these tags were removed are returned */ + removedTags?: string[] + reportTypes?: string[] cursor?: string } @@ -43,7 +60,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts b/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts index 6e1aea1f679..f5031d25117 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -35,6 +35,8 @@ export interface QueryParams { /** Get subjects in unresolved appealed status */ appealed?: boolean limit: number + tags?: string[] + excludeTags?: string[] cursor?: string } @@ -59,7 +61,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams 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 1e7e1a36bb6..d1529956c17 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/searchRepos.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/searchRepos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams { @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/sendEmail.ts b/packages/pds/src/lexicon/types/com/atproto/admin/sendEmail.ts index f94cfb3a083..836fba39f79 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/sendEmail.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/sendEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts b/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts index 9e6140256ef..ebabffbccdb 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts b/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts index c378f421926..d6dc4a2dc25 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts b/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts new file mode 100644 index 00000000000..948568f0d3d --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts @@ -0,0 +1,39 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + did: string + password: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/updateCommunicationTemplate.ts b/packages/pds/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts index 5dc5cecda4a..73e079cfe58 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' export interface QueryParams {} @@ -44,7 +44,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts b/packages/pds/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts index 559ee948380..94df3041cf3 100644 --- a/packages/pds/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts +++ b/packages/pds/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoAdminDefs from './defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -48,7 +48,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts b/packages/pds/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts new file mode 100644 index 00000000000..5fa374de737 --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/identity/getRecommendedDidCredentials.ts @@ -0,0 +1,47 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + /** Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs. */ + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/identity/requestPlcOperationSignature.ts b/packages/pds/src/lexicon/types/com/atproto/identity/requestPlcOperationSignature.ts new file mode 100644 index 00000000000..82672f1d1c7 --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/identity/requestPlcOperationSignature.ts @@ -0,0 +1,31 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined +export type HandlerInput = undefined + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/identity/resolveHandle.ts b/packages/pds/src/lexicon/types/com/atproto/identity/resolveHandle.ts index ef90e99bb30..05019df6166 100644 --- a/packages/pds/src/lexicon/types/com/atproto/identity/resolveHandle.ts +++ b/packages/pds/src/lexicon/types/com/atproto/identity/resolveHandle.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle to resolve. */ @@ -33,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/temp/transferAccount.ts b/packages/pds/src/lexicon/types/com/atproto/identity/signPlcOperation.ts similarity index 70% rename from packages/pds/src/lexicon/types/com/atproto/temp/transferAccount.ts rename to packages/pds/src/lexicon/types/com/atproto/identity/signPlcOperation.ts index 86c1d750e07..3c908c049f2 100644 --- a/packages/pds/src/lexicon/types/com/atproto/temp/transferAccount.ts +++ b/packages/pds/src/lexicon/types/com/atproto/identity/signPlcOperation.ts @@ -6,22 +6,23 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - handle: string - did: string - plcOp: {} + /** A token received through com.atproto.identity.requestPlcOperationSignature */ + token?: string + rotationKeys?: string[] + alsoKnownAs?: string[] + verificationMethods?: {} + services?: {} [k: string]: unknown } export interface OutputSchema { - accessJwt: string - refreshJwt: string - handle: string - did: string + /** A signed DID PLC operation. */ + operation: {} [k: string]: unknown } @@ -39,17 +40,9 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string - error?: - | 'InvalidHandle' - | 'InvalidPassword' - | 'InvalidInviteCode' - | 'HandleNotAvailable' - | 'UnsupportedDomain' - | 'UnresolvableDid' - | 'IncompatibleDidDoc' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts b/packages/pds/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts new file mode 100644 index 00000000000..5290b55d023 --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/identity/submitPlcOperation.ts @@ -0,0 +1,38 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + operation: {} + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/identity/updateHandle.ts b/packages/pds/src/lexicon/types/com/atproto/identity/updateHandle.ts index 1f639c344e9..f451d1f57c7 100644 --- a/packages/pds/src/lexicon/types/com/atproto/identity/updateHandle.ts +++ b/packages/pds/src/lexicon/types/com/atproto/identity/updateHandle.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { + /** The new handle. */ handle: string [k: string]: unknown } diff --git a/packages/pds/src/lexicon/types/com/atproto/label/queryLabels.ts b/packages/pds/src/lexicon/types/com/atproto/label/queryLabels.ts index 1d7f8a4def5..0c9d55a6961 100644 --- a/packages/pds/src/lexicon/types/com/atproto/label/queryLabels.ts +++ b/packages/pds/src/lexicon/types/com/atproto/label/queryLabels.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoLabelDefs from './defs' export interface QueryParams { @@ -39,7 +39,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/label/subscribeLabels.ts b/packages/pds/src/lexicon/types/com/atproto/label/subscribeLabels.ts index 9d4b4441ae0..6034b35d895 100644 --- a/packages/pds/src/lexicon/types/com/atproto/label/subscribeLabels.ts +++ b/packages/pds/src/lexicon/types/com/atproto/label/subscribeLabels.ts @@ -10,7 +10,7 @@ import { IncomingMessage } from 'http' import * as ComAtprotoLabelDefs from './defs' export interface QueryParams { - /** The last known event to backfill from. */ + /** The last known event seq number to backfill from. */ cursor?: number } diff --git a/packages/pds/src/lexicon/types/com/atproto/moderation/createReport.ts b/packages/pds/src/lexicon/types/com/atproto/moderation/createReport.ts index 96aaf4a9c29..aa3f810a91c 100644 --- a/packages/pds/src/lexicon/types/com/atproto/moderation/createReport.ts +++ b/packages/pds/src/lexicon/types/com/atproto/moderation/createReport.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoModerationDefs from './defs' import * as ComAtprotoAdminDefs from '../admin/defs' import * as ComAtprotoRepoStrongRef from '../repo/strongRef' @@ -15,6 +15,7 @@ export interface QueryParams {} export interface InputSchema { reasonType: ComAtprotoModerationDefs.ReasonType + /** Additional context about the content and violation. */ reason?: string subject: | ComAtprotoAdminDefs.RepoRef @@ -52,7 +53,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/applyWrites.ts b/packages/pds/src/lexicon/types/com/atproto/repo/applyWrites.ts index 61d1e7c28e4..3956d7c3048 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/applyWrites.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/applyWrites.ts @@ -6,16 +6,17 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string - /** Flag for validating the records. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data, for all operations. */ validate: boolean writes: (Create | Update | Delete)[] + /** If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations. */ swapCommit?: string [k: string]: unknown } @@ -43,7 +44,7 @@ export type Handler = ( ctx: HandlerReqCtx, ) => Promise | HandlerOutput -/** Create a new record. */ +/** Operation which creates a new record. */ export interface Create { collection: string rkey?: string @@ -63,7 +64,7 @@ export function validateCreate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#create', v) } -/** Update an existing record. */ +/** Operation which updates an existing record. */ export interface Update { collection: string rkey: string @@ -83,7 +84,7 @@ export function validateUpdate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.repo.applyWrites#update', v) } -/** Delete an existing record. */ +/** Operation which deletes an existing record. */ export interface Delete { collection: string rkey: string diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/createRecord.ts b/packages/pds/src/lexicon/types/com/atproto/repo/createRecord.ts index df8c5d9e600..55cc95d0ad7 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/createRecord.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/createRecord.ts @@ -6,20 +6,20 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey?: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate: boolean - /** The record to create. */ + /** The record itself. Must contain a $type field. */ record: {} /** Compare and swap with the previous commit by CID. */ swapCommit?: string @@ -49,7 +49,7 @@ export interface HandlerError { error?: 'InvalidSwap' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/deleteRecord.ts b/packages/pds/src/lexicon/types/com/atproto/repo/deleteRecord.ts index f45118a3769..3bb97be0aad 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/deleteRecord.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/deleteRecord.ts @@ -6,16 +6,16 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** Compare and swap with the previous record by CID. */ swapRecord?: string diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/describeRepo.ts b/packages/pds/src/lexicon/types/com/atproto/repo/describeRepo.ts index 7b8a2b995eb..749bedcfeb7 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/describeRepo.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/describeRepo.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ @@ -18,8 +18,11 @@ export type InputSchema = undefined export interface OutputSchema { handle: string did: string + /** The complete DID document for this account. */ didDoc: {} + /** List of all the collections (NSIDs) for which this repo contains at least one record. */ collections: string[] + /** Indicates if handle is currently valid (resolves bi-directionally) */ handleIsCorrect: boolean [k: string]: unknown } @@ -37,7 +40,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/getRecord.ts b/packages/pds/src/lexicon/types/com/atproto/repo/getRecord.ts index 35c9b4b7166..1a737a848be 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/getRecord.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/getRecord.ts @@ -6,14 +6,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string /** The CID of the version of the record. If not specified, then return the most recent version. */ cid?: string @@ -41,7 +41,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/com/atproto/temp/pushBlob.ts b/packages/pds/src/lexicon/types/com/atproto/repo/importRepo.ts similarity index 84% rename from packages/ozone/src/lexicon/types/com/atproto/temp/pushBlob.ts rename to packages/pds/src/lexicon/types/com/atproto/repo/importRepo.ts index 97e890dbb14..921798c0ded 100644 --- a/packages/ozone/src/lexicon/types/com/atproto/temp/pushBlob.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/importRepo.ts @@ -7,17 +7,14 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' -export interface QueryParams { - /** The DID of the repo. */ - did: string -} +export interface QueryParams {} export type InputSchema = string | Uint8Array export interface HandlerInput { - encoding: '*/*' + encoding: 'application/vnd.ipld.car' body: stream.Readable } diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts b/packages/pds/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts new file mode 100644 index 00000000000..40f4d385e47 --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/repo/listMissingBlobs.ts @@ -0,0 +1,65 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams { + limit: number + cursor?: string +} + +export type InputSchema = undefined + +export interface OutputSchema { + cursor?: string + blobs: RecordBlob[] + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +export type HandlerReqCtx = { + auth: HA + params: QueryParams + input: HandlerInput + req: express.Request + res: express.Response +} +export type Handler = ( + ctx: HandlerReqCtx, +) => Promise | HandlerOutput + +export interface RecordBlob { + cid: string + recordUri: string + [k: string]: unknown +} + +export function isRecordBlob(v: unknown): v is RecordBlob { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.repo.listMissingBlobs#recordBlob' + ) +} + +export function validateRecordBlob(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.repo.listMissingBlobs#recordBlob', v) +} diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/listRecords.ts b/packages/pds/src/lexicon/types/com/atproto/repo/listRecords.ts index a6cf6abd1f3..f46f6eb0f7f 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/listRecords.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/listRecords.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The handle or DID of the repo. */ @@ -45,7 +45,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/putRecord.ts b/packages/pds/src/lexicon/types/com/atproto/repo/putRecord.ts index f10f773c1c4..193841a2294 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/putRecord.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/putRecord.ts @@ -6,22 +6,22 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The handle or DID of the repo. */ + /** The handle or DID of the repo (aka, current account). */ repo: string /** The NSID of the record collection. */ collection: string - /** The key of the record. */ + /** The Record Key. */ rkey: string - /** Flag for validating the record. */ + /** Can be set to 'false' to skip Lexicon schema validation of record data. */ validate: boolean /** The record to write. */ record: {} - /** Compare and swap with the previous record by CID. */ + /** Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation */ swapRecord?: string | null /** Compare and swap with the previous commit by CID. */ swapCommit?: string @@ -51,7 +51,7 @@ export interface HandlerError { error?: 'InvalidSwap' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/repo/uploadBlob.ts b/packages/pds/src/lexicon/types/com/atproto/repo/uploadBlob.ts index ad6002df925..febbbff9d16 100644 --- a/packages/pds/src/lexicon/types/com/atproto/repo/uploadBlob.ts +++ b/packages/pds/src/lexicon/types/com/atproto/repo/uploadBlob.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/activateAccount.ts b/packages/pds/src/lexicon/types/com/atproto/server/activateAccount.ts new file mode 100644 index 00000000000..82672f1d1c7 --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/server/activateAccount.ts @@ -0,0 +1,31 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined +export type HandlerInput = undefined + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/server/checkAccountStatus.ts b/packages/pds/src/lexicon/types/com/atproto/server/checkAccountStatus.ts new file mode 100644 index 00000000000..f17182a8dce --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/server/checkAccountStatus.ts @@ -0,0 +1,51 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + activated: boolean + validDid: boolean + repoCommit: string + repoRev: string + repoBlocks: number + indexedRecords: number + privateStateValues: number + expectedBlobs: number + importedBlobs: number + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/server/confirmEmail.ts b/packages/pds/src/lexicon/types/com/atproto/server/confirmEmail.ts index ffaeeb8fe75..b667a04b996 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/confirmEmail.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/confirmEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts b/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts index bbf2c009bf5..6e9b2f9f3c2 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/createAccount.ts @@ -6,28 +6,36 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { email?: string + /** Requested handle for the account. */ handle: string + /** Pre-existing atproto DID, being imported to a new account. */ did?: string inviteCode?: string verificationCode?: string verificationPhone?: string + /** Initial account password. May need to meet instance-specific password strength requirements. */ password?: string + /** DID PLC rotation key (aka, recovery key) to be included in PLC creation operation. */ recoveryKey?: string + /** A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented. */ plcOp?: {} [k: string]: unknown } +/** Account login session returned on successful account creation. */ export interface OutputSchema { accessJwt: string refreshJwt: string handle: string + /** The DID of the new account. */ did: string + /** Complete DID document. */ didDoc?: {} [k: string]: unknown } @@ -56,7 +64,7 @@ export interface HandlerError { | 'IncompatibleDidDoc' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/createAppPassword.ts b/packages/pds/src/lexicon/types/com/atproto/server/createAppPassword.ts index 8e4a0a519e0..dcc5178ecfa 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/createAppPassword.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/createAppPassword.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { + /** A short name for the App Password, to help distinguish them. */ name: string [k: string]: unknown } @@ -34,7 +35,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/createInviteCode.ts b/packages/pds/src/lexicon/types/com/atproto/server/createInviteCode.ts index acfac56ba76..9cfeacc7e28 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/createInviteCode.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/createInviteCode.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -37,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/createInviteCodes.ts b/packages/pds/src/lexicon/types/com/atproto/server/createInviteCodes.ts index 5887d77fada..eb6cd2bb1b1 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/createInviteCodes.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/createInviteCodes.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/createSession.ts b/packages/pds/src/lexicon/types/com/atproto/server/createSession.ts index 2cd448703a6..3952959fe5e 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/createSession.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/createSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -45,7 +45,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/deactivateAccount.ts b/packages/pds/src/lexicon/types/com/atproto/server/deactivateAccount.ts new file mode 100644 index 00000000000..b3793d6b2e0 --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/server/deactivateAccount.ts @@ -0,0 +1,39 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export interface InputSchema { + /** A recommendation to server as to how long they should hold onto the deactivated account before deleting. */ + deleteAfter?: string + [k: string]: unknown +} + +export interface HandlerInput { + encoding: 'application/json' + body: InputSchema +} + +export interface HandlerError { + status: number + message?: string +} + +export type HandlerOutput = HandlerError | void +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/server/deleteAccount.ts b/packages/pds/src/lexicon/types/com/atproto/server/deleteAccount.ts index 37ddbba13e0..4fcec360a11 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/deleteAccount.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/deleteAccount.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/deleteSession.ts b/packages/pds/src/lexicon/types/com/atproto/server/deleteSession.ts index e4244870425..82672f1d1c7 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/deleteSession.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/deleteSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/describeServer.ts b/packages/pds/src/lexicon/types/com/atproto/server/describeServer.ts index bb574dba9ff..c2625347f20 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/describeServer.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/describeServer.ts @@ -6,17 +6,21 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export type InputSchema = undefined export interface OutputSchema { + /** If true, an invite code must be supplied to create an account on this instance. */ inviteCodeRequired?: boolean + /** If true, a phone verification token must be supplied to create an account on this instance. */ phoneVerificationRequired?: boolean + /** List of domain suffixes that can be used in account handles. */ availableUserDomains: string[] links?: Links + did: string [k: string]: unknown } @@ -33,7 +37,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts b/packages/pds/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts index e387a5e38e4..82c3ffa8c31 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts @@ -6,11 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoServerDefs from './defs' export interface QueryParams { includeUsed: boolean + /** Controls whether any new 'earned' but not 'created' invites should be created. */ createAvailable: boolean } @@ -35,7 +36,7 @@ export interface HandlerError { error?: 'DuplicateCreate' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/ozone/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts b/packages/pds/src/lexicon/types/com/atproto/server/getServiceAuth.ts similarity index 77% rename from packages/ozone/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts rename to packages/pds/src/lexicon/types/com/atproto/server/getServiceAuth.ts index 4ccad20c902..73efe2313a9 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/getServiceAuth.ts @@ -6,19 +6,17 @@ 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 '../feed/defs' +import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { - limit: number - cursor?: string + /** The DID of the service that the token will be used to authenticate with */ + aud: string } export type InputSchema = undefined export interface OutputSchema { - cursor?: string - feed: AppBskyFeedDefs.SkeletonFeedPost[] + token: string [k: string]: unknown } @@ -33,10 +31,9 @@ export interface HandlerSuccess { export interface HandlerError { status: number message?: string - error?: 'UnknownFeed' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/getSession.ts b/packages/pds/src/lexicon/types/com/atproto/server/getSession.ts index 4f95acf523d..5a8c40b947e 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/getSession.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/getSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/listAppPasswords.ts b/packages/pds/src/lexicon/types/com/atproto/server/listAppPasswords.ts index ebd74da9d39..241418d932d 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/listAppPasswords.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/listAppPasswords.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -31,7 +31,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/refreshSession.ts b/packages/pds/src/lexicon/types/com/atproto/server/refreshSession.ts index 35874f78a69..3adeb7fc20e 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/refreshSession.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/refreshSession.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -35,7 +35,7 @@ export interface HandlerError { error?: 'AccountTakedown' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/requestAccountDelete.ts b/packages/pds/src/lexicon/types/com/atproto/server/requestAccountDelete.ts index e4244870425..82672f1d1c7 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/requestAccountDelete.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/requestAccountDelete.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts b/packages/pds/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts index e4244870425..82672f1d1c7 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts b/packages/pds/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts index 6876d44ca46..24dce3e12af 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/requestPasswordReset.ts b/packages/pds/src/lexicon/types/com/atproto/server/requestPasswordReset.ts index 47fb4bb62f3..d0f3f2ad769 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/requestPasswordReset.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/requestPasswordReset.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/reserveSigningKey.ts b/packages/pds/src/lexicon/types/com/atproto/server/reserveSigningKey.ts index ad5a5a8758c..0ec1e80c77c 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/reserveSigningKey.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/reserveSigningKey.ts @@ -6,18 +6,18 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** The did to reserve a new did:key for */ + /** The DID to reserve a key for. */ did?: string [k: string]: unknown } export interface OutputSchema { - /** Public signing key in the form of a did:key. */ + /** The public key for the reserved signing key, in did:key serialization. */ signingKey: string [k: string]: unknown } @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/server/resetPassword.ts b/packages/pds/src/lexicon/types/com/atproto/server/resetPassword.ts index 9e6ece3e4c4..38f63382cf0 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/resetPassword.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/resetPassword.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/revokeAppPassword.ts b/packages/pds/src/lexicon/types/com/atproto/server/revokeAppPassword.ts index 4627f68eaa2..769ad6aa521 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/revokeAppPassword.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/revokeAppPassword.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/server/updateEmail.ts b/packages/pds/src/lexicon/types/com/atproto/server/updateEmail.ts index c88bd3021b2..5473d7571e9 100644 --- a/packages/pds/src/lexicon/types/com/atproto/server/updateEmail.ts +++ b/packages/pds/src/lexicon/types/com/atproto/server/updateEmail.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/getBlob.ts b/packages/pds/src/lexicon/types/com/atproto/sync/getBlob.ts index 60750902472..93e50403f20 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/getBlob.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/getBlob.ts @@ -7,10 +7,10 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { - /** The DID of the repo. */ + /** The DID of the account. */ did: string /** The CID of the blob to fetch */ cid: string @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/getBlocks.ts b/packages/pds/src/lexicon/types/com/atproto/sync/getBlocks.ts index e73410efb41..f1b8ebe5db1 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/getBlocks.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/getBlocks.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -29,7 +29,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/getCheckout.ts b/packages/pds/src/lexicon/types/com/atproto/sync/getCheckout.ts index 63a657e56b9..51856b9088d 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/getCheckout.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/getCheckout.ts @@ -7,7 +7,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -28,7 +28,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/getHead.ts b/packages/pds/src/lexicon/types/com/atproto/sync/getHead.ts index 586ae1a4189..adedd4cf211 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/getHead.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/getHead.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -34,7 +34,7 @@ export interface HandlerError { error?: 'HeadNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/getLatestCommit.ts b/packages/pds/src/lexicon/types/com/atproto/sync/getLatestCommit.ts index 9b91e878724..bbae68bbe76 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/getLatestCommit.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/getLatestCommit.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -35,7 +35,7 @@ export interface HandlerError { error?: 'RepoNotFound' } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/getRecord.ts b/packages/pds/src/lexicon/types/com/atproto/sync/getRecord.ts index 297f0ac7794..c78ff8c2089 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/getRecord.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/getRecord.ts @@ -7,12 +7,13 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ did: string collection: string + /** Record Key */ rkey: string /** An optional past commit CID. */ commit?: string @@ -32,7 +33,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/getRepo.ts b/packages/pds/src/lexicon/types/com/atproto/sync/getRepo.ts index 495d31a1a22..0d426557c5f 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/getRepo.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/getRepo.ts @@ -7,12 +7,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ did: string - /** The revision of the repo to catch up from. */ + /** The revision ('rev') of the repo to create a diff from. */ since?: string } @@ -30,7 +30,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/listBlobs.ts b/packages/pds/src/lexicon/types/com/atproto/sync/listBlobs.ts index b397bb3b3df..67a66577809 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/listBlobs.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/listBlobs.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { /** The DID of the repo. */ @@ -38,7 +38,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/listRepos.ts b/packages/pds/src/lexicon/types/com/atproto/sync/listRepos.ts index 783a8e314c2..e5a8e2ca9d6 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/listRepos.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/listRepos.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams { limit: number @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams @@ -48,6 +48,7 @@ export type Handler = ( export interface Repo { did: string + /** Current repo commit CID */ head: string rev: string [k: string]: unknown diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts b/packages/pds/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts index 3d310c1139a..8a0af577c7c 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts @@ -6,12 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is notifying of update. */ + /** Hostname of the current service (usually a PDS) that is notifying of update. */ hostname: string [k: string]: unknown } diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/requestCrawl.ts b/packages/pds/src/lexicon/types/com/atproto/sync/requestCrawl.ts index 87ef20d7297..31180aabf58 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/requestCrawl.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/requestCrawl.ts @@ -6,12 +6,12 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} export interface InputSchema { - /** Hostname of the service that is requesting to be crawled. */ + /** Hostname of the current service (eg, PDS) that is requesting to be crawled. */ hostname: string [k: string]: unknown } diff --git a/packages/pds/src/lexicon/types/com/atproto/sync/subscribeRepos.ts b/packages/pds/src/lexicon/types/com/atproto/sync/subscribeRepos.ts index fb334778bf6..19874b06083 100644 --- a/packages/pds/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +++ b/packages/pds/src/lexicon/types/com/atproto/sync/subscribeRepos.ts @@ -9,12 +9,13 @@ import { HandlerAuth, ErrorFrame } from '@atproto/xrpc-server' import { IncomingMessage } from 'http' export interface QueryParams { - /** The last known event to backfill from. */ + /** The last known event seq number to backfill from. */ cursor?: number } export type OutputSchema = | Commit + | Identity | Handle | Migrate | Tombstone @@ -32,21 +33,29 @@ export type Handler = ( ctx: HandlerReqCtx, ) => AsyncIterable +/** Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature. */ export interface Commit { + /** The stream sequence number of this message. */ seq: number + /** DEPRECATED -- unused */ rebase: boolean + /** Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data. */ tooBig: boolean + /** The repo this event comes from. */ repo: string + /** Repo commit object CID. */ commit: CID + /** DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability. */ prev?: CID | null - /** The rev of the emitted commit. */ + /** The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event. */ rev: string - /** The rev of the last emitted commit from this repo. */ + /** The rev of the last emitted commit from this repo (if any). */ since: string | null - /** CAR file containing relevant blocks. */ + /** CAR file containing relevant blocks, as a diff since the previous repo state. */ blocks: Uint8Array ops: RepoOp[] blobs: CID[] + /** Timestamp of when this message was originally broadcast. */ time: string [k: string]: unknown } @@ -63,6 +72,27 @@ export function validateCommit(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#commit', v) } +/** Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache. */ +export interface Identity { + seq: number + did: string + time: string + [k: string]: unknown +} + +export function isIdentity(v: unknown): v is Identity { + return ( + isObj(v) && + hasProp(v, '$type') && + v.$type === 'com.atproto.sync.subscribeRepos#identity' + ) +} + +export function validateIdentity(v: unknown): ValidationResult { + return lexicons.validate('com.atproto.sync.subscribeRepos#identity', v) +} + +/** Represents an update of the account's handle, or transition to/from invalid state. NOTE: Will be deprecated in favor of #identity. */ export interface Handle { seq: number did: string @@ -83,6 +113,7 @@ export function validateHandle(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#handle', v) } +/** Represents an account moving from one PDS instance to another. NOTE: not implemented; account migration uses #identity instead */ export interface Migrate { seq: number did: string @@ -103,6 +134,7 @@ export function validateMigrate(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#migrate', v) } +/** Indicates that an account has been deleted. NOTE: may be deprecated in favor of #identity or a future #account event */ export interface Tombstone { seq: number did: string @@ -140,10 +172,11 @@ export function validateInfo(v: unknown): ValidationResult { return lexicons.validate('com.atproto.sync.subscribeRepos#info', v) } -/** A repo operation, ie a write of a single record. For creates and updates, CID is the record's CID as of this operation. For deletes, it's null. */ +/** A repo operation, ie a mutation of a single record. */ export interface RepoOp { action: 'create' | 'update' | 'delete' | (string & {}) path: string + /** For creates and updates, the new record CID. For deletions, null. */ cid: CID | null [k: string]: unknown } diff --git a/packages/pds/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts b/packages/pds/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts new file mode 100644 index 00000000000..9486bce2b2b --- /dev/null +++ b/packages/pds/src/lexicon/types/com/atproto/temp/checkSignupQueue.ts @@ -0,0 +1,45 @@ +/** + * 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, HandlerPipeThrough } from '@atproto/xrpc-server' + +export interface QueryParams {} + +export type InputSchema = undefined + +export interface OutputSchema { + activated: boolean + placeInQueue?: number + estimatedTimeMs?: number + [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 +} + +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough +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/temp/fetchLabels.ts b/packages/pds/src/lexicon/types/com/atproto/temp/fetchLabels.ts index 39341fd3a0e..0fbdeed1196 100644 --- a/packages/pds/src/lexicon/types/com/atproto/temp/fetchLabels.ts +++ b/packages/pds/src/lexicon/types/com/atproto/temp/fetchLabels.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' import * as ComAtprotoLabelDefs from '../label/defs' export interface QueryParams { @@ -34,7 +34,7 @@ export interface HandlerError { message?: string } -export type HandlerOutput = HandlerError | HandlerSuccess +export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough export type HandlerReqCtx = { auth: HA params: QueryParams diff --git a/packages/pds/src/lexicon/types/com/atproto/temp/importRepo.ts b/packages/pds/src/lexicon/types/com/atproto/temp/importRepo.ts deleted file mode 100644 index d88361d9856..00000000000 --- a/packages/pds/src/lexicon/types/com/atproto/temp/importRepo.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * GENERATED CODE - DO NOT MODIFY - */ -import express from 'express' -import stream from 'stream' -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' - -export interface QueryParams { - /** The DID of the repo. */ - did: string -} - -export type InputSchema = string | Uint8Array - -export interface HandlerInput { - encoding: 'application/vnd.ipld.car' - body: stream.Readable -} - -export interface HandlerSuccess { - encoding: 'text/plain' - body: Uint8Array | stream.Readable - headers?: { [key: string]: string } -} - -export interface HandlerError { - status: number - message?: string -} - -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/temp/requestPhoneVerification.ts b/packages/pds/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts index 5a295f701eb..c977500fc33 100644 --- a/packages/pds/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts +++ b/packages/pds/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts @@ -6,7 +6,7 @@ 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 { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server' export interface QueryParams {} diff --git a/packages/pds/src/mailer/index.ts b/packages/pds/src/mailer/index.ts index df539ac03b9..f6c57cec40e 100644 --- a/packages/pds/src/mailer/index.ts +++ b/packages/pds/src/mailer/index.ts @@ -53,6 +53,13 @@ export class ServerMailer { }) } + async sendPlcOperation(params: { token: string }, mailOpts: Mail.Options) { + return this.sendTemplate('plcOperation', params, { + subject: 'PLC Update Operation Requested', + ...mailOpts, + }) + } + private async sendTemplate(templateName, params, mailOpts: Mail.Options) { const html = this.templates[templateName]({ ...params, diff --git a/packages/pds/src/mailer/templates.ts b/packages/pds/src/mailer/templates.ts index 08c3f3883fb..86a683053f9 100644 --- a/packages/pds/src/mailer/templates.ts +++ b/packages/pds/src/mailer/templates.ts @@ -5,3 +5,4 @@ export { default as resetPassword } from './templates/reset-password.hbs' export { default as deleteAccount } from './templates/delete-account.hbs' export { default as confirmEmail } from './templates/confirm-email.hbs' export { default as updateEmail } from './templates/update-email.hbs' +export { default as plcOperation } from './templates/plc-operation.hbs' diff --git a/packages/pds/src/mailer/templates/plc-operation.hbs b/packages/pds/src/mailer/templates/plc-operation.hbs new file mode 100644 index 00000000000..2d998245202 --- /dev/null +++ b/packages/pds/src/mailer/templates/plc-operation.hbs @@ -0,0 +1,384 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/pds/src/pipethrough.ts b/packages/pds/src/pipethrough.ts new file mode 100644 index 00000000000..a4c11856502 --- /dev/null +++ b/packages/pds/src/pipethrough.ts @@ -0,0 +1,93 @@ +import * as ui8 from 'uint8arrays' +import { jsonToLex } from '@atproto/lexicon' +import { HandlerPipeThrough } from '@atproto/xrpc-server' +import { CallOptions, ResponseType, XRPCError } from '@atproto/xrpc' +import { lexicons } from './lexicon/lexicons' +import { httpLogger } from './logger' +import { noUndefinedVals } from '@atproto/common' + +export const pipethrough = async ( + serviceUrl: string, + nsid: string, + params: Record, + opts?: CallOptions, +): Promise => { + const url = constructUrl(serviceUrl, nsid, params) + let res: Response + let buffer: ArrayBuffer + try { + res = await fetch(url, opts) + buffer = await res.arrayBuffer() + } catch (err) { + httpLogger.warn({ err }, 'pipethrough network error') + throw new XRPCError(ResponseType.UpstreamFailure) + } + if (res.status !== ResponseType.Success) { + const ui8Buffer = new Uint8Array(buffer) + const errInfo = safeParseJson(ui8.toString(ui8Buffer, 'utf8')) + throw new XRPCError( + res.status, + safeString(errInfo?.['error']), + safeString(errInfo?.['message']), + simpleHeaders(res.headers), + ) + } + const encoding = res.headers.get('content-type') ?? 'application/json' + const repoRevHeader = res.headers.get('atproto-repo-rev') + const contentLanguage = res.headers.get('content-language') + const headers = noUndefinedVals({ + ['atproto-repo-rev']: repoRevHeader ?? undefined, + ['content-language']: contentLanguage ?? undefined, + }) + return { encoding, buffer, headers } +} + +export const constructUrl = ( + serviceUrl: string, + nsid: string, + params?: Record, +): string => { + const uri = new URL(serviceUrl) + uri.pathname = `/xrpc/${nsid}` + + for (const [key, value] of Object.entries(params ?? {})) { + if (value === undefined) { + continue + } else if (Array.isArray(value)) { + for (const item of value) { + uri.searchParams.append(key, String(item)) + } + } else { + uri.searchParams.set(key, String(value)) + } + } + + return uri.toString() +} + +export const parseRes = (nsid: string, res: HandlerPipeThrough): T => { + const buffer = new Uint8Array(res.buffer) + const json = safeParseJson(ui8.toString(buffer, 'utf8')) + const lex = json && jsonToLex(json) + return lexicons.assertValidXrpcOutput(nsid, lex) as T +} + +const safeString = (str: string): string | undefined => { + return typeof str === 'string' ? str : undefined +} + +const safeParseJson = (json: string): unknown => { + try { + return JSON.parse(json) + } catch { + return null + } +} + +const simpleHeaders = (headers: Headers): Record => { + const result = {} + for (const [key, val] of headers) { + result[key] = val + } + return result +} diff --git a/packages/pds/src/read-after-write/types.ts b/packages/pds/src/read-after-write/types.ts index 170256e566e..cfdd6ff7fe3 100644 --- a/packages/pds/src/read-after-write/types.ts +++ b/packages/pds/src/read-after-write/types.ts @@ -6,6 +6,7 @@ import { Record as ProfileRecord } from '../lexicon/types/app/bsky/actor/profile import { LocalViewer } from './viewer' export type LocalRecords = { + count: number profile: RecordDescript | null posts: RecordDescript[] } diff --git a/packages/pds/src/read-after-write/util.ts b/packages/pds/src/read-after-write/util.ts index db8770a32b6..cb659a84121 100644 --- a/packages/pds/src/read-after-write/util.ts +++ b/packages/pds/src/read-after-write/util.ts @@ -1,10 +1,15 @@ import { Headers } from '@atproto/xrpc' import { readStickyLogger as log } from '../logger' import AppContext from '../context' -import { ApiRes, HandlerResponse, LocalRecords, MungeFn } from './types' +import { HandlerResponse, LocalRecords, MungeFn } from './types' +import { getRecordsSinceRev } from './viewer' +import { HandlerPipeThrough } from '@atproto/xrpc-server' +import { parseRes } from '../pipethrough' + +const REPO_REV_HEADER = 'atproto-repo-rev' export const getRepoRev = (headers: Headers): string | undefined => { - return headers['atproto-repo-rev'] + return headers[REPO_REV_HEADER] } export const getLocalLag = (local: LocalRecords): number | undefined => { @@ -20,45 +25,51 @@ export const getLocalLag = (local: LocalRecords): number | undefined => { export const handleReadAfterWrite = async ( ctx: AppContext, + nsid: string, requester: string, - res: ApiRes, + res: HandlerPipeThrough, munge: MungeFn, -): Promise> => { - let body: T - let lag: number | undefined = undefined +): Promise | HandlerPipeThrough> => { try { - const withLocal = await readAfterWriteInternal(ctx, requester, res, munge) - body = withLocal.data - lag = withLocal.lag + return await readAfterWriteInternal(ctx, nsid, requester, res, munge) } catch (err) { - body = res.data log.warn({ err, requester }, 'error in read after write munge') - } - return { - encoding: 'application/json', - body, - headers: - lag !== undefined - ? { - 'Atproto-Upstream-Lag': lag.toString(10), - } - : undefined, + return res } } export const readAfterWriteInternal = async ( ctx: AppContext, + nsid: string, requester: string, - res: ApiRes, + res: HandlerPipeThrough, munge: MungeFn, -): Promise<{ data: T; lag?: number }> => { - const rev = getRepoRev(res.headers) - if (!rev) return { data: res.data } - const keypair = await ctx.actorStore.keypair(requester) +): Promise | HandlerPipeThrough> => { + const rev = getRepoRev(res.headers ?? {}) + if (!rev) return res return ctx.actorStore.read(requester, async (store) => { + const local = await getRecordsSinceRev(store, rev) + if (local.count === 0) { + return res + } + const keypair = await ctx.actorStore.keypair(requester) const localViewer = ctx.localViewer(store, keypair) - const local = await localViewer.getRecordsSinceRev(rev) - const data = await munge(localViewer, res.data, local, requester) - return { data, lag: getLocalLag(local) } + const parsedRes = parseRes(nsid, res) + const data = await munge(localViewer, parsedRes, local, requester) + return formatMungedResponse(data, getLocalLag(local)) }) } + +export const formatMungedResponse = ( + body: T, + lag?: number, +): HandlerResponse => ({ + encoding: 'application/json', + body, + headers: + lag !== undefined + ? { + 'Atproto-Upstream-Lag': lag.toString(10), + } + : undefined, +}) diff --git a/packages/pds/src/read-after-write/viewer.ts b/packages/pds/src/read-after-write/viewer.ts index a3da0e5eb88..6777b951cdf 100644 --- a/packages/pds/src/read-after-write/viewer.ts +++ b/packages/pds/src/read-after-write/viewer.ts @@ -97,51 +97,7 @@ export class LocalViewer { } async getRecordsSinceRev(rev: string): Promise { - const res = await this.actorStore.db.db - .selectFrom('record') - .innerJoin('repo_block', 'repo_block.cid', 'record.cid') - .select([ - 'repo_block.content', - 'uri', - 'repo_block.cid', - 'record.indexedAt', - ]) - .where('record.repoRev', '>', rev) - .limit(10) - .orderBy('record.repoRev', 'asc') - .execute() - // sanity check to ensure that the clock received is not before _all_ local records (for instance in case of account migration) - if (res.length > 0) { - const sanityCheckRes = await this.actorStore.db.db - .selectFrom('record') - .selectAll() - .where('record.repoRev', '<=', rev) - .limit(1) - .executeTakeFirst() - if (!sanityCheckRes) { - return { profile: null, posts: [] } - } - } - return res.reduce( - (acc, cur) => { - const descript = { - uri: new AtUri(cur.uri), - cid: CID.parse(cur.cid), - indexedAt: cur.indexedAt, - record: cborToLexRecord(cur.content), - } - if ( - descript.uri.collection === ids.AppBskyActorProfile && - descript.uri.rkey === 'self' - ) { - acc.profile = descript as RecordDescript - } else if (descript.uri.collection === ids.AppBskyFeedPost) { - acc.posts.push(descript as RecordDescript) - } - return acc - }, - { profile: null, posts: [] } as LocalRecords, - ) + return getRecordsSinceRev(this.actorStore, rev) } async getProfileBasic(): Promise { @@ -364,3 +320,50 @@ export class LocalViewer { } } } + +export const getRecordsSinceRev = async ( + actorStore: ActorStoreReader, + rev: string, +): Promise => { + const res = await actorStore.db.db + .selectFrom('record') + .innerJoin('repo_block', 'repo_block.cid', 'record.cid') + .select(['repo_block.content', 'uri', 'repo_block.cid', 'record.indexedAt']) + .where('record.repoRev', '>', rev) + .limit(10) + .orderBy('record.repoRev', 'asc') + .execute() + // sanity check to ensure that the clock received is not before _all_ local records (for instance in case of account migration) + if (res.length > 0) { + const sanityCheckRes = await actorStore.db.db + .selectFrom('record') + .selectAll() + .where('record.repoRev', '<=', rev) + .limit(1) + .executeTakeFirst() + if (!sanityCheckRes) { + return { count: 0, profile: null, posts: [] } + } + } + return res.reduce( + (acc, cur) => { + const descript = { + uri: new AtUri(cur.uri), + cid: CID.parse(cur.cid), + indexedAt: cur.indexedAt, + record: cborToLexRecord(cur.content), + } + if ( + descript.uri.collection === ids.AppBskyActorProfile && + descript.uri.rkey === 'self' + ) { + acc.profile = descript as RecordDescript + } else if (descript.uri.collection === ids.AppBskyFeedPost) { + acc.posts.push(descript as RecordDescript) + } + acc.count++ + return acc + }, + { count: 0, profile: null, posts: [] } as LocalRecords, + ) +} diff --git a/packages/pds/src/repo/prepare.ts b/packages/pds/src/repo/prepare.ts index 0c311462d23..ffc8cd80843 100644 --- a/packages/pds/src/repo/prepare.ts +++ b/packages/pds/src/repo/prepare.ts @@ -4,12 +4,15 @@ import { ensureValidRecordKey, ensureValidDatetime, } from '@atproto/syntax' -import { MINUTE, TID, dataToCborBlock } from '@atproto/common' +import { TID, check, dataToCborBlock } from '@atproto/common' import { + BlobRef, + LexValue, LexiconDefNotFoundError, RepoRecord, ValidationError, lexToIpld, + untypedJsonBlobRef, } from '@atproto/lexicon' import { cborToLex, @@ -28,91 +31,12 @@ import { PreparedBlobRef, } from './types' import * as lex from '../lexicon/lexicons' -import { isMain as isExternalEmbed } from '../lexicon/types/app/bsky/embed/external' -import { isMain as isImagesEmbed } from '../lexicon/types/app/bsky/embed/images' -import { isMain as isRecordWithMediaEmbed } from '../lexicon/types/app/bsky/embed/recordWithMedia' import { isRecord as isFeedGenerator } from '../lexicon/types/app/bsky/feed/generator' -import { - Record as PostRecord, - isRecord as isPost, -} from '../lexicon/types/app/bsky/feed/post' +import { isRecord as isPost } from '../lexicon/types/app/bsky/feed/post' import { isTag } from '../lexicon/types/app/bsky/richtext/facet' import { isRecord as isList } from '../lexicon/types/app/bsky/graph/list' import { isRecord as isProfile } from '../lexicon/types/app/bsky/actor/profile' import { hasExplicitSlur } from '../handle/explicit-slurs' -import { InvalidRequestError } from '@atproto/xrpc-server' - -// @TODO do this dynamically off of schemas -export const blobsForWrite = (record: unknown): PreparedBlobRef[] => { - if (isProfile(record)) { - const doc = lex.schemaDict.AppBskyActorProfile - const refs: PreparedBlobRef[] = [] - if (record.avatar) { - refs.push({ - cid: record.avatar.ref, - mimeType: record.avatar.mimeType, - constraints: doc.defs.main.record.properties.avatar, - }) - } - if (record.banner) { - refs.push({ - cid: record.banner.ref, - mimeType: record.banner.mimeType, - constraints: doc.defs.main.record.properties.banner, - }) - } - return refs - } else if (isFeedGenerator(record)) { - const doc = lex.schemaDict.AppBskyFeedGenerator - if (!record.avatar) { - return [] - } - return [ - { - cid: record.avatar.ref, - mimeType: record.avatar.mimeType, - constraints: doc.defs.main.record.properties.avatar, - }, - ] - } else if (isList(record)) { - const doc = lex.schemaDict.AppBskyGraphList - if (!record.avatar) { - return [] - } - return [ - { - cid: record.avatar.ref, - mimeType: record.avatar.mimeType, - constraints: doc.defs.main.record.properties.avatar, - }, - ] - } else if (isPost(record)) { - const refs: PreparedBlobRef[] = [] - const embeds = separateEmbeds(record.embed) - for (const embed of embeds) { - if (isImagesEmbed(embed)) { - const doc = lex.schemaDict.AppBskyEmbedImages - for (let i = 0; i < embed.images.length || 0; i++) { - const img = embed.images[i] - refs.push({ - cid: img.image.ref, - mimeType: img.image.mimeType, - constraints: doc.defs.image.properties.image, - }) - } - } else if (isExternalEmbed(embed) && embed.external.thumb) { - const doc = lex.schemaDict.AppBskyEmbedExternal - refs.push({ - cid: embed.external.thumb.ref, - mimeType: embed.external.thumb.mimeType, - constraints: doc.defs.external.properties.thumb, - }) - } - } - return refs - } - return [] -} export const assertValidRecord = (record: Record) => { if (typeof record.$type !== 'string') { @@ -180,17 +104,6 @@ export const prepareCreate = async (opts: { } const nextRkey = TID.next() - if ( - collection === lex.ids.AppBskyFeedPost && - opts.rkey && - !rkeyIsInWindow(nextRkey, new TID(opts.rkey)) - ) { - // @TODO temporary. allowing a window supports creation of post and gate records at the same time. - throw new InvalidRequestError( - 'Custom rkeys for post records should be near the present.', - ) - } - const rkey = opts.rkey || nextRkey.toString() // @TODO: validate against Lexicon record 'key' type, not just overall recordkey syntax ensureValidRecordKey(rkey) @@ -201,17 +114,10 @@ export const prepareCreate = async (opts: { cid: await cidForSafeRecord(record), swapCid, record, - blobs: blobsForWrite(record), + blobs: blobsForWrite(record, validate), } } -// only allow PUTs to certain collections -const ALLOWED_PUTS = [ - lex.ids.AppBskyActorProfile, - lex.ids.AppBskyGraphList, - lex.ids.AppBskyFeedGenerator, -] - export const prepareUpdate = async (opts: { did: string collection: string @@ -221,15 +127,6 @@ export const prepareUpdate = async (opts: { validate?: boolean }): Promise => { const { did, collection, rkey, swapCid, validate = true } = opts - if (!ALLOWED_PUTS.includes(collection)) { - // @TODO temporary - throw new InvalidRequestError( - `Temporarily only accepting updates for collections: ${ALLOWED_PUTS.join( - ', ', - )}`, - ) - } - const record = setCollectionName(collection, opts.record, validate) if (validate) { assertValidRecord(record) @@ -241,7 +138,7 @@ export const prepareUpdate = async (opts: { cid: await cidForSafeRecord(record), swapCid, record, - blobs: blobsForWrite(record), + blobs: blobsForWrite(record, validate), } } @@ -292,16 +189,6 @@ export const writeToOp = (write: PreparedWrite): RecordWriteOp => { } } -function separateEmbeds(embed: PostRecord['embed']) { - if (!embed) { - return [] - } - if (isRecordWithMediaEmbed(embed)) { - return [{ $type: lex.ids.AppBskyEmbedRecord, ...embed.record }, embed.media] - } - return [embed] -} - async function cidForSafeRecord(record: RepoRecord) { try { const block = await dataToCborBlock(lexToIpld(record)) @@ -342,8 +229,92 @@ function assertNoExplicitSlurs(rkey: string, record: RepoRecord) { } } -// ensures two rkeys are not far apart -function rkeyIsInWindow(rkey1: TID, rkey2: TID) { - const ms = Math.abs(rkey1.timestamp() - rkey2.timestamp()) / 1000 - return ms < 10 * MINUTE +type FoundBlobRef = { + ref: BlobRef + path: string[] +} + +export const blobsForWrite = ( + record: RepoRecord, + validate: boolean, +): PreparedBlobRef[] => { + const refs = findBlobRefs(record) + const recordType = + typeof record['$type'] === 'string' ? record['$type'] : undefined + + for (const ref of refs) { + if (check.is(ref.ref.original, untypedJsonBlobRef)) { + throw new InvalidRecordError(`Legacy blob ref at '${ref.path.join('/')}'`) + } + } + + return refs.map(({ ref, path }) => ({ + cid: ref.ref, + mimeType: ref.mimeType, + constraints: + validate && recordType + ? CONSTRAINTS[recordType]?.[path.join('/')] ?? {} + : {}, + })) +} + +export const findBlobRefs = ( + val: LexValue, + path: string[] = [], + layer = 0, +): FoundBlobRef[] => { + if (layer > 32) { + return [] + } + // walk arrays + if (Array.isArray(val)) { + return val.flatMap((item) => findBlobRefs(item, path, layer + 1)) + } + // objects + if (val && typeof val === 'object') { + // convert blobs, leaving the original encoding so that we don't change CIDs on re-encode + if (val instanceof BlobRef) { + return [ + { + ref: val, + path, + }, + ] + } + // retain cids & bytes + if (CID.asCID(val) || val instanceof Uint8Array) { + return [] + } + return Object.entries(val).flatMap(([key, item]) => + findBlobRefs(item, [...path, key], layer + 1), + ) + } + // pass through + return [] +} + +const CONSTRAINTS = { + [lex.ids.AppBskyActorProfile]: { + avatar: + lex.schemaDict.AppBskyActorProfile.defs.main.record.properties.avatar, + banner: + lex.schemaDict.AppBskyActorProfile.defs.main.record.properties.banner, + }, + [lex.ids.AppBskyFeedGenerator]: { + avatar: + lex.schemaDict.AppBskyFeedGenerator.defs.main.record.properties.avatar, + }, + [lex.ids.AppBskyGraphList]: { + avatar: lex.schemaDict.AppBskyGraphList.defs.main.record.properties.avatar, + }, + [lex.ids.AppBskyFeedPost]: { + 'embed/images/image': + lex.schemaDict.AppBskyEmbedImages.defs.image.properties.image, + 'embed/external/thumb': + lex.schemaDict.AppBskyEmbedExternal.defs.external.properties.thumb, + 'embed/media/images/image': + lex.schemaDict.AppBskyEmbedImages.defs.image.properties.image, + 'embed/media/external/thumb': + lex.schemaDict.AppBskyEmbedExternal.defs.external.properties.thumb, + }, } diff --git a/packages/pds/src/sequencer/db/schema.ts b/packages/pds/src/sequencer/db/schema.ts index c479c40d884..63f4911c514 100644 --- a/packages/pds/src/sequencer/db/schema.ts +++ b/packages/pds/src/sequencer/db/schema.ts @@ -5,6 +5,7 @@ export type RepoSeqEventType = | 'rebase' | 'handle' | 'migrate' + | 'identity' | 'tombstone' export interface RepoSeq { diff --git a/packages/pds/src/sequencer/events.ts b/packages/pds/src/sequencer/events.ts index 4ba9ab4d06d..12bcd0827c6 100644 --- a/packages/pds/src/sequencer/events.ts +++ b/packages/pds/src/sequencer/events.ts @@ -81,6 +81,20 @@ export const formatSeqHandleUpdate = async ( } } +export const formatSeqIdentityEvt = async ( + did: string, +): Promise => { + const evt: IdentityEvt = { + did, + } + return { + did, + eventType: 'identity', + event: cborEncode(evt), + sequencedAt: new Date().toISOString(), + } +} + export const formatSeqTombstone = async ( did: string, ): Promise => { @@ -126,6 +140,11 @@ export const handleEvt = z.object({ }) export type HandleEvt = z.infer +export const identityEvt = z.object({ + did: z.string(), +}) +export type IdentityEvt = z.infer + export const tombstoneEvt = z.object({ did: z.string(), }) @@ -143,10 +162,20 @@ type TypedHandleEvt = { time: string evt: HandleEvt } +type TypedIdentityEvt = { + type: 'identity' + seq: number + time: string + evt: IdentityEvt +} type TypedTombstoneEvt = { type: 'tombstone' seq: number time: string evt: TombstoneEvt } -export type SeqEvt = TypedCommitEvt | TypedHandleEvt | TypedTombstoneEvt +export type SeqEvt = + | TypedCommitEvt + | TypedHandleEvt + | TypedIdentityEvt + | TypedTombstoneEvt diff --git a/packages/pds/src/sequencer/sequencer.ts b/packages/pds/src/sequencer/sequencer.ts index 7ea23db13f0..444b39e195f 100644 --- a/packages/pds/src/sequencer/sequencer.ts +++ b/packages/pds/src/sequencer/sequencer.ts @@ -6,10 +6,12 @@ import { CommitData } from '@atproto/repo' import { CommitEvt, HandleEvt, + IdentityEvt, SeqEvt, TombstoneEvt, formatSeqCommit, formatSeqHandleUpdate, + formatSeqIdentityEvt, formatSeqTombstone, } from './events' import { @@ -145,6 +147,13 @@ export class Sequencer extends (EventEmitter as new () => SequencerEmitter) { time: row.sequencedAt, evt: evt as HandleEvt, }) + } else if (row.eventType === 'identity') { + seqEvts.push({ + type: 'identity', + seq: row.seq, + time: row.sequencedAt, + evt: evt as IdentityEvt, + }) } else if (row.eventType === 'tombstone') { seqEvts.push({ type: 'tombstone', @@ -209,6 +218,11 @@ export class Sequencer extends (EventEmitter as new () => SequencerEmitter) { await this.sequenceEvt(evt) } + async sequenceIdentityEvt(did: string) { + const evt = await formatSeqIdentityEvt(did) + await this.sequenceEvt(evt) + } + async sequenceTombstone(did: string) { const evt = await formatSeqTombstone(did) await this.sequenceEvt(evt) diff --git a/packages/pds/src/well-known.ts b/packages/pds/src/well-known.ts index d1c6169cac9..a2c0fe4a7b1 100644 --- a/packages/pds/src/well-known.ts +++ b/packages/pds/src/well-known.ts @@ -14,7 +14,7 @@ export const createRouter = (ctx: AppContext): express.Router => { } let did: string | undefined try { - const user = await ctx.accountManager.getAccount(handle, true) + const user = await ctx.accountManager.getAccount(handle) did = user?.did } catch (err) { return res.status(500).send('Internal Server Error') diff --git a/packages/pds/tests/account-deactivation.test.ts b/packages/pds/tests/account-deactivation.test.ts new file mode 100644 index 00000000000..83820f24e49 --- /dev/null +++ b/packages/pds/tests/account-deactivation.test.ts @@ -0,0 +1,148 @@ +import AtpAgent from '@atproto/api' +import { SeedClient, TestNetworkNoAppView, basicSeed } from '@atproto/dev-env' + +describe('account deactivation', () => { + let network: TestNetworkNoAppView + + let sc: SeedClient + let agent: AtpAgent + + let alice: string + + beforeAll(async () => { + network = await TestNetworkNoAppView.create({ + dbPostgresSchema: 'account_deactivation', + }) + + sc = network.getSeedClient() + agent = network.pds.getClient() + + await basicSeed(sc) + alice = sc.dids.alice + await network.processAll() + }) + + afterAll(async () => { + await network.close() + }) + + it('deactivates account', async () => { + await agent.com.atproto.server.deactivateAccount( + {}, + { encoding: 'application/json', headers: sc.getHeaders(alice) }, + ) + }) + + it('no longer serves repo data', async () => { + await expect( + agent.com.atproto.sync.getRepo({ did: alice }), + ).rejects.toThrow() + await expect( + agent.com.atproto.sync.getLatestCommit({ did: alice }), + ).rejects.toThrow() + await expect( + agent.com.atproto.sync.listBlobs({ did: alice }), + ).rejects.toThrow() + const recordUri = sc.posts[alice][0].ref.uri + await expect( + agent.com.atproto.sync.getRecord({ + did: alice, + collection: recordUri.collection, + rkey: recordUri.rkey, + }), + ).rejects.toThrow() + await expect( + agent.com.atproto.repo.getRecord({ + repo: alice, + collection: recordUri.collection, + rkey: recordUri.rkey, + }), + ).rejects.toThrow() + await expect( + agent.com.atproto.repo.describeRepo({ + repo: alice, + }), + ).rejects.toThrow() + + const blobCid = sc.profiles[alice].avatar.cid + await expect( + agent.com.atproto.sync.getBlob({ + did: alice, + cid: blobCid, + }), + ).rejects.toThrow() + const listedRepos = await agent.com.atproto.sync.listRepos() + expect(listedRepos.data.repos.find((r) => r.did === alice)).toBeUndefined() + }) + + it('no longer resolves handle', async () => { + await expect( + agent.com.atproto.identity.resolveHandle({ + handle: sc.accounts[alice].handle, + }), + ).rejects.toThrow() + }) + + it('still allows login', async () => { + await agent.com.atproto.server.createSession({ + identifier: alice, + password: sc.accounts[alice].password, + }) + }) + + it('does not allow writes', async () => { + const createAttempt = agent.com.atproto.repo.createRecord( + { + repo: alice, + collection: 'app.bsky.feed.post', + record: { + text: 'blah', + createdAt: new Date().toISOString(), + }, + }, + { + encoding: 'application/json', + headers: sc.getHeaders(alice), + }, + ) + const uri = sc.posts[alice][0].ref.uri + await expect(createAttempt).rejects.toThrow('Account is deactivated') + + const putAttempt = agent.com.atproto.repo.putRecord( + { + repo: alice, + collection: uri.collection, + rkey: uri.rkey, + record: { + text: 'blah', + createdAt: new Date().toISOString(), + }, + }, + { + encoding: 'application/json', + headers: sc.getHeaders(alice), + }, + ) + await expect(putAttempt).rejects.toThrow('Account is deactivated') + + const deleteAttempt = agent.com.atproto.repo.deleteRecord( + { + repo: alice, + collection: uri.collection, + rkey: uri.rkey, + }, + { + encoding: 'application/json', + headers: sc.getHeaders(alice), + }, + ) + await expect(deleteAttempt).rejects.toThrow('Account is deactivated') + }) + + it('reactivates', async () => { + await agent.com.atproto.server.activateAccount(undefined, { + headers: sc.getHeaders(alice), + }) + await agent.com.atproto.sync.getRepo({ did: alice }) + }) +}) diff --git a/packages/pds/tests/account-migration.test.ts b/packages/pds/tests/account-migration.test.ts new file mode 100644 index 00000000000..beb14599e38 --- /dev/null +++ b/packages/pds/tests/account-migration.test.ts @@ -0,0 +1,219 @@ +import AtpAgent, { AtUri } from '@atproto/api' +import { + SeedClient, + TestNetworkNoAppView, + TestPds, + mockNetworkUtilities, +} from '@atproto/dev-env' +import { readCar } from '@atproto/repo' +import assert from 'assert' + +describe('account migration', () => { + let network: TestNetworkNoAppView + let newPds: TestPds + + let sc: SeedClient + let oldAgent: AtpAgent + let newAgent: AtpAgent + + let alice: string + + beforeAll(async () => { + network = await TestNetworkNoAppView.create({ + dbPostgresSchema: 'account_migration', + }) + newPds = await TestPds.create({ + didPlcUrl: network.plc.url, + }) + mockNetworkUtilities(newPds) + + sc = network.getSeedClient() + oldAgent = network.pds.getClient() + newAgent = newPds.getClient() + + await sc.createAccount('alice', { + email: 'alice@test.com', + handle: 'alice.test', + password: 'alice-pass', + }) + alice = sc.dids.alice + + for (let i = 0; i < 100; i++) { + await sc.post(alice, 'test post') + } + const img1 = await sc.uploadFile( + alice, + '../dev-env/src/seed/img/at.png', + 'image/png', + ) + const img2 = await sc.uploadFile( + alice, + '../dev-env/src/seed/img/key-alt.jpg', + 'image/jpeg', + ) + const img3 = await sc.uploadFile( + alice, + '../dev-env/src/seed/img/key-landscape-small.jpg', + 'image/jpeg', + ) + + await sc.post(alice, 'test', undefined, [img1]) + await sc.post(alice, 'test', undefined, [img1, img2]) + await sc.post(alice, 'test', undefined, [img3]) + + await network.processAll() + + await oldAgent.login({ + identifier: sc.accounts[alice].handle, + password: sc.accounts[alice].password, + }) + }) + + afterAll(async () => { + await newPds.close() + await network.close() + }) + + it('migrates an account', async () => { + const describeRes = await newAgent.api.com.atproto.server.describeServer() + const newServerDid = describeRes.data.did + + const serviceJwtRes = await oldAgent.com.atproto.server.getServiceAuth({ + aud: newServerDid, + }) + const serviceJwt = serviceJwtRes.data.token + + await newAgent.api.com.atproto.server.createAccount( + { + handle: 'new-alice.test', + email: 'alice@test.com', + password: 'alice-pass', + did: alice, + }, + { + headers: { authorization: `Bearer ${serviceJwt}` }, + encoding: 'application/json', + }, + ) + await newAgent.login({ + identifier: 'new-alice.test', + password: 'alice-pass', + }) + + const statusRes1 = await newAgent.com.atproto.server.checkAccountStatus() + expect(statusRes1.data).toMatchObject({ + activated: false, + validDid: false, + repoBlocks: 2, // commit & empty data root + indexedRecords: 0, + privateStateValues: 0, + expectedBlobs: 0, + importedBlobs: 0, + }) + + const repoRes = await oldAgent.com.atproto.sync.getRepo({ did: alice }) + const carBlocks = await readCar(repoRes.data) + + await newAgent.com.atproto.repo.importRepo(repoRes.data, { + encoding: 'application/vnd.ipld.car', + }) + + const statusRes2 = await newAgent.com.atproto.server.checkAccountStatus() + expect(statusRes2.data).toMatchObject({ + activated: false, + validDid: false, + indexedRecords: 103, + privateStateValues: 0, + expectedBlobs: 3, + importedBlobs: 0, + }) + expect(statusRes2.data.repoBlocks).toBe(carBlocks.blocks.size) + + const missingBlobs = await newAgent.com.atproto.repo.listMissingBlobs() + expect(missingBlobs.data.blobs.length).toBe(3) + + let blobCursor: string | undefined = undefined + do { + const listedBlobs = await oldAgent.com.atproto.sync.listBlobs({ + did: alice, + cursor: blobCursor, + }) + for (const cid of listedBlobs.data.cids) { + const blobRes = await oldAgent.com.atproto.sync.getBlob({ + did: alice, + cid, + }) + await newAgent.com.atproto.repo.uploadBlob(blobRes.data, { + encoding: blobRes.headers['content-type'], + }) + } + blobCursor = listedBlobs.data.cursor + } while (blobCursor) + + const statusRes3 = await newAgent.com.atproto.server.checkAccountStatus() + expect(statusRes3.data.expectedBlobs).toBe(3) + expect(statusRes3.data.importedBlobs).toBe(3) + + const prefs = await oldAgent.api.app.bsky.actor.getPreferences() + await newAgent.api.app.bsky.actor.putPreferences(prefs.data) + + const getDidCredentials = + await newAgent.com.atproto.identity.getRecommendedDidCredentials() + + await oldAgent.com.atproto.identity.requestPlcOperationSignature() + const res = await network.pds.ctx.accountManager.db.db + .selectFrom('email_token') + .selectAll() + .where('did', '=', alice) + .where('purpose', '=', 'plc_operation') + .executeTakeFirst() + const token = res?.token + assert(token) + + const plcOp = await oldAgent.com.atproto.identity.signPlcOperation({ + token, + ...getDidCredentials.data, + }) + + await newAgent.com.atproto.identity.submitPlcOperation({ + operation: plcOp.data.operation, + }) + + await newAgent.com.atproto.server.activateAccount() + + const statusRes4 = await newAgent.com.atproto.server.checkAccountStatus() + expect(statusRes4.data).toMatchObject({ + activated: true, + validDid: true, + indexedRecords: 103, + privateStateValues: 0, + expectedBlobs: 3, + importedBlobs: 3, + }) + + await oldAgent.com.atproto.server.deactivateAccount({}) + + const statusResOldPds = + await oldAgent.com.atproto.server.checkAccountStatus() + expect(statusResOldPds.data).toMatchObject({ + activated: false, + validDid: false, + }) + + const postRes = await newAgent.api.app.bsky.feed.post.create( + { repo: alice }, + { + text: 'new pds!', + createdAt: new Date().toISOString(), + }, + ) + const postUri = new AtUri(postRes.uri) + const fetchedPost = await newAgent.api.app.bsky.feed.post.get({ + repo: postUri.hostname, + rkey: postUri.rkey, + }) + expect(fetchedPost.value.text).toEqual('new pds!') + const statusRes5 = await newAgent.com.atproto.server.checkAccountStatus() + expect(statusRes5.data.indexedRecords).toBe(104) + }) +}) diff --git a/packages/pds/tests/account.test.ts b/packages/pds/tests/account.test.ts index 70ca5abf741..743248814f8 100644 --- a/packages/pds/tests/account.test.ts +++ b/packages/pds/tests/account.test.ts @@ -559,4 +559,46 @@ describe('account', () => { }), ).resolves.toBeDefined() }) + + it('allows an admin to update password', async () => { + const tryUnauthed = agent.api.com.atproto.admin.updateAccountPassword({ + did, + password: 'new-admin-pass', + }) + await expect(tryUnauthed).rejects.toThrow('Authentication Required') + + const tryAsModerator = agent.api.com.atproto.admin.updateAccountPassword( + { did, password: 'new-admin-pass' }, + { + headers: network.pds.adminAuthHeaders('moderator'), + encoding: 'application/json', + }, + ) + await expect(tryAsModerator).rejects.toThrow( + 'Must be an admin to update an account password', + ) + + await agent.api.com.atproto.admin.updateAccountPassword( + { did, password: 'new-admin-password' }, + { + headers: network.pds.adminAuthHeaders('admin'), + encoding: 'application/json', + }, + ) + + // old password fails + await expect( + agent.api.com.atproto.server.createSession({ + identifier: did, + password, + }), + ).rejects.toThrow('Invalid identifier or password') + + await expect( + agent.api.com.atproto.server.createSession({ + identifier: did, + password: 'new-admin-password', + }), + ).resolves.toBeDefined() + }) }) diff --git a/packages/pds/tests/admin-auth.test.ts b/packages/pds/tests/admin-auth.test.ts index 4cf7d5c26a5..dffd9261874 100644 --- a/packages/pds/tests/admin-auth.test.ts +++ b/packages/pds/tests/admin-auth.test.ts @@ -96,7 +96,7 @@ describe('admin auth', () => { encoding: 'application/json', }, ) - await expect(attempt).rejects.toThrow('Untrusted issuer for admin actions') + await expect(attempt).rejects.toThrow('Untrusted issuer') }) it('does not allow requests with a bad signature', async () => { diff --git a/packages/pds/tests/crud.test.ts b/packages/pds/tests/crud.test.ts index e675119dca2..dd3f3f3b11f 100644 --- a/packages/pds/tests/crud.test.ts +++ b/packages/pds/tests/crud.test.ts @@ -483,32 +483,6 @@ describe('crud operations', () => { expect(rootRes2.data.rev).toEqual(rootRes1.data.rev) }) - it('temporarily only allows updates to profile', async () => { - const { repo } = bobAgent.api.com.atproto - const put = await repo.putRecord({ - repo: bob.did, - collection: ids.AppBskyGraphFollow, - rkey: TID.nextStr(), - record: { - subject: alice.did, - createdAt: new Date().toISOString(), - }, - }) - const edit = repo.putRecord({ - repo: bob.did, - collection: ids.AppBskyGraphFollow, - rkey: new AtUri(put.data.uri).rkey, - record: { - subject: bob.did, - createdAt: new Date().toISOString(), - }, - }) - - await expect(edit).rejects.toThrow( - 'Temporarily only accepting updates for collections: app.bsky.actor.profile, app.bsky.graph.list, app.bsky.feed.generator', - ) - }) - it('fails on user mismatch', async () => { const { repo } = aliceAgent.api.com.atproto const put = repo.putRecord({ @@ -638,6 +612,146 @@ describe('crud operations', () => { ) }) + describe('unvalidated writes', () => { + it('disallows creation of unknown lexicons when validate is set to true', async () => { + const attempt = aliceAgent.api.com.atproto.repo.createRecord({ + repo: alice.did, + collection: 'com.example.record', + record: { + blah: 'thing', + }, + }) + await expect(attempt).rejects.toThrow( + 'Lexicon not found: lex:com.example.record', + ) + }) + + it('allows creation of unknown lexicons when validate is set to false', async () => { + const res = await aliceAgent.api.com.atproto.repo.createRecord({ + repo: alice.did, + collection: 'com.example.record', + record: { + blah: 'thing', + }, + validate: false, + }) + const record = await ctx.actorStore.read(alice.did, (store) => + store.record.getRecord(new AtUri(res.data.uri), res.data.cid), + ) + expect(record?.value).toEqual({ + $type: 'com.example.record', + blah: 'thing', + }) + }) + + it('allows update of unknown lexicons when validate is set to false', async () => { + const createRes = await aliceAgent.api.com.atproto.repo.createRecord({ + repo: alice.did, + collection: 'com.example.record', + record: { + blah: 'thing', + }, + validate: false, + }) + const uri = new AtUri(createRes.data.uri) + const updateRes = await aliceAgent.api.com.atproto.repo.putRecord({ + repo: alice.did, + collection: 'com.example.record', + rkey: uri.rkey, + record: { + blah: 'something else', + }, + validate: false, + }) + const record = await ctx.actorStore.read(alice.did, (store) => + store.record.getRecord(uri, updateRes.data.cid), + ) + expect(record?.value).toEqual({ + $type: 'com.example.record', + blah: 'something else', + }) + }) + + it('correctly associates images with unknown record types', async () => { + const file = await fs.readFile( + '../dev-env/src/seed/img/key-portrait-small.jpg', + ) + const uploadedRes = await aliceAgent.api.com.atproto.repo.uploadBlob( + file, + { + encoding: 'image/jpeg', + }, + ) + + const res = await aliceAgent.api.com.atproto.repo.createRecord({ + repo: alice.did, + collection: 'com.example.record', + record: { + blah: 'thing', + image: uploadedRes.data.blob, + }, + validate: false, + }) + const record = await ctx.actorStore.read(alice.did, (store) => + store.record.getRecord(new AtUri(res.data.uri), res.data.cid), + ) + expect(record?.value).toMatchObject({ + $type: 'com.example.record', + blah: 'thing', + }) + const recordBlobs = await ctx.actorStore.read(alice.did, (store) => + store.db.db + .selectFrom('blob') + .innerJoin('record_blob', 'record_blob.blobCid', 'blob.cid') + .where('recordUri', '=', res.data.uri) + .selectAll() + .execute(), + ) + expect(recordBlobs.length).toBe(1) + expect(recordBlobs.at(0)?.cid).toBe(uploadedRes.data.blob.ref.toString()) + }) + + it('enforces record type constraint even when unvalidated', async () => { + const attempt = aliceAgent.api.com.atproto.repo.createRecord({ + repo: alice.did, + collection: 'com.example.record', + record: { + $type: 'com.example.other', + blah: 'thing', + }, + }) + await expect(attempt).rejects.toThrow( + 'Invalid $type: expected com.example.record, got com.example.other', + ) + }) + + it('enforces blob ref format even when unvalidated', async () => { + const file = await fs.readFile( + '../dev-env/src/seed/img/key-portrait-small.jpg', + ) + const uploadedRes = await aliceAgent.api.com.atproto.repo.uploadBlob( + file, + { + encoding: 'image/jpeg', + }, + ) + + const attempt = aliceAgent.api.com.atproto.repo.createRecord({ + repo: alice.did, + collection: 'com.example.record', + record: { + blah: 'thing', + image: { + cid: uploadedRes.data.blob.ref.toString(), + mimeType: uploadedRes.data.blob.mimeType, + }, + }, + validate: false, + }) + await expect(attempt).rejects.toThrow(`Legacy blob ref at 'image'`) + }) + }) + describe('compare-and-swap', () => { let recordCount = 0 // Ensures unique cids const postRecord = () => ({ @@ -937,7 +1051,7 @@ describe('crud operations', () => { record: { text: 'x', createdAt: new Date().toISOString(), - deepObject: createDeepObject(4000), + deepObject: createDeepObject(3000), }, }), ) diff --git a/packages/pds/tests/entryway.test.ts b/packages/pds/tests/entryway.test.ts index dc3ba5c7e35..8ef77239a4d 100644 --- a/packages/pds/tests/entryway.test.ts +++ b/packages/pds/tests/entryway.test.ts @@ -145,13 +145,11 @@ describe('entryway', () => { pds: pds.ctx.cfg.service.publicUrl, signer: rotationKey, }) - const tryCreateAccount = pdsAgent.api.com.atproto.server.createAccount( - { did: plcCreate.did, plcOp: plcCreate.op, handle: 'weirdalice.test' }, - { - headers: SeedClient.getHeaders(accessToken), - encoding: 'application/json', - }, - ) + const tryCreateAccount = pdsAgent.api.com.atproto.server.createAccount({ + did: plcCreate.did, + plcOp: plcCreate.op, + handle: 'weirdalice.test', + }) await expect(tryCreateAccount).rejects.toThrow('invalid plc operation') }) }) @@ -176,6 +174,8 @@ const createEntryway = async ( bskyAppViewCdnUrlPattern: 'http://cdn.appview.com/%s/%s/%s', jwtSecret: randomStr(8, 'base32'), repoSigningKeyK256PrivateKeyHex: await getPrivateHex(signingKey), + modServiceUrl: 'https://mod.invalid', + modServiceDid: 'did:example:invalid', ...config, } const cfg = pdsEntryway.envToCfg(env) @@ -183,6 +183,8 @@ const createEntryway = async ( const server = await pdsEntryway.PDS.create(cfg, secrets) await server.ctx.db.migrateToLatestOrThrow() await server.start() + // @TODO temp hack because entryway teardown calls signupActivator.run() by mistake + server.ctx.signupActivator.run = server.ctx.signupActivator.destroy return server } diff --git a/packages/pds/tests/moderation.test.ts b/packages/pds/tests/moderation.test.ts index ba58bcc70eb..4d3acfe2e25 100644 --- a/packages/pds/tests/moderation.test.ts +++ b/packages/pds/tests/moderation.test.ts @@ -198,14 +198,19 @@ describe('moderation', () => { }) it('prevents blob from being referenced again.', async () => { - const uploaded = await sc.uploadFile( + const referenceBlob = sc.post(sc.dids.carol, 'pic', [], [blobRef]) + await expect(referenceBlob).rejects.toThrow('Could not find blob:') + }) + + it('prevents blob from being reuploaded', async () => { + const attempt = sc.uploadFile( sc.dids.carol, '../dev-env/src/seed/img/key-alt.jpg', 'image/jpeg', ) - expect(uploaded.image.ref.equals(blobRef.image.ref)).toBeTruthy() - const referenceBlob = sc.post(sc.dids.carol, 'pic', [], [blobRef]) - await expect(referenceBlob).rejects.toThrow('Could not find blob:') + await expect(attempt).rejects.toThrow( + 'Blob has been takendown, cannot re-upload', + ) }) it('prevents image blob from being served.', async () => { diff --git a/packages/pds/tests/plc-operations.test.ts b/packages/pds/tests/plc-operations.test.ts new file mode 100644 index 00000000000..9c4ed9002cb --- /dev/null +++ b/packages/pds/tests/plc-operations.test.ts @@ -0,0 +1,226 @@ +import AtpAgent from '@atproto/api' +import { Secp256k1Keypair } from '@atproto/crypto' +import { SeedClient, TestNetworkNoAppView, basicSeed } from '@atproto/dev-env' +import * as plc from '@did-plc/lib' +import assert from 'assert' +import { once } from 'events' +import Mail from 'nodemailer/lib/mailer' +import { EventEmitter } from 'stream' +import { AppContext } from '../src' +import { check } from '@atproto/common' + +describe('plc operations', () => { + let network: TestNetworkNoAppView + let ctx: AppContext + let agent: AtpAgent + let sc: SeedClient + + const mailCatcher = new EventEmitter() + let _origSendMail + + let alice: string + + let sampleKey: string + + beforeAll(async () => { + network = await TestNetworkNoAppView.create({ + dbPostgresSchema: 'plc_operations', + }) + ctx = network.pds.ctx + const mailer = ctx.mailer + + sc = network.getSeedClient() + agent = network.pds.getClient() + + await basicSeed(sc) + alice = sc.dids.alice + await network.processAll() + + sampleKey = (await Secp256k1Keypair.create()).did() + + // Catch emails for use in tests + _origSendMail = mailer.transporter.sendMail + mailer.transporter.sendMail = async (opts) => { + const result = await _origSendMail.call(mailer.transporter, opts) + mailCatcher.emit('mail', opts) + return result + } + }) + + afterAll(async () => { + await network.close() + }) + + const getMailFrom = async (promise): Promise => { + const result = await Promise.all([once(mailCatcher, 'mail'), promise]) + return result[0][0] + } + + const getTokenFromMail = (mail: Mail.Options) => + mail.html?.toString().match(/>([a-z0-9]{5}-[a-z0-9]{5})) => { + const lastOp = await ctx.plcClient.getLastOp(did) + if (check.is(lastOp, plc.def.tombstone)) { + throw new Error('Did is tombstoned') + } + return plc.createUpdateOp(lastOp, ctx.plcRotationKey, (lastOp) => ({ + ...lastOp, + rotationKeys: op.rotationKeys ?? lastOp.rotationKeys, + alsoKnownAs: op.alsoKnownAs ?? lastOp.alsoKnownAs, + verificationMethods: op.verificationMethods ?? lastOp.verificationMethods, + services: op.services ?? lastOp.services, + })) + } + + const expectFailedOp = async ( + did: string, + op: Partial, + expectedErr?: string, + ) => { + const operation = await signOp(did, op) + const attempt = agent.com.atproto.identity.submitPlcOperation( + { operation }, + { + encoding: 'application/json', + headers: sc.getHeaders(alice), + }, + ) + await expect(attempt).rejects.toThrow(expectedErr) + } + + it("prevents submitting an operation that removes the server's rotation key", async () => { + await expectFailedOp( + alice, + { rotationKeys: [sampleKey] }, + "Rotation keys do not include server's rotation key", + ) + }) + + it('prevents submitting an operation that incorrectly sets the signing key', async () => { + await expectFailedOp( + alice, + { + verificationMethods: { + atproto: sampleKey, + }, + }, + 'Incorrect signing key', + ) + }) + + it('prevents submitting an operation that incorrectly sets the handle', async () => { + await expectFailedOp( + alice, + { + alsoKnownAs: ['at://new-alice.test'], + }, + 'Incorrect handle in alsoKnownAs', + ) + }) + + it('prevents submitting an operation that incorrectly sets the pds endpoint', async () => { + await expectFailedOp( + alice, + { + services: { + atproto_pds: { + type: 'AtprotoPersonalDataServer', + endpoint: 'https://example.com', + }, + }, + }, + 'Incorrect endpoint on atproto_pds service', + ) + }) + + it('prevents submitting an operation that incorrectly sets the pds service type', async () => { + await expectFailedOp( + alice, + { + services: { + atproto_pds: { + type: 'NotAPersonalDataServer', + endpoint: ctx.cfg.service.publicUrl, + }, + }, + }, + 'Incorrect type on atproto_pds service', + ) + }) + + it('does not allow signing plc operation without a token', async () => { + const attempt = agent.com.atproto.identity.signPlcOperation( + { + rotationKeys: [sampleKey], + }, + { encoding: 'application/json', headers: sc.getHeaders(alice) }, + ) + await expect(attempt).rejects.toThrow( + 'email confirmation token required to sign PLC operations', + ) + }) + + let token: string + + it('requests a plc signature', async () => { + const mail = await getMailFrom( + agent.api.com.atproto.identity.requestPlcOperationSignature(undefined, { + headers: sc.getHeaders(alice), + }), + ) + + expect(mail.to).toEqual(sc.accounts[alice].email) + expect(mail.html).toContain('PLC Update Requested') + + const gotToken = getTokenFromMail(mail) + assert(gotToken) + token = gotToken + }) + + it('does not sign a plc operation with a bad token', async () => { + const attempt = agent.api.com.atproto.identity.signPlcOperation( + { + token: '123456', + rotationKeys: [sampleKey], + }, + { encoding: 'application/json', headers: sc.getHeaders(alice) }, + ) + await expect(attempt).rejects.toThrow('Token is invalid') + }) + + let operation: any + + it('signs a plc operation with a valid token', async () => { + const res = await agent.api.com.atproto.identity.signPlcOperation( + { + token, + rotationKeys: [sampleKey, ctx.plcRotationKey.did()], + }, + { encoding: 'application/json', headers: sc.getHeaders(alice) }, + ) + const currData = await ctx.plcClient.getDocumentData(alice) + expect(res.data.operation['alsoKnownAs']).toEqual(currData.alsoKnownAs) + expect(res.data.operation['verificationMethods']).toEqual( + currData.verificationMethods, + ) + expect(res.data.operation['services']).toEqual(currData.services) + expect(res.data.operation['rotationKeys']).toEqual([ + sampleKey, + ctx.plcRotationKey.did(), + ]) + operation = res.data.operation + }) + + it('submits a valid operation', async () => { + await agent.com.atproto.identity.submitPlcOperation( + { operation }, + { + encoding: 'application/json', + headers: sc.getHeaders(alice), + }, + ) + const didData = await ctx.plcClient.getDocumentData(alice) + expect(didData.rotationKeys).toEqual([sampleKey, ctx.plcRotationKey.did()]) + }) +}) diff --git a/packages/pds/tests/proxied/__snapshots__/admin.test.ts.snap b/packages/pds/tests/proxied/__snapshots__/admin.test.ts.snap index 5e9b4e0882a..285c24cf8f0 100644 --- a/packages/pds/tests/proxied/__snapshots__/admin.test.ts.snap +++ b/packages/pds/tests/proxied/__snapshots__/admin.test.ts.snap @@ -14,7 +14,7 @@ Array [ }, Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 5, + "id": 6, "reason": "impersonation", "reasonType": "com.atproto.moderation.defs#reasonOther", "reportedBy": "user(2)", @@ -34,7 +34,7 @@ Array [ "event": Object { "$type": "com.atproto.admin.defs#modEventAcknowledge", }, - "id": 7, + "id": 9, "subject": Object { "$type": "com.atproto.admin.defs#repoRef", "did": "user(0)", @@ -51,7 +51,7 @@ Array [ "comment": "impersonation", "reportType": "com.atproto.moderation.defs#reasonOther", }, - "id": 5, + "id": 6, "subject": Object { "$type": "com.atproto.admin.defs#repoRef", "did": "user(0)", @@ -62,6 +62,25 @@ Array [ Object { "createdAt": "1970-01-01T00:00:00.000Z", "createdBy": "user(2)", + "event": Object { + "$type": "com.atproto.admin.defs#modEventTag", + "add": Array [ + "lang:en", + "lang:i", + ], + "remove": Array [], + }, + "id": 5, + "subject": Object { + "$type": "com.atproto.admin.defs#repoRef", + "did": "user(0)", + }, + "subjectBlobCids": Array [], + "subjectHandle": "bob.test", + }, + Object { + "createdAt": "1970-01-01T00:00:00.000Z", + "createdBy": "user(3)", "creatorHandle": "alice.test", "event": Object { "$type": "com.atproto.admin.defs#modEventReport", @@ -118,6 +137,10 @@ Object { }, "subjectBlobCids": Array [], "subjectRepoHandle": "bob.test", + "tags": Array [ + "lang:en", + "lang:i", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, @@ -178,13 +201,32 @@ Object { exports[`proxies admin requests fetches moderation events. 1`] = ` Array [ + Object { + "createdAt": "1970-01-01T00:00:00.000Z", + "createdBy": "user(0)", + "event": Object { + "$type": "com.atproto.admin.defs#modEventTag", + "add": Array [ + "lang:und", + ], + "remove": Array [], + }, + "id": 8, + "subject": Object { + "$type": "com.atproto.repo.strongRef", + "cid": "cids(0)", + "uri": "record(0)", + }, + "subjectBlobCids": Array [], + "subjectHandle": "bob.test", + }, Object { "createdAt": "1970-01-01T00:00:00.000Z", "createdBy": "did:example:admin", "event": Object { "$type": "com.atproto.admin.defs#modEventAcknowledge", }, - "id": 6, + "id": 7, "subject": Object { "$type": "com.atproto.repo.strongRef", "cid": "cids(0)", @@ -206,7 +248,7 @@ Object { "moderation": Object { "subjectStatus": Object { "createdAt": "1970-01-01T00:00:00.000Z", - "id": 3, + "id": 4, "lastReviewedAt": "1970-01-01T00:00:00.000Z", "lastReviewedBy": "did:example:admin", "reviewState": "com.atproto.admin.defs#reviewClosed", @@ -217,6 +259,9 @@ Object { }, "subjectBlobCids": Array [], "subjectRepoHandle": "bob.test", + "tags": Array [ + "lang:und", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, @@ -267,6 +312,10 @@ Object { }, "subjectBlobCids": Array [], "subjectRepoHandle": "bob.test", + "tags": Array [ + "lang:en", + "lang:i", + ], "takendown": false, "updatedAt": "1970-01-01T00:00:00.000Z", }, @@ -368,7 +417,7 @@ Object { "event": Object { "$type": "com.atproto.admin.defs#modEventAcknowledge", }, - "id": 6, + "id": 7, "subject": Object { "$type": "com.atproto.repo.strongRef", "cid": "cids(0)", @@ -385,7 +434,7 @@ Object { "event": Object { "$type": "com.atproto.admin.defs#modEventAcknowledge", }, - "id": 7, + "id": 9, "subject": Object { "$type": "com.atproto.admin.defs#repoRef", "did": "user(0)", diff --git a/packages/pds/tests/proxied/feedgen.test.ts b/packages/pds/tests/proxied/feedgen.test.ts index 0e9e40f2a5c..c3cd5d208d6 100644 --- a/packages/pds/tests/proxied/feedgen.test.ts +++ b/packages/pds/tests/proxied/feedgen.test.ts @@ -17,6 +17,7 @@ describe('feedgen proxy view', () => { agent = network.pds.getClient() sc = network.getSeedClient() await basicSeed(sc, { addModLabels: network.bsky }) + feedUri = AtUri.make(sc.dids.alice, 'app.bsky.feed.generator', 'mutuals') const feedGen = await network.createFeedGen({ diff --git a/packages/pds/tests/proxied/read-after-write.test.ts b/packages/pds/tests/proxied/read-after-write.test.ts index 8e864f0c8d5..5f70416751a 100644 --- a/packages/pds/tests/proxied/read-after-write.test.ts +++ b/packages/pds/tests/proxied/read-after-write.test.ts @@ -1,4 +1,5 @@ -import util from 'util' +import util from 'node:util' +import assert from 'node:assert' import AtpAgent from '@atproto/api' import { TestNetwork, SeedClient, RecordRef } from '@atproto/dev-env' import basicSeed from '../seeds/basic' @@ -43,6 +44,7 @@ describe('proxy read after write', () => { }) it('handles image formatting', async () => { + assert(network.pds.ctx.cfg.bskyAppView) const blob = await sc.uploadFile( alice, '../dev-env/src/seed/img/key-landscape-small.jpg', @@ -123,6 +125,7 @@ describe('proxy read after write', () => { }) it('handles read after write on threads with record embeds', async () => { + assert(network.pds.ctx.cfg.bskyAppView) const img = await sc.uploadFile( alice, '../dev-env/src/seed/img/key-landscape-small.jpg', diff --git a/packages/pds/tests/sequencer.test.ts b/packages/pds/tests/sequencer.test.ts index 3d9fed7a152..82308b4db35 100644 --- a/packages/pds/tests/sequencer.test.ts +++ b/packages/pds/tests/sequencer.test.ts @@ -24,8 +24,8 @@ describe('sequencer', () => { await userSeed(sc) alice = sc.dids.alice bob = sc.dids.bob - // 6 events in userSeed - totalEvts = 6 + // 10 events in userSeed + totalEvts = 10 }) afterAll(async () => { @@ -63,10 +63,11 @@ describe('sequencer', () => { const evtToDbRow = (e: SeqEvt) => { const did = e.type === 'commit' ? e.evt.repo : e.evt.did + const eventType = e.type === 'commit' ? 'append' : e.type return { seq: e.seq, did, - eventType: 'append', + eventType, event: Buffer.from(cborEncode(e.evt)), invalidated: 0, sequencedAt: e.time, diff --git a/packages/pds/tests/sync/subscribe-repos.test.ts b/packages/pds/tests/sync/subscribe-repos.test.ts index bc877ec11ee..d6f11cc4121 100644 --- a/packages/pds/tests/sync/subscribe-repos.test.ts +++ b/packages/pds/tests/sync/subscribe-repos.test.ts @@ -302,7 +302,7 @@ describe('repo subscribe repos', () => { ws.terminate() await verifyCommitEvents(evts) - const handleEvts = getHandleEvts(evts.slice(-3)) + const handleEvts = getHandleEvts(evts.slice(-6)) verifyHandleEvent(handleEvts[0], alice, 'alice2.test') verifyHandleEvent(handleEvts[1], bob, 'bob2.test') }) @@ -318,7 +318,7 @@ describe('repo subscribe repos', () => { const evts = await readTillCaughtUp(gen, update) ws.terminate() - const handleEvts = getHandleEvts(evts.slice(-1)) + const handleEvts = getHandleEvts(evts.slice(-2)) verifyHandleEvent(handleEvts[0], bob, 'bob2.test') }) diff --git a/packages/pds/tests/transfer-repo.test.ts b/packages/pds/tests/transfer-repo.test.ts deleted file mode 100644 index 53393fa89d1..00000000000 --- a/packages/pds/tests/transfer-repo.test.ts +++ /dev/null @@ -1,217 +0,0 @@ -import path from 'node:path' -import os from 'node:os' -import axios from 'axios' -import * as ui8 from 'uint8arrays' -import { SeedClient, TestPds, TestPlc, mockResolvers } from '@atproto/dev-env' -import AtpAgent from '@atproto/api' -import * as pdsEntryway from '@atproto/pds-entryway' -import { Secp256k1Keypair, randomStr } from '@atproto/crypto' -import * as plcLib from '@did-plc/lib' -import getPort from 'get-port' - -describe('transfer repo', () => { - let plc: TestPlc - let pds: TestPds - let entryway: pdsEntryway.PDS - let entrywaySc: SeedClient - let pdsAgent: AtpAgent - let entrywayAgent: AtpAgent - - let did: string - const accountDetail = { - email: 'alice@test.com', - handle: 'alice.test', - password: 'test123', - } - - beforeAll(async () => { - const jwtSigningKey = await Secp256k1Keypair.create({ exportable: true }) - const plcRotationKey = await Secp256k1Keypair.create({ exportable: true }) - const entrywayPort = await getPort() - plc = await TestPlc.create({}) - pds = await TestPds.create({ - entrywayUrl: `http://localhost:${entrywayPort}`, - entrywayDid: 'did:example:entryway', - entrywayJwtVerifyKeyK256PublicKeyHex: getPublicHex(jwtSigningKey), - entrywayPlcRotationKey: plcRotationKey.did(), - adminPassword: 'admin-pass', - serviceHandleDomains: [], - didPlcUrl: plc.url, - serviceDid: 'did:example:pds', - inviteRequired: false, - }) - entryway = await createEntryway({ - dbPostgresSchema: 'transfer_repo', - port: entrywayPort, - adminPassword: 'admin-pass', - jwtSigningKeyK256PrivateKeyHex: await getPrivateHex(jwtSigningKey), - plcRotationKeyK256PrivateKeyHex: await getPrivateHex(plcRotationKey), - inviteRequired: false, - serviceDid: 'did:example:entryway', - didPlcUrl: plc.url, - }) - mockResolvers(pds.ctx.idResolver, pds) - mockResolvers(entryway.ctx.idResolver, pds) - await entryway.ctx.db.db - .insertInto('pds') - .values({ - did: pds.ctx.cfg.service.did, - host: new URL(pds.ctx.cfg.service.publicUrl).host, - weight: 0, - }) - .execute() - pdsAgent = pds.getClient() - entrywayAgent = new AtpAgent({ - service: entryway.ctx.cfg.service.publicUrl, - }) - - // @ts-ignore network not needed - entrywaySc = new SeedClient({}, entrywayAgent) - await entrywaySc.createAccount('alice', accountDetail) - did = entrywaySc.dids.alice - for (let i = 0; i < 50; i++) { - const post = await entrywaySc.post(did, 'blah') - await entrywaySc.like(did, post.ref) - } - const img = await entrywaySc.uploadFile( - did, - '../dev-env/src/seed/img/key-landscape-small.jpg', - 'image/jpeg', - ) - await entrywaySc.post(did, 'img post', undefined, [img]) - }) - - afterAll(async () => { - await plc.close() - await entryway.destroy() - await pds.close() - }) - - it('transfers', async () => { - const signingKeyRes = - await pdsAgent.api.com.atproto.server.reserveSigningKey({ did }) - const signingKey = signingKeyRes.data.signingKey - - const repo = await entrywayAgent.api.com.atproto.sync.getRepo({ did }) - const importRes = await axios.post( - `${pds.url}/xrpc/com.atproto.temp.importRepo`, - repo.data, - { - params: { did }, - headers: { - 'content-type': 'application/vnd.ipld.car', - ...pds.adminAuthHeaders('admin'), - }, - decompress: true, - responseType: 'stream', - }, - ) - - for await (const _log of importRes.data) { - // noop just wait till import is finished - } - - const lastOp = await pds.ctx.plcClient.getLastOp(did) - if (!lastOp || lastOp.type === 'plc_tombstone') { - throw new Error('could not find last plc op') - } - const plcOp = await plcLib.createUpdateOp( - lastOp, - entryway.ctx.plcRotationKey, - (normalized) => ({ - ...normalized, - rotationKeys: [pds.ctx.plcRotationKey.did()], - verificationMethods: { - atproto: signingKey, - }, - services: { - atproto_pds: { - type: 'AtprotoPersonalDataServer', - endpoint: pds.ctx.cfg.service.publicUrl, - }, - }, - }), - ) - await pdsAgent.api.com.atproto.temp.transferAccount( - { - did, - handle: accountDetail.handle, - plcOp, - }, - { headers: pds.adminAuthHeaders('admin'), encoding: 'application/json' }, - ) - - await entryway.ctx.db.db - .updateTable('user_account') - .set({ - pdsId: entryway.ctx.db.db.selectFrom('pds').select('id').limit(1), - }) - .where('did', '=', did) - .execute() - - await pdsAgent.login({ - identifier: accountDetail.handle, - password: accountDetail.password, - }) - - await pdsAgent.api.app.bsky.feed.post.create( - { repo: did }, - { - text: 'asdflsidkfu', - createdAt: new Date().toISOString(), - }, - ) - - const listPosts = await pdsAgent.api.com.atproto.repo.listRecords({ - repo: did, - collection: 'app.bsky.feed.post', - limit: 100, - }) - const listLikes = await pdsAgent.api.com.atproto.repo.listRecords({ - repo: did, - collection: 'app.bsky.feed.like', - limit: 100, - }) - - expect(listPosts.data.records.length).toBe(52) - expect(listLikes.data.records.length).toBe(50) - }) -}) - -const createEntryway = async ( - config: pdsEntryway.ServerEnvironment & { - adminPassword: string - jwtSigningKeyK256PrivateKeyHex: string - plcRotationKeyK256PrivateKeyHex: string - }, -) => { - const signingKey = await Secp256k1Keypair.create({ exportable: true }) - const recoveryKey = await Secp256k1Keypair.create({ exportable: true }) - const env: pdsEntryway.ServerEnvironment = { - isEntryway: true, - recoveryDidKey: recoveryKey.did(), - serviceHandleDomains: ['.test'], - dbPostgresUrl: process.env.DB_POSTGRES_URL, - blobstoreDiskLocation: path.join(os.tmpdir(), randomStr(8, 'base32')), - bskyAppViewUrl: 'https://appview.invalid', - bskyAppViewDid: 'did:example:invalid', - bskyAppViewCdnUrlPattern: 'http://cdn.appview.com/%s/%s/%s', - jwtSecret: randomStr(8, 'base32'), - repoSigningKeyK256PrivateKeyHex: await getPrivateHex(signingKey), - ...config, - } - const cfg = pdsEntryway.envToCfg(env) - const secrets = pdsEntryway.envToSecrets(env) - const server = await pdsEntryway.PDS.create(cfg, secrets) - await server.ctx.db.migrateToLatestOrThrow() - await server.start() - return server -} - -const getPublicHex = (key: Secp256k1Keypair) => { - return key.publicKeyStr('hex') -} - -const getPrivateHex = async (key: Secp256k1Keypair) => { - return ui8.toString(await key.export(), 'hex') -} diff --git a/packages/repo/CHANGELOG.md b/packages/repo/CHANGELOG.md index 448005d16d2..4a52264ad23 100644 --- a/packages/repo/CHANGELOG.md +++ b/packages/repo/CHANGELOG.md @@ -1,5 +1,11 @@ # @atproto/repo +## 0.3.7 + +### Patch Changes + +- [#2173](https://github.com/bluesky-social/atproto/pull/2173) [`fcf8e3faf`](https://github.com/bluesky-social/atproto/commit/fcf8e3faf311559162c3aa0d9af36f84951914bc) Thanks [@bnewbold](https://github.com/bnewbold)! - repo commit object prev field is nullable, but no longer nullable + ## 0.3.6 ### Patch Changes diff --git a/packages/repo/package.json b/packages/repo/package.json index b6a3b87607e..9badb9f9a42 100644 --- a/packages/repo/package.json +++ b/packages/repo/package.json @@ -1,6 +1,6 @@ { "name": "@atproto/repo", - "version": "0.3.6", + "version": "0.3.7", "license": "MIT", "description": "atproto repo and MST implementation", "keywords": [ diff --git a/packages/repo/src/types.ts b/packages/repo/src/types.ts index 7aeaba03fca..e9debe013ed 100644 --- a/packages/repo/src/types.ts +++ b/packages/repo/src/types.ts @@ -16,7 +16,7 @@ const unsignedCommit = z.object({ data: common.cid, rev: z.string(), // `prev` added for backwards compatibility with v2, no requirement of keeping around history - prev: common.cid.nullable().optional(), + prev: common.cid.nullable(), }) export type UnsignedCommit = z.infer & { sig?: never } @@ -25,7 +25,7 @@ const commit = z.object({ version: z.literal(3), data: common.cid, rev: z.string(), - prev: common.cid.nullable().optional(), + prev: common.cid.nullable(), sig: common.bytes, }) export type Commit = z.infer diff --git a/packages/syntax/src/recordkey.ts b/packages/syntax/src/recordkey.ts index 6d424a1b8b4..a12668ff1e5 100644 --- a/packages/syntax/src/recordkey.ts +++ b/packages/syntax/src/recordkey.ts @@ -3,7 +3,7 @@ export const ensureValidRecordKey = (rkey: string): void => { throw new InvalidRecordKeyError('record key must be 1 to 512 characters') } // simple regex to enforce most constraints via just regex and length. - if (!/^[a-zA-Z0-9_~.-]{1,512}$/.test(rkey)) { + if (!/^[a-zA-Z0-9_~.:-]{1,512}$/.test(rkey)) { throw new InvalidRecordKeyError('record key syntax not valid (regex)') } if (rkey == '.' || rkey == '..') diff --git a/packages/xrpc-server/src/server.ts b/packages/xrpc-server/src/server.ts index 9a666488c1c..75621136995 100644 --- a/packages/xrpc-server/src/server.ts +++ b/packages/xrpc-server/src/server.ts @@ -36,6 +36,8 @@ import { RateLimiterConsume, isShared, RateLimitExceededError, + HandlerPipeThrough, + handlerPipeThrough, } from './types' import { decodeQueryParams, @@ -263,6 +265,20 @@ export class Server { throw XRPCError.fromError(outputUnvalidated) } + if (outputUnvalidated && isHandlerPipeThrough(outputUnvalidated)) { + // set headers + if (outputUnvalidated?.headers) { + Object.entries(outputUnvalidated.headers).forEach(([name, val]) => { + res.header(name, val) + }) + } + res + .header('Content-Type', outputUnvalidated.encoding) + .status(200) + .send(Buffer.from(outputUnvalidated.buffer)) + return + } + if (!outputUnvalidated || isHandlerSuccess(outputUnvalidated)) { // validate response const output = validateResOutput(outputUnvalidated) @@ -448,6 +464,26 @@ function isHandlerSuccess(v: HandlerOutput): v is HandlerSuccess { return handlerSuccess.safeParse(v).success } +function isHandlerPipeThrough(v: HandlerOutput): v is HandlerPipeThrough { + if (v === null || typeof v !== 'object') { + return false + } + if (!isString(v['encoding']) || !(v['buffer'] instanceof ArrayBuffer)) { + return false + } + if (v['headers'] !== undefined) { + if (v['headers'] === null || typeof v['headers'] !== 'object') { + return false + } + if (!Object.values(v['headers']).every(isString)) { + return false + } + } + return true +} + +const isString = (val: unknown): val is string => typeof val === 'string' + const kRequestLocals = Symbol('requestLocals') function createLocalsMiddleware(nsid: string): RequestHandler { diff --git a/packages/xrpc-server/src/types.ts b/packages/xrpc-server/src/types.ts index cba891a0d63..5d406d77a11 100644 --- a/packages/xrpc-server/src/types.ts +++ b/packages/xrpc-server/src/types.ts @@ -46,6 +46,13 @@ export const handlerSuccess = zod.object({ }) export type HandlerSuccess = zod.infer +export const handlerPipeThrough = zod.object({ + encoding: zod.string(), + buffer: zod.instanceof(ArrayBuffer), + headers: zod.record(zod.string()).optional(), +}) +export type HandlerPipeThrough = zod.infer + export const handlerError = zod.object({ status: zod.number(), error: zod.string().optional(), @@ -53,7 +60,7 @@ export const handlerError = zod.object({ }) export type HandlerError = zod.infer -export type HandlerOutput = HandlerSuccess | HandlerError +export type HandlerOutput = HandlerSuccess | HandlerPipeThrough | HandlerError export type XRPCReqContext = { auth: HandlerAuth | undefined diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e64ed822c0a..8ec8d78ae3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -231,6 +231,9 @@ importers: ioredis: specifier: ^5.3.2 version: 5.3.2 + jose: + specifier: ^5.0.1 + version: 5.1.3 kysely: specifier: ^0.22.0 version: 0.22.0 @@ -460,8 +463,8 @@ importers: specifier: ^0.27.2 version: 0.27.2 better-sqlite3: - specifier: ^7.6.2 - version: 7.6.2 + specifier: ^9.4.0 + version: 9.4.0 chalk: specifier: ^5.0.1 version: 5.1.1 @@ -694,8 +697,8 @@ importers: specifier: ^0.0.4 version: 0.0.4 better-sqlite3: - specifier: ^7.6.2 - version: 7.6.2 + specifier: ^9.4.0 + version: 9.4.0 bytes: specifier: ^3.1.2 version: 3.1.2 @@ -785,8 +788,8 @@ importers: specifier: workspace:^ version: link:../lex-cli '@atproto/pds-entryway': - specifier: npm:@atproto/pds@0.3.0-entryway.2 - version: /@atproto/pds@0.3.0-entryway.2 + specifier: npm:@atproto/pds@0.3.0-entryway.3 + version: /@atproto/pds@0.3.0-entryway.3 '@did-plc/server': specifier: ^0.0.1 version: 0.0.1 @@ -944,9 +947,6 @@ importers: '@atproto/crypto': specifier: workspace:^ version: link:../../packages/crypto - '@atproto/identity': - specifier: workspace:^ - version: link:../../packages/identity dd-trace: specifier: 3.13.2 version: 3.13.2 @@ -988,7 +988,7 @@ importers: version: 4.20.0 opentelemetry-plugin-better-sqlite3: specifier: ^1.1.0 - version: 1.1.0(better-sqlite3@7.6.2) + version: 1.1.0(better-sqlite3@9.4.0) packages: @@ -1030,9 +1030,8 @@ packages: one-webcrypto: 1.0.3 uint8arrays: 3.0.0 - /@atproto/pds@0.3.0-entryway.2: - resolution: {integrity: sha512-nj3cOgPBiX0PLMG8Wn6Vy9mpRa891nGDXiOURoeSzQPSJMkWlk/4SlfYEFSrGSHlBnkUNd1fKE3NsJMMQJ/Utg==} - hasBin: true + /@atproto/pds@0.3.0-entryway.3: + resolution: {integrity: sha512-hc/KcBgFjSfrnNgrc9vx/QaCov79cXbRRQEWrAt/rdMLhcFEGCydN7ukddjOiLkLdhDqywSHrLOEbqg+MReQXw==} dependencies: '@atproto/api': link:packages/api '@atproto/aws': link:packages/aws @@ -1044,8 +1043,11 @@ packages: '@atproto/syntax': link:packages/syntax '@atproto/xrpc': link:packages/xrpc '@atproto/xrpc-server': link:packages/xrpc-server + '@bufbuild/protobuf': 1.6.0 + '@connectrpc/connect': 1.3.0(@bufbuild/protobuf@1.6.0) + '@connectrpc/connect-node': 1.3.0(@bufbuild/protobuf@1.6.0)(@connectrpc/connect@1.3.0) '@did-plc/lib': 0.0.1 - better-sqlite3: 7.6.2 + better-sqlite3: 9.4.0 bytes: 3.1.2 compression: 1.7.4 cors: 2.8.5 @@ -1068,7 +1070,9 @@ packages: pg: 8.10.0 pino: 8.15.0 pino-http: 8.4.0 - sharp: 0.31.3 + rate-limiter-flexible: 2.4.1 + sharp: 0.32.6 + twilio: 4.21.0 typed-emitter: 2.1.0 uint8arrays: 3.0.0 zod: 3.21.4 @@ -4641,48 +4645,48 @@ packages: - supports-color dev: true - /@cbor-extract/cbor-extract-darwin-arm64@2.1.1: - resolution: {integrity: sha512-blVBy5MXz6m36Vx0DfLd7PChOQKEs8lK2bD1WJn/vVgG4FXZiZmZb2GECHFvVPA5T7OnODd9xZiL3nMCv6QUhA==} + /@cbor-extract/cbor-extract-darwin-arm64@2.2.0: + resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} cpu: [arm64] os: [darwin] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-darwin-x64@2.1.1: - resolution: {integrity: sha512-h6KFOzqk8jXTvkOftyRIWGrd7sKQzQv2jVdTL9nKSf3D2drCvQB/LHUxAOpPXo3pv2clDtKs3xnHalpEh3rDsw==} + /@cbor-extract/cbor-extract-darwin-x64@2.2.0: + resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} cpu: [x64] os: [darwin] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-linux-arm64@2.1.1: - resolution: {integrity: sha512-SxAaRcYf8S0QHaMc7gvRSiTSr7nUYMqbUdErBEu+HYA4Q6UNydx1VwFE68hGcp1qvxcy9yT5U7gA+a5XikfwSQ==} + /@cbor-extract/cbor-extract-linux-arm64@2.2.0: + resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-linux-arm@2.1.1: - resolution: {integrity: sha512-ds0uikdcIGUjPyraV4oJqyVE5gl/qYBpa/Wnh6l6xLE2lj/hwnjT2XcZCChdXwW/YFZ1LUHs6waoYN8PmK0nKQ==} + /@cbor-extract/cbor-extract-linux-arm@2.2.0: + resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} cpu: [arm] os: [linux] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-linux-x64@2.1.1: - resolution: {integrity: sha512-GVK+8fNIE9lJQHAlhOROYiI0Yd4bAZ4u++C2ZjlkS3YmO6hi+FUxe6Dqm+OKWTcMpL/l71N6CQAmaRcb4zyJuA==} + /@cbor-extract/cbor-extract-linux-x64@2.2.0: + resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} cpu: [x64] os: [linux] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-win32-x64@2.1.1: - resolution: {integrity: sha512-2Niq1C41dCRIDeD8LddiH+mxGlO7HJ612Ll3D/E73ZWBmycued+8ghTr/Ho3CMOWPUEr08XtyBMVXAjqF+TcKw==} + /@cbor-extract/cbor-extract-win32-x64@2.2.0: + resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} cpu: [x64] os: [win32] requiresBuild: true @@ -4916,7 +4920,6 @@ packages: '@bufbuild/protobuf': 1.6.0 '@connectrpc/connect': 1.3.0(@bufbuild/protobuf@1.6.0) undici: 5.28.2 - dev: false /@connectrpc/connect@1.3.0(@bufbuild/protobuf@1.6.0): resolution: {integrity: sha512-kTeWxJnLLtxKc2ZSDN0rIBgwfP8RwcLknthX4AKlIAmN9ZC4gGnCbwp+3BKcP/WH5c8zGBAWqSY3zeqCM+ah7w==} @@ -5127,7 +5130,6 @@ packages: /@fastify/busboy@2.1.0: resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==} engines: {node: '>=14'} - dev: false /@fastify/deepmerge@1.3.0: resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==} @@ -6436,7 +6438,6 @@ packages: /b4a@1.6.4: resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} - dev: false /babel-eslint@10.1.0(eslint@8.24.0): resolution: {integrity: sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==} @@ -6577,8 +6578,8 @@ packages: is-windows: 1.0.2 dev: true - /better-sqlite3@7.6.2: - resolution: {integrity: sha512-S5zIU1Hink2AH4xPsN0W43T1/AJ5jrPh7Oy07ocuW/AKYYY02GWzz9NH0nbSMn/gw6fDZ5jZ1QsHt1BXAwJ6Lg==} + /better-sqlite3@9.4.0: + resolution: {integrity: sha512-5kynxekMxSjCMiFyUBLHggFcJkCmiZi6fUkiGz/B5GZOvdRWQJD0klqCx5/Y+bm2AKP7I/DHbSFx26AxjruWNg==} requiresBuild: true dependencies: bindings: 1.5.0 @@ -6673,6 +6674,10 @@ packages: node-int64: 0.4.0 dev: true + /buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + dev: true + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true @@ -6768,26 +6773,26 @@ packages: resolution: {integrity: sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==} dev: true - /cbor-extract@2.1.1: - resolution: {integrity: sha512-1UX977+L+zOJHsp0mWFG13GLwO6ucKgSmSW6JTl8B9GUvACvHeIVpFqhU92299Z6PfD09aTXDell5p+lp1rUFA==} + /cbor-extract@2.2.0: + resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} hasBin: true requiresBuild: true dependencies: - node-gyp-build-optional-packages: 5.0.3 + node-gyp-build-optional-packages: 5.1.1 optionalDependencies: - '@cbor-extract/cbor-extract-darwin-arm64': 2.1.1 - '@cbor-extract/cbor-extract-darwin-x64': 2.1.1 - '@cbor-extract/cbor-extract-linux-arm': 2.1.1 - '@cbor-extract/cbor-extract-linux-arm64': 2.1.1 - '@cbor-extract/cbor-extract-linux-x64': 2.1.1 - '@cbor-extract/cbor-extract-win32-x64': 2.1.1 + '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 + '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 + '@cbor-extract/cbor-extract-linux-x64': 2.2.0 + '@cbor-extract/cbor-extract-win32-x64': 2.2.0 dev: false optional: true /cbor-x@1.5.1: resolution: {integrity: sha512-/vAkC4tiKCQCm5en4sA+mpKmjwY6Xxp1LO+BgZCNhp+Zow3pomyUHeBOK5EDp0mDaE36jw39l5eLHsoF3M1Lmg==} optionalDependencies: - cbor-extract: 2.1.1 + cbor-extract: 2.2.0 dev: false /cborg@1.10.2: @@ -7064,6 +7069,10 @@ packages: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} dev: true + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: true + /dc-polyfill@0.1.3: resolution: {integrity: sha512-Wyk5n/5KUj3GfVKV2jtDbtChC/Ff9fjKsBcg4ZtYW1yQe3DXNHcGURvmoxhqQdfOQ9TwyMjnfyv1lyYcOkFkFA==} engines: {node: '>=12.17'} @@ -7322,6 +7331,12 @@ packages: engines: {node: '>=10'} dev: true + /ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -7979,7 +7994,6 @@ packages: /fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} - dev: false /fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} @@ -9432,6 +9446,37 @@ packages: graceful-fs: 4.2.11 dev: true + /jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.5.4 + dev: true + + /jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: true + + /jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + dev: true + /key-encoder@2.0.3: resolution: {integrity: sha512-fgBtpAGIr/Fy5/+ZLQZIPPhsZEcbSlYu/Wu96tNDFNSjSACw5lEIOFeaVdQ/iwrb8oxjlWi6wmWdH76hV6GZjg==} dependencies: @@ -9520,9 +9565,33 @@ packages: /lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + /lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + dev: true + /lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + /lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + dev: true + + /lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + dev: true + + /lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + dev: true + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: true + + /lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + dev: true + /lodash.kebabcase@4.1.1: resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} dev: false @@ -9531,6 +9600,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: true + /lodash.pick@4.4.0: resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==} dev: false @@ -9861,13 +9934,8 @@ packages: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} dev: false - /node-addon-api@5.1.0: - resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} - dev: true - /node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} - dev: false /node-cache@5.1.2: resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} @@ -9888,10 +9956,12 @@ packages: whatwg-url: 5.0.0 dev: true - /node-gyp-build-optional-packages@5.0.3: - resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} + /node-gyp-build-optional-packages@5.1.1: + resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} hasBin: true requiresBuild: true + dependencies: + detect-libc: 2.0.2 dev: false optional: true @@ -10038,7 +10108,7 @@ packages: mimic-fn: 2.1.0 dev: true - /opentelemetry-plugin-better-sqlite3@1.1.0(better-sqlite3@7.6.2): + /opentelemetry-plugin-better-sqlite3@1.1.0(better-sqlite3@9.4.0): resolution: {integrity: sha512-yd+mgaB5W5JxzcQt9TvX1VIrusqtbbeuxSoZ6KQe4Ra0J/Kqkp6kz7dg0VQUU5+cenOWkza6xtvsT0KGXI03HA==} peerDependencies: better-sqlite3: ^7.1.1 || ^8.0.0 || ^9.0.0 @@ -10047,7 +10117,7 @@ packages: '@opentelemetry/core': 1.18.1(@opentelemetry/api@1.7.0) '@opentelemetry/instrumentation': 0.44.0(@opentelemetry/api@1.7.0) '@opentelemetry/semantic-conventions': 1.18.1 - better-sqlite3: 7.6.2 + better-sqlite3: 9.4.0 transitivePeerDependencies: - supports-color dev: false @@ -10523,12 +10593,15 @@ packages: dependencies: side-channel: 1.0.4 + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: true + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} /queue-tick@1.0.1: resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} - dev: false /quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} @@ -10544,7 +10617,6 @@ packages: /rate-limiter-flexible@2.4.1: resolution: {integrity: sha512-dgH4T44TzKVO9CLArNto62hJOwlWJMLUjVVr/ii0uUzZXEXthDNr7/yefW5z/1vvHAfycc1tnuiYyNJ8CTRB3g==} - dev: false /raw-body@2.5.1: resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} @@ -10721,6 +10793,10 @@ packages: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} dev: true + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + /resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -10834,6 +10910,10 @@ packages: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} requiresBuild: true + /scmp@2.1.0: + resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + dev: true + /secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} dev: true @@ -10916,21 +10996,6 @@ packages: /setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - /sharp@0.31.3: - resolution: {integrity: sha512-XcR4+FCLBFKw1bdB+GEhnUNXNXvnt0tDo4WsBsraKymuo/IAuPuCBVAL2wIkUw2r/dwFW5Q5+g66Kwl2dgDFVg==} - engines: {node: '>=14.15.0'} - requiresBuild: true - dependencies: - color: 4.2.3 - detect-libc: 2.0.2 - node-addon-api: 5.1.0 - prebuild-install: 7.1.1 - semver: 7.5.4 - simple-get: 4.0.1 - tar-fs: 2.1.1 - tunnel-agent: 0.6.0 - dev: true - /sharp@0.32.6: resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} engines: {node: '>=14.15.0'} @@ -10944,7 +11009,6 @@ packages: simple-get: 4.0.1 tar-fs: 3.0.4 tunnel-agent: 0.6.0 - dev: false /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} @@ -11154,7 +11218,6 @@ packages: dependencies: fast-fifo: 1.3.2 queue-tick: 1.0.1 - dev: false /string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} @@ -11299,7 +11362,6 @@ packages: mkdirp-classic: 0.5.3 pump: 3.0.0 tar-stream: 3.1.6 - dev: false /tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} @@ -11317,7 +11379,6 @@ packages: b4a: 1.6.4 fast-fifo: 1.3.2 streamx: 2.15.5 - dev: false /tar@6.1.15: resolution: {integrity: sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==} @@ -11524,6 +11585,23 @@ packages: dependencies: safe-buffer: 5.2.1 + /twilio@4.21.0: + resolution: {integrity: sha512-+meDbJPOxs6vEysJ7xX7XMn6FLKmZFSeVzMKjzN9NWgDXssp713Kf1ukteZlXhnhd7/NtNiUv5OU17qVgBb/BQ==} + engines: {node: '>=14.0'} + dependencies: + axios: 1.6.2 + dayjs: 1.11.10 + https-proxy-agent: 5.0.1 + jsonwebtoken: 9.0.2 + qs: 6.11.0 + scmp: 2.1.0 + url-parse: 1.5.10 + xmlbuilder: 13.0.2 + transitivePeerDependencies: + - debug + - supports-color + dev: true + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -11653,7 +11731,6 @@ packages: engines: {node: '>=14.0'} dependencies: '@fastify/busboy': 2.1.0 - dev: false /unicode-canonical-property-names-ecmascript@2.0.0: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} @@ -11717,6 +11794,13 @@ packages: dependencies: punycode: 2.3.0 + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -11878,6 +11962,11 @@ packages: utf-8-validate: optional: true + /xmlbuilder@13.0.2: + resolution: {integrity: sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==} + engines: {node: '>=6.0'} + dev: true + /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} diff --git a/services/bsky/README.md b/services/bsky/README.md index c8bbb8ad4d2..fea1bf3c602 100644 --- a/services/bsky/README.md +++ b/services/bsky/README.md @@ -6,15 +6,18 @@ This is the service entrypoint for the bsky appview. The entrypoint command shou - `BSKY_DID_PLC_URL` - (required) the url of the PLC service used for looking up did documents, e.g. `https://plc.directory`. - `BSKY_DATAPLANE_URL` - (required) the url where the backing dataplane service lives. - `BSKY_SERVICE_SIGNING_KEY` - (required) the public signing key in the form of a `did:key`, used for service-to-service auth. Advertised in the appview's `did:web`` document. -- `BSKY_ADMIN_PASSWORD` - (required) the admin password used for role-based auth. +- `BSKY_ADMIN_PASSWORDS` - (alt. `BSKY_ADMIN_PASSWORD`) (required) comma-separated list of admin passwords used for role-based auth. - `NODE_ENV` - (recommended) for production usage, should be set to `production`. Otherwise all responses are validated on their way out. There may be other effects of not setting this to `production`, as dependencies may also implement debug modes based on its value. - `BSKY_VERSION` - (recommended) version of the bsky service. This is advertised by the health endpoint. - `BSKY_PORT` - (recommended) the port that the service will run on. - `BSKY_IMG_URI_ENDPOINT` - (recommended) the base url for resized images, e.g. `https://cdn.bsky.app/img`. When not set, sets-up an image resizing service directly on the appview. - `BSKY_SERVER_DID` - (recommended) the did of the appview service. When this is a `did:web` that matches the appview's public url, a `did:web` document is served. -- `BSKY_FEED_PUBLISHER_DID` - indicates the publisher did of any feedgen records which the appview supports. -- `BSKY_FEED_GEN_DID` - the did of the appview's feed generator service. When present the appview implements `app.bsky.feed.describeFeedGenerator`. - `BSKY_HANDLE_RESOLVE_NAMESERVERS` - alternative domain name servers used for handle resolution, comma-separated. - `BSKY_BLOB_CACHE_LOC` - when `BSKY_IMG_URI_ENDPOINT` is not set, this determines where resized blobs are cached by the image resizing service. -- `BSKY_MODERATOR_PASSWORD` - the moderator password used for role-based auth. -- `BSKY_TRIAGE_PASSWORD` - the triage password used for role-based auth. +- `BSKY_COURIER_URL` - URL of courier service. +- `BSKY_COURIER_API_KEY` - API key for courier service. +- `BSKY_BSYNC_URL` - URL of bsync service. +- `BSKY_BSYNC_API_KEY` - API key for bsync service. +- `BSKY_SEARCH_URL` - (alt. `BSKY_SEARCH_ENDPOINT`) - +- `BSKY_LABELS_FROM_ISSUER_DIDS` - comma-separated list of labelers to always use for record labels. +- `MOD_SERVICE_DID` - the DID of the mod service, used to receive service authed requests. diff --git a/services/bsky/api.js b/services/bsky/api.js index 682a9336433..44d8f96b37d 100644 --- a/services/bsky/api.js +++ b/services/bsky/api.js @@ -41,23 +41,14 @@ const path = require('node:path') const assert = require('node:assert') const cluster = require('cluster') const { Secp256k1Keypair } = require('@atproto/crypto') -const { ServerConfig, BskyAppView, makeAlgos } = require('@atproto/bsky') -const { MemoryCache: MemoryDidCache } = require('@atproto/identity') +const { ServerConfig, BskyAppView } = require('@atproto/bsky') const main = async () => { const env = getEnv() const config = ServerConfig.readEnv() assert(env.serviceSigningKey, 'must set BSKY_SERVICE_SIGNING_KEY') const signingKey = await Secp256k1Keypair.import(env.serviceSigningKey) - const algos = env.feedPublisherDid ? makeAlgos(env.feedPublisherDid) : {} - const didCache = new MemoryDidCache() // @TODO persistent, shared cache - const bsky = BskyAppView.create({ - config, - signingKey, - didCache, - algos, - }) - + const bsky = BskyAppView.create({ config, signingKey }) await bsky.start() // Graceful shutdown (see also https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/) const shutdown = async () => { @@ -69,7 +60,6 @@ const main = async () => { const getEnv = () => ({ serviceSigningKey: process.env.BSKY_SERVICE_SIGNING_KEY || undefined, - feedPublisherDid: process.env.BSKY_FEED_PUBLISHER_DID || undefined, }) const maybeParseInt = (str) => { diff --git a/services/bsky/package.json b/services/bsky/package.json index 2c4da882b62..c1feff5b40b 100644 --- a/services/bsky/package.json +++ b/services/bsky/package.json @@ -4,7 +4,6 @@ "dependencies": { "@atproto/bsky": "workspace:^", "@atproto/crypto": "workspace:^", - "@atproto/identity": "workspace:^", "dd-trace": "3.13.2" } } diff --git a/services/pds/Dockerfile b/services/pds/Dockerfile index 6d092bb5229..e5f7b057184 100644 --- a/services/pds/Dockerfile +++ b/services/pds/Dockerfile @@ -1,6 +1,6 @@ # @NOTE just a temp fix: alpine3.19 breaks sharp install, see nodejs/docker-node#2009 # see additional reference to this image further down. -FROM node:18-alpine3.18 as build +FROM node:20.11-alpine3.18 as build RUN npm install -g pnpm @@ -37,7 +37,7 @@ RUN pnpm install --prod --shamefully-hoist --frozen-lockfile --prefer-offline > WORKDIR services/pds # Uses assets from build stage to reduce build size -FROM node:18-alpine3.18 +FROM node:20.11-alpine3.18 RUN apk add --update dumb-init @@ -52,6 +52,8 @@ VOLUME /app/data EXPOSE 3000 ENV PDS_PORT=3000 ENV NODE_ENV=production +# potential perf issues w/ io_uring on this version of node +ENV UV_USE_IO_URING=0 # https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user USER node