diff --git a/Makefile b/Makefile index b509ad927..013219901 100644 --- a/Makefile +++ b/Makefile @@ -379,8 +379,7 @@ golangci-lint: lexicons: $(MAKE) go-lexicons \ && $(MAKE) js-lexicons \ - && $(MAKE) md-lexicons \ - && make fix + && $(MAKE) md-lexicons # glex is the standalone Go lexicon codegen tool (github.com/streamplace/glex). # It generates Go types that serialize as canonical DAG-CBOR via go-dasl, @@ -393,23 +392,18 @@ go-lexicons: --lexicons-dir lexicons \ --output-dir pkg \ --module-path stream.place/streamplace/pkg \ + --gen-server spxrpc \ lexicons .PHONY: js-lexicons js-lexicons: - rm -rf .build/lexmerge \ - && mkdir -p .build/lexmerge \ - && node js/streamplace/scripts/dump-external-lexicons.mjs .build/lexmerge \ - && cp -r lexicons/. .build/lexmerge/ \ - && node_modules/.bin/lex build \ - --lexicons .build/lexmerge \ - --out js/streamplace/src/lexicons \ - --clear --index-file --no-pretty \ - --exclude place.stream.live.subscribeSegments \ - && node js/streamplace/scripts/gen-raw-lexicons.mjs \ - && rm -rf .build/lexmerge \ - && npx prettier --ignore-unknown --write \ - ./js/streamplace/src/lexicons ./js/streamplace/src/raw-lexicons.ts + pnpm exec lex install \ + && node js/streamplace/scripts/gen-raw-lexicons.mjs \ + && pnpm exec lex build \ + --lexicons lexicons \ + --out js/streamplace/src/lexicons \ + --clear --index-file --no-pretty \ + --exclude place.stream.live.subscribeSegments .PHONY: md-lexicons md-lexicons: @@ -417,47 +411,12 @@ md-lexicons: && pnpm exec lexmd \ ./lexicons \ .build/temp \ - subprojects/atproto/lexicons \ + ./lexicons \ js/docs/src/content/docs/lex-reference/openapi.json \ && ls -R .build/temp \ && cp -rf .build/temp/place/stream/* js/docs/src/content/docs/lex-reference/ \ && rm -rf .build/temp \ - && $(MAKE) fix - -.PHONY: lexgen -lexgen: - $(MAKE) lexgen-types - $(MAKE) lexgen-server - -.PHONY: lexgen-types -lexgen-types: - go tool github.com/bluesky-social/indigo/cmd/lexgen \ - -outdir ./pkg/spxrpc \ - --build-file util/lexgen-types.json \ - --external-lexicons subprojects/atproto/lexicons \ - lexicons/place/stream \ - lexicons/games/gamesgamesgamesgames \ - ./subprojects/atproto/lexicons - -.PHONY: lexgen-server -lexgen-server: - mkdir -p ./pkg/spxrpc \ - && go tool github.com/bluesky-social/indigo/cmd/lexgen \ - --gen-server \ - --types-import place.stream:stream.place/streamplace/pkg/streamplace \ - --types-import games.gamesgamesgamesgames:stream.place/streamplace/pkg/gamesgamesgamesgames \ - --types-import app.bsky:github.com/bluesky-social/indigo/api/bsky \ - --types-import com.atproto:github.com/bluesky-social/indigo/api/atproto \ - --types-import chat.bsky:github.com/bluesky-social/indigo/api/chat \ - --types-import tools.ozone:github.com/bluesky-social/indigo/api/ozone \ - -outdir ./pkg/spxrpc \ - --build-file util/lexgen-types.json \ - --external-lexicons subprojects/atproto/lexicons \ - --external-lexicons lexicons/games/gamesgamesgamesgames \ - --package spxrpc \ - lexicons/place/stream \ - lexicons/app/bsky \ - lexicons/com/atproto + && find js/docs/src/content/docs/lex-reference -type f | xargs prettier --write --ignore-unknown .PHONY: ci-lexicons ci-lexicons: diff --git a/js/docs/src/content/docs/lex-reference/openapi.json b/js/docs/src/content/docs/lex-reference/openapi.json index ab49ea5c1..f6d6707e8 100644 --- a/js/docs/src/content/docs/lex-reference/openapi.json +++ b/js/docs/src/content/docs/lex-reference/openapi.json @@ -4278,6 +4278,1184 @@ } ] } + }, + "/xrpc/games.gamesgamesgamesgames.search": { + "get": { + "summary": "Search across all entity types (games, profiles, platforms, collections, engines).", + "operationId": "games.gamesgamesgamesgames.search", + "tags": ["games.gamesgamesgamesgames"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cursor": { + "type": "string" + }, + "results": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_gameSummaryView" + }, + { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_profileSummaryView" + }, + { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_platformSummaryView" + }, + { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_collectionSummaryView" + }, + { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_engineSummaryView" + } + ] + } + }, + "totalResults": { + "type": "integer", + "description": "Total number of results matching the query above the relevance threshold." + } + }, + "required": ["results"] + } + } + } + } + }, + "parameters": [ + { + "name": "q", + "in": "query", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "minimum": 1, + "maximum": 100 + } + }, + { + "name": "modes", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "types", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "genres", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "themes", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "ageRatings", + "in": "query", + "required": false, + "description": "Filter game results by age rating in 'organization:rating' format (e.g. esrb:M, pegi:Eighteen).", + "schema": { + "type": "array", + "description": "Filter game results by age rating in 'organization:rating' format (e.g. esrb:M, pegi:Eighteen).", + "items": { + "type": "string" + } + } + }, + { + "name": "includeUnrated", + "in": "query", + "required": false, + "description": "When age rating filters are active, also include games with no age ratings.", + "schema": { + "type": "boolean", + "description": "When age rating filters are active, also include games with no age ratings.", + "default": false + } + }, + { + "name": "applicationTypes", + "in": "query", + "required": false, + "description": "Filter game results by application type (e.g. game, dlc, bundle). Only applies when types includes game.", + "schema": { + "type": "array", + "description": "Filter game results by application type (e.g. game, dlc, bundle). Only applies when types includes game.", + "items": { + "type": "string" + } + } + }, + { + "name": "includeCancelled", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "playerPerspectives", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ] + } + }, + "/xrpc/com.atproto.sync.getRepo": { + "get": { + "summary": "Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS.", + "operationId": "com.atproto.sync.getRepo", + "tags": ["com.atproto.sync"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.ipld.car": { + "schema": {} + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "RepoNotFound" + }, + { + "const": "RepoTakendown" + }, + { + "const": "RepoSuspended" + }, + { + "const": "RepoDeactivated" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "did", + "in": "query", + "required": true, + "description": "The DID of the repo.", + "schema": { + "type": "string", + "description": "The DID of the repo.", + "format": "did" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "description": "The revision ('rev') of the repo to create a diff from.", + "schema": { + "type": "string", + "description": "The revision ('rev') of the repo to create a diff from.", + "format": "tid" + } + } + ] + } + }, + "/xrpc/com.atproto.sync.subscribeRepos": { + "get": { + "summary": "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.", + "operationId": "com.atproto.sync.subscribeRepos", + "tags": ["com.atproto.sync"], + "x-websocket": true, + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "FutureCursor" + }, + { + "const": "ConsumerTooSlow" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false, + "description": "The last known event seq number to backfill from.", + "schema": { + "type": "integer", + "description": "The last known event seq number to backfill from." + } + } + ], + "x-websocket-message": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_commit" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_sync" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_identity" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_account" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_info" + } + ] + } + } + } + }, + "/xrpc/com.atproto.server.createSession": { + "post": { + "summary": "Create an authentication session.", + "operationId": "com.atproto.server.createSession", + "tags": ["com.atproto.server"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "did": { + "type": "string", + "format": "did" + }, + "email": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "didDoc": {}, + "handle": { + "type": "string", + "format": "handle" + }, + "status": { + "type": "string", + "description": "If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted." + }, + "accessJwt": { + "type": "string" + }, + "refreshJwt": { + "type": "string" + }, + "emailConfirmed": { + "type": "boolean" + }, + "emailAuthFactor": { + "type": "boolean" + } + }, + "required": ["accessJwt", "refreshJwt", "handle", "did"] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "AccountTakedown" + }, + { + "const": "AuthFactorTokenRequired" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "identifier": { + "type": "string", + "description": "Handle or other identifier supported by the server for the authenticating user." + }, + "allowTakendown": { + "type": "boolean", + "description": "When true, instead of throwing error for takendown accounts, a valid response with a narrow scoped token will be returned" + }, + "authFactorToken": { + "type": "string" + } + }, + "required": ["identifier", "password"] + } + } + } + } + } + }, + "/xrpc/com.atproto.repo.createRecord": { + "post": { + "summary": "Create a single new repository record. Requires auth, implemented by PDS.", + "operationId": "com.atproto.repo.createRecord", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cid": { + "type": "string", + "format": "cid" + }, + "uri": { + "type": "string", + "format": "uri" + }, + "commit": { + "$ref": "#/components/schemas/com.atproto.repo.defs_commitMeta" + }, + "validationStatus": { + "type": "string" + } + }, + "required": ["uri", "cid"] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidSwap" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "repo": { + "type": "string", + "description": "The handle or DID of the repo (aka, current account).", + "format": "at-identifier" + }, + "rkey": { + "type": "string", + "description": "The Record Key.", + "maxLength": 512, + "format": "record-key" + }, + "record": { + "description": "The record itself. Must contain a $type field." + }, + "validate": { + "type": "boolean", + "description": "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons." + }, + "collection": { + "type": "string", + "description": "The NSID of the record collection.", + "format": "nsid" + }, + "swapCommit": { + "type": "string", + "description": "Compare and swap with the previous commit by CID.", + "format": "cid" + } + }, + "required": ["repo", "collection", "record"] + } + } + } + } + } + }, + "/xrpc/com.atproto.repo.deleteRecord": { + "post": { + "summary": "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", + "operationId": "com.atproto.repo.deleteRecord", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "commit": { + "$ref": "#/components/schemas/com.atproto.repo.defs_commitMeta" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidSwap" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "repo": { + "type": "string", + "description": "The handle or DID of the repo (aka, current account).", + "format": "at-identifier" + }, + "rkey": { + "type": "string", + "description": "The Record Key.", + "format": "record-key" + }, + "collection": { + "type": "string", + "description": "The NSID of the record collection.", + "format": "nsid" + }, + "swapCommit": { + "type": "string", + "description": "Compare and swap with the previous commit by CID.", + "format": "cid" + }, + "swapRecord": { + "type": "string", + "description": "Compare and swap with the previous record by CID.", + "format": "cid" + } + }, + "required": ["repo", "collection", "rkey"] + } + } + } + } + } + }, + "/xrpc/com.atproto.repo.describeRepo": { + "get": { + "summary": "Get information about an account and repository, including the list of collections. Does not require auth.", + "operationId": "com.atproto.repo.describeRepo", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "did": { + "type": "string", + "format": "did" + }, + "didDoc": { + "description": "The complete DID document for this account." + }, + "handle": { + "type": "string", + "format": "handle" + }, + "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", + "description": "Indicates if handle is currently valid (resolves bi-directionally)" + } + }, + "required": [ + "handle", + "did", + "didDoc", + "collections", + "handleIsCorrect" + ] + } + } + } + } + }, + "parameters": [ + { + "name": "repo", + "in": "query", + "required": true, + "description": "The handle or DID of the repo.", + "schema": { + "type": "string", + "description": "The handle or DID of the repo.", + "format": "at-identifier" + } + } + ] + } + }, + "/xrpc/com.atproto.repo.getRecord": { + "get": { + "summary": "Get a single record from a repository. Does not require auth.", + "operationId": "com.atproto.repo.getRecord", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cid": { + "type": "string", + "format": "cid" + }, + "uri": { + "type": "string", + "format": "uri" + }, + "value": {} + }, + "required": ["uri", "value"] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "RecordNotFound" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "cid", + "in": "query", + "required": false, + "description": "The CID of the version of the record. If not specified, then return the most recent version.", + "schema": { + "type": "string", + "description": "The CID of the version of the record. If not specified, then return the most recent version.", + "format": "cid" + } + }, + { + "name": "repo", + "in": "query", + "required": true, + "description": "The handle or DID of the repo.", + "schema": { + "type": "string", + "description": "The handle or DID of the repo.", + "format": "at-identifier" + } + }, + { + "name": "rkey", + "in": "query", + "required": true, + "description": "The Record Key.", + "schema": { + "type": "string", + "description": "The Record Key.", + "format": "record-key" + } + }, + { + "name": "collection", + "in": "query", + "required": true, + "description": "The NSID of the record collection.", + "schema": { + "type": "string", + "description": "The NSID of the record collection.", + "format": "nsid" + } + } + ] + } + }, + "/xrpc/com.atproto.repo.listRecords": { + "get": { + "summary": "List a range of records in a repository, matching a specific collection. Does not require auth.", + "operationId": "com.atproto.repo.listRecords", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cursor": { + "type": "string" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.repo.listRecords_record" + } + } + }, + "required": ["records"] + } + } + } + } + }, + "parameters": [ + { + "name": "repo", + "in": "query", + "required": true, + "description": "The handle or DID of the repo.", + "schema": { + "type": "string", + "description": "The handle or DID of the repo.", + "format": "at-identifier" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "description": "The number of records to return.", + "schema": { + "type": "integer", + "description": "The number of records to return.", + "default": 50, + "minimum": 1, + "maximum": 100 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "reverse", + "in": "query", + "required": false, + "description": "Flag to reverse the order of the returned records.", + "schema": { + "type": "boolean", + "description": "Flag to reverse the order of the returned records." + } + }, + { + "name": "collection", + "in": "query", + "required": true, + "description": "The NSID of the record type.", + "schema": { + "type": "string", + "description": "The NSID of the record type.", + "format": "nsid" + } + } + ] + } + }, + "/xrpc/com.atproto.repo.putRecord": { + "post": { + "summary": "Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.", + "operationId": "com.atproto.repo.putRecord", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cid": { + "type": "string", + "format": "cid" + }, + "uri": { + "type": "string", + "format": "uri" + }, + "commit": { + "$ref": "#/components/schemas/com.atproto.repo.defs_commitMeta" + }, + "validationStatus": { + "type": "string" + } + }, + "required": ["uri", "cid"] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidSwap" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "repo": { + "type": "string", + "description": "The handle or DID of the repo (aka, current account).", + "format": "at-identifier" + }, + "rkey": { + "type": "string", + "description": "The Record Key.", + "maxLength": 512, + "format": "record-key" + }, + "record": { + "description": "The record to write." + }, + "validate": { + "type": "boolean", + "description": "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons." + }, + "collection": { + "type": "string", + "description": "The NSID of the record collection.", + "format": "nsid" + }, + "swapCommit": { + "type": "string", + "description": "Compare and swap with the previous commit by CID.", + "format": "cid" + }, + "swapRecord": { + "oneOf": [ + { + "type": "string", + "description": "Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation", + "format": "cid" + } + ] + } + }, + "required": ["repo", "collection", "rkey", "record"] + } + } + } + } + } + }, + "/xrpc/com.atproto.repo.uploadBlob": { + "post": { + "summary": "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.", + "operationId": "com.atproto.repo.uploadBlob", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "blob": { + "type": "string", + "format": "binary" + } + }, + "required": ["blob"] + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "*/*": { + "schema": {} + } + } + } + } + }, + "/xrpc/com.atproto.identity.updateHandle": { + "post": { + "summary": "Updates the current account's handle. Verifies handle validity, and updates did:plc document if necessary. Implemented by PDS, and requires auth.", + "operationId": "com.atproto.identity.updateHandle", + "tags": ["com.atproto.identity"], + "responses": { + "200": { + "description": "Success" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "handle": { + "type": "string", + "description": "The new handle.", + "format": "handle" + } + }, + "required": ["handle"] + } + } + } + } + } + }, + "/xrpc/app.bsky.feed.getFeedSkeleton": { + "get": { + "summary": "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.", + "operationId": "app.bsky.feed.getFeedSkeleton", + "tags": ["app.bsky.feed"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "feed": { + "type": "array", + "items": { + "$ref": "#/components/schemas/app.bsky.feed.defs_skeletonFeedPost" + } + }, + "reqId": { + "type": "string", + "description": "Unique identifier per request that may be passed back alongside interactions.", + "maxLength": 100 + }, + "cursor": { + "type": "string" + } + }, + "required": ["feed"] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "UnknownFeed" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "feed", + "in": "query", + "required": true, + "description": "Reference to feed generator record describing the specific feed being requested.", + "schema": { + "type": "string", + "description": "Reference to feed generator record describing the specific feed being requested.", + "format": "uri" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 50, + "minimum": 1, + "maximum": 100 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] + } + }, + "/xrpc/app.bsky.actor.getProfile": { + "get": { + "summary": "Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth.", + "operationId": "app.bsky.actor.getProfile", + "tags": ["app.bsky.actor"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewDetailed" + } + } + } + } + }, + "parameters": [ + { + "name": "actor", + "in": "query", + "required": true, + "description": "Handle or DID of account to fetch profile of.", + "schema": { + "type": "string", + "description": "Handle or DID of account to fetch profile of.", + "format": "at-identifier" + } + } + ] + } } }, "components": { @@ -4302,346 +5480,790 @@ "format": "date-time" } }, - "required": ["uri", "cid", "author", "record", "indexedAt"] + "required": ["uri", "cid", "author", "record", "indexedAt"] + }, + "app.bsky.actor.defs_profileViewBasic": { + "type": "object", + "properties": { + "did": { + "type": "string", + "format": "did" + }, + "debug": { + "description": "Debug information for internal development" + }, + "avatar": { + "type": "string", + "format": "uri" + }, + "handle": { + "type": "string", + "format": "handle" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.label.defs_label" + } + }, + "status": { + "$ref": "#/components/schemas/app.bsky.actor.defs_statusView" + }, + "viewer": { + "$ref": "#/components/schemas/app.bsky.actor.defs_viewerState" + }, + "pronouns": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "associated": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileAssociated" + }, + "displayName": { + "type": "string", + "maxLength": 640 + }, + "verification": { + "$ref": "#/components/schemas/app.bsky.actor.defs_verificationState" + } + }, + "required": ["did", "handle"] + }, + "com.atproto.label.defs_label": { + "type": "object", + "description": "Metadata tag on an atproto resource (eg, repo or record).", + "properties": { + "cid": { + "type": "string", + "description": "Optionally, CID specifying the specific version of 'uri' resource this label applies to.", + "format": "cid" + }, + "cts": { + "type": "string", + "description": "Timestamp when this label was created.", + "format": "date-time" + }, + "exp": { + "type": "string", + "description": "Timestamp at which this label expires (no longer applies).", + "format": "date-time" + }, + "neg": { + "type": "boolean", + "description": "If true, this is a negation label, overwriting a previous label." + }, + "sig": { + "type": "string", + "format": "byte", + "description": "Signature of dag-cbor encoded label." + }, + "src": { + "type": "string", + "description": "DID of the actor who created this label.", + "format": "did" + }, + "uri": { + "type": "string", + "description": "AT URI of the record, repository (account), or other resource that this label applies to.", + "format": "uri" + }, + "val": { + "type": "string", + "description": "The short string name of the value or type of this label.", + "maxLength": 128 + }, + "ver": { + "type": "integer", + "description": "The AT Protocol version of the label object." + } + }, + "required": ["src", "uri", "val", "cts"] + }, + "app.bsky.actor.defs_statusView": { + "type": "object", + "properties": { + "cid": { + "type": "string", + "format": "cid" + }, + "uri": { + "type": "string", + "format": "uri" + }, + "embed": { + "oneOf": [ + { + "$ref": "#/components/schemas/app.bsky.embed.external_view" + } + ], + "description": "An optional embed associated with the status." + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.label.defs_label" + } + }, + "record": {}, + "status": { + "type": "string", + "description": "The status for the account." + }, + "isActive": { + "type": "boolean", + "description": "True if the status is not expired, false if it is expired. Only present if expiration was set." + }, + "expiresAt": { + "type": "string", + "description": "The date when this status will expire. The application might choose to no longer return the status after expiration.", + "format": "date-time" + }, + "isDisabled": { + "type": "boolean", + "description": "True if the user's go-live access has been disabled by a moderator, false otherwise." + } + }, + "required": ["status", "record"] + }, + "app.bsky.embed.external_view": { + "type": "object", + "properties": { + "external": { + "$ref": "#/components/schemas/app.bsky.embed.external_viewExternal" + } + }, + "required": ["external"] + }, + "app.bsky.embed.external_viewExternal": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri" + }, + "thumb": { + "type": "string", + "format": "uri" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": ["uri", "title", "description"] + }, + "app.bsky.actor.defs_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" + }, + "blocking": { + "type": "string", + "format": "uri" + }, + "blockedBy": { + "type": "boolean" + }, + "following": { + "type": "string", + "format": "uri" + }, + "followedBy": { + "type": "string", + "format": "uri" + }, + "mutedByList": { + "$ref": "#/components/schemas/app.bsky.graph.defs_listViewBasic" + }, + "blockingByList": { + "$ref": "#/components/schemas/app.bsky.graph.defs_listViewBasic" + }, + "knownFollowers": { + "$ref": "#/components/schemas/app.bsky.actor.defs_knownFollowers", + "description": "This property is present only in selected cases, as an optimization." + }, + "activitySubscription": { + "$ref": "#/components/schemas/app.bsky.notification.defs_activitySubscription", + "description": "This property is present only in selected cases, as an optimization." + } + } + }, + "app.bsky.graph.defs_listViewBasic": { + "type": "object", + "properties": { + "cid": { + "type": "string", + "format": "cid" + }, + "uri": { + "type": "string", + "format": "uri" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "avatar": { + "type": "string", + "format": "uri" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.label.defs_label" + } + }, + "viewer": { + "$ref": "#/components/schemas/app.bsky.graph.defs_listViewerState" + }, + "purpose": { + "$ref": "#/components/schemas/app.bsky.graph.defs_listPurpose" + }, + "indexedAt": { + "type": "string", + "format": "date-time" + }, + "listItemCount": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["uri", "cid", "name", "purpose"] + }, + "app.bsky.graph.defs_listViewerState": { + "type": "object", + "properties": { + "muted": { + "type": "boolean" + }, + "blocked": { + "type": "string", + "format": "uri" + } + } + }, + "app.bsky.graph.defs_listPurpose": { + "type": "string" + }, + "app.bsky.actor.defs_knownFollowers": { + "type": "object", + "description": "The subject's followers whom you also follow", + "properties": { + "count": { + "type": "integer" + }, + "followers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + }, + "minItems": 0, + "maxItems": 5 + } + }, + "required": ["count", "followers"] + }, + "app.bsky.notification.defs_activitySubscription": { + "type": "object", + "properties": { + "post": { + "type": "boolean" + }, + "reply": { + "type": "boolean" + } + }, + "required": ["post", "reply"] + }, + "app.bsky.actor.defs_profileAssociated": { + "type": "object", + "properties": { + "chat": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileAssociatedChat" + }, + "germ": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileAssociatedGerm" + }, + "lists": { + "type": "integer" + }, + "labeler": { + "type": "boolean" + }, + "feedgens": { + "type": "integer" + }, + "starterPacks": { + "type": "integer" + }, + "activitySubscription": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileAssociatedActivitySubscription" + } + } + }, + "app.bsky.actor.defs_profileAssociatedChat": { + "type": "object", + "properties": { + "allowIncoming": { + "type": "string" + } + }, + "required": ["allowIncoming"] + }, + "app.bsky.actor.defs_profileAssociatedGerm": { + "type": "object", + "properties": { + "messageMeUrl": { + "type": "string", + "format": "uri" + }, + "showButtonTo": { + "type": "string" + } + }, + "required": ["showButtonTo", "messageMeUrl"] + }, + "app.bsky.actor.defs_profileAssociatedActivitySubscription": { + "type": "object", + "properties": { + "allowSubscriptions": { + "type": "string" + } + }, + "required": ["allowSubscriptions"] + }, + "app.bsky.actor.defs_verificationState": { + "type": "object", + "description": "Represents the verification information about the user this object is attached to.", + "properties": { + "verifications": { + "type": "array", + "description": "All verifications issued by trusted verifiers on behalf of this user. Verifications by untrusted verifiers are not included.", + "items": { + "$ref": "#/components/schemas/app.bsky.actor.defs_verificationView" + } + }, + "verifiedStatus": { + "type": "string", + "description": "The user's status as a verified account." + }, + "trustedVerifierStatus": { + "type": "string", + "description": "The user's status as a trusted verifier." + } + }, + "required": ["verifications", "verifiedStatus", "trustedVerifierStatus"] + }, + "app.bsky.actor.defs_verificationView": { + "type": "object", + "description": "An individual verification for an associated subject.", + "properties": { + "uri": { + "type": "string", + "description": "The AT-URI of the verification record.", + "format": "uri" + }, + "issuer": { + "type": "string", + "description": "The user who issued this verification.", + "format": "did" + }, + "isValid": { + "type": "boolean", + "description": "True if the verification passes validation, otherwise false." + }, + "createdAt": { + "type": "string", + "description": "Timestamp when the verification was created.", + "format": "date-time" + } + }, + "required": ["issuer", "uri", "isValid", "createdAt"] + }, + "place.stream.vod.defs_commentView": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri" + }, + "cid": { + "type": "string", + "format": "cid" + }, + "author": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + }, + "record": {}, + "indexedAt": { + "type": "string", + "format": "date-time" + }, + "replyTo": { + "oneOf": [ + { + "$ref": "#/components/schemas/place.stream.vod.defs_commentViewBasic" + } + ], + "description": "The parent comment this one replies to, if any. A non-recursive view (it carries no replyTo of its own), so the thread is flattened to a single hop; walk `record.reply` to follow the chain further." + }, + "likeCount": { + "type": "integer", + "description": "Number of likes on this comment.", + "minimum": 0 + } + }, + "required": ["uri", "cid", "author", "record", "indexedAt", "likeCount"] + }, + "place.stream.vod.defs_commentViewBasic": { + "type": "object", + "description": "A comment view without its own `replyTo`, used to represent the parent of a reply without recursively nesting the whole thread.", + "properties": { + "uri": { + "type": "string", + "format": "uri" + }, + "cid": { + "type": "string", + "format": "cid" + }, + "author": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + }, + "record": {}, + "indexedAt": { + "type": "string", + "format": "date-time" + }, + "likeCount": { + "type": "integer", + "description": "Number of likes on this comment.", + "minimum": 0 + } + }, + "required": ["uri", "cid", "author", "record", "indexedAt", "likeCount"] }, - "app.bsky.actor.defs_profileViewBasic": { + "place.stream.vod.draftDefs_draftView": { "type": "object", + "description": "A draft VOD with its ats:// URI and CID, for list/get responses.", "properties": { - "did": { - "type": "string", - "format": "did" - }, - "handle": { - "type": "string", - "format": "handle" - }, - "displayName": { + "uri": { "type": "string", - "maxLength": 640 + "description": "The ats:// URI of the draft record." }, - "avatar": { + "cid": { "type": "string", - "format": "uri" - }, - "associated": { - "$ref": "#/components/schemas/app.bsky.actor.defs_profileAssociated" + "description": "CID (sha256 of CBOR record bytes, base32) of the draft record." }, - "viewer": { - "$ref": "#/components/schemas/app.bsky.actor.defs_viewerState" + "record": { + "description": "The place.stream.vod.draftVideo record body. Typed as unknown (matching commentView/livestreamView/videoView) because the @atproto/api client validator cannot validate a ref to a record-type lexicon." + } + }, + "required": ["uri", "cid", "record"] + }, + "place.stream.richtext.videoFacet": { + "type": "object", + "description": "Annotation of a sub-string within rich text in a VOD description or comment.", + "properties": { + "index": { + "$ref": "#/components/schemas/app.bsky.richtext.facet_byteSlice" }, - "labels": { + "features": { "type": "array", "items": { - "$ref": "#/components/schemas/com.atproto.label.defs_label" + "oneOf": [ + { + "$ref": "#/components/schemas/app.bsky.richtext.facet_mention" + }, + { + "$ref": "#/components/schemas/app.bsky.richtext.facet_link" + } + ] } - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "verification": { - "$ref": "#/components/schemas/app.bsky.actor.defs_verificationState" - }, - "status": { - "$ref": "#/components/schemas/app.bsky.actor.defs_statusView" } }, - "required": ["did", "handle"] + "required": ["index", "features"] }, - "app.bsky.actor.defs_profileAssociated": { + "app.bsky.richtext.facet_byteSlice": { "type": "object", + "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.", "properties": { - "lists": { - "type": "integer" - }, - "feedgens": { - "type": "integer" - }, - "starterPacks": { - "type": "integer" - }, - "labeler": { - "type": "boolean" + "byteEnd": { + "type": "integer", + "minimum": 0 }, - "chat": { - "$ref": "#/components/schemas/app.bsky.actor.defs_profileAssociatedChat" + "byteStart": { + "type": "integer", + "minimum": 0 } - } + }, + "required": ["byteStart", "byteEnd"] }, - "app.bsky.actor.defs_profileAssociatedChat": { + "app.bsky.richtext.facet_mention": { "type": "object", + "description": "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID.", "properties": { - "allowIncoming": { - "type": "string" + "did": { + "type": "string", + "format": "did" } }, - "required": ["allowIncoming"] + "required": ["did"] }, - "app.bsky.actor.defs_viewerState": { + "app.bsky.richtext.facet_link": { "type": "object", - "description": "Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests.", + "description": "Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.", "properties": { - "muted": { - "type": "boolean" - }, - "mutedByList": { - "$ref": "#/components/schemas/app.bsky.graph.defs_listViewBasic" - }, - "blockedBy": { - "type": "boolean" - }, - "blocking": { - "type": "string", - "format": "uri" - }, - "blockingByList": { - "$ref": "#/components/schemas/app.bsky.graph.defs_listViewBasic" - }, - "following": { - "type": "string", - "format": "uri" - }, - "followedBy": { + "uri": { "type": "string", "format": "uri" - }, - "knownFollowers": { - "$ref": "#/components/schemas/app.bsky.actor.defs_knownFollowers" } - } + }, + "required": ["uri"] }, - "app.bsky.graph.defs_listViewBasic": { + "place.stream.defs_activityGame": { "type": "object", + "description": "A game from the gamesgamesgamesgames catalog, identified by its AT URI.", "properties": { "uri": { "type": "string", "format": "uri" }, - "cid": { - "type": "string", - "format": "cid" - }, "name": { "type": "string", - "minLength": 1, - "maxLength": 64 - }, - "purpose": { - "$ref": "#/components/schemas/app.bsky.graph.defs_listPurpose" + "description": "Cached display name of the game." + } + }, + "required": ["uri"] + }, + "place.stream.defs_activityLabel": { + "type": "object", + "description": "A non-game activity with a well-known label.", + "properties": { + "label": { + "type": "string" + } + }, + "required": ["label"] + }, + "place.stream.metadata.contentWarnings": { + "type": "object", + "description": "Content warnings for a stream.", + "properties": { + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "place.stream.metadata.contentRights": { + "type": "object", + "description": "Content rights and attribution information.", + "properties": { + "creator": { + "type": "string", + "description": "Name of the creator of the work." }, - "avatar": { + "copyrightNotice": { "type": "string", - "format": "uri" + "description": "Copyright notice for the work." }, - "listItemCount": { + "copyrightYear": { "type": "integer", - "minimum": 0 + "description": "Year of creation or publication." }, - "labels": { - "type": "array", - "items": { - "$ref": "#/components/schemas/com.atproto.label.defs_label" - } + "license": { + "type": "string", + "description": "License URL or identifier." }, - "viewer": { - "$ref": "#/components/schemas/app.bsky.graph.defs_listViewerState" + "creditLine": { + "type": "string", + "description": "Credit line for the work." + } + } + }, + "place.stream.server.defs_rewriteRule": { + "type": "object", + "properties": { + "from": { + "type": "string", + "description": "Text to search for and replace.", + "minLength": 1, + "maxLength": 100 }, - "indexedAt": { + "to": { "type": "string", - "format": "date-time" + "description": "Text to replace with.", + "maxLength": 100 } }, - "required": ["uri", "cid", "name", "purpose"] - }, - "app.bsky.graph.defs_listPurpose": { - "type": "string" + "required": ["from", "to"] }, - "com.atproto.label.defs_label": { + "place.stream.server.defs_webhook": { "type": "object", - "description": "Metadata tag on an atproto resource (eg, repo or record).", + "description": "A webhook configuration for receiving Streamplace events.", "properties": { - "ver": { - "type": "integer", - "description": "The AT Protocol version of the label object." - }, - "src": { + "id": { "type": "string", - "description": "DID of the actor who created this label.", - "format": "did" + "description": "Unique identifier for this webhook." }, - "uri": { + "url": { "type": "string", - "description": "AT URI of the record, repository (account), or other resource that this label applies to.", + "description": "The webhook URL where events will be sent.", "format": "uri" }, - "cid": { + "events": { + "type": "array", + "description": "The types of events this webhook should receive.", + "items": { + "type": "string", + "enum": [ + "chat", + "livestream", + "follow", + "mention", + "stream.received" + ] + } + }, + "active": { + "type": "boolean", + "description": "Whether this webhook is currently active." + }, + "prefix": { "type": "string", - "description": "Optionally, CID specifying the specific version of 'uri' resource this label applies to.", - "format": "cid" + "description": "Text to prepend to webhook messages.", + "maxLength": 100 }, - "val": { + "suffix": { "type": "string", - "description": "The short string name of the value or type of this label.", - "maxLength": 128 + "description": "Text to append to webhook messages.", + "maxLength": 100 }, - "neg": { - "type": "boolean", - "description": "If true, this is a negation label, overwriting a previous label." + "rewrite": { + "type": "array", + "description": "Text replacement rules for webhook messages.", + "items": { + "$ref": "#/components/schemas/place.stream.server.defs_rewriteRule" + } }, - "cts": { + "createdAt": { "type": "string", - "description": "Timestamp when this label was created.", + "description": "When this webhook was created.", "format": "date-time" }, - "exp": { + "updatedAt": { "type": "string", - "description": "Timestamp at which this label expires (no longer applies).", + "description": "When this webhook was last updated.", "format": "date-time" }, - "sig": { + "name": { "type": "string", - "format": "byte", - "description": "Signature of dag-cbor encoded label." - } - }, - "required": ["src", "uri", "val", "cts"] - }, - "app.bsky.graph.defs_listViewerState": { - "type": "object", - "properties": { - "muted": { - "type": "boolean" + "description": "A user-friendly name for this webhook.", + "maxLength": 100 }, - "blocked": { + "description": { "type": "string", - "format": "uri" - } - } - }, - "app.bsky.actor.defs_knownFollowers": { - "type": "object", - "description": "The subject's followers whom you also follow", - "properties": { - "count": { - "type": "integer" + "description": "A description of what this webhook is used for.", + "maxLength": 500 }, - "followers": { + "lastTriggered": { + "type": "string", + "description": "When this webhook was last triggered.", + "format": "date-time" + }, + "errorCount": { + "type": "integer", + "description": "Number of consecutive errors for this webhook." + }, + "muteWords": { "type": "array", + "description": "Words to filter out from chat messages. Messages containing any of these words will not be forwarded.", "items": { - "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" - }, - "minItems": 0, - "maxItems": 5 + "type": "string", + "maxLength": 100 + } } }, - "required": ["count", "followers"] + "required": ["id", "url", "events", "active", "createdAt"] }, - "app.bsky.actor.defs_verificationState": { + "place.stream.server.defs_storage": { "type": "object", - "description": "Represents the verification information about the user this object is attached to.", + "description": "S3 storage configuration for backups.", "properties": { - "verifications": { - "type": "array", - "description": "All verifications issued by trusted verifiers on behalf of this user. Verifications by untrusted verifiers are not included.", - "items": { - "$ref": "#/components/schemas/app.bsky.actor.defs_verificationView" - } - }, - "verifiedStatus": { + "url": { "type": "string", - "description": "The user's status as a verified account." + "description": "S3 storage URL with masked secret key in format: s3+https://ACCESS_KEY:***@endpoint/bucket" }, - "trustedVerifierStatus": { - "type": "string", - "description": "The user's status as a trusted verifier." + "isActive": { + "type": "boolean", + "description": "Whether backup storage is currently active." } }, - "required": ["verifications", "verifiedStatus", "trustedVerifierStatus"] + "required": ["url", "isActive"] }, - "app.bsky.actor.defs_verificationView": { + "place.stream.multistream.target": { + "description": "Unknown type" + }, + "place.stream.multistream.defs_targetView": { "type": "object", - "description": "An individual verification for an associated subject.", "properties": { - "issuer": { - "type": "string", - "description": "The user who issued this verification.", - "format": "did" - }, "uri": { "type": "string", - "description": "The AT-URI of the verification record.", "format": "uri" }, - "isValid": { - "type": "boolean", - "description": "True if the verification passes validation, otherwise false." - }, - "createdAt": { + "cid": { "type": "string", - "description": "Timestamp when the verification was created.", - "format": "date-time" + "format": "cid" + }, + "record": {}, + "latestEvent": { + "$ref": "#/components/schemas/place.stream.multistream.defs_event" } }, - "required": ["issuer", "uri", "isValid", "createdAt"] + "required": ["uri", "cid", "record"] }, - "app.bsky.actor.defs_statusView": { + "place.stream.multistream.defs_event": { "type": "object", "properties": { + "message": { + "type": "string" + }, "status": { "type": "string", - "description": "The status for the account." - }, - "record": {}, - "embed": { - "oneOf": [ - { - "$ref": "#/components/schemas/app.bsky.embed.external_view" - } - ], - "description": "An optional embed associated with the status." + "enum": ["inactive", "pending", "active", "error"] }, - "expiresAt": { + "createdAt": { "type": "string", - "description": "The date when this status will expire. The application might choose to no longer return the status after expiration.", "format": "date-time" - }, - "isActive": { - "type": "boolean", - "description": "True if the status is not expired, false if it is expired. Only present if expiration was set." - } - }, - "required": ["status", "record"] - }, - "app.bsky.embed.external_view": { - "type": "object", - "properties": { - "external": { - "$ref": "#/components/schemas/app.bsky.embed.external_viewExternal" } }, - "required": ["external"] + "required": ["message", "status", "createdAt"] }, - "app.bsky.embed.external_viewExternal": { + "place.stream.media.getUploadStatus_trackRef": { "type": "object", "properties": { "uri": { "type": "string", "format": "uri" }, - "title": { - "type": "string" - }, - "description": { + "cid": { "type": "string" - }, - "thumb": { - "type": "string", - "format": "uri" } }, - "required": ["uri", "title", "description"] + "required": ["uri", "cid"] }, - "place.stream.vod.defs_commentView": { + "place.stream.media.getVideo_videoView": { "type": "object", "properties": { "uri": { @@ -4656,29 +6278,81 @@ "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" }, "record": {}, - "indexedAt": { - "type": "string", - "format": "date-time" + "likeCount": { + "type": "integer", + "description": "Total number of place.stream.like records whose subject is this video. Always present; zero when none, so consumers can render a count unconditionally.", + "minimum": 0 }, - "replyTo": { - "oneOf": [ - { - "$ref": "#/components/schemas/place.stream.vod.defs_commentViewBasic" - } - ], - "description": "The parent comment this one replies to, if any. A non-recursive view (it carries no replyTo of its own), so the thread is flattened to a single hop; walk `record.reply` to follow the chain further." + "viewCounts": { + "$ref": "#/components/schemas/place.stream.media.getVideo_viewCountSummary", + "description": "Aggregated view counts across every indexed reporter. Always present; zero-valued (count=0, reporters=0) when no place.stream.media.viewCount records have been observed yet, so consumers can render a count unconditionally." }, - "likeCount": { + "tracks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/place.stream.media.track_trackView" + } + } + }, + "required": [ + "uri", + "cid", + "author", + "record", + "viewCounts", + "likeCount" + ] + }, + "place.stream.media.getVideo_viewCountSummary": { + "type": "object", + "description": "Sums across every place.stream.media.viewCount record indexed for this video, regardless of reporter or window. The underlying records are window-bounded; the consumer sees a running total.", + "properties": { + "count": { "type": "integer", - "description": "Number of likes on this comment.", + "description": "Sum of `count` across every indexed report.", + "minimum": 0 + }, + "bytes": { + "type": "integer", + "description": "Sum of bytes transferred across every track row in every indexed report.", + "minimum": 0 + }, + "durationMs": { + "type": "integer", + "description": "Sum of playback duration (ms) across every track row in every indexed report.", + "minimum": 0 + }, + "reporters": { + "type": "integer", + "description": "Number of distinct streamplace nodes that have contributed at least one viewCount record for this video.", "minimum": 0 } }, - "required": ["uri", "cid", "author", "record", "indexedAt", "likeCount"] + "required": ["count", "bytes", "durationMs", "reporters"] + }, + "place.stream.media.track_trackView": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri" + }, + "cid": { + "type": "string", + "format": "cid" + }, + "author": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + }, + "record": {} + }, + "required": ["uri", "cid", "author", "record"] + }, + "place.stream.video": { + "description": "Unknown type" }, - "place.stream.vod.defs_commentViewBasic": { + "place.stream.livestream_livestreamView": { "type": "object", - "description": "A comment view without its own `replyTo`, used to represent the parent of a reply without recursively nesting the whole thread.", "properties": { "uri": { "type": "string", @@ -4696,655 +6370,810 @@ "type": "string", "format": "date-time" }, - "likeCount": { - "type": "integer", - "description": "Number of likes on this comment.", - "minimum": 0 + "viewerCount": { + "$ref": "#/components/schemas/place.stream.livestream_viewerCount", + "description": "The number of viewers watching this livestream. Use when you can't reasonably use #viewerCount directly." } }, - "required": ["uri", "cid", "author", "record", "indexedAt", "likeCount"] + "required": ["uri", "cid", "author", "record", "indexedAt"] }, - "place.stream.vod.draftDefs_draftView": { + "place.stream.livestream_viewerCount": { "type": "object", - "description": "A draft VOD with its ats:// URI and CID, for list/get responses.", "properties": { - "uri": { - "type": "string", - "description": "The ats:// URI of the draft record." - }, - "cid": { - "type": "string", - "description": "CID (sha256 of CBOR record bytes, base32) of the draft record." - }, - "record": { - "description": "The place.stream.vod.draftVideo record body. Typed as unknown (matching commentView/livestreamView/videoView) because the @atproto/api client validator cannot validate a ref to a record-type lexicon." + "count": { + "type": "integer" } }, - "required": ["uri", "cid", "record"] + "required": ["count"] }, - "place.stream.richtext.videoFacet": { + "place.stream.live.getRecommendations_livestreamRecommendation": { "type": "object", - "description": "Annotation of a sub-string within rich text in a VOD description or comment.", "properties": { - "index": { - "$ref": "#/components/schemas/app.bsky.richtext.facet_byteSlice" + "did": { + "type": "string", + "description": "The DID of the recommended streamer", + "format": "did" }, - "features": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/app.bsky.richtext.facet_mention" - }, - { - "$ref": "#/components/schemas/app.bsky.richtext.facet_link" - } - ] - } + "source": { + "type": "string", + "description": "Source of the recommendation", + "enum": ["streamer", "follows", "host"] } }, - "required": ["index", "features"] + "required": ["did", "source"] }, - "app.bsky.richtext.facet_byteSlice": { + "place.stream.segment_segmentView": { "type": "object", - "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.", "properties": { - "byteStart": { - "type": "integer", - "minimum": 0 + "cid": { + "type": "string", + "format": "cid" }, - "byteEnd": { - "type": "integer", - "minimum": 0 - } + "record": {} }, - "required": ["byteStart", "byteEnd"] + "required": ["cid", "record"] }, - "app.bsky.richtext.facet_mention": { + "place.stream.live.searchActorsTypeahead_actor": { "type": "object", - "description": "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID.", "properties": { "did": { "type": "string", + "description": "The actor's DID", "format": "did" + }, + "handle": { + "type": "string", + "description": "The actor's handle", + "format": "handle" } }, - "required": ["did"] + "required": ["did", "handle"] }, - "app.bsky.richtext.facet_link": { + "place.stream.livestream": { + "description": "Unknown type" + }, + "place.stream.live.subscribeSegments_segment": { + "type": "string", + "format": "byte", + "description": "MP4 file of a user's signed livestream segment" + }, + "place.stream.ingest.defs_ingest": { "type": "object", - "description": "Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.", + "description": "An ingest URL for a Streamplace station.", "properties": { - "uri": { + "type": { + "type": "string", + "description": "The type of ingest endpoint, currently 'rtmp' and 'whip' are supported." + }, + "url": { "type": "string", + "description": "The URL of the ingest endpoint.", "format": "uri" } }, - "required": ["uri"] + "required": ["type", "url"] }, - "place.stream.defs_activityGame": { + "com.atproto.repo.strongRef": { "type": "object", - "description": "A game from the gamesgamesgamesgames catalog, identified by its AT URI.", "properties": { - "uri": { + "cid": { "type": "string", - "format": "uri" + "format": "cid" }, - "name": { + "uri": { "type": "string", - "description": "Cached display name of the game." + "format": "uri" } }, - "required": ["uri"] + "required": ["uri", "cid"] }, - "place.stream.defs_activityLabel": { + "games.gamesgamesgamesgames.defs_gameSummaryView": { "type": "object", - "description": "A non-game activity with a well-known label.", "properties": { - "label": { + "uri": { + "type": "string", + "format": "uri" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "media": { + "type": "array", + "items": { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_mediaItem" + } + }, + "summary": { "type": "string" + }, + "applicationType": { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_applicationType" + }, + "firstReleaseDate": { + "type": "integer", + "description": "Earliest release date as YYYYMMDD integer." } }, - "required": ["label"] + "required": ["uri", "name"] }, - "place.stream.metadata.contentWarnings": { + "games.gamesgamesgamesgames.defs_mediaItem": { "type": "object", - "description": "Content warnings for a stream.", "properties": { - "warnings": { - "type": "array", - "items": { - "type": "string" - } + "blob": { + "type": "string", + "format": "binary" + }, + "title": { + "type": "string" + }, + "width": { + "type": "integer" + }, + "height": { + "type": "integer" + }, + "locale": { + "type": "string" + }, + "mediaType": { + "type": "string", + "enum": [ + "accoladesTrailer", + "announcementTrailer", + "artwork", + "cinematicTrailer", + "conceptArt", + "cover", + "coverAlt", + "coverHistorical", + "coverSquare", + "cutscene", + "devDiary", + "gameplayImage", + "gameplayTrailer", + "icon", + "infographic", + "intro", + "keyArt", + "keyArtLogo", + "launchTrailer", + "logoBlack", + "logoColor", + "logoWhite", + "releaseDateTrailer", + "screenshot", + "teaser", + "trailer" + ] + }, + "description": { + "type": "string" } } }, - "place.stream.metadata.contentRights": { + "games.gamesgamesgamesgames.defs_applicationType": { + "type": "string", + "enum": [ + "addon", + "bundle", + "dlc", + "episode", + "expandedGame", + "expansion", + "fork", + "game", + "mod", + "port", + "remake", + "remaster", + "season", + "standaloneExpansion", + "update" + ] + }, + "games.gamesgamesgamesgames.defs_profileSummaryView": { "type": "object", - "description": "Content rights and attribution information.", "properties": { - "creator": { + "did": { "type": "string", - "description": "Name of the creator of the work." + "format": "did" }, - "copyrightNotice": { + "uri": { "type": "string", - "description": "Copyright notice for the work." - }, - "copyrightYear": { - "type": "integer", - "description": "Year of creation or publication." + "format": "uri" }, - "license": { + "avatar": { "type": "string", - "description": "License URL or identifier." + "format": "binary" }, - "creditLine": { + "displayName": { "type": "string", - "description": "Credit line for the work." + "maxLength": 640 + }, + "profileType": { + "type": "string" } - } + }, + "required": ["uri", "did", "profileType"] }, - "place.stream.server.defs_rewriteRule": { + "games.gamesgamesgamesgames.defs_platformSummaryView": { "type": "object", "properties": { - "from": { + "uri": { "type": "string", - "description": "Text to search for and replace.", - "minLength": 1, - "maxLength": 100 + "format": "uri" }, - "to": { - "type": "string", - "description": "Text to replace with.", - "maxLength": 100 + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "category": { + "$ref": "#/components/schemas/games.gamesgamesgamesgames.defs_platformCategory" + }, + "abbreviation": { + "type": "string" } }, - "required": ["from", "to"] + "required": ["uri", "name"] }, - "place.stream.server.defs_webhook": { + "games.gamesgamesgamesgames.defs_platformCategory": { + "type": "string" + }, + "games.gamesgamesgamesgames.defs_collectionSummaryView": { "type": "object", - "description": "A webhook configuration for receiving Streamplace events.", "properties": { - "id": { + "uri": { "type": "string", - "description": "Unique identifier for this webhook." + "format": "uri" }, - "url": { + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": ["uri", "name"] + }, + "games.gamesgamesgamesgames.defs_engineSummaryView": { + "type": "object", + "properties": { + "uri": { "type": "string", - "description": "The webhook URL where events will be sent.", "format": "uri" }, - "events": { - "type": "array", - "description": "The types of events this webhook should receive.", - "items": { - "type": "string", - "enum": [ - "chat", - "livestream", - "follow", - "mention", - "stream.received" - ] - } + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": ["uri", "name"] + }, + "place.stream.branding.getBranding_brandingAsset": { + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "Asset key identifier" }, - "active": { - "type": "boolean", - "description": "Whether this webhook is currently active." + "mimeType": { + "type": "string", + "description": "MIME type of the asset" }, - "prefix": { + "url": { "type": "string", - "description": "Text to prepend to webhook messages.", - "maxLength": 100 + "description": "URL to fetch the asset blob (for images)" }, - "suffix": { + "data": { "type": "string", - "description": "Text to append to webhook messages.", - "maxLength": 100 + "description": "Inline data for text assets" }, - "rewrite": { - "type": "array", - "description": "Text replacement rules for webhook messages.", - "items": { - "$ref": "#/components/schemas/place.stream.server.defs_rewriteRule" - } + "width": { + "type": "integer", + "description": "Image width in pixels (optional, for images only)" }, - "createdAt": { + "height": { + "type": "integer", + "description": "Image height in pixels (optional, for images only)" + } + }, + "required": ["key", "mimeType"] + }, + "place.stream.badge.defs_badgeView": { + "type": "object", + "description": "View of a badge record, with fields resolved for display. If the DID in issuer is not the current streamplace node, the signature field shall be required.", + "properties": { + "badgeType": { + "type": "string" + }, + "issuer": { "type": "string", - "description": "When this webhook was created.", - "format": "date-time" + "description": "DID of the badge issuer.", + "format": "did" }, - "updatedAt": { + "recipient": { "type": "string", - "description": "When this webhook was last updated.", - "format": "date-time" + "description": "DID of the badge recipient.", + "format": "did" }, "name": { "type": "string", - "description": "A user-friendly name for this webhook.", - "maxLength": 100 + "description": "Display name from the badge definition." }, "description": { "type": "string", - "description": "A description of what this webhook is used for.", - "maxLength": 500 + "description": "Description from the badge definition." }, - "lastTriggered": { + "imageUrl": { "type": "string", - "description": "When this webhook was last triggered.", - "format": "date-time" - }, - "errorCount": { - "type": "integer", - "description": "Number of consecutive errors for this webhook." + "description": "Resolved image URL for the badge icon.", + "format": "uri" }, - "muteWords": { - "type": "array", - "description": "Words to filter out from chat messages. Messages containing any of these words will not be forwarded.", - "items": { - "type": "string", - "maxLength": 100 - } + "signature": { + "type": "string", + "description": "TODO: Cryptographic signature of the badge (of a place.stream.key)." } }, - "required": ["id", "url", "events", "active", "createdAt"] + "required": ["badgeType", "issuer", "recipient"] }, - "place.stream.server.defs_storage": { + "place.stream.badge.defs_badgeSlot": { "type": "object", - "description": "S3 storage configuration for backups.", + "description": "A display slot containing available issuance-based badges and which one (if any) is currently selected.", "properties": { - "url": { - "type": "string", - "description": "S3 storage URL with masked secret key in format: s3+https://ACCESS_KEY:***@endpoint/bucket" + "selected": { + "$ref": "#/components/schemas/place.stream.badge.defs_badgeIssuanceView", + "description": "The currently selected badge in this slot, if any." }, - "isActive": { - "type": "boolean", - "description": "Whether backup storage is currently active." + "available": { + "type": "array", + "description": "All badges available for this slot.", + "items": { + "$ref": "#/components/schemas/place.stream.badge.defs_badgeIssuanceView" + } } }, - "required": ["url", "isActive"] - }, - "place.stream.multistream.target": { - "description": "Unknown type" + "required": ["available"] }, - "place.stream.multistream.defs_targetView": { + "place.stream.badge.defs_badgeIssuanceView": { "type": "object", + "description": "A resolved view of a badge issuance, including def fields for display.", "properties": { - "uri": { + "issuanceUri": { "type": "string", + "description": "AT URI of the place.stream.badge.issuance record.", "format": "uri" }, - "cid": { + "issuanceCid": { "type": "string", - "format": "cid" + "description": "CID of the place.stream.badge.issuance record." }, - "record": {}, - "latestEvent": { - "$ref": "#/components/schemas/place.stream.multistream.defs_event" - } - }, - "required": ["uri", "cid", "record"] - }, - "place.stream.multistream.defs_event": { - "type": "object", - "properties": { - "message": { + "badgeType": { "type": "string" }, - "status": { + "name": { "type": "string", - "enum": ["inactive", "pending", "active", "error"] + "description": "Display name from the badge definition." }, - "createdAt": { + "description": { "type": "string", - "format": "date-time" - } - }, - "required": ["message", "status", "createdAt"] - }, - "place.stream.media.getUploadStatus_trackRef": { - "type": "object", - "properties": { - "uri": { + "description": "Description from the badge definition." + }, + "imageUrl": { "type": "string", + "description": "Resolved image URL for the badge icon.", "format": "uri" }, - "cid": { - "type": "string" + "issuer": { + "type": "string", + "description": "DID of the badge issuer.", + "format": "did" + }, + "selected": { + "type": "boolean", + "description": "Whether this badge is currently in the user's chat profile selection." } }, - "required": ["uri", "cid"] + "required": ["issuanceUri", "badgeType", "issuer"] }, - "place.stream.media.getVideo_videoView": { + "com.atproto.sync.subscribeRepos_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.", "properties": { - "uri": { - "type": "string", - "format": "uri" + "ops": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_repoOp", + "description": "List of repo mutation operations in this commit (eg, records created, updated, or deleted)." + }, + "maxItems": 200 }, - "cid": { + "rev": { "type": "string", - "format": "cid" - }, - "author": { - "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + "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.", + "format": "tid" }, - "record": {}, - "likeCount": { + "seq": { "type": "integer", - "description": "Total number of place.stream.like records whose subject is this video. Always present; zero when none, so consumers can render a count unconditionally.", - "minimum": 0 + "description": "The stream sequence number of this message." }, - "viewCounts": { - "$ref": "#/components/schemas/place.stream.media.getVideo_viewCountSummary", - "description": "Aggregated view counts across every indexed reporter. Always present; zero-valued (count=0, reporters=0) when no place.stream.media.viewCount records have been observed yet, so consumers can render a count unconditionally." + "repo": { + "type": "string", + "description": "The repo this event comes from. Note that all other message types name this field 'did'.", + "format": "did" }, - "tracks": { + "time": { + "type": "string", + "description": "Timestamp of when this message was originally broadcast.", + "format": "date-time" + }, + "blobs": { "type": "array", "items": { - "$ref": "#/components/schemas/place.stream.media.track_trackView" + "type": "string", + "description": "DEPRECATED -- will soon always be empty. List of new blobs (by CID) referenced by records in this commit." } - } - }, - "required": [ - "uri", - "cid", - "author", - "record", - "viewCounts", - "likeCount" - ] - }, - "place.stream.media.getVideo_viewCountSummary": { - "type": "object", - "description": "Sums across every place.stream.media.viewCount record indexed for this video, regardless of reporter or window. The underlying records are window-bounded; the consumer sees a running total.", - "properties": { - "count": { - "type": "integer", - "description": "Sum of `count` across every indexed report.", - "minimum": 0 }, - "bytes": { - "type": "integer", - "description": "Sum of bytes transferred across every track row in every indexed report.", - "minimum": 0 + "since": { + "oneOf": [ + { + "type": "string", + "description": "The rev of the last emitted commit from this repo (if any).", + "format": "tid" + } + ] }, - "durationMs": { - "type": "integer", - "description": "Sum of playback duration (ms) across every track row in every indexed report.", - "minimum": 0 + "blocks": { + "type": "string", + "format": "byte", + "description": "CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list.", + "maxLength": 2000000 }, - "reporters": { - "type": "integer", - "description": "Number of distinct streamplace nodes that have contributed at least one viewCount record for this video.", - "minimum": 0 + "commit": { + "type": "string", + "description": "Repo commit object CID." + }, + "rebase": { + "type": "boolean", + "description": "DEPRECATED -- unused" + }, + "tooBig": { + "type": "boolean", + "description": "DEPRECATED -- replaced by #sync event and data limits. 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." + }, + "prevData": { + "type": "string", + "description": "The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose." } }, - "required": ["count", "bytes", "durationMs", "reporters"] + "required": [ + "seq", + "rebase", + "tooBig", + "repo", + "commit", + "rev", + "since", + "blocks", + "ops", + "blobs", + "time" + ] }, - "place.stream.media.track_trackView": { + "com.atproto.sync.subscribeRepos_repoOp": { "type": "object", + "description": "A repo operation, ie a mutation of a single record.", "properties": { - "uri": { - "type": "string", - "format": "uri" - }, "cid": { - "type": "string", - "format": "cid" + "oneOf": [ + { + "type": "string", + "description": "For creates and updates, the new record CID. For deletions, null." + } + ] }, - "author": { - "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + "path": { + "type": "string" }, - "record": {} - }, - "required": ["uri", "cid", "author", "record"] - }, - "place.stream.video": { - "description": "Unknown type" + "prev": { + "type": "string", + "description": "For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined." + }, + "action": { + "type": "string" + } + }, + "required": ["action", "path", "cid"] }, - "place.stream.livestream_livestreamView": { + "com.atproto.sync.subscribeRepos_sync": { "type": "object", + "description": "Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository.", "properties": { - "uri": { + "did": { "type": "string", - "format": "uri" + "description": "The account this repo event corresponds to. Must match that in the commit object.", + "format": "did" }, - "cid": { + "rev": { "type": "string", - "format": "cid" + "description": "The rev of the commit. This value must match that in the commit object." }, - "author": { - "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + "seq": { + "type": "integer", + "description": "The stream sequence number of this message." }, - "record": {}, - "indexedAt": { + "time": { "type": "string", + "description": "Timestamp of when this message was originally broadcast.", "format": "date-time" }, - "viewerCount": { - "$ref": "#/components/schemas/place.stream.livestream_viewerCount", - "description": "The number of viewers watching this livestream. Use when you can't reasonably use #viewerCount directly." + "blocks": { + "type": "string", + "format": "byte", + "description": "CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'.", + "maxLength": 10000 } }, - "required": ["uri", "cid", "author", "record", "indexedAt"] + "required": ["seq", "did", "blocks", "rev", "time"] }, - "place.stream.livestream_viewerCount": { + "com.atproto.sync.subscribeRepos_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.", "properties": { - "count": { + "did": { + "type": "string", + "format": "did" + }, + "seq": { "type": "integer" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "handle": { + "type": "string", + "description": "The current handle for the account, or 'handle.invalid' if validation fails. This field is optional, might have been validated or passed-through from an upstream source. Semantics and behaviors for PDS vs Relay may evolve in the future; see atproto specs for more details.", + "format": "handle" } }, - "required": ["count"] + "required": ["seq", "did", "time"] }, - "place.stream.live.getRecommendations_livestreamRecommendation": { + "com.atproto.sync.subscribeRepos_account": { "type": "object", + "description": "Represents a change to an account's status on a host (eg, PDS or Relay). The semantics of this event are that the status is at the host which emitted the event, not necessarily that at the currently active PDS. Eg, a Relay takedown would emit a takedown with active=false, even if the PDS is still active.", "properties": { "did": { "type": "string", - "description": "The DID of the recommended streamer", "format": "did" }, - "source": { + "seq": { + "type": "integer" + }, + "time": { "type": "string", - "description": "Source of the recommendation", - "enum": ["streamer", "follows", "host"] + "format": "date-time" + }, + "active": { + "type": "boolean", + "description": "Indicates that the account has a repository which can be fetched from the host that emitted this event." + }, + "status": { + "type": "string", + "description": "If active=false, this optional field indicates a reason for why the account is not active." } }, - "required": ["did", "source"] + "required": ["seq", "did", "time", "active"] }, - "place.stream.segment_segmentView": { + "com.atproto.sync.subscribeRepos_info": { "type": "object", "properties": { - "cid": { - "type": "string", - "format": "cid" + "name": { + "type": "string" }, - "record": {} + "message": { + "type": "string" + } }, - "required": ["cid", "record"] + "required": ["name"] }, - "place.stream.live.searchActorsTypeahead_actor": { + "com.atproto.repo.defs_commitMeta": { "type": "object", "properties": { - "did": { + "cid": { "type": "string", - "description": "The actor's DID", - "format": "did" + "format": "cid" }, - "handle": { + "rev": { "type": "string", - "description": "The actor's handle", - "format": "handle" + "format": "tid" } }, - "required": ["did", "handle"] - }, - "place.stream.livestream": { - "description": "Unknown type" - }, - "place.stream.live.subscribeSegments_segment": { - "type": "string", - "format": "byte", - "description": "MP4 file of a user's signed livestream segment" + "required": ["cid", "rev"] }, - "place.stream.ingest.defs_ingest": { + "com.atproto.repo.listRecords_record": { "type": "object", - "description": "An ingest URL for a Streamplace station.", "properties": { - "type": { + "cid": { "type": "string", - "description": "The type of ingest endpoint, currently 'rtmp' and 'whip' are supported." + "format": "cid" }, - "url": { + "uri": { "type": "string", - "description": "The URL of the ingest endpoint.", "format": "uri" - } + }, + "value": {} }, - "required": ["type", "url"] + "required": ["uri", "cid", "value"] }, - "com.atproto.repo.strongRef": { + "app.bsky.feed.defs_skeletonFeedPost": { "type": "object", "properties": { - "uri": { + "post": { "type": "string", "format": "uri" }, - "cid": { + "reason": { + "oneOf": [ + { + "$ref": "#/components/schemas/app.bsky.feed.defs_skeletonReasonRepost" + }, + { + "$ref": "#/components/schemas/app.bsky.feed.defs_skeletonReasonPin" + } + ] + }, + "feedContext": { "type": "string", - "format": "cid" + "description": "Context that will be passed through to client and may be passed to feed generator back alongside interactions.", + "maxLength": 2000 } }, - "required": ["uri", "cid"] + "required": ["post"] }, - "place.stream.branding.getBranding_brandingAsset": { + "app.bsky.feed.defs_skeletonReasonRepost": { "type": "object", "properties": { - "key": { + "repost": { "type": "string", - "description": "Asset key identifier" + "format": "uri" + } + }, + "required": ["repost"] + }, + "app.bsky.feed.defs_skeletonReasonPin": { + "type": "object", + "properties": {} + }, + "app.bsky.actor.defs_profileViewDetailed": { + "type": "object", + "properties": { + "did": { + "type": "string", + "format": "did" }, - "mimeType": { + "debug": { + "description": "Debug information for internal development" + }, + "avatar": { "type": "string", - "description": "MIME type of the asset" + "format": "uri" }, - "url": { + "banner": { "type": "string", - "description": "URL to fetch the asset blob (for images)" + "format": "uri" }, - "data": { + "handle": { "type": "string", - "description": "Inline data for text assets" + "format": "handle" }, - "width": { - "type": "integer", - "description": "Image width in pixels (optional, for images only)" + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.label.defs_label" + } }, - "height": { - "type": "integer", - "description": "Image height in pixels (optional, for images only)" - } - }, - "required": ["key", "mimeType"] - }, - "place.stream.badge.defs_badgeView": { - "type": "object", - "description": "View of a badge record, with fields resolved for display. If the DID in issuer is not the current streamplace node, the signature field shall be required.", - "properties": { - "badgeType": { - "type": "string" + "status": { + "$ref": "#/components/schemas/app.bsky.actor.defs_statusView" }, - "issuer": { + "viewer": { + "$ref": "#/components/schemas/app.bsky.actor.defs_viewerState" + }, + "website": { "type": "string", - "description": "DID of the badge issuer.", - "format": "did" + "format": "uri" }, - "recipient": { + "pronouns": { + "type": "string" + }, + "createdAt": { "type": "string", - "description": "DID of the badge recipient.", - "format": "did" + "format": "date-time" }, - "name": { + "indexedAt": { "type": "string", - "description": "Display name from the badge definition." + "format": "date-time" + }, + "associated": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileAssociated" + }, + "pinnedPost": { + "$ref": "#/components/schemas/com.atproto.repo.strongRef" + }, + "postsCount": { + "type": "integer" }, "description": { "type": "string", - "description": "Description from the badge definition." + "maxLength": 2560 }, - "imageUrl": { + "displayName": { "type": "string", - "description": "Resolved image URL for the badge icon.", - "format": "uri" + "maxLength": 640 }, - "signature": { - "type": "string", - "description": "TODO: Cryptographic signature of the badge (of a place.stream.key)." - } - }, - "required": ["badgeType", "issuer", "recipient"] - }, - "place.stream.badge.defs_badgeSlot": { - "type": "object", - "description": "A display slot containing available issuance-based badges and which one (if any) is currently selected.", - "properties": { - "selected": { - "$ref": "#/components/schemas/place.stream.badge.defs_badgeIssuanceView", - "description": "The currently selected badge in this slot, if any." + "followsCount": { + "type": "integer" }, - "available": { - "type": "array", - "description": "All badges available for this slot.", - "items": { - "$ref": "#/components/schemas/place.stream.badge.defs_badgeIssuanceView" - } + "verification": { + "$ref": "#/components/schemas/app.bsky.actor.defs_verificationState" + }, + "followersCount": { + "type": "integer" + }, + "joinedViaStarterPack": { + "$ref": "#/components/schemas/app.bsky.graph.defs_starterPackViewBasic" } }, - "required": ["available"] + "required": ["did", "handle"] }, - "place.stream.badge.defs_badgeIssuanceView": { + "app.bsky.graph.defs_starterPackViewBasic": { "type": "object", - "description": "A resolved view of a badge issuance, including def fields for display.", "properties": { - "issuanceUri": { + "cid": { "type": "string", - "description": "AT URI of the place.stream.badge.issuance record.", - "format": "uri" + "format": "cid" }, - "issuanceCid": { + "uri": { "type": "string", - "description": "CID of the place.stream.badge.issuance record." + "format": "uri" }, - "badgeType": { - "type": "string" + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.label.defs_label" + } }, - "name": { - "type": "string", - "description": "Display name from the badge definition." + "record": {}, + "creator": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" }, - "description": { + "indexedAt": { "type": "string", - "description": "Description from the badge definition." + "format": "date-time" }, - "imageUrl": { - "type": "string", - "description": "Resolved image URL for the badge icon.", - "format": "uri" + "listItemCount": { + "type": "integer", + "minimum": 0 }, - "issuer": { - "type": "string", - "description": "DID of the badge issuer.", - "format": "did" + "joinedWeekCount": { + "type": "integer", + "minimum": 0 }, - "selected": { - "type": "boolean", - "description": "Whether this badge is currently in the user's chat profile selection." + "joinedAllTimeCount": { + "type": "integer", + "minimum": 0 } }, - "required": ["issuanceUri", "badgeType", "issuer"] + "required": ["uri", "cid", "record", "creator", "indexedAt"] } } } diff --git a/pkg/spxrpc/com_atproto_identity.go b/pkg/spxrpc/com_atproto_identity.go index 0f3e9abe3..608baa0e7 100644 --- a/pkg/spxrpc/com_atproto_identity.go +++ b/pkg/spxrpc/com_atproto_identity.go @@ -4,8 +4,10 @@ import ( "context" indigoatproto "github.com/bluesky-social/indigo/api/atproto" + "github.com/labstack/echo/v4" "github.com/streamplace/oatproxy/pkg/oatproxy" "stream.place/streamplace/pkg/aqhttp" + "stream.place/streamplace/pkg/comatproto" ) func (s *Server) handleComAtprotoIdentityResolveHandle(ctx context.Context, handle string) (*indigoatproto.IdentityResolveHandle_Output, error) { @@ -27,3 +29,7 @@ func (s *Server) handleComAtprotoIdentityRefreshIdentity(ctx context.Context, bo DidDoc: ident.DIDDocument(), }, nil } + +func (s *Server) handleComAtprotoIdentityUpdateHandle(ctx context.Context, body *comatproto.IdentityUpdateHandle_Input) error { + return echo.NewHTTPError(501, "not implemented") +} diff --git a/pkg/spxrpc/com_atproto_repo.go b/pkg/spxrpc/com_atproto_repo.go index a2c77e1c3..04fcb5a5a 100644 --- a/pkg/spxrpc/com_atproto_repo.go +++ b/pkg/spxrpc/com_atproto_repo.go @@ -5,11 +5,12 @@ import ( "context" "errors" "fmt" - glex "github.com/streamplace/glex/runtime" "io" "net/http" "strings" + glex "github.com/streamplace/glex/runtime" + "stream.place/streamplace/pkg/comatproto" "github.com/bluesky-social/indigo/xrpc" @@ -124,7 +125,7 @@ func (s *Server) handleComAtprotoRepoDescribeRepo(ctx context.Context, repo stri }, nil } -func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context, collection string, cursor string, limit int, repo string, reverse *bool) (*comatproto.RepoListRecords_Output, error) { +func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context, collection string, cursor string, limit int, repo string, reverse bool) (*comatproto.RepoListRecords_Output, error) { isLocal, svc, err := s.isLocalPDS(ctx, repo) if err != nil { return nil, fmt.Errorf("error checking for local PDS: %w", err) @@ -139,9 +140,7 @@ func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context, collection if limit != 0 { params["limit"] = limit } - if reverse != nil { - params["reverse"] = *reverse - } + params["reverse"] = reverse params["repo"] = repo err = makeUnauthenticatedRequest(ctx, svc, "com.atproto.repo.listRecords", params, &out) @@ -153,9 +152,9 @@ func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context, collection } if s.isServerPDS(ctx) { - return atproto.ServerRepoListRecords(ctx, collection, cursor, limit, repo, reverse) + return atproto.ServerRepoListRecords(ctx, collection, cursor, limit, repo, &reverse) } - return atproto.LexiconRepoListRecords(ctx, collection, cursor, limit, repo, reverse) + return atproto.LexiconRepoListRecords(ctx, collection, cursor, limit, repo, &reverse) } func (s *Server) handleComAtprotoRepoGetRecord(ctx context.Context, c string, collection string, repo string, rkey string) (*comatproto.RepoGetRecord_Output, error) { @@ -186,3 +185,15 @@ func (s *Server) handleComAtprotoRepoGetRecord(ctx context.Context, c string, co } return atproto.LexiconRepoGetRecord(ctx, repo, collection, rkey) } + +func (s *Server) handleComAtprotoRepoCreateRecord(ctx context.Context, body *comatproto.RepoCreateRecord_Input) (*comatproto.RepoCreateRecord_Output, error) { + return nil, echo.NewHTTPError(501, "not implemented") +} + +func (s *Server) handleComAtprotoRepoDeleteRecord(ctx context.Context, body *comatproto.RepoDeleteRecord_Input) (*comatproto.RepoDeleteRecord_Output, error) { + return nil, echo.NewHTTPError(501, "not implemented") +} + +func (s *Server) handleComAtprotoRepoPutRecord(ctx context.Context, body *comatproto.RepoPutRecord_Input) (*comatproto.RepoPutRecord_Output, error) { + return nil, echo.NewHTTPError(501, "not implemented") +} diff --git a/pkg/spxrpc/com_atproto_server.go b/pkg/spxrpc/com_atproto_server.go index 865861884..873ac3a04 100644 --- a/pkg/spxrpc/com_atproto_server.go +++ b/pkg/spxrpc/com_atproto_server.go @@ -5,6 +5,8 @@ import ( "fmt" indigoatproto "github.com/bluesky-social/indigo/api/atproto" + "github.com/labstack/echo/v4" + "stream.place/streamplace/pkg/comatproto" ) func (s *Server) handleComAtprotoServerDescribeServer(ctx context.Context) (*indigoatproto.ServerDescribeServer_Output, error) { @@ -18,3 +20,7 @@ func (s *Server) handleComAtprotoServerDescribeServer(ctx context.Context) (*ind }, }, nil } + +func (s *Server) handleComAtprotoServerCreateSession(ctx context.Context, body *comatproto.ServerCreateSession_Input) (*comatproto.ServerCreateSession_Output, error) { + return nil, echo.NewHTTPError(501, "not implemented") +} diff --git a/pkg/spxrpc/stubs.go b/pkg/spxrpc/stubs.go index 193d5e6fb..92244e950 100644 --- a/pkg/spxrpc/stubs.go +++ b/pkg/spxrpc/stubs.go @@ -6,10 +6,246 @@ import ( "github.com/labstack/echo/v4" "go.opentelemetry.io/otel" + appbsky "stream.place/streamplace/pkg/appbsky" + comatproto "stream.place/streamplace/pkg/comatproto" gamesgamesgamesgamesgames "stream.place/streamplace/pkg/gamesgamesgamesgamesgames" placestream "stream.place/streamplace/pkg/placestream" ) +func (s *Server) RegisterHandlersAppbsky(e *echo.Echo) error { + e.GET("/xrpc/app.bsky.actor.getProfile", s.HandleAppBskyActorGetProfile) + e.GET("/xrpc/app.bsky.feed.getFeedSkeleton", s.HandleAppBskyFeedGetFeedSkeleton) + return nil +} + +func (s *Server) HandleAppBskyActorGetProfile(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleAppBskyActorGetProfile") + defer span.End() + actor := c.QueryParam("actor") + var out *appbsky.ActorDefs_ProfileViewDetailed + var handleErr error + // func (s *Server) handleAppBskyActorGetProfile(ctx context.Context,actor string) (*appbsky.ActorDefs_ProfileViewDetailed, error) + out, handleErr = s.handleAppBskyActorGetProfile(ctx, actor) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleAppBskyFeedGetFeedSkeleton(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleAppBskyFeedGetFeedSkeleton") + defer span.End() + cursor := c.QueryParam("cursor") + feed := c.QueryParam("feed") + limit := 0 + if p := c.QueryParam("limit"); p != "" { + var err error + limit, err = strconv.Atoi(p) + if err != nil { + return err + } + } + var out *appbsky.FeedGetFeedSkeleton_Output + var handleErr error + // func (s *Server) handleAppBskyFeedGetFeedSkeleton(ctx context.Context,cursor string,feed string,limit int) (*appbsky.FeedGetFeedSkeleton_Output, error) + out, handleErr = s.handleAppBskyFeedGetFeedSkeleton(ctx, cursor, feed, limit) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) RegisterHandlersComatproto(e *echo.Echo) error { + e.POST("/xrpc/com.atproto.identity.updateHandle", s.HandleComAtprotoIdentityUpdateHandle) + e.POST("/xrpc/com.atproto.repo.createRecord", s.HandleComAtprotoRepoCreateRecord) + e.POST("/xrpc/com.atproto.repo.deleteRecord", s.HandleComAtprotoRepoDeleteRecord) + e.GET("/xrpc/com.atproto.repo.describeRepo", s.HandleComAtprotoRepoDescribeRepo) + e.GET("/xrpc/com.atproto.repo.getRecord", s.HandleComAtprotoRepoGetRecord) + e.GET("/xrpc/com.atproto.repo.listRecords", s.HandleComAtprotoRepoListRecords) + e.POST("/xrpc/com.atproto.repo.putRecord", s.HandleComAtprotoRepoPutRecord) + e.POST("/xrpc/com.atproto.repo.uploadBlob", s.HandleComAtprotoRepoUploadBlob) + e.POST("/xrpc/com.atproto.server.createSession", s.HandleComAtprotoServerCreateSession) + e.GET("/xrpc/com.atproto.sync.getRepo", s.HandleComAtprotoSyncGetRepo) + return nil +} + +func (s *Server) HandleComAtprotoIdentityUpdateHandle(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoIdentityUpdateHandle") + defer span.End() + var body comatproto.IdentityUpdateHandle_Input + if err := c.Bind(&body); err != nil { + return err + } + var handleErr error + // func (s *Server) handleComAtprotoIdentityUpdateHandle(ctx context.Context,body *comatproto.IdentityUpdateHandle_Input) error + handleErr = s.handleComAtprotoIdentityUpdateHandle(ctx, &body) + if handleErr != nil { + return handleErr + } + return nil +} + +func (s *Server) HandleComAtprotoRepoCreateRecord(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoCreateRecord") + defer span.End() + var body comatproto.RepoCreateRecord_Input + if err := c.Bind(&body); err != nil { + return err + } + var out *comatproto.RepoCreateRecord_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoCreateRecord(ctx context.Context,body *comatproto.RepoCreateRecord_Input) (*comatproto.RepoCreateRecord_Output, error) + out, handleErr = s.handleComAtprotoRepoCreateRecord(ctx, &body) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoDeleteRecord(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoDeleteRecord") + defer span.End() + var body comatproto.RepoDeleteRecord_Input + if err := c.Bind(&body); err != nil { + return err + } + var out *comatproto.RepoDeleteRecord_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoDeleteRecord(ctx context.Context,body *comatproto.RepoDeleteRecord_Input) (*comatproto.RepoDeleteRecord_Output, error) + out, handleErr = s.handleComAtprotoRepoDeleteRecord(ctx, &body) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoDescribeRepo(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoDescribeRepo") + defer span.End() + repo := c.QueryParam("repo") + var out *comatproto.RepoDescribeRepo_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoDescribeRepo(ctx context.Context,repo string) (*comatproto.RepoDescribeRepo_Output, error) + out, handleErr = s.handleComAtprotoRepoDescribeRepo(ctx, repo) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoGetRecord(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoGetRecord") + defer span.End() + cid := c.QueryParam("cid") + collection := c.QueryParam("collection") + repo := c.QueryParam("repo") + rkey := c.QueryParam("rkey") + var out *comatproto.RepoGetRecord_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoGetRecord(ctx context.Context,cid string,collection string,repo string,rkey string) (*comatproto.RepoGetRecord_Output, error) + out, handleErr = s.handleComAtprotoRepoGetRecord(ctx, cid, collection, repo, rkey) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoListRecords(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoListRecords") + defer span.End() + collection := c.QueryParam("collection") + cursor := c.QueryParam("cursor") + limit := 0 + if p := c.QueryParam("limit"); p != "" { + var err error + limit, err = strconv.Atoi(p) + if err != nil { + return err + } + } + repo := c.QueryParam("repo") + reverse := false + if p := c.QueryParam("reverse"); p != "" { + var err error + reverse, err = strconv.ParseBool(p) + if err != nil { + return err + } + } + var out *comatproto.RepoListRecords_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context,collection string,cursor string,limit int,repo string,reverse bool) (*comatproto.RepoListRecords_Output, error) + out, handleErr = s.handleComAtprotoRepoListRecords(ctx, collection, cursor, limit, repo, reverse) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoPutRecord(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoPutRecord") + defer span.End() + var body comatproto.RepoPutRecord_Input + if err := c.Bind(&body); err != nil { + return err + } + var out *comatproto.RepoPutRecord_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoPutRecord(ctx context.Context,body *comatproto.RepoPutRecord_Input) (*comatproto.RepoPutRecord_Output, error) + out, handleErr = s.handleComAtprotoRepoPutRecord(ctx, &body) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoUploadBlob(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoUploadBlob") + defer span.End() + body := c.Request().Body + contentType := c.Request().Header.Get("Content-Type") + var out *comatproto.RepoUploadBlob_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoUploadBlob(ctx context.Context,r io.Reader,contentType string) (*comatproto.RepoUploadBlob_Output, error) + out, handleErr = s.handleComAtprotoRepoUploadBlob(ctx, body, contentType) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoServerCreateSession(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoServerCreateSession") + defer span.End() + var body comatproto.ServerCreateSession_Input + if err := c.Bind(&body); err != nil { + return err + } + var out *comatproto.ServerCreateSession_Output + var handleErr error + // func (s *Server) handleComAtprotoServerCreateSession(ctx context.Context,body *comatproto.ServerCreateSession_Input) (*comatproto.ServerCreateSession_Output, error) + out, handleErr = s.handleComAtprotoServerCreateSession(ctx, &body) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoSyncGetRepo(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoSyncGetRepo") + defer span.End() + did := c.QueryParam("did") + since := c.QueryParam("since") + var out io.Reader + var handleErr error + // func (s *Server) handleComAtprotoSyncGetRepo(ctx context.Context,did string,since string) (io.Reader, error) + out, handleErr = s.handleComAtprotoSyncGetRepo(ctx, did, since) + if handleErr != nil { + return handleErr + } + return c.Stream(200, "application/octet-stream", out) +} + func (s *Server) RegisterHandlersGamesgamesgamesgamesgames(e *echo.Echo) error { e.GET("/xrpc/games.gamesgamesgamesgames.search", s.HandleGamesGamesgamesgamesgamesSearch) return nil @@ -1213,3 +1449,7 @@ func (s *Server) HandlePlaceStreamVodUpdateDraft(c echo.Context) error { } return c.JSON(200, out) } + +func (s *Server) RegisterHandlersToolsozone(e *echo.Echo) error { + return nil +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8a65e6ff4..c41d91200 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,7 @@ packages: - js/* onlyBuiltDependencies: - - '@swc/core' + - "@swc/core" - better-sqlite3 - bufferutil - cbor-extract diff --git a/subprojects/atproto.wrap b/subprojects/atproto.wrap deleted file mode 100644 index f74e505f0..000000000 --- a/subprojects/atproto.wrap +++ /dev/null @@ -1,5 +0,0 @@ -[wrap-git] -url = https://github.com/bluesky-social/atproto.git -revision = fb283edbaf8aa3ecc7db014a40a28173ce81bc4c -depth = 1 -patch_directory = atproto diff --git a/subprojects/packagefiles/atproto/meson.build b/subprojects/packagefiles/atproto/meson.build deleted file mode 100644 index 3ed89a5ec..000000000 --- a/subprojects/packagefiles/atproto/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -project('atproto') - -