From 07f6c65eea9d9f54e7f06da3abcbafd5b0681af1 Mon Sep 17 00:00:00 2001 From: rafaeleyng Date: Tue, 13 Jan 2026 10:58:51 -0300 Subject: [PATCH] Add drafts lexicon --- api/bsky/draftcreateDraft.go | 32 ++++ api/bsky/draftdefs.go | 204 ++++++++++++++++++++++ api/bsky/draftdeleteDraft.go | 25 +++ api/bsky/draftgetDrafts.go | 35 ++++ api/bsky/draftupdateDraft.go | 25 +++ lexicons/app/bsky/draft/createDraft.json | 42 +++++ lexicons/app/bsky/draft/defs.json | 211 +++++++++++++++++++++++ lexicons/app/bsky/draft/deleteDraft.json | 23 +++ lexicons/app/bsky/draft/getDrafts.json | 39 +++++ lexicons/app/bsky/draft/updateDraft.json | 23 +++ 10 files changed, 659 insertions(+) create mode 100644 api/bsky/draftcreateDraft.go create mode 100644 api/bsky/draftdefs.go create mode 100644 api/bsky/draftdeleteDraft.go create mode 100644 api/bsky/draftgetDrafts.go create mode 100644 api/bsky/draftupdateDraft.go create mode 100644 lexicons/app/bsky/draft/createDraft.json create mode 100644 lexicons/app/bsky/draft/defs.json create mode 100644 lexicons/app/bsky/draft/deleteDraft.json create mode 100644 lexicons/app/bsky/draft/getDrafts.json create mode 100644 lexicons/app/bsky/draft/updateDraft.json diff --git a/api/bsky/draftcreateDraft.go b/api/bsky/draftcreateDraft.go new file mode 100644 index 00000000..492372d9 --- /dev/null +++ b/api/bsky/draftcreateDraft.go @@ -0,0 +1,32 @@ +// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. + +// Lexicon schema: app.bsky.draft.createDraft + +package bsky + +import ( + "context" + + lexutil "github.com/bluesky-social/indigo/lex/util" +) + +// DraftCreateDraft_Input is the input argument to a app.bsky.draft.createDraft call. +type DraftCreateDraft_Input struct { + Draft *DraftDefs_Draft `json:"draft" cborgen:"draft"` +} + +// DraftCreateDraft_Output is the output of a app.bsky.draft.createDraft call. +type DraftCreateDraft_Output struct { + // id: The ID of the created draft. + Id string `json:"id" cborgen:"id"` +} + +// DraftCreateDraft calls the XRPC method "app.bsky.draft.createDraft". +func DraftCreateDraft(ctx context.Context, c lexutil.LexClient, input *DraftCreateDraft_Input) (*DraftCreateDraft_Output, error) { + var out DraftCreateDraft_Output + if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "app.bsky.draft.createDraft", nil, input, &out); err != nil { + return nil, err + } + + return &out, nil +} diff --git a/api/bsky/draftdefs.go b/api/bsky/draftdefs.go new file mode 100644 index 00000000..5d45e9c8 --- /dev/null +++ b/api/bsky/draftdefs.go @@ -0,0 +1,204 @@ +// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. + +// Lexicon schema: app.bsky.draft.defs + +package bsky + +import ( + "encoding/json" + "fmt" + + comatproto "github.com/bluesky-social/indigo/api/atproto" + lexutil "github.com/bluesky-social/indigo/lex/util" +) + +// DraftDefs_Draft is a "draft" in the app.bsky.draft.defs schema. +// +// A draft containing an array of draft posts. +type DraftDefs_Draft struct { + // langs: Indicates human language of posts primary text content. + Langs []string `json:"langs,omitempty" cborgen:"langs,omitempty"` + // postgateEmbeddingRules: Embedding rules for the postgates to be created when this draft is published. + PostgateEmbeddingRules []*DraftDefs_Draft_PostgateEmbeddingRules_Elem `json:"postgateEmbeddingRules,omitempty" cborgen:"postgateEmbeddingRules,omitempty"` + // posts: Array of draft posts that compose this draft. + Posts []*DraftDefs_DraftPost `json:"posts" cborgen:"posts"` + // threadgateAllow: Allow-rules for the threadgate to be created when this draft is published. + ThreadgateAllow []*DraftDefs_Draft_ThreadgateAllow_Elem `json:"threadgateAllow,omitempty" cborgen:"threadgateAllow,omitempty"` +} + +// DraftDefs_DraftEmbedCaption is a "draftEmbedCaption" in the app.bsky.draft.defs schema. +type DraftDefs_DraftEmbedCaption struct { + Content string `json:"content" cborgen:"content"` + Lang string `json:"lang" cborgen:"lang"` +} + +// DraftDefs_DraftEmbedExternal is a "draftEmbedExternal" in the app.bsky.draft.defs schema. +type DraftDefs_DraftEmbedExternal struct { + Uri string `json:"uri" cborgen:"uri"` +} + +// DraftDefs_DraftEmbedImage is a "draftEmbedImage" in the app.bsky.draft.defs schema. +type DraftDefs_DraftEmbedImage struct { + Alt *string `json:"alt,omitempty" cborgen:"alt,omitempty"` + LocalRef *DraftDefs_DraftEmbedLocalRef `json:"localRef" cborgen:"localRef"` +} + +// DraftDefs_DraftEmbedLocalRef is a "draftEmbedLocalRef" in the app.bsky.draft.defs schema. +type DraftDefs_DraftEmbedLocalRef struct { + // path: Local, on-device ref to file to be embedded. Embeds are currently device-bound for drafts. + Path string `json:"path" cborgen:"path"` +} + +// DraftDefs_DraftEmbedRecord is a "draftEmbedRecord" in the app.bsky.draft.defs schema. +type DraftDefs_DraftEmbedRecord struct { + Record *comatproto.RepoStrongRef `json:"record" cborgen:"record"` +} + +// DraftDefs_DraftEmbedVideo is a "draftEmbedVideo" in the app.bsky.draft.defs schema. +type DraftDefs_DraftEmbedVideo struct { + Alt *string `json:"alt,omitempty" cborgen:"alt,omitempty"` + Captions []*DraftDefs_DraftEmbedCaption `json:"captions,omitempty" cborgen:"captions,omitempty"` + LocalRef *DraftDefs_DraftEmbedLocalRef `json:"localRef" cborgen:"localRef"` +} + +// DraftDefs_DraftPost is a "draftPost" in the app.bsky.draft.defs schema. +// +// One of the posts that compose a draft. +type DraftDefs_DraftPost struct { + EmbedExternals []*DraftDefs_DraftEmbedExternal `json:"embedExternals,omitempty" cborgen:"embedExternals,omitempty"` + EmbedImages []*DraftDefs_DraftEmbedImage `json:"embedImages,omitempty" cborgen:"embedImages,omitempty"` + EmbedRecords []*DraftDefs_DraftEmbedRecord `json:"embedRecords,omitempty" cborgen:"embedRecords,omitempty"` + EmbedVideos []*DraftDefs_DraftEmbedVideo `json:"embedVideos,omitempty" cborgen:"embedVideos,omitempty"` + // labels: Self-label values for this post. Effectively content warnings. + Labels *DraftDefs_DraftPost_Labels `json:"labels,omitempty" cborgen:"labels,omitempty"` + // text: The primary post content. + Text string `json:"text" cborgen:"text"` +} + +// Self-label values for this post. Effectively content warnings. +type DraftDefs_DraftPost_Labels struct { + LabelDefs_SelfLabels *comatproto.LabelDefs_SelfLabels +} + +func (t *DraftDefs_DraftPost_Labels) MarshalJSON() ([]byte, error) { + if t.LabelDefs_SelfLabels != nil { + t.LabelDefs_SelfLabels.LexiconTypeID = "com.atproto.label.defs#selfLabels" + return json.Marshal(t.LabelDefs_SelfLabels) + } + return nil, fmt.Errorf("can not marshal empty union as JSON") +} + +func (t *DraftDefs_DraftPost_Labels) UnmarshalJSON(b []byte) error { + typ, err := lexutil.TypeExtract(b) + if err != nil { + return err + } + + switch typ { + case "com.atproto.label.defs#selfLabels": + t.LabelDefs_SelfLabels = new(comatproto.LabelDefs_SelfLabels) + return json.Unmarshal(b, t.LabelDefs_SelfLabels) + default: + return nil + } +} + +// DraftDefs_DraftView is a "draftView" in the app.bsky.draft.defs schema. +// +// View to present drafts data to users. +type DraftDefs_DraftView struct { + // createdAt: The time the draft was created. + CreatedAt string `json:"createdAt" cborgen:"createdAt"` + Draft *DraftDefs_Draft `json:"draft" cborgen:"draft"` + // id: A TID to be used as a draft identifier. + Id string `json:"id" cborgen:"id"` + // updatedAt: The time the draft was last updated. + UpdatedAt string `json:"updatedAt" cborgen:"updatedAt"` +} + +// DraftDefs_DraftWithId is a "draftWithId" in the app.bsky.draft.defs schema. +// +// A draft with an identifier, used to store drafts in private storage (stash). +type DraftDefs_DraftWithId struct { + Draft *DraftDefs_Draft `json:"draft" cborgen:"draft"` + // id: A TID to be used as a draft identifier. + Id string `json:"id" cborgen:"id"` +} + +type DraftDefs_Draft_PostgateEmbeddingRules_Elem struct { + FeedPostgate_DisableRule *FeedPostgate_DisableRule +} + +func (t *DraftDefs_Draft_PostgateEmbeddingRules_Elem) MarshalJSON() ([]byte, error) { + if t.FeedPostgate_DisableRule != nil { + t.FeedPostgate_DisableRule.LexiconTypeID = "app.bsky.feed.postgate#disableRule" + return json.Marshal(t.FeedPostgate_DisableRule) + } + return nil, fmt.Errorf("can not marshal empty union as JSON") +} + +func (t *DraftDefs_Draft_PostgateEmbeddingRules_Elem) UnmarshalJSON(b []byte) error { + typ, err := lexutil.TypeExtract(b) + if err != nil { + return err + } + + switch typ { + case "app.bsky.feed.postgate#disableRule": + t.FeedPostgate_DisableRule = new(FeedPostgate_DisableRule) + return json.Unmarshal(b, t.FeedPostgate_DisableRule) + default: + return nil + } +} + +type DraftDefs_Draft_ThreadgateAllow_Elem struct { + FeedThreadgate_MentionRule *FeedThreadgate_MentionRule + FeedThreadgate_FollowerRule *FeedThreadgate_FollowerRule + FeedThreadgate_FollowingRule *FeedThreadgate_FollowingRule + FeedThreadgate_ListRule *FeedThreadgate_ListRule +} + +func (t *DraftDefs_Draft_ThreadgateAllow_Elem) MarshalJSON() ([]byte, error) { + if t.FeedThreadgate_MentionRule != nil { + t.FeedThreadgate_MentionRule.LexiconTypeID = "app.bsky.feed.threadgate#mentionRule" + return json.Marshal(t.FeedThreadgate_MentionRule) + } + if t.FeedThreadgate_FollowerRule != nil { + t.FeedThreadgate_FollowerRule.LexiconTypeID = "app.bsky.feed.threadgate#followerRule" + return json.Marshal(t.FeedThreadgate_FollowerRule) + } + if t.FeedThreadgate_FollowingRule != nil { + t.FeedThreadgate_FollowingRule.LexiconTypeID = "app.bsky.feed.threadgate#followingRule" + return json.Marshal(t.FeedThreadgate_FollowingRule) + } + if t.FeedThreadgate_ListRule != nil { + t.FeedThreadgate_ListRule.LexiconTypeID = "app.bsky.feed.threadgate#listRule" + return json.Marshal(t.FeedThreadgate_ListRule) + } + return nil, fmt.Errorf("can not marshal empty union as JSON") +} + +func (t *DraftDefs_Draft_ThreadgateAllow_Elem) UnmarshalJSON(b []byte) error { + typ, err := lexutil.TypeExtract(b) + if err != nil { + return err + } + + switch typ { + case "app.bsky.feed.threadgate#mentionRule": + t.FeedThreadgate_MentionRule = new(FeedThreadgate_MentionRule) + return json.Unmarshal(b, t.FeedThreadgate_MentionRule) + case "app.bsky.feed.threadgate#followerRule": + t.FeedThreadgate_FollowerRule = new(FeedThreadgate_FollowerRule) + return json.Unmarshal(b, t.FeedThreadgate_FollowerRule) + case "app.bsky.feed.threadgate#followingRule": + t.FeedThreadgate_FollowingRule = new(FeedThreadgate_FollowingRule) + return json.Unmarshal(b, t.FeedThreadgate_FollowingRule) + case "app.bsky.feed.threadgate#listRule": + t.FeedThreadgate_ListRule = new(FeedThreadgate_ListRule) + return json.Unmarshal(b, t.FeedThreadgate_ListRule) + default: + return nil + } +} diff --git a/api/bsky/draftdeleteDraft.go b/api/bsky/draftdeleteDraft.go new file mode 100644 index 00000000..dafd61f0 --- /dev/null +++ b/api/bsky/draftdeleteDraft.go @@ -0,0 +1,25 @@ +// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. + +// Lexicon schema: app.bsky.draft.deleteDraft + +package bsky + +import ( + "context" + + lexutil "github.com/bluesky-social/indigo/lex/util" +) + +// DraftDeleteDraft_Input is the input argument to a app.bsky.draft.deleteDraft call. +type DraftDeleteDraft_Input struct { + Id string `json:"id" cborgen:"id"` +} + +// DraftDeleteDraft calls the XRPC method "app.bsky.draft.deleteDraft". +func DraftDeleteDraft(ctx context.Context, c lexutil.LexClient, input *DraftDeleteDraft_Input) error { + if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "app.bsky.draft.deleteDraft", nil, input, nil); err != nil { + return err + } + + return nil +} diff --git a/api/bsky/draftgetDrafts.go b/api/bsky/draftgetDrafts.go new file mode 100644 index 00000000..64b80ac1 --- /dev/null +++ b/api/bsky/draftgetDrafts.go @@ -0,0 +1,35 @@ +// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. + +// Lexicon schema: app.bsky.draft.getDrafts + +package bsky + +import ( + "context" + + lexutil "github.com/bluesky-social/indigo/lex/util" +) + +// DraftGetDrafts_Output is the output of a app.bsky.draft.getDrafts call. +type DraftGetDrafts_Output struct { + Cursor *string `json:"cursor,omitempty" cborgen:"cursor,omitempty"` + Drafts []*DraftDefs_DraftView `json:"drafts" cborgen:"drafts"` +} + +// DraftGetDrafts calls the XRPC method "app.bsky.draft.getDrafts". +func DraftGetDrafts(ctx context.Context, c lexutil.LexClient, cursor string, limit int64) (*DraftGetDrafts_Output, error) { + var out DraftGetDrafts_Output + + params := map[string]interface{}{} + if cursor != "" { + params["cursor"] = cursor + } + if limit != 0 { + params["limit"] = limit + } + if err := c.LexDo(ctx, lexutil.Query, "", "app.bsky.draft.getDrafts", params, nil, &out); err != nil { + return nil, err + } + + return &out, nil +} diff --git a/api/bsky/draftupdateDraft.go b/api/bsky/draftupdateDraft.go new file mode 100644 index 00000000..c0a25829 --- /dev/null +++ b/api/bsky/draftupdateDraft.go @@ -0,0 +1,25 @@ +// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. + +// Lexicon schema: app.bsky.draft.updateDraft + +package bsky + +import ( + "context" + + lexutil "github.com/bluesky-social/indigo/lex/util" +) + +// DraftUpdateDraft_Input is the input argument to a app.bsky.draft.updateDraft call. +type DraftUpdateDraft_Input struct { + Draft *DraftDefs_DraftWithId `json:"draft" cborgen:"draft"` +} + +// DraftUpdateDraft calls the XRPC method "app.bsky.draft.updateDraft". +func DraftUpdateDraft(ctx context.Context, c lexutil.LexClient, input *DraftUpdateDraft_Input) error { + if err := c.LexDo(ctx, lexutil.Procedure, "application/json", "app.bsky.draft.updateDraft", nil, input, nil); err != nil { + return err + } + + return nil +} diff --git a/lexicons/app/bsky/draft/createDraft.json b/lexicons/app/bsky/draft/createDraft.json new file mode 100644 index 00000000..d18239d8 --- /dev/null +++ b/lexicons/app/bsky/draft/createDraft.json @@ -0,0 +1,42 @@ +{ + "lexicon": 1, + "id": "app.bsky.draft.createDraft", + "defs": { + "main": { + "type": "procedure", + "description": "Inserts a draft using private storage (stash). An upper limit of drafts might be enforced. Requires authentication.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["draft"], + "properties": { + "draft": { + "type": "ref", + "ref": "app.bsky.draft.defs#draft" + } + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "string", + "description": "The ID of the created draft." + } + } + } + }, + "errors": [ + { + "name": "DraftLimitReached", + "description": "Trying to insert a new draft when the limit was already reached." + } + ] + } + } +} diff --git a/lexicons/app/bsky/draft/defs.json b/lexicons/app/bsky/draft/defs.json new file mode 100644 index 00000000..b5a0d1c7 --- /dev/null +++ b/lexicons/app/bsky/draft/defs.json @@ -0,0 +1,211 @@ +{ + "lexicon": 1, + "id": "app.bsky.draft.defs", + "defs": { + "draftWithId": { + "description": "A draft with an identifier, used to store drafts in private storage (stash).", + "type": "object", + "required": ["id", "draft"], + "properties": { + "id": { + "description": "A TID to be used as a draft identifier.", + "type": "string", + "format": "tid" + }, + "draft": { + "type": "ref", + "ref": "#draft" + } + } + }, + "draft": { + "description": "A draft containing an array of draft posts.", + "type": "object", + "required": ["posts"], + "properties": { + "posts": { + "description": "Array of draft posts that compose this draft.", + "type": "array", + "minLength": 1, + "maxLength": 100, + "items": { + "type": "ref", + "ref": "#draftPost" + } + }, + "langs": { + "type": "array", + "description": "Indicates human language of posts primary text content.", + "maxLength": 3, + "items": { "type": "string", "format": "language" } + }, + "postgateEmbeddingRules": { + "description": "Embedding rules for the postgates to be created when this draft is published.", + "type": "array", + "maxLength": 5, + "items": { + "type": "union", + "refs": ["app.bsky.feed.postgate#disableRule"] + } + }, + "threadgateAllow": { + "description": "Allow-rules for the threadgate to be created when this draft is published.", + "type": "array", + "maxLength": 5, + "items": { + "type": "union", + "refs": [ + "app.bsky.feed.threadgate#mentionRule", + "app.bsky.feed.threadgate#followerRule", + "app.bsky.feed.threadgate#followingRule", + "app.bsky.feed.threadgate#listRule" + ] + } + } + } + }, + "draftPost": { + "description": "One of the posts that compose a draft.", + "type": "object", + "required": ["text"], + "properties": { + "text": { + "type": "string", + "maxLength": 3000, + "maxGraphemes": 300, + "description": "The primary post content." + }, + "labels": { + "type": "union", + "description": "Self-label values for this post. Effectively content warnings.", + "refs": ["com.atproto.label.defs#selfLabels"] + }, + "embedImages": { + "type": "array", + "items": { "type": "ref", "ref": "#draftEmbedImage" }, + "maxLength": 4 + }, + "embedVideos": { + "type": "array", + "items": { "type": "ref", "ref": "#draftEmbedVideo" }, + "maxLength": 1 + }, + "embedExternals": { + "type": "array", + "items": { "type": "ref", "ref": "#draftEmbedExternal" }, + "maxLength": 1 + }, + "embedRecords": { + "type": "array", + "items": { "type": "ref", "ref": "#draftEmbedRecord" }, + "maxLength": 1 + } + } + }, + + "draftView": { + "description": "View to present drafts data to users.", + "type": "object", + "required": ["id", "draft", "createdAt", "updatedAt"], + "properties": { + "id": { + "description": "A TID to be used as a draft identifier.", + "type": "string", + "format": "tid" + }, + "draft": { + "type": "ref", + "ref": "#draft" + }, + "createdAt": { + "description": "The time the draft was created.", + "type": "string", + "format": "datetime" + }, + "updatedAt": { + "description": "The time the draft was last updated.", + "type": "string", + "format": "datetime" + } + } + }, + + "draftEmbedLocalRef": { + "type": "object", + "required": ["path"], + "properties": { + "path": { + "type": "string", + "description": "Local, on-device ref to file to be embedded. Embeds are currently device-bound for drafts.", + "minLength": 1, + "maxLength": 1024 + } + } + }, + "draftEmbedCaption": { + "type": "object", + "required": ["lang", "content"], + "properties": { + "lang": { + "type": "string", + "format": "language" + }, + "content": { + "type": "string", + "maxLength": 10000 + } + } + }, + + "draftEmbedImage": { + "type": "object", + "required": ["localRef"], + "properties": { + "localRef": { + "type": "ref", + "ref": "#draftEmbedLocalRef" + }, + "alt": { + "type": "string", + "maxGraphemes": 2000 + } + } + }, + "draftEmbedVideo": { + "type": "object", + "required": ["localRef"], + "properties": { + "localRef": { + "type": "ref", + "ref": "#draftEmbedLocalRef" + }, + "alt": { + "type": "string", + "maxGraphemes": 2000 + }, + "captions": { + "type": "array", + "items": { + "type": "ref", + "ref": "#draftEmbedCaption" + }, + "maxLength": 20 + } + } + }, + "draftEmbedExternal": { + "type": "object", + "required": ["uri"], + "properties": { + "uri": { "type": "string", "format": "uri" } + } + }, + "draftEmbedRecord": { + "type": "object", + "required": ["record"], + "properties": { + "record": { "type": "ref", "ref": "com.atproto.repo.strongRef" } + } + } + } +} diff --git a/lexicons/app/bsky/draft/deleteDraft.json b/lexicons/app/bsky/draft/deleteDraft.json new file mode 100644 index 00000000..0445a0fd --- /dev/null +++ b/lexicons/app/bsky/draft/deleteDraft.json @@ -0,0 +1,23 @@ +{ + "lexicon": 1, + "id": "app.bsky.draft.deleteDraft", + "defs": { + "main": { + "type": "procedure", + "description": "Deletes a draft by ID. Requires authentication.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "string", + "format": "tid" + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/draft/getDrafts.json b/lexicons/app/bsky/draft/getDrafts.json new file mode 100644 index 00000000..3e607409 --- /dev/null +++ b/lexicons/app/bsky/draft/getDrafts.json @@ -0,0 +1,39 @@ +{ + "lexicon": 1, + "id": "app.bsky.draft.getDrafts", + "defs": { + "main": { + "type": "query", + "description": "Gets views of user drafts. Requires authentication.", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "cursor": { "type": "string" } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["drafts"], + "properties": { + "cursor": { "type": "string" }, + "drafts": { + "type": "array", + "items": { + "type": "ref", + "ref": "app.bsky.draft.defs#draftView" + } + } + } + } + } + } + } +} diff --git a/lexicons/app/bsky/draft/updateDraft.json b/lexicons/app/bsky/draft/updateDraft.json new file mode 100644 index 00000000..6b1b6fc7 --- /dev/null +++ b/lexicons/app/bsky/draft/updateDraft.json @@ -0,0 +1,23 @@ +{ + "lexicon": 1, + "id": "app.bsky.draft.updateDraft", + "defs": { + "main": { + "type": "procedure", + "description": "Updates a draft using private storage (stash). If the draft ID points to a non-existing ID, the update will be silently ignored. This is done because updates don't enforce draft limit, so it accepts all writes, but will ignore invalid ones. Requires authentication.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["draft"], + "properties": { + "draft": { + "type": "ref", + "ref": "app.bsky.draft.defs#draftWithId" + } + } + } + } + } + } +} -- 2.51.2