@@ -38,9 +38,10 @@ type clientConfig struct {
3838}
3939
4040type apiClient struct {
41- opts clientOptions
42- defaults clientDefaults
43- http * http.Client
41+ opts clientOptions
42+ defaults clientDefaults
43+ http * http.Client
44+ correlationID string
4445}
4546
4647type clientDefaults struct {
@@ -71,6 +72,8 @@ func client(args []string) error {
7172 return c .whoami (rest [1 :])
7273 case "status" :
7374 return c .status (rest [1 :])
75+ case "canary" :
76+ return c .canary (rest [1 :])
7477 case "workspaces" :
7578 return c .workspaces (rest [1 :])
7679 case "channels" :
@@ -161,27 +164,39 @@ func (c apiClient) withOptions(opts clientOptions, useStoredToken bool) apiClien
161164}
162165
163166func (c apiClient ) currentUser () (store.User , error ) {
167+ return c .currentUserContext (context .Background ())
168+ }
169+
170+ func (c apiClient ) currentUserContext (ctx context.Context ) (store.User , error ) {
164171 var result struct {
165172 User store.User `json:"user"`
166173 }
167- if err := c .get ( "/api/me" , & result ); err != nil {
174+ if err := c .doJSON ( ctx , http . MethodGet , "/api/me" , nil , & result ); err != nil {
168175 return store.User {}, err
169176 }
170177 return result .User , nil
171178}
172179
173180func (c apiClient ) listWorkspaces () ([]store.Workspace , error ) {
181+ return c .listWorkspacesContext (context .Background ())
182+ }
183+
184+ func (c apiClient ) listWorkspacesContext (ctx context.Context ) ([]store.Workspace , error ) {
174185 var result struct {
175186 Workspaces []store.Workspace `json:"workspaces"`
176187 }
177- if err := c .get ( "/api/workspaces" , & result ); err != nil {
188+ if err := c .doJSON ( ctx , http . MethodGet , "/api/workspaces" , nil , & result ); err != nil {
178189 return nil , err
179190 }
180191 return result .Workspaces , nil
181192}
182193
183194func (c apiClient ) resolveWorkspace () (store.Workspace , error ) {
184- items , err := c .listWorkspaces ()
195+ return c .resolveWorkspaceContext (context .Background ())
196+ }
197+
198+ func (c apiClient ) resolveWorkspaceContext (ctx context.Context ) (store.Workspace , error ) {
199+ items , err := c .listWorkspacesContext (ctx )
185200 if err != nil {
186201 return store.Workspace {}, err
187202 }
@@ -201,24 +216,32 @@ func (c apiClient) resolveWorkspace() (store.Workspace, error) {
201216}
202217
203218func (c apiClient ) listChannels (workspaceID string ) ([]store.Channel , error ) {
219+ return c .listChannelsContext (context .Background (), workspaceID )
220+ }
221+
222+ func (c apiClient ) listChannelsContext (ctx context.Context , workspaceID string ) ([]store.Channel , error ) {
204223 var result struct {
205224 Channels []store.Channel `json:"channels"`
206225 }
207- if err := c .get ( "/api/workspaces/" + url .PathEscape (workspaceID )+ "/channels" , & result ); err != nil {
226+ if err := c .doJSON ( ctx , http . MethodGet , "/api/workspaces/" + url .PathEscape (workspaceID )+ "/channels" , nil , & result ); err != nil {
208227 return nil , err
209228 }
210229 return result .Channels , nil
211230}
212231
213232func (c apiClient ) resolveChannel () (store.Channel , error ) {
233+ return c .resolveChannelContext (context .Background ())
234+ }
235+
236+ func (c apiClient ) resolveChannelContext (ctx context.Context ) (store.Channel , error ) {
214237 needle := strings .TrimSpace (c .opts .Channel )
215238 if strings .HasPrefix (needle , "chn_" ) {
216- workspaces , err := c .channelSearchWorkspaces ( )
239+ workspaces , err := c .channelSearchWorkspacesContext ( ctx )
217240 if err != nil {
218241 return store.Channel {}, err
219242 }
220243 for _ , workspace := range workspaces {
221- items , err := c .listChannels ( workspace .ID )
244+ items , err := c .listChannelsContext ( ctx , workspace .ID )
222245 if err != nil {
223246 return store.Channel {}, err
224247 }
@@ -230,11 +253,11 @@ func (c apiClient) resolveChannel() (store.Channel, error) {
230253 }
231254 return store.Channel {}, fmt .Errorf ("channel %q not found" , needle )
232255 }
233- workspace , err := c .resolveWorkspace ( )
256+ workspace , err := c .resolveWorkspaceContext ( ctx )
234257 if err != nil {
235258 return store.Channel {}, err
236259 }
237- items , err := c .listChannels ( workspace .ID )
260+ items , err := c .listChannelsContext ( ctx , workspace .ID )
238261 if err != nil {
239262 return store.Channel {}, err
240263 }
@@ -257,15 +280,15 @@ func (c apiClient) resolveChannel() (store.Channel, error) {
257280 return store.Channel {}, fmt .Errorf ("channel %q not found" , needle )
258281}
259282
260- func (c apiClient ) channelSearchWorkspaces ( ) ([]store.Workspace , error ) {
283+ func (c apiClient ) channelSearchWorkspacesContext ( ctx context. Context ) ([]store.Workspace , error ) {
261284 if strings .TrimSpace (c .opts .Workspace ) != "" {
262- workspace , err := c .resolveWorkspace ( )
285+ workspace , err := c .resolveWorkspaceContext ( ctx )
263286 if err != nil {
264287 return nil , err
265288 }
266289 return []store.Workspace {workspace }, nil
267290 }
268- return c .listWorkspaces ( )
291+ return c .listWorkspacesContext ( ctx )
269292}
270293
271294func (c apiClient ) get (path string , out any ) error {
@@ -290,6 +313,9 @@ func (c apiClient) doJSON(ctx context.Context, method, path string, body any, ou
290313 if c .opts .UserID != "" {
291314 req .Header .Set ("X-ClickClack-User" , c .opts .UserID )
292315 }
316+ if c .correlationID != "" {
317+ req .Header .Set ("X-Correlation-ID" , c .correlationID )
318+ }
293319 resp , err := c .http .Do (req )
294320 if err != nil {
295321 return err
0 commit comments