Skip to content

Commit 6d37bf4

Browse files
feat(api): add upload asset and edit message endpoints
1 parent ebb892c commit 6d37bf4

File tree

12 files changed

+347
-33
lines changed

12 files changed

+347
-33
lines changed

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 15
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-bea2e5f3b01053a66261a824c75c2640856d0ba00ad795ab71734c4ab9ae33b0.yml
3-
openapi_spec_hash: d766f6e344c12ca6d23e6ef6713b38c4
4-
config_hash: c1e9e27b4965dd90c14c8e88c9036be4
1+
configured_endpoints: 17
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-0e4d333e81e670e605a6706dbb365bc96957a59331fdc87dd1550c59880cb130.yml
3+
openapi_spec_hash: 564146e6d318ecb486ff7c0d7983b398
4+
config_hash: e3418e22e2ca1df0f8a9fcaf7153285a

accountcontact.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ func NewAccountContactService(opts ...option.RequestOption) (r AccountContactSer
3939
return
4040
}
4141

42-
// Search contacts across on a specific account using the network's search API.
43-
// Only use for creating new chats.
42+
// Search contacts on a specific account using the network's search API. Only use
43+
// for creating new chats.
4444
func (r *AccountContactService) Search(ctx context.Context, accountID string, query AccountContactSearchParams, opts ...option.RequestOption) (res *AccountContactSearchResponse, err error) {
4545
opts = slices.Concat(r.Options, opts)
4646
if accountID == "" {

aliases.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,42 @@ type AttachmentSize = shared.AttachmentSize
4444
// This is an alias to an internal type.
4545
type Message = shared.Message
4646

47+
// Message content type. Useful for distinguishing reactions, media messages, and
48+
// state events from regular text messages.
49+
//
50+
// This is an alias to an internal type.
51+
type MessageType = shared.MessageType
52+
53+
// Equals "TEXT"
54+
const MessageTypeText = shared.MessageTypeText
55+
56+
// Equals "NOTICE"
57+
const MessageTypeNotice = shared.MessageTypeNotice
58+
59+
// Equals "IMAGE"
60+
const MessageTypeImage = shared.MessageTypeImage
61+
62+
// Equals "VIDEO"
63+
const MessageTypeVideo = shared.MessageTypeVideo
64+
65+
// Equals "VOICE"
66+
const MessageTypeVoice = shared.MessageTypeVoice
67+
68+
// Equals "AUDIO"
69+
const MessageTypeAudio = shared.MessageTypeAudio
70+
71+
// Equals "FILE"
72+
const MessageTypeFile = shared.MessageTypeFile
73+
74+
// Equals "STICKER"
75+
const MessageTypeSticker = shared.MessageTypeSticker
76+
77+
// Equals "LOCATION"
78+
const MessageTypeLocation = shared.MessageTypeLocation
79+
80+
// Equals "REACTION"
81+
const MessageTypeReaction = shared.MessageTypeReaction
82+
4783
// This is an alias to an internal type.
4884
type Reaction = shared.Reaction
4985

api.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@ Methods:
6464

6565
Response Types:
6666

67+
- <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageUpdateResponse">MessageUpdateResponse</a>
6768
- <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageSendResponse">MessageSendResponse</a>
6869

6970
Methods:
7071

72+
- <code title="put /v1/chats/{chatID}/messages/{messageID}">client.Messages.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageService.Update">Update</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageUpdateParams">MessageUpdateParams</a>) (\*<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageUpdateResponse">MessageUpdateResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
7173
- <code title="get /v1/chats/{chatID}/messages">client.Messages.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, chatID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageListParams">MessageListParams</a>) (\*<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/packages/pagination#CursorSortKey">CursorSortKey</a>[<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/shared#Message">Message</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
7274
- <code title="get /v1/messages/search">client.Messages.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageService.Search">Search</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageSearchParams">MessageSearchParams</a>) (\*<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/packages/pagination#CursorSearch">CursorSearch</a>[<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go/shared#Message">Message</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
7375
- <code title="post /v1/chats/{chatID}/messages">client.Messages.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageService.Send">Send</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, chatID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageSendParams">MessageSendParams</a>) (\*<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#MessageSendResponse">MessageSendResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
@@ -77,7 +79,9 @@ Methods:
7779
Response Types:
7880

7981
- <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetDownloadResponse">AssetDownloadResponse</a>
82+
- <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetUploadResponse">AssetUploadResponse</a>
8083

8184
Methods:
8285

8386
- <code title="post /v1/assets/download">client.Assets.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetService.Download">Download</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetDownloadParams">AssetDownloadParams</a>) (\*<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetDownloadResponse">AssetDownloadResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
87+
- <code title="post /v1/assets/upload">client.Assets.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetService.Upload">Upload</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetUploadParams">AssetUploadParams</a>) (\*<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go">beeperdesktopapi</a>.<a href="https://pkg.go.dev/github.com/beeper/desktop-api-go#AssetUploadResponse">AssetUploadResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>

asset.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ func (r *AssetService) Download(ctx context.Context, body AssetDownloadParams, o
4444
return
4545
}
4646

47+
// Upload a file to a temporary location. Supports JSON body with base64 `content`
48+
// field, or multipart/form-data with `file` field. Returns a local file URL that
49+
// can be used when sending messages with attachments.
50+
func (r *AssetService) Upload(ctx context.Context, body AssetUploadParams, opts ...option.RequestOption) (res *AssetUploadResponse, err error) {
51+
opts = slices.Concat(r.Options, opts)
52+
path := "v1/assets/upload"
53+
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
54+
return
55+
}
56+
4757
type AssetDownloadResponse struct {
4858
// Error message if the download failed.
4959
Error string `json:"error"`
@@ -64,6 +74,47 @@ func (r *AssetDownloadResponse) UnmarshalJSON(data []byte) error {
6474
return apijson.UnmarshalRoot(data, r)
6575
}
6676

77+
type AssetUploadResponse struct {
78+
// Duration in seconds (audio/videos)
79+
Duration float64 `json:"duration"`
80+
// Error message if upload failed
81+
Error string `json:"error"`
82+
// Resolved filename
83+
FileName string `json:"fileName"`
84+
// File size in bytes
85+
FileSize float64 `json:"fileSize"`
86+
// Height in pixels (images/videos)
87+
Height float64 `json:"height"`
88+
// Detected or provided MIME type
89+
MimeType string `json:"mimeType"`
90+
// Local file URL (file://) for the uploaded asset
91+
SrcURL string `json:"srcURL"`
92+
// Unique upload ID for this asset
93+
UploadID string `json:"uploadID"`
94+
// Width in pixels (images/videos)
95+
Width float64 `json:"width"`
96+
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
97+
JSON struct {
98+
Duration respjson.Field
99+
Error respjson.Field
100+
FileName respjson.Field
101+
FileSize respjson.Field
102+
Height respjson.Field
103+
MimeType respjson.Field
104+
SrcURL respjson.Field
105+
UploadID respjson.Field
106+
Width respjson.Field
107+
ExtraFields map[string]respjson.Field
108+
raw string
109+
} `json:"-"`
110+
}
111+
112+
// Returns the unmodified JSON received from the API
113+
func (r AssetUploadResponse) RawJSON() string { return r.JSON.raw }
114+
func (r *AssetUploadResponse) UnmarshalJSON(data []byte) error {
115+
return apijson.UnmarshalRoot(data, r)
116+
}
117+
67118
type AssetDownloadParams struct {
68119
// Matrix content URL (mxc:// or localmxc://) for the asset to download.
69120
URL string `json:"url,required"`
@@ -77,3 +128,21 @@ func (r AssetDownloadParams) MarshalJSON() (data []byte, err error) {
77128
func (r *AssetDownloadParams) UnmarshalJSON(data []byte) error {
78129
return apijson.UnmarshalRoot(data, r)
79130
}
131+
132+
type AssetUploadParams struct {
133+
// Base64-encoded file content (max ~500MB decoded)
134+
Content string `json:"content,required"`
135+
// Original filename. Generated if omitted
136+
FileName param.Opt[string] `json:"fileName,omitzero"`
137+
// MIME type. Auto-detected from magic bytes if omitted
138+
MimeType param.Opt[string] `json:"mimeType,omitzero"`
139+
paramObj
140+
}
141+
142+
func (r AssetUploadParams) MarshalJSON() (data []byte, err error) {
143+
type shadow AssetUploadParams
144+
return param.MarshalObject(r, (*shadow)(&r))
145+
}
146+
func (r *AssetUploadParams) UnmarshalJSON(data []byte) error {
147+
return apijson.UnmarshalRoot(data, r)
148+
}

asset_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,29 @@ func TestAssetDownload(t *testing.T) {
3636
t.Fatalf("err should be nil: %s", err.Error())
3737
}
3838
}
39+
40+
func TestAssetUploadWithOptionalParams(t *testing.T) {
41+
baseURL := "http://localhost:4010"
42+
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
43+
baseURL = envURL
44+
}
45+
if !testutil.CheckTestServer(t, baseURL) {
46+
return
47+
}
48+
client := beeperdesktopapi.NewClient(
49+
option.WithBaseURL(baseURL),
50+
option.WithAccessToken("My Access Token"),
51+
)
52+
_, err := client.Assets.Upload(context.TODO(), beeperdesktopapi.AssetUploadParams{
53+
Content: "x",
54+
FileName: beeperdesktopapi.String("fileName"),
55+
MimeType: beeperdesktopapi.String("mimeType"),
56+
})
57+
if err != nil {
58+
var apierr *beeperdesktopapi.Error
59+
if errors.As(err, &apierr) {
60+
t.Log(string(apierr.DumpRequest(true)))
61+
}
62+
t.Fatalf("err should be nil: %s", err.Error())
63+
}
64+
}

beeperdesktopapi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func (r *FocusParams) UnmarshalJSON(data []byte) error {
121121
}
122122

123123
type SearchParams struct {
124-
// User-typed search text. Literal word matching (NOT semantic).
124+
// User-typed search text. Literal word matching (non-semantic).
125125
Query string `query:"query,required" json:"-"`
126126
paramObj
127127
}

chat.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,44 +141,41 @@ type Chat struct {
141141
Network string `json:"network,required"`
142142
// Chat participants information.
143143
Participants ChatParticipants `json:"participants,required"`
144+
// Display title of the chat as computed by the client/server.
145+
Title string `json:"title,required"`
144146
// Chat type: 'single' for direct messages, 'group' for group chats.
145147
//
146148
// Any of "single", "group".
147149
Type ChatType `json:"type,required"`
148150
// Number of unread messages.
149151
UnreadCount int64 `json:"unreadCount,required"`
150-
// Description of the chat.
151-
Description string `json:"description,nullable"`
152152
// True if chat is archived.
153153
IsArchived bool `json:"isArchived"`
154-
// True if the chat is muted.
154+
// True if chat notifications are muted.
155155
IsMuted bool `json:"isMuted"`
156-
// True if the chat is pinned.
156+
// True if chat is pinned.
157157
IsPinned bool `json:"isPinned"`
158158
// Timestamp of last activity.
159159
LastActivity time.Time `json:"lastActivity" format:"date-time"`
160160
// Last read message sortKey.
161161
LastReadMessageSortKey string `json:"lastReadMessageSortKey"`
162162
// Local chat ID specific to this Beeper Desktop installation.
163163
LocalChatID string `json:"localChatID,nullable"`
164-
// Display title of the chat.
165-
Title string `json:"title,nullable"`
166164
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
167165
JSON struct {
168166
ID respjson.Field
169167
AccountID respjson.Field
170168
Network respjson.Field
171169
Participants respjson.Field
170+
Title respjson.Field
172171
Type respjson.Field
173172
UnreadCount respjson.Field
174-
Description respjson.Field
175173
IsArchived respjson.Field
176174
IsMuted respjson.Field
177175
IsPinned respjson.Field
178176
LastActivity respjson.Field
179177
LastReadMessageSortKey respjson.Field
180178
LocalChatID respjson.Field
181-
Title respjson.Field
182179
ExtraFields map[string]respjson.Field
183180
raw string
184181
} `json:"-"`

chat_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func TestChatListWithOptionalParams(t *testing.T) {
8383
option.WithAccessToken("My Access Token"),
8484
)
8585
_, err := client.Chats.List(context.TODO(), beeperdesktopapi.ChatListParams{
86-
AccountIDs: []string{"whatsapp", "local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc", "local-instagram_ba_eRfQMmnSNy_p7Ih7HL7RduRpKFU"},
86+
AccountIDs: []string{"local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc", "local-instagram_ba_eRfQMmnSNy_p7Ih7HL7RduRpKFU"},
8787
Cursor: beeperdesktopapi.String("1725489123456|c29tZUltc2dQYWdl"),
8888
Direction: beeperdesktopapi.ChatListParamsDirectionBefore,
8989
})

0 commit comments

Comments
 (0)