From 55aa5587610f4fc3d01d058e593830cea52a32c5 Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Tue, 14 Jul 2026 13:29:46 -0700 Subject: [PATCH] implement com.atproto.identity.refreshIdentity; add glex.Unknown for DID docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The refreshIdentity output's didDocument field is lexicon type unknown — a W3C DID document, not a lexicon record, so it can't satisfy the sealed glex.Record interface. glex now provides Unknown(v) as the one-call way to put a non-lexicon payload into an unknown field (sugar over RawJSON + LexiconTypeDecoder, round-trips the value verbatim): didDoc, err := glex.Unknown(ident.DIDDocument()) - handleComAtprotoIdentityRefreshIdentity: wrap the DID document via glex.Unknown and fill in the required handle field. - handleComAtprotoIdentityResolveHandle: return the endpoint's own IdentityResolveHandle_Output type per the regenerated stubs. - describeRepo: migrate both DidDoc sites to glex.Unknown (same wire bytes). - Includes the vendored com.atproto.identity.* lexicons + regenerated types/stubs and the app.bsky re-resolution that came with the install. Co-Authored-By: Claude Fable 5 --- go.mod | 2 +- go.sum | 2 + .../content/docs/lex-reference/openapi.json | 290 +++++++++++++++++- lexicons.json | 32 +- pkg/appbsky/actordefs.go | 11 +- pkg/appbsky/embedexternal.go | 122 +++++++- pkg/appbsky/embedgallery.go | 232 ++++++++++++++ pkg/appbsky/embedrecord.go | 14 + pkg/appbsky/embedrecordwithmedia.go | 28 ++ pkg/appbsky/feeddefs.go | 14 + pkg/appbsky/feedpost.go | 14 + pkg/appbsky/notificationdefs.go | 5 +- pkg/comatproto/identitydefs.go | 40 +++ pkg/comatproto/identityrefreshidentity.go | 48 +++ pkg/comatproto/identityresolvehandle.go | 53 ++++ pkg/spxrpc/com_atproto_identity.go | 17 +- pkg/spxrpc/com_atproto_repo.go | 8 +- pkg/spxrpc/stubs.go | 33 ++ 18 files changed, 920 insertions(+), 45 deletions(-) create mode 100644 pkg/appbsky/embedgallery.go create mode 100644 pkg/comatproto/identitydefs.go create mode 100644 pkg/comatproto/identityrefreshidentity.go create mode 100644 pkg/comatproto/identityresolvehandle.go diff --git a/go.mod b/go.mod index 32f41cceb..92a6a48fe 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( github.com/starttoaster/prometheus-exporter-scraper v0.0.1 github.com/streamplace/atmoq-go v0.0.2 github.com/streamplace/atproto-oauth-golang v0.0.0-20260413212710-98956064d06c - github.com/streamplace/glex v0.0.0-20260713025044-48835ef7879b + github.com/streamplace/glex v0.0.0-20260714202640-f3b7557a2bdf github.com/streamplace/muxl/go v0.3.4 github.com/streamplace/oatproxy v0.0.0-20260710202406-60d97b9d780b github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index a566eb736..02386d8a1 100644 --- a/go.sum +++ b/go.sum @@ -1382,6 +1382,8 @@ github.com/streamplace/glex v0.0.0-20260712210145-b0354b3b167c h1:OBII3YaKbiCN42 github.com/streamplace/glex v0.0.0-20260712210145-b0354b3b167c/go.mod h1:LRaoeSMvSgOrhFX8s7ygjRlyka7wXdDa1s7JJ9o1IzY= github.com/streamplace/glex v0.0.0-20260713025044-48835ef7879b h1:cp+BGMUJEHK9srFoEaqXCv2Q030bnIjxDQUt9Mhb9SA= github.com/streamplace/glex v0.0.0-20260713025044-48835ef7879b/go.mod h1:LRaoeSMvSgOrhFX8s7ygjRlyka7wXdDa1s7JJ9o1IzY= +github.com/streamplace/glex v0.0.0-20260714202640-f3b7557a2bdf h1:KQLi0Ht1trBdr1lo+4VD4bsk7NbTGtjwZr7k9gME3zE= +github.com/streamplace/glex v0.0.0-20260714202640-f3b7557a2bdf/go.mod h1:LRaoeSMvSgOrhFX8s7ygjRlyka7wXdDa1s7JJ9o1IzY= github.com/streamplace/go-dpop v0.0.0-20250510031900-c897158a8ad4 h1:L1fS4HJSaAyNnkwfuZubgfeZy8rkWmA0cMtH5Z0HqNc= github.com/streamplace/go-dpop v0.0.0-20250510031900-c897158a8ad4/go.mod h1:bGUXY9Wd4mnd+XUrOYZr358J2f6z9QO/dLhL1SsiD+0= github.com/streamplace/indigo v0.0.0-20260218231908-939cdaf0c507 h1:e8M3qPLr37NxEjlr18TaAwGP+OVyherVjgUG5VVmgWI= diff --git a/js/docs/src/content/docs/lex-reference/openapi.json b/js/docs/src/content/docs/lex-reference/openapi.json index f6d6707e8..18816e6c6 100644 --- a/js/docs/src/content/docs/lex-reference/openapi.json +++ b/js/docs/src/content/docs/lex-reference/openapi.json @@ -5303,6 +5303,135 @@ } } }, + "/xrpc/com.atproto.identity.refreshIdentity": { + "post": { + "summary": "Request that the server re-resolve an identity (DID and handle). The server may ignore this request, or require authentication, depending on the role, implementation, and policy of the server.", + "operationId": "com.atproto.identity.refreshIdentity", + "tags": ["com.atproto.identity"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/com.atproto.identity.defs_identityInfo" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "HandleNotFound" + }, + { + "const": "DidNotFound" + }, + { + "const": "DidDeactivated" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "identifier": { + "type": "string", + "format": "at-identifier" + } + }, + "required": ["identifier"] + } + } + } + } + } + }, + "/xrpc/com.atproto.identity.resolveHandle": { + "get": { + "summary": "Resolves an atproto handle (hostname) to a DID. Does not necessarily bi-directionally verify against the the DID document.", + "operationId": "com.atproto.identity.resolveHandle", + "tags": ["com.atproto.identity"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "did": { + "type": "string", + "format": "did" + } + }, + "required": ["did"] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "HandleNotFound" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "handle", + "in": "query", + "required": true, + "description": "The handle to resolve.", + "schema": { + "type": "string", + "description": "The handle to resolve.", + "format": "handle" + } + } + ] + } + }, "/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.", @@ -5651,12 +5780,129 @@ "title": { "type": "string" }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.label.defs_label" + } + }, + "source": { + "$ref": "#/components/schemas/app.bsky.embed.external_viewExternalSource" + }, + "createdAt": { + "type": "string", + "description": "When the external content was created, if available. Example: a publication date, for an article.", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "description": "When the external content was updated, if available.", + "format": "date-time" + }, "description": { "type": "string" + }, + "readingTime": { + "type": "integer", + "description": "Estimated reading time in minutes, if applicable and available." + }, + "associatedRefs": { + "type": "array", + "description": "StrongRefs (uri+cid) of the Atmosphere records that backed this view.", + "items": { + "$ref": "#/components/schemas/com.atproto.repo.strongRef" + } + }, + "associatedProfiles": { + "type": "array", + "description": "Profiles of the owners of the Atmosphere records that backed this view.", + "items": { + "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" + } } }, "required": ["uri", "title", "description"] }, + "app.bsky.embed.external_viewExternalSource": { + "type": "object", + "description": "The source of an external embed, such as a standard.site publication.", + "properties": { + "uri": { + "type": "string", + "description": "URI of the source, if available. Example: the https:// URL of a site.standard.publication record.", + "format": "uri" + }, + "icon": { + "type": "string", + "description": "Fully-qualified URL where an icon representing the source can be fetched. For example, CDN location provided by the App View.", + "format": "uri" + }, + "theme": { + "$ref": "#/components/schemas/app.bsky.embed.external_viewExternalSourceTheme" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": ["uri", "title"] + }, + "app.bsky.embed.external_viewExternalSourceTheme": { + "type": "object", + "description": "The theme colors of an external source, such as a site.standard.publication. These colors may be used when rendering an embed from that source.", + "properties": { + "accentRGB": { + "$ref": "#/components/schemas/app.bsky.embed.external_colorRGB" + }, + "backgroundRGB": { + "$ref": "#/components/schemas/app.bsky.embed.external_colorRGB" + }, + "foregroundRGB": { + "$ref": "#/components/schemas/app.bsky.embed.external_colorRGB" + }, + "accentForegroundRGB": { + "$ref": "#/components/schemas/app.bsky.embed.external_colorRGB" + } + } + }, + "app.bsky.embed.external_colorRGB": { + "type": "object", + "description": "RGB color definition, inspired by site.standard.theme.color#rgb", + "properties": { + "b": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "g": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "r": { + "type": "integer", + "minimum": 0, + "maximum": 255 + } + }, + "required": ["r", "g", "b"] + }, + "com.atproto.repo.strongRef": { + "type": "object", + "properties": { + "cid": { + "type": "string", + "format": "cid" + }, + "uri": { + "type": "string", + "format": "uri" + } + }, + "required": ["uri", "cid"] + }, "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.", @@ -5814,6 +6060,9 @@ "properties": { "allowIncoming": { "type": "string" + }, + "allowGroupInvites": { + "type": "string" } }, "required": ["allowIncoming"] @@ -5884,6 +6133,15 @@ "type": "string", "description": "Timestamp when the verification was created.", "format": "date-time" + }, + "issuerHandle": { + "type": "string", + "description": "The handle of the issuer.", + "format": "handle" + }, + "issuerDisplayName": { + "type": "string", + "description": "The display name of the issuer." } }, "required": ["issuer", "uri", "isValid", "createdAt"] @@ -6453,20 +6711,6 @@ }, "required": ["type", "url"] }, - "com.atproto.repo.strongRef": { - "type": "object", - "properties": { - "cid": { - "type": "string", - "format": "cid" - }, - "uri": { - "type": "string", - "format": "uri" - } - }, - "required": ["uri", "cid"] - }, "games.gamesgamesgamesgames.defs_gameSummaryView": { "type": "object", "properties": { @@ -7015,6 +7259,24 @@ }, "required": ["uri", "cid", "value"] }, + "com.atproto.identity.defs_identityInfo": { + "type": "object", + "properties": { + "did": { + "type": "string", + "format": "did" + }, + "didDoc": { + "description": "The complete DID document for the identity." + }, + "handle": { + "type": "string", + "description": "The validated handle of the account; or 'handle.invalid' if the handle did not bi-directionally match the DID document.", + "format": "handle" + } + }, + "required": ["did", "handle", "didDoc"] + }, "app.bsky.feed.defs_skeletonFeedPost": { "type": "object", "properties": { diff --git a/lexicons.json b/lexicons.json index b69112072..fd025b1c1 100644 --- a/lexicons.json +++ b/lexicons.json @@ -9,6 +9,8 @@ "app.bsky.graph.block", "app.bsky.graph.follow", "app.bsky.richtext.facet", + "com.atproto.identity.refreshIdentity", + "com.atproto.identity.resolveHandle", "com.atproto.identity.updateHandle", "com.atproto.label.defs", "com.atproto.moderation.defs", @@ -29,7 +31,7 @@ "resolutions": { "app.bsky.actor.defs": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.actor.defs", - "cid": "bafyreiel3mr6hz7g4wy5l6pkrwqh7affgluhfszvrrduc7p66os5cfkqdq" + "cid": "bafyreielcp7ccfxuvtdthry5qqdqmvcqo5wx3shkuz32xd5rlypmhw6ufa" }, "app.bsky.actor.getProfile": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.actor.getProfile", @@ -49,7 +51,11 @@ }, "app.bsky.embed.external": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.embed.external", - "cid": "bafyreiblxmpzgwg4fbr45b4xzts3h4k72k7cdnrxy2ub2w5d7mnwzznkwi" + "cid": "bafyreigwach36azu4xg3jvcmb6fe53umfln3wkuj5srqsvcjaypa6rw534" + }, + "app.bsky.embed.gallery": { + "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.embed.gallery", + "cid": "bafyreia4tixag4sadkirfo63qfma6fz3ifbqanify4e6ce6swkl5lwjnfq" }, "app.bsky.embed.images": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.embed.images", @@ -57,11 +63,11 @@ }, "app.bsky.embed.record": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.embed.record", - "cid": "bafyreigdtmu53blwxoygphg5zh5zpmlftz64c3jyqpv2yqpx3nrichkyla" + "cid": "bafyreia7yq4c6rqkz32fjf6gj5rcvxsirguducn545s3dvls7qutnn2ali" }, "app.bsky.embed.recordWithMedia": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.embed.recordWithMedia", - "cid": "bafyreia7jrw2p73egm7vrunssgzeyj2rwmk3s4dymfhgzcavxjfaje3qfi" + "cid": "bafyreidszvpeqf7copdmowm4ln4eyhahlqxktlvootjjjdmtkwy6s62jya" }, "app.bsky.embed.video": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.embed.video", @@ -69,7 +75,7 @@ }, "app.bsky.feed.defs": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.feed.defs", - "cid": "bafyreiadwvxawxifsnm7ae6l56aq23qs7ndih7npgs6pxmkoin7gi3k6pu" + "cid": "bafyreibg2zvz4n25vtd5yfqlodqra72s4h4lz7vwdexoutv3523wbw6jca" }, "app.bsky.feed.getFeedSkeleton": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.feed.getFeedSkeleton", @@ -77,7 +83,7 @@ }, "app.bsky.feed.post": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.feed.post", - "cid": "bafyreidgbehqwweghrrddfu6jgj7lyr6fwhzgazhirnszdb5lvr7iynkiy" + "cid": "bafyreia7rgxu7467phwpcgzaw62l5bzmxufkpikrc5zm4q3xhjmuhq4pti" }, "app.bsky.feed.postgate": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.feed.postgate", @@ -105,12 +111,24 @@ }, "app.bsky.notification.defs": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.notification.defs", - "cid": "bafyreickbpnayydlyfakliahgf23jjuesllh6qrslyofk5yz5xizjavhui" + "cid": "bafyreifzktxnol5rafjoznauk5j7ub2gsxxm7qjskg3vqmcgn6krrsz55u" }, "app.bsky.richtext.facet": { "uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.richtext.facet", "cid": "bafyreidg56eo7zynf6ihz4xb627vwoqf5idnevkmwp7sxc4tijg6xngbu4" }, + "com.atproto.identity.defs": { + "uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.identity.defs", + "cid": "bafyreiftikhen7lwpyay4e4sycmmflexkroqjwwpfuqtmog3vjhs2qnz3m" + }, + "com.atproto.identity.refreshIdentity": { + "uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.identity.refreshIdentity", + "cid": "bafyreiabglay3heljv6azsioza4lbbq7ocfnllbugb4ep4cmoofvhbz74q" + }, + "com.atproto.identity.resolveHandle": { + "uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.identity.resolveHandle", + "cid": "bafyreigckmqtt3jrtzd7tvigjatnz6ajqyafs26h5pwcudwag2anedxnmu" + }, "com.atproto.identity.updateHandle": { "uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.identity.updateHandle", "cid": "bafyreibzqwkofzc7g5j7vatyyzolgnarm3zd2g6swegkc3ivz4xivm2buu" diff --git a/pkg/appbsky/actordefs.go b/pkg/appbsky/actordefs.go index 8e2655323..7c7ae9394 100644 --- a/pkg/appbsky/actordefs.go +++ b/pkg/appbsky/actordefs.go @@ -71,6 +71,8 @@ func (t *ActorDefs_BskyAppProgressGuide) UnmarshalCBOR(r io.Reader) error { type ActorDefs_BskyAppStatePref struct { LexiconTypeID string `json:"$type,omitempty"` ActiveProgressGuide *ActorDefs_BskyAppProgressGuide `json:"activeProgressGuide,omitempty"` + // isBetaUser: Indicates if the user is participating in the beta features program. + IsBetaUser *bool `json:"isBetaUser,omitempty"` // nuxs: Storage for NUXs the user has encountered. Nuxs []ActorDefs_Nux `json:"nuxs,omitempty"` // queuedNudges: An array of tokens which identify nudges (modals, popups, tours, highlight dots) that should be shown to the user. @@ -942,8 +944,9 @@ func (t *ActorDefs_ProfileAssociatedActivitySubscription) UnmarshalCBOR(r io.Rea // ActorDefs_ProfileAssociatedChat is a "profileAssociatedChat" in the app.bsky.actor.defs schema. type ActorDefs_ProfileAssociatedChat struct { - LexiconTypeID string `json:"$type,omitempty"` - AllowIncoming string `json:"allowIncoming"` + LexiconTypeID string `json:"$type,omitempty"` + AllowGroupInvites *string `json:"allowGroupInvites,omitempty"` + AllowIncoming string `json:"allowIncoming"` } // RecordTypeID implements glex.Record. @@ -1361,6 +1364,10 @@ type ActorDefs_VerificationView struct { IsValid bool `json:"isValid"` // issuer: The user who issued this verification. Issuer string `json:"issuer"` + // issuerDisplayName: The display name of the issuer. + IssuerDisplayName *string `json:"issuerDisplayName,omitempty"` + // issuerHandle: The handle of the issuer. + IssuerHandle *string `json:"issuerHandle,omitempty"` // uri: The AT-URI of the verification record. Uri string `json:"uri"` } diff --git a/pkg/appbsky/embedexternal.go b/pkg/appbsky/embedexternal.go index 777e0a6c5..42057cc2b 100644 --- a/pkg/appbsky/embedexternal.go +++ b/pkg/appbsky/embedexternal.go @@ -10,6 +10,7 @@ import ( glex "github.com/streamplace/glex/runtime" cbg "github.com/whyrusleeping/cbor-gen" + comatproto "stream.place/streamplace/pkg/comatproto" ) func init() { @@ -45,13 +46,41 @@ func (t *EmbedExternal) UnmarshalCBOR(r io.Reader) error { return glex.UnmarshalCBOR(r, t) } +// EmbedExternal_ColorRGB is a "colorRGB" in the app.bsky.embed.external schema. +// +// RGB color definition, inspired by site.standard.theme.color#rgb +type EmbedExternal_ColorRGB struct { + LexiconTypeID string `json:"$type,omitempty"` + B int64 `json:"b"` + G int64 `json:"g"` + R int64 `json:"r"` +} + +// RecordTypeID implements glex.Record. +func (t *EmbedExternal_ColorRGB) RecordTypeID() string { return "app.bsky.embed.external#colorRGB" } + +func (t *EmbedExternal_ColorRGB) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "app.bsky.embed.external#colorRGB" + return glex.MarshalCBOR(w, t) +} + +func (t *EmbedExternal_ColorRGB) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} + // EmbedExternal_External is a "external" in the app.bsky.embed.external schema. type EmbedExternal_External struct { - LexiconTypeID string `json:"$type,omitempty"` - Description string `json:"description"` - Thumb *glex.Blob `json:"thumb,omitempty"` - Title string `json:"title"` - Uri string `json:"uri"` + LexiconTypeID string `json:"$type,omitempty"` + // associatedRefs: StrongRefs (uri+cid) of the Atmosphere records that backed this view. + AssociatedRefs []comatproto.RepoStrongRef `json:"associatedRefs,omitempty"` + Description string `json:"description"` + Thumb *glex.Blob `json:"thumb,omitempty"` + Title string `json:"title"` + Uri string `json:"uri"` } // RecordTypeID implements glex.Record. @@ -94,11 +123,23 @@ func (t *EmbedExternal_View) UnmarshalCBOR(r io.Reader) error { // EmbedExternal_ViewExternal is a "viewExternal" in the app.bsky.embed.external schema. type EmbedExternal_ViewExternal struct { - LexiconTypeID string `json:"$type,omitempty"` - Description string `json:"description"` - Thumb *string `json:"thumb,omitempty"` - Title string `json:"title"` - Uri string `json:"uri"` + LexiconTypeID string `json:"$type,omitempty"` + // associatedProfiles: Profiles of the owners of the Atmosphere records that backed this view. + AssociatedProfiles []ActorDefs_ProfileViewBasic `json:"associatedProfiles,omitempty"` + // associatedRefs: StrongRefs (uri+cid) of the Atmosphere records that backed this view. + AssociatedRefs []comatproto.RepoStrongRef `json:"associatedRefs,omitempty"` + // createdAt: When the external content was created, if available. Example: a publication date, for an article. + CreatedAt *string `json:"createdAt,omitempty"` + Description string `json:"description"` + Labels []comatproto.LabelDefs_Label `json:"labels,omitempty"` + // readingTime: Estimated reading time in minutes, if applicable and available. + ReadingTime *int64 `json:"readingTime,omitempty"` + Source *EmbedExternal_ViewExternalSource `json:"source,omitempty"` + Thumb *string `json:"thumb,omitempty"` + Title string `json:"title"` + // updatedAt: When the external content was updated, if available. + UpdatedAt *string `json:"updatedAt,omitempty"` + Uri string `json:"uri"` } // RecordTypeID implements glex.Record. @@ -118,3 +159,64 @@ func (t *EmbedExternal_ViewExternal) MarshalCBOR(w io.Writer) error { func (t *EmbedExternal_ViewExternal) UnmarshalCBOR(r io.Reader) error { return glex.UnmarshalCBOR(r, t) } + +// EmbedExternal_ViewExternalSource is a "viewExternalSource" in the app.bsky.embed.external schema. +// +// The source of an external embed, such as a standard.site publication. +type EmbedExternal_ViewExternalSource struct { + LexiconTypeID string `json:"$type,omitempty"` + Description *string `json:"description,omitempty"` + // icon: Fully-qualified URL where an icon representing the source can be fetched. For example, CDN location provided by the App View. + Icon *string `json:"icon,omitempty"` + Theme *EmbedExternal_ViewExternalSourceTheme `json:"theme,omitempty"` + Title string `json:"title"` + // uri: URI of the source, if available. Example: the https:// URL of a site.standard.publication record. + Uri string `json:"uri"` +} + +// RecordTypeID implements glex.Record. +func (t *EmbedExternal_ViewExternalSource) RecordTypeID() string { + return "app.bsky.embed.external#viewExternalSource" +} + +func (t *EmbedExternal_ViewExternalSource) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "app.bsky.embed.external#viewExternalSource" + return glex.MarshalCBOR(w, t) +} + +func (t *EmbedExternal_ViewExternalSource) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} + +// EmbedExternal_ViewExternalSourceTheme is a "viewExternalSourceTheme" in the app.bsky.embed.external schema. +// +// The theme colors of an external source, such as a site.standard.publication. These colors may be used when rendering an embed from that source. +type EmbedExternal_ViewExternalSourceTheme struct { + LexiconTypeID string `json:"$type,omitempty"` + AccentForegroundRGB *EmbedExternal_ColorRGB `json:"accentForegroundRGB,omitempty"` + AccentRGB *EmbedExternal_ColorRGB `json:"accentRGB,omitempty"` + BackgroundRGB *EmbedExternal_ColorRGB `json:"backgroundRGB,omitempty"` + ForegroundRGB *EmbedExternal_ColorRGB `json:"foregroundRGB,omitempty"` +} + +// RecordTypeID implements glex.Record. +func (t *EmbedExternal_ViewExternalSourceTheme) RecordTypeID() string { + return "app.bsky.embed.external#viewExternalSourceTheme" +} + +func (t *EmbedExternal_ViewExternalSourceTheme) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "app.bsky.embed.external#viewExternalSourceTheme" + return glex.MarshalCBOR(w, t) +} + +func (t *EmbedExternal_ViewExternalSourceTheme) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} diff --git a/pkg/appbsky/embedgallery.go b/pkg/appbsky/embedgallery.go new file mode 100644 index 000000000..f92f69267 --- /dev/null +++ b/pkg/appbsky/embedgallery.go @@ -0,0 +1,232 @@ +// Code generated by glex; DO NOT EDIT. + +// Lexicon schema: app.bsky.embed.gallery + +package appbsky + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + + glex "github.com/streamplace/glex/runtime" + cbg "github.com/whyrusleeping/cbor-gen" +) + +func init() { + glex.RegisterType("app.bsky.embed.gallery#main", &EmbedGallery{}) +} + +type EmbedGallery struct { + LexiconTypeID string `json:"$type,omitempty"` + // items: The schema-level maxLength of 20 is a future-proof ceiling. Clients should currently enforce a soft limit of 10 items in authoring UIs. + Items []EmbedGallery_Items_Elem `json:"items"` +} + +// RecordTypeID implements glex.Record. +func (t *EmbedGallery) RecordTypeID() string { return "app.bsky.embed.gallery" } + +// MarshalJSON stamps the $type field, like MarshalCBOR does. +func (t *EmbedGallery) MarshalJSON() ([]byte, error) { + t.LexiconTypeID = "app.bsky.embed.gallery" + type alias EmbedGallery + return json.Marshal((*alias)(t)) +} + +func (t *EmbedGallery) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "app.bsky.embed.gallery" + return glex.MarshalCBOR(w, t) +} + +func (t *EmbedGallery) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} + +// The media items in the gallery. Each item may be of a different type, but all types must be supported by the client. +type EmbedGallery_Items_Elem struct { + EmbedGallery_Image *EmbedGallery_Image +} + +func (t *EmbedGallery_Items_Elem) MarshalJSON() ([]byte, error) { + if t.EmbedGallery_Image != nil { + t.EmbedGallery_Image.LexiconTypeID = "app.bsky.embed.gallery#image" + return json.Marshal(t.EmbedGallery_Image) + } + return nil, fmt.Errorf("can not marshal empty union as JSON") +} + +func (t *EmbedGallery_Items_Elem) UnmarshalJSON(b []byte) error { + typ, err := glex.TypeExtract(b) + if err != nil { + return err + } + + switch typ { + case "app.bsky.embed.gallery#image": + t.EmbedGallery_Image = new(EmbedGallery_Image) + return json.Unmarshal(b, t.EmbedGallery_Image) + default: + return nil + } +} + +func (t *EmbedGallery_Items_Elem) MarshalCBOR(w io.Writer) error { + + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if t.EmbedGallery_Image != nil { + return t.EmbedGallery_Image.MarshalCBOR(w) + } + return fmt.Errorf("can not marshal empty union as CBOR") +} + +func (t *EmbedGallery_Items_Elem) UnmarshalCBOR(r io.Reader) error { + typ, b, err := glex.CborTypeExtractReader(r) + if err != nil { + return err + } + + switch typ { + case "app.bsky.embed.gallery#image": + t.EmbedGallery_Image = new(EmbedGallery_Image) + return t.EmbedGallery_Image.UnmarshalCBOR(bytes.NewReader(b)) + default: + return nil + } +} + +// EmbedGallery_Image is a "image" in the app.bsky.embed.gallery schema. +type EmbedGallery_Image struct { + LexiconTypeID string `json:"$type,omitempty"` + // alt: Alt text description of the image, for accessibility. + Alt string `json:"alt"` + AspectRatio EmbedDefs_AspectRatio `json:"aspectRatio"` + Image glex.Blob `json:"image"` +} + +// RecordTypeID implements glex.Record. +func (t *EmbedGallery_Image) RecordTypeID() string { return "app.bsky.embed.gallery#image" } + +func (t *EmbedGallery_Image) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "app.bsky.embed.gallery#image" + return glex.MarshalCBOR(w, t) +} + +func (t *EmbedGallery_Image) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} + +// EmbedGallery_View is a "view" in the app.bsky.embed.gallery schema. +type EmbedGallery_View struct { + LexiconTypeID string `json:"$type,omitempty"` + Items []EmbedGallery_View_Items_Elem `json:"items"` +} + +// RecordTypeID implements glex.Record. +func (t *EmbedGallery_View) RecordTypeID() string { return "app.bsky.embed.gallery#view" } + +func (t *EmbedGallery_View) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "app.bsky.embed.gallery#view" + return glex.MarshalCBOR(w, t) +} + +func (t *EmbedGallery_View) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} + +type EmbedGallery_View_Items_Elem struct { + EmbedGallery_ViewImage *EmbedGallery_ViewImage +} + +func (t *EmbedGallery_View_Items_Elem) MarshalJSON() ([]byte, error) { + if t.EmbedGallery_ViewImage != nil { + t.EmbedGallery_ViewImage.LexiconTypeID = "app.bsky.embed.gallery#viewImage" + return json.Marshal(t.EmbedGallery_ViewImage) + } + return nil, fmt.Errorf("can not marshal empty union as JSON") +} + +func (t *EmbedGallery_View_Items_Elem) UnmarshalJSON(b []byte) error { + typ, err := glex.TypeExtract(b) + if err != nil { + return err + } + + switch typ { + case "app.bsky.embed.gallery#viewImage": + t.EmbedGallery_ViewImage = new(EmbedGallery_ViewImage) + return json.Unmarshal(b, t.EmbedGallery_ViewImage) + default: + return nil + } +} + +func (t *EmbedGallery_View_Items_Elem) MarshalCBOR(w io.Writer) error { + + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if t.EmbedGallery_ViewImage != nil { + return t.EmbedGallery_ViewImage.MarshalCBOR(w) + } + return fmt.Errorf("can not marshal empty union as CBOR") +} + +func (t *EmbedGallery_View_Items_Elem) UnmarshalCBOR(r io.Reader) error { + typ, b, err := glex.CborTypeExtractReader(r) + if err != nil { + return err + } + + switch typ { + case "app.bsky.embed.gallery#viewImage": + t.EmbedGallery_ViewImage = new(EmbedGallery_ViewImage) + return t.EmbedGallery_ViewImage.UnmarshalCBOR(bytes.NewReader(b)) + default: + return nil + } +} + +// EmbedGallery_ViewImage is a "viewImage" in the app.bsky.embed.gallery schema. +type EmbedGallery_ViewImage struct { + LexiconTypeID string `json:"$type,omitempty"` + // alt: Alt text description of the image, for accessibility. + Alt string `json:"alt"` + AspectRatio EmbedDefs_AspectRatio `json:"aspectRatio"` + // fullsize: Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. + Fullsize string `json:"fullsize"` + // thumbnail: Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. + Thumbnail string `json:"thumbnail"` +} + +// RecordTypeID implements glex.Record. +func (t *EmbedGallery_ViewImage) RecordTypeID() string { return "app.bsky.embed.gallery#viewImage" } + +func (t *EmbedGallery_ViewImage) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "app.bsky.embed.gallery#viewImage" + return glex.MarshalCBOR(w, t) +} + +func (t *EmbedGallery_ViewImage) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} diff --git a/pkg/appbsky/embedrecord.go b/pkg/appbsky/embedrecord.go index 16d93f128..f52568ea3 100644 --- a/pkg/appbsky/embedrecord.go +++ b/pkg/appbsky/embedrecord.go @@ -326,6 +326,7 @@ func (t *EmbedRecord_ViewRecord) UnmarshalCBOR(r io.Reader) error { type EmbedRecord_ViewRecord_Embeds_Elem struct { EmbedExternal_View *EmbedExternal_View + EmbedGallery_View *EmbedGallery_View EmbedImages_View *EmbedImages_View EmbedRecordWithMedia_View *EmbedRecordWithMedia_View EmbedRecord_View *EmbedRecord_View @@ -337,6 +338,10 @@ func (t *EmbedRecord_ViewRecord_Embeds_Elem) MarshalJSON() ([]byte, error) { t.EmbedExternal_View.LexiconTypeID = "app.bsky.embed.external#view" return json.Marshal(t.EmbedExternal_View) } + if t.EmbedGallery_View != nil { + t.EmbedGallery_View.LexiconTypeID = "app.bsky.embed.gallery#view" + return json.Marshal(t.EmbedGallery_View) + } if t.EmbedImages_View != nil { t.EmbedImages_View.LexiconTypeID = "app.bsky.embed.images#view" return json.Marshal(t.EmbedImages_View) @@ -366,6 +371,9 @@ func (t *EmbedRecord_ViewRecord_Embeds_Elem) UnmarshalJSON(b []byte) error { case "app.bsky.embed.external#view": t.EmbedExternal_View = new(EmbedExternal_View) return json.Unmarshal(b, t.EmbedExternal_View) + case "app.bsky.embed.gallery#view": + t.EmbedGallery_View = new(EmbedGallery_View) + return json.Unmarshal(b, t.EmbedGallery_View) case "app.bsky.embed.images#view": t.EmbedImages_View = new(EmbedImages_View) return json.Unmarshal(b, t.EmbedImages_View) @@ -392,6 +400,9 @@ func (t *EmbedRecord_ViewRecord_Embeds_Elem) MarshalCBOR(w io.Writer) error { if t.EmbedExternal_View != nil { return t.EmbedExternal_View.MarshalCBOR(w) } + if t.EmbedGallery_View != nil { + return t.EmbedGallery_View.MarshalCBOR(w) + } if t.EmbedImages_View != nil { return t.EmbedImages_View.MarshalCBOR(w) } @@ -417,6 +428,9 @@ func (t *EmbedRecord_ViewRecord_Embeds_Elem) UnmarshalCBOR(r io.Reader) error { case "app.bsky.embed.external#view": t.EmbedExternal_View = new(EmbedExternal_View) return t.EmbedExternal_View.UnmarshalCBOR(bytes.NewReader(b)) + case "app.bsky.embed.gallery#view": + t.EmbedGallery_View = new(EmbedGallery_View) + return t.EmbedGallery_View.UnmarshalCBOR(bytes.NewReader(b)) case "app.bsky.embed.images#view": t.EmbedImages_View = new(EmbedImages_View) return t.EmbedImages_View.UnmarshalCBOR(bytes.NewReader(b)) diff --git a/pkg/appbsky/embedrecordwithmedia.go b/pkg/appbsky/embedrecordwithmedia.go index a53409c89..e2bf0a558 100644 --- a/pkg/appbsky/embedrecordwithmedia.go +++ b/pkg/appbsky/embedrecordwithmedia.go @@ -49,6 +49,7 @@ func (t *EmbedRecordWithMedia) UnmarshalCBOR(r io.Reader) error { type EmbedRecordWithMedia_Media struct { EmbedExternal *EmbedExternal + EmbedGallery *EmbedGallery EmbedImages *EmbedImages EmbedVideo *EmbedVideo } @@ -58,6 +59,10 @@ func (t *EmbedRecordWithMedia_Media) MarshalJSON() ([]byte, error) { t.EmbedExternal.LexiconTypeID = "app.bsky.embed.external" return json.Marshal(t.EmbedExternal) } + if t.EmbedGallery != nil { + t.EmbedGallery.LexiconTypeID = "app.bsky.embed.gallery" + return json.Marshal(t.EmbedGallery) + } if t.EmbedImages != nil { t.EmbedImages.LexiconTypeID = "app.bsky.embed.images" return json.Marshal(t.EmbedImages) @@ -79,6 +84,9 @@ func (t *EmbedRecordWithMedia_Media) UnmarshalJSON(b []byte) error { case "app.bsky.embed.external": t.EmbedExternal = new(EmbedExternal) return json.Unmarshal(b, t.EmbedExternal) + case "app.bsky.embed.gallery": + t.EmbedGallery = new(EmbedGallery) + return json.Unmarshal(b, t.EmbedGallery) case "app.bsky.embed.images": t.EmbedImages = new(EmbedImages) return json.Unmarshal(b, t.EmbedImages) @@ -99,6 +107,9 @@ func (t *EmbedRecordWithMedia_Media) MarshalCBOR(w io.Writer) error { if t.EmbedExternal != nil { return t.EmbedExternal.MarshalCBOR(w) } + if t.EmbedGallery != nil { + return t.EmbedGallery.MarshalCBOR(w) + } if t.EmbedImages != nil { return t.EmbedImages.MarshalCBOR(w) } @@ -118,6 +129,9 @@ func (t *EmbedRecordWithMedia_Media) UnmarshalCBOR(r io.Reader) error { case "app.bsky.embed.external": t.EmbedExternal = new(EmbedExternal) return t.EmbedExternal.UnmarshalCBOR(bytes.NewReader(b)) + case "app.bsky.embed.gallery": + t.EmbedGallery = new(EmbedGallery) + return t.EmbedGallery.UnmarshalCBOR(bytes.NewReader(b)) case "app.bsky.embed.images": t.EmbedImages = new(EmbedImages) return t.EmbedImages.UnmarshalCBOR(bytes.NewReader(b)) @@ -156,6 +170,7 @@ func (t *EmbedRecordWithMedia_View) UnmarshalCBOR(r io.Reader) error { type EmbedRecordWithMedia_View_Media struct { EmbedExternal_View *EmbedExternal_View + EmbedGallery_View *EmbedGallery_View EmbedImages_View *EmbedImages_View EmbedVideo_View *EmbedVideo_View } @@ -165,6 +180,10 @@ func (t *EmbedRecordWithMedia_View_Media) MarshalJSON() ([]byte, error) { t.EmbedExternal_View.LexiconTypeID = "app.bsky.embed.external#view" return json.Marshal(t.EmbedExternal_View) } + if t.EmbedGallery_View != nil { + t.EmbedGallery_View.LexiconTypeID = "app.bsky.embed.gallery#view" + return json.Marshal(t.EmbedGallery_View) + } if t.EmbedImages_View != nil { t.EmbedImages_View.LexiconTypeID = "app.bsky.embed.images#view" return json.Marshal(t.EmbedImages_View) @@ -186,6 +205,9 @@ func (t *EmbedRecordWithMedia_View_Media) UnmarshalJSON(b []byte) error { case "app.bsky.embed.external#view": t.EmbedExternal_View = new(EmbedExternal_View) return json.Unmarshal(b, t.EmbedExternal_View) + case "app.bsky.embed.gallery#view": + t.EmbedGallery_View = new(EmbedGallery_View) + return json.Unmarshal(b, t.EmbedGallery_View) case "app.bsky.embed.images#view": t.EmbedImages_View = new(EmbedImages_View) return json.Unmarshal(b, t.EmbedImages_View) @@ -206,6 +228,9 @@ func (t *EmbedRecordWithMedia_View_Media) MarshalCBOR(w io.Writer) error { if t.EmbedExternal_View != nil { return t.EmbedExternal_View.MarshalCBOR(w) } + if t.EmbedGallery_View != nil { + return t.EmbedGallery_View.MarshalCBOR(w) + } if t.EmbedImages_View != nil { return t.EmbedImages_View.MarshalCBOR(w) } @@ -225,6 +250,9 @@ func (t *EmbedRecordWithMedia_View_Media) UnmarshalCBOR(r io.Reader) error { case "app.bsky.embed.external#view": t.EmbedExternal_View = new(EmbedExternal_View) return t.EmbedExternal_View.UnmarshalCBOR(bytes.NewReader(b)) + case "app.bsky.embed.gallery#view": + t.EmbedGallery_View = new(EmbedGallery_View) + return t.EmbedGallery_View.UnmarshalCBOR(bytes.NewReader(b)) case "app.bsky.embed.images#view": t.EmbedImages_View = new(EmbedImages_View) return t.EmbedImages_View.UnmarshalCBOR(bytes.NewReader(b)) diff --git a/pkg/appbsky/feeddefs.go b/pkg/appbsky/feeddefs.go index 7aa2bebd0..d37bf5df7 100644 --- a/pkg/appbsky/feeddefs.go +++ b/pkg/appbsky/feeddefs.go @@ -306,6 +306,7 @@ func (t *FeedDefs_PostView) UnmarshalCBOR(r io.Reader) error { type FeedDefs_PostView_Embed struct { EmbedExternal_View *EmbedExternal_View + EmbedGallery_View *EmbedGallery_View EmbedImages_View *EmbedImages_View EmbedRecordWithMedia_View *EmbedRecordWithMedia_View EmbedRecord_View *EmbedRecord_View @@ -317,6 +318,10 @@ func (t *FeedDefs_PostView_Embed) MarshalJSON() ([]byte, error) { t.EmbedExternal_View.LexiconTypeID = "app.bsky.embed.external#view" return json.Marshal(t.EmbedExternal_View) } + if t.EmbedGallery_View != nil { + t.EmbedGallery_View.LexiconTypeID = "app.bsky.embed.gallery#view" + return json.Marshal(t.EmbedGallery_View) + } if t.EmbedImages_View != nil { t.EmbedImages_View.LexiconTypeID = "app.bsky.embed.images#view" return json.Marshal(t.EmbedImages_View) @@ -346,6 +351,9 @@ func (t *FeedDefs_PostView_Embed) UnmarshalJSON(b []byte) error { case "app.bsky.embed.external#view": t.EmbedExternal_View = new(EmbedExternal_View) return json.Unmarshal(b, t.EmbedExternal_View) + case "app.bsky.embed.gallery#view": + t.EmbedGallery_View = new(EmbedGallery_View) + return json.Unmarshal(b, t.EmbedGallery_View) case "app.bsky.embed.images#view": t.EmbedImages_View = new(EmbedImages_View) return json.Unmarshal(b, t.EmbedImages_View) @@ -372,6 +380,9 @@ func (t *FeedDefs_PostView_Embed) MarshalCBOR(w io.Writer) error { if t.EmbedExternal_View != nil { return t.EmbedExternal_View.MarshalCBOR(w) } + if t.EmbedGallery_View != nil { + return t.EmbedGallery_View.MarshalCBOR(w) + } if t.EmbedImages_View != nil { return t.EmbedImages_View.MarshalCBOR(w) } @@ -397,6 +408,9 @@ func (t *FeedDefs_PostView_Embed) UnmarshalCBOR(r io.Reader) error { case "app.bsky.embed.external#view": t.EmbedExternal_View = new(EmbedExternal_View) return t.EmbedExternal_View.UnmarshalCBOR(bytes.NewReader(b)) + case "app.bsky.embed.gallery#view": + t.EmbedGallery_View = new(EmbedGallery_View) + return t.EmbedGallery_View.UnmarshalCBOR(bytes.NewReader(b)) case "app.bsky.embed.images#view": t.EmbedImages_View = new(EmbedImages_View) return t.EmbedImages_View.UnmarshalCBOR(bytes.NewReader(b)) diff --git a/pkg/appbsky/feedpost.go b/pkg/appbsky/feedpost.go index 08af38c55..ac44d43c9 100644 --- a/pkg/appbsky/feedpost.go +++ b/pkg/appbsky/feedpost.go @@ -65,6 +65,7 @@ func (t *FeedPost) UnmarshalCBOR(r io.Reader) error { type FeedPost_Embed struct { EmbedExternal *EmbedExternal + EmbedGallery *EmbedGallery EmbedImages *EmbedImages EmbedRecord *EmbedRecord EmbedRecordWithMedia *EmbedRecordWithMedia @@ -76,6 +77,10 @@ func (t *FeedPost_Embed) MarshalJSON() ([]byte, error) { t.EmbedExternal.LexiconTypeID = "app.bsky.embed.external" return json.Marshal(t.EmbedExternal) } + if t.EmbedGallery != nil { + t.EmbedGallery.LexiconTypeID = "app.bsky.embed.gallery" + return json.Marshal(t.EmbedGallery) + } if t.EmbedImages != nil { t.EmbedImages.LexiconTypeID = "app.bsky.embed.images" return json.Marshal(t.EmbedImages) @@ -105,6 +110,9 @@ func (t *FeedPost_Embed) UnmarshalJSON(b []byte) error { case "app.bsky.embed.external": t.EmbedExternal = new(EmbedExternal) return json.Unmarshal(b, t.EmbedExternal) + case "app.bsky.embed.gallery": + t.EmbedGallery = new(EmbedGallery) + return json.Unmarshal(b, t.EmbedGallery) case "app.bsky.embed.images": t.EmbedImages = new(EmbedImages) return json.Unmarshal(b, t.EmbedImages) @@ -131,6 +139,9 @@ func (t *FeedPost_Embed) MarshalCBOR(w io.Writer) error { if t.EmbedExternal != nil { return t.EmbedExternal.MarshalCBOR(w) } + if t.EmbedGallery != nil { + return t.EmbedGallery.MarshalCBOR(w) + } if t.EmbedImages != nil { return t.EmbedImages.MarshalCBOR(w) } @@ -156,6 +167,9 @@ func (t *FeedPost_Embed) UnmarshalCBOR(r io.Reader) error { case "app.bsky.embed.external": t.EmbedExternal = new(EmbedExternal) return t.EmbedExternal.UnmarshalCBOR(bytes.NewReader(b)) + case "app.bsky.embed.gallery": + t.EmbedGallery = new(EmbedGallery) + return t.EmbedGallery.UnmarshalCBOR(bytes.NewReader(b)) case "app.bsky.embed.images": t.EmbedImages = new(EmbedImages) return t.EmbedImages.UnmarshalCBOR(bytes.NewReader(b)) diff --git a/pkg/appbsky/notificationdefs.go b/pkg/appbsky/notificationdefs.go index 2ad80e49e..8c4d75c4f 100644 --- a/pkg/appbsky/notificationdefs.go +++ b/pkg/appbsky/notificationdefs.go @@ -37,6 +37,8 @@ func (t *NotificationDefs_ActivitySubscription) UnmarshalCBOR(r io.Reader) error } // NotificationDefs_ChatPreference is a "chatPreference" in the app.bsky.notification.defs schema. +// +// Deprecated: use chat.bsky.notification preferences instead. This will only return a default value. type NotificationDefs_ChatPreference struct { LexiconTypeID string `json:"$type,omitempty"` Include string `json:"include"` @@ -114,7 +116,8 @@ func (t *NotificationDefs_Preference) UnmarshalCBOR(r io.Reader) error { // NotificationDefs_Preferences is a "preferences" in the app.bsky.notification.defs schema. type NotificationDefs_Preferences struct { - LexiconTypeID string `json:"$type,omitempty"` + LexiconTypeID string `json:"$type,omitempty"` + // chat: Deprecated: use chat.bsky.notification preferences instead. This will only return a default value. Chat NotificationDefs_ChatPreference `json:"chat"` Follow NotificationDefs_FilterablePreference `json:"follow"` Like NotificationDefs_FilterablePreference `json:"like"` diff --git a/pkg/comatproto/identitydefs.go b/pkg/comatproto/identitydefs.go new file mode 100644 index 000000000..58cfce468 --- /dev/null +++ b/pkg/comatproto/identitydefs.go @@ -0,0 +1,40 @@ +// Code generated by glex; DO NOT EDIT. + +// Lexicon schema: com.atproto.identity.defs + +package comatproto + +import ( + "io" + + glex "github.com/streamplace/glex/runtime" + cbg "github.com/whyrusleeping/cbor-gen" +) + +// IdentityDefs_IdentityInfo is a "identityInfo" in the com.atproto.identity.defs schema. +type IdentityDefs_IdentityInfo struct { + LexiconTypeID string `json:"$type,omitempty"` + Did string `json:"did"` + // didDoc: The complete DID document for the identity. + DidDoc *glex.LexiconTypeDecoder `json:"didDoc"` + // handle: The validated handle of the account; or 'handle.invalid' if the handle did not bi-directionally match the DID document. + Handle string `json:"handle"` +} + +// RecordTypeID implements glex.Record. +func (t *IdentityDefs_IdentityInfo) RecordTypeID() string { + return "com.atproto.identity.defs#identityInfo" +} + +func (t *IdentityDefs_IdentityInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "com.atproto.identity.defs#identityInfo" + return glex.MarshalCBOR(w, t) +} + +func (t *IdentityDefs_IdentityInfo) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} diff --git a/pkg/comatproto/identityrefreshidentity.go b/pkg/comatproto/identityrefreshidentity.go new file mode 100644 index 000000000..67f2b8bd0 --- /dev/null +++ b/pkg/comatproto/identityrefreshidentity.go @@ -0,0 +1,48 @@ +// Code generated by glex; DO NOT EDIT. + +// Lexicon schema: com.atproto.identity.refreshIdentity + +package comatproto + +import ( + "context" + "io" + + glex "github.com/streamplace/glex/runtime" + cbg "github.com/whyrusleeping/cbor-gen" +) + +type IdentityRefreshIdentity_Input struct { + LexiconTypeID string `json:"$type,omitempty"` + Identifier string `json:"identifier"` +} + +// RecordTypeID implements glex.Record. +func (t *IdentityRefreshIdentity_Input) RecordTypeID() string { + return "com.atproto.identity.refreshIdentity" +} + +func (t *IdentityRefreshIdentity_Input) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "com.atproto.identity.refreshIdentity" + return glex.MarshalCBOR(w, t) +} + +func (t *IdentityRefreshIdentity_Input) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} + +// IdentityRefreshIdentity calls the XRPC method "com.atproto.identity.refreshIdentity". +// +// Request that the server re-resolve an identity (DID and handle). The server may ignore this request, or require authentication, depending on the role, implementation, and policy of the server. +func IdentityRefreshIdentity(ctx context.Context, c glex.LexClient, input *IdentityRefreshIdentity_Input) (*IdentityDefs_IdentityInfo, error) { + var out IdentityDefs_IdentityInfo + + if err := c.LexDo(ctx, glex.Procedure, "application/json", "com.atproto.identity.refreshIdentity", nil, input, &out); err != nil { + return nil, err + } + return &out, nil +} diff --git a/pkg/comatproto/identityresolvehandle.go b/pkg/comatproto/identityresolvehandle.go new file mode 100644 index 000000000..320a3186c --- /dev/null +++ b/pkg/comatproto/identityresolvehandle.go @@ -0,0 +1,53 @@ +// Code generated by glex; DO NOT EDIT. + +// Lexicon schema: com.atproto.identity.resolveHandle + +package comatproto + +import ( + "context" + "io" + + glex "github.com/streamplace/glex/runtime" + cbg "github.com/whyrusleeping/cbor-gen" +) + +type IdentityResolveHandle_Output struct { + LexiconTypeID string `json:"$type,omitempty"` + Did string `json:"did"` +} + +// RecordTypeID implements glex.Record. +func (t *IdentityResolveHandle_Output) RecordTypeID() string { + return "com.atproto.identity.resolveHandle" +} + +func (t *IdentityResolveHandle_Output) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + t.LexiconTypeID = "com.atproto.identity.resolveHandle" + return glex.MarshalCBOR(w, t) +} + +func (t *IdentityResolveHandle_Output) UnmarshalCBOR(r io.Reader) error { + return glex.UnmarshalCBOR(r, t) +} + +// IdentityResolveHandle calls the XRPC method "com.atproto.identity.resolveHandle". +// +// Resolves an atproto handle (hostname) to a DID. Does not necessarily bi-directionally verify against the the DID document. +// +// handle: The handle to resolve. +func IdentityResolveHandle(ctx context.Context, c glex.LexClient, handle string) (*IdentityResolveHandle_Output, error) { + var out IdentityResolveHandle_Output + + params := map[string]interface{}{} + params["handle"] = handle + + if err := c.LexDo(ctx, glex.Query, "", "com.atproto.identity.resolveHandle", params, nil, &out); err != nil { + return nil, err + } + return &out, nil +} diff --git a/pkg/spxrpc/com_atproto_identity.go b/pkg/spxrpc/com_atproto_identity.go index 608baa0e7..87e962d2f 100644 --- a/pkg/spxrpc/com_atproto_identity.go +++ b/pkg/spxrpc/com_atproto_identity.go @@ -2,31 +2,36 @@ package spxrpc import ( "context" + "net/http" - indigoatproto "github.com/bluesky-social/indigo/api/atproto" "github.com/labstack/echo/v4" + glex "github.com/streamplace/glex/runtime" "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) { +func (s *Server) handleComAtprotoIdentityResolveHandle(ctx context.Context, handle string) (*comatproto.IdentityResolveHandle_Output, error) { did, err := oatproxy.ResolveHandleWithClient(ctx, handle, &aqhttp.Client) if err != nil { return nil, err } - return &indigoatproto.IdentityResolveHandle_Output{Did: did}, nil + return &comatproto.IdentityResolveHandle_Output{Did: did}, nil } -func (s *Server) handleComAtprotoIdentityRefreshIdentity(ctx context.Context, body *indigoatproto.IdentityRefreshIdentity_Input) (*indigoatproto.IdentityDefs_IdentityInfo, error) { +func (s *Server) handleComAtprotoIdentityRefreshIdentity(ctx context.Context, body *comatproto.IdentityRefreshIdentity_Input) (*comatproto.IdentityDefs_IdentityInfo, error) { ident, err := s.ATSync.RefreshIdentity(ctx, body.Identifier) if err != nil { return nil, err } - return &indigoatproto.IdentityDefs_IdentityInfo{ + didDoc, err := glex.Unknown(ident.DIDDocument()) + if err != nil { + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to encode DID document") + } + return &comatproto.IdentityDefs_IdentityInfo{ Did: ident.DID.String(), Handle: ident.Handle.String(), - DidDoc: ident.DIDDocument(), + DidDoc: didDoc, }, nil } diff --git a/pkg/spxrpc/com_atproto_repo.go b/pkg/spxrpc/com_atproto_repo.go index 04fcb5a5a..6a1c8b239 100644 --- a/pkg/spxrpc/com_atproto_repo.go +++ b/pkg/spxrpc/com_atproto_repo.go @@ -97,27 +97,27 @@ func (s *Server) handleComAtprotoRepoDescribeRepo(ctx context.Context, repo stri if err != nil { return nil, fmt.Errorf("list server repo collections: %w", err) } - didDoc, err := glex.RawJSON(atproto.DIDDoc(s.cli.ServerHost, atproto.ServerPubMultibase)) + didDoc, err := glex.Unknown(atproto.DIDDoc(s.cli.ServerHost, atproto.ServerPubMultibase)) if err != nil { return nil, fmt.Errorf("marshal did doc: %w", err) } return &comatproto.RepoDescribeRepo_Output{ Handle: s.cli.ServerDID(), Did: s.cli.ServerDID(), - DidDoc: &glex.LexiconTypeDecoder{Val: didDoc}, + DidDoc: didDoc, Collections: collections, HandleIsCorrect: true, }, nil } - didDoc, err := glex.RawJSON(atproto.DIDDoc(s.cli.BroadcasterHost, atproto.LexiconPubMultibase)) + didDoc, err := glex.Unknown(atproto.DIDDoc(s.cli.BroadcasterHost, atproto.LexiconPubMultibase)) if err != nil { return nil, fmt.Errorf("marshal did doc: %w", err) } return &comatproto.RepoDescribeRepo_Output{ Handle: s.cli.BroadcasterDID(), Did: s.cli.BroadcasterDID(), - DidDoc: &glex.LexiconTypeDecoder{Val: didDoc}, + DidDoc: didDoc, Collections: []string{ "com.atproto.lexicon.schema", }, diff --git a/pkg/spxrpc/stubs.go b/pkg/spxrpc/stubs.go index 9090093c8..5ce17ae76 100644 --- a/pkg/spxrpc/stubs.go +++ b/pkg/spxrpc/stubs.go @@ -58,6 +58,8 @@ func (s *Server) HandleAppBskyFeedGetFeedSkeleton(c echo.Context) error { } func (s *Server) RegisterHandlersComatproto(e *echo.Echo) error { + e.POST("/xrpc/com.atproto.identity.refreshIdentity", s.HandleComAtprotoIdentityRefreshIdentity) + e.GET("/xrpc/com.atproto.identity.resolveHandle", s.HandleComAtprotoIdentityResolveHandle) 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) @@ -71,6 +73,37 @@ func (s *Server) RegisterHandlersComatproto(e *echo.Echo) error { return nil } +func (s *Server) HandleComAtprotoIdentityRefreshIdentity(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoIdentityRefreshIdentity") + defer span.End() + var body comatproto.IdentityRefreshIdentity_Input + if err := c.Bind(&body); err != nil { + return err + } + var out *comatproto.IdentityDefs_IdentityInfo + var handleErr error + // func (s *Server) handleComAtprotoIdentityRefreshIdentity(ctx context.Context,body *comatproto.IdentityRefreshIdentity_Input) (*comatproto.IdentityDefs_IdentityInfo, error) + out, handleErr = s.handleComAtprotoIdentityRefreshIdentity(ctx, &body) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoIdentityResolveHandle(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoIdentityResolveHandle") + defer span.End() + handle := c.QueryParam("handle") + var out *comatproto.IdentityResolveHandle_Output + var handleErr error + // func (s *Server) handleComAtprotoIdentityResolveHandle(ctx context.Context,handle string) (*comatproto.IdentityResolveHandle_Output, error) + out, handleErr = s.handleComAtprotoIdentityResolveHandle(ctx, handle) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + func (s *Server) HandleComAtprotoIdentityUpdateHandle(c echo.Context) error { ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoIdentityUpdateHandle") defer span.End() -- 2.51.2