hookdeck-cli 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/.github/workflows/publish-npm.yml +19 -0
  2. package/.github/workflows/release.yml +85 -0
  3. package/.goreleaser/linux.yml +68 -0
  4. package/.goreleaser/mac.yml +69 -0
  5. package/.goreleaser/windows.yml +52 -0
  6. package/.tool-versions +1 -0
  7. package/Dockerfile +5 -0
  8. package/LICENSE +202 -0
  9. package/README.md +223 -0
  10. package/docs/cli-demo.gif +0 -0
  11. package/go.mod +58 -0
  12. package/go.sum +444 -0
  13. package/main.go +22 -0
  14. package/package.json +30 -0
  15. package/pkg/ansi/ansi.go +208 -0
  16. package/pkg/ansi/init_windows.go +23 -0
  17. package/pkg/cmd/completion.go +128 -0
  18. package/pkg/cmd/listen.go +114 -0
  19. package/pkg/cmd/login.go +37 -0
  20. package/pkg/cmd/logout.go +35 -0
  21. package/pkg/cmd/root.go +112 -0
  22. package/pkg/cmd/version.go +25 -0
  23. package/pkg/cmd/whoami.go +50 -0
  24. package/pkg/config/config.go +326 -0
  25. package/pkg/config/config_test.go +20 -0
  26. package/pkg/config/profile.go +296 -0
  27. package/pkg/config/profile_test.go +109 -0
  28. package/pkg/hookdeck/client.go +210 -0
  29. package/pkg/hookdeck/client_test.go +203 -0
  30. package/pkg/hookdeck/connections.go +61 -0
  31. package/pkg/hookdeck/destinations.go +14 -0
  32. package/pkg/hookdeck/guest.go +37 -0
  33. package/pkg/hookdeck/session.go +37 -0
  34. package/pkg/hookdeck/sources.go +73 -0
  35. package/pkg/hookdeck/telemetry.go +84 -0
  36. package/pkg/hookdeck/telemetry_test.go +35 -0
  37. package/pkg/hookdeck/verbosetransport.go +82 -0
  38. package/pkg/hookdeck/verbosetransport_test.go +47 -0
  39. package/pkg/listen/connection.go +91 -0
  40. package/pkg/listen/listen.go +140 -0
  41. package/pkg/listen/source.go +84 -0
  42. package/pkg/login/client_login.go +209 -0
  43. package/pkg/login/interactive_login.go +180 -0
  44. package/pkg/login/login_message.go +24 -0
  45. package/pkg/login/poll.go +78 -0
  46. package/pkg/login/validate.go +52 -0
  47. package/pkg/logout/logout.go +48 -0
  48. package/pkg/open/open.go +50 -0
  49. package/pkg/proxy/proxy.go +433 -0
  50. package/pkg/useragent/uname_unix.go +25 -0
  51. package/pkg/useragent/uname_unix_test.go +24 -0
  52. package/pkg/useragent/uname_windows.go +9 -0
  53. package/pkg/useragent/useragent.go +74 -0
  54. package/pkg/validators/cmds.go +71 -0
  55. package/pkg/validators/validate.go +144 -0
  56. package/pkg/version/version.go +58 -0
  57. package/pkg/version/version_test.go +15 -0
  58. package/pkg/websocket/attempt_messages.go +47 -0
  59. package/pkg/websocket/client.go +525 -0
  60. package/pkg/websocket/connection_messages.go +11 -0
  61. package/pkg/websocket/messages.go +64 -0
@@ -0,0 +1,109 @@
1
+ package config
2
+
3
+ import (
4
+ "fmt"
5
+ "io/ioutil"
6
+ "os"
7
+ "path/filepath"
8
+ "testing"
9
+
10
+ "github.com/spf13/viper"
11
+ "github.com/stretchr/testify/require"
12
+ )
13
+
14
+ func TestWriteProfile(t *testing.T) {
15
+ profilesFile := filepath.Join(os.TempDir(), "hookdeck", "config.toml")
16
+ p := Profile{
17
+ DeviceName: "st-testing",
18
+ ProfileName: "tests",
19
+ APIKey: "sk_test_123",
20
+ DisplayName: "test-account-display-name",
21
+ }
22
+
23
+ c := &Config{
24
+ Color: "auto",
25
+ LogLevel: "info",
26
+ Profile: p,
27
+ ProfilesFile: profilesFile,
28
+ }
29
+ c.InitConfig()
30
+
31
+ v := viper.New()
32
+
33
+ fmt.Println(profilesFile)
34
+
35
+ err := p.writeProfile(v)
36
+ require.NoError(t, err)
37
+
38
+ require.FileExists(t, c.ProfilesFile)
39
+
40
+ configValues := helperLoadBytes(t, c.ProfilesFile)
41
+ expectedConfig := `
42
+ [tests]
43
+ api_key = "sk_test_123"
44
+ device_name = "st-testing"
45
+ display_name = "test-account-display-name"
46
+ `
47
+ require.EqualValues(t, expectedConfig, string(configValues))
48
+
49
+ cleanUp(c.ProfilesFile)
50
+ }
51
+
52
+ func TestWriteProfilesMerge(t *testing.T) {
53
+ profilesFile := filepath.Join(os.TempDir(), "hookdeck", "config.toml")
54
+ p := Profile{
55
+ ProfileName: "tests",
56
+ DeviceName: "st-testing",
57
+ APIKey: "sk_test_123",
58
+ DisplayName: "test-account-display-name",
59
+ }
60
+
61
+ c := &Config{
62
+ Color: "auto",
63
+ LogLevel: "info",
64
+ Profile: p,
65
+ ProfilesFile: profilesFile,
66
+ }
67
+ c.InitConfig()
68
+
69
+ v := viper.New()
70
+ writeErr := p.writeProfile(v)
71
+
72
+ require.NoError(t, writeErr)
73
+ require.FileExists(t, c.ProfilesFile)
74
+
75
+ p.ProfileName = "tests-merge"
76
+ writeErrTwo := p.writeProfile(v)
77
+ require.NoError(t, writeErrTwo)
78
+ require.FileExists(t, c.ProfilesFile)
79
+
80
+ configValues := helperLoadBytes(t, c.ProfilesFile)
81
+ expectedConfig := `
82
+ [tests]
83
+ api_key = "sk_test_123"
84
+ device_name = "st-testing"
85
+ display_name = "test-account-display-name"
86
+
87
+ [tests-merge]
88
+ api_key = "sk_test_123"
89
+ device_name = "st-testing"
90
+ display_name = "test-account-display-name"
91
+ `
92
+
93
+ require.EqualValues(t, expectedConfig, string(configValues))
94
+
95
+ cleanUp(c.ProfilesFile)
96
+ }
97
+
98
+ func helperLoadBytes(t *testing.T, name string) []byte {
99
+ bytes, err := ioutil.ReadFile(name)
100
+ if err != nil {
101
+ t.Fatal(err)
102
+ }
103
+
104
+ return bytes
105
+ }
106
+
107
+ func cleanUp(file string) {
108
+ os.Remove(file)
109
+ }
@@ -0,0 +1,210 @@
1
+ package hookdeck
2
+
3
+ import (
4
+ "bytes"
5
+ "context"
6
+ "encoding/json"
7
+ "fmt"
8
+ "io/ioutil"
9
+ "net"
10
+ "net/http"
11
+ "net/url"
12
+ "os"
13
+ "time"
14
+
15
+ "github.com/hookdeck/hookdeck-cli/pkg/useragent"
16
+ )
17
+
18
+ // DefaultAPIBaseURL is the default base URL for API requests
19
+ const DefaultAPIBaseURL = "https://api.hookdeck.com"
20
+
21
+ // DefaultDashboardURL is the default base URL for web links
22
+ const DefaultDashboardURL = "https://dashboard.hookdeck.com"
23
+
24
+ // DefaultDashboardBaseURL is the default base URL for dashboard requests
25
+ const DefaultDashboardBaseURL = "http://dashboard.hookdeck.com"
26
+
27
+ const DefaultConsoleBaseURL = "http://console.hookdeck.com"
28
+
29
+ const DefaultWebsocektURL = "wss://ws.hookdeck.com"
30
+
31
+ // Client is the API client used to sent requests to Hookdeck.
32
+ type Client struct {
33
+ // The base URL (protocol + hostname) used for all requests sent by this
34
+ // client.
35
+ BaseURL *url.URL
36
+
37
+ // API key used to authenticate requests sent by this client. If left
38
+ // empty, the `Authorization` header will be omitted.
39
+ APIKey string
40
+
41
+ // When this is enabled, request and response headers will be printed to
42
+ // stdout.
43
+ Verbose bool
44
+
45
+ // Cached HTTP client, lazily created the first time the Client is used to
46
+ // send a request.
47
+ httpClient *http.Client
48
+ }
49
+
50
+ type ErrorResponse struct {
51
+ Handled bool `json:"Handled"`
52
+ Message string `json:"message"`
53
+ }
54
+
55
+ // PerformRequest sends a request to Hookdeck and returns the response.
56
+ func (c *Client) PerformRequest(ctx context.Context, req *http.Request) (*http.Response, error) {
57
+ if req.Header == nil {
58
+ req.Header = http.Header{}
59
+ }
60
+ req.Header.Set("Content-Type", "application/json")
61
+ req.Header.Set("User-Agent", useragent.GetEncodedUserAgent())
62
+ req.Header.Set("X-Hookdeck-Client-User-Agent", useragent.GetEncodedHookdeckUserAgent())
63
+
64
+ if !telemetryOptedOut(os.Getenv("HOOKDECK_CLI_TELEMETRY_OPTOUT")) {
65
+ telemetryHdr, err := getTelemetryHeader()
66
+ if err == nil {
67
+ req.Header.Set("Hookdeck-CLI-Telemetry", telemetryHdr)
68
+ }
69
+ }
70
+
71
+ if c.APIKey != "" {
72
+ req.SetBasicAuth(c.APIKey, "")
73
+ }
74
+
75
+ if c.httpClient == nil {
76
+ c.httpClient = newHTTPClient(c.Verbose, os.Getenv("HOOKDECK_CLI_UNIX_SOCKET"))
77
+ }
78
+
79
+ if ctx != nil {
80
+ req = req.WithContext(ctx)
81
+ }
82
+
83
+ resp, err := c.httpClient.Do(req)
84
+ if err != nil {
85
+ return nil, err
86
+ }
87
+
88
+ err = checkAndPrintError(resp)
89
+ if err != nil {
90
+ return nil, err
91
+ }
92
+
93
+ return resp, nil
94
+ }
95
+
96
+ func (c *Client) Get(ctx context.Context, path string, params string, configure func(*http.Request)) (*http.Response, error) {
97
+ url, err := url.Parse(path)
98
+ if err != nil {
99
+ return nil, err
100
+ }
101
+
102
+ url = c.BaseURL.ResolveReference(url)
103
+
104
+ url.RawQuery = params
105
+
106
+ req, err := http.NewRequest(http.MethodGet, url.String(), nil)
107
+ if err != nil {
108
+ return nil, err
109
+ }
110
+
111
+ return c.PerformRequest(ctx, req)
112
+ }
113
+
114
+ func (c *Client) Post(ctx context.Context, path string, data []byte, configure func(*http.Request)) (*http.Response, error) {
115
+ url, err := url.Parse(path)
116
+ if err != nil {
117
+ return nil, err
118
+ }
119
+ url = c.BaseURL.ResolveReference(url)
120
+ req, err := http.NewRequest(http.MethodPost, url.String(), bytes.NewBuffer(data))
121
+ if err != nil {
122
+ return nil, err
123
+ }
124
+
125
+ return c.PerformRequest(ctx, req)
126
+ }
127
+
128
+ func (c *Client) Put(ctx context.Context, path string, data []byte, configure func(*http.Request)) (*http.Response, error) {
129
+ url, err := url.Parse(path)
130
+ if err != nil {
131
+ return nil, err
132
+ }
133
+ url = c.BaseURL.ResolveReference(url)
134
+ req, err := http.NewRequest(http.MethodPut, url.String(), bytes.NewBuffer(data))
135
+ if err != nil {
136
+ return nil, err
137
+ }
138
+
139
+ return c.PerformRequest(ctx, req)
140
+ }
141
+
142
+ func checkAndPrintError(res *http.Response) error {
143
+ if res.StatusCode != http.StatusOK {
144
+ defer res.Body.Close()
145
+ body, err := ioutil.ReadAll(res.Body)
146
+ if err != nil {
147
+ return err
148
+ }
149
+ response := &ErrorResponse{}
150
+ err = json.Unmarshal(body, &response)
151
+ if err != nil {
152
+ // Not a valid JSON response, just use body
153
+ return fmt.Errorf("unexpected http status code: %d %s", res.StatusCode, body)
154
+ }
155
+ if response.Message != "" {
156
+ return fmt.Errorf("error: %s", response.Message)
157
+ }
158
+ return fmt.Errorf("unexpected http status code: %d %s", res.StatusCode, body)
159
+ }
160
+ return nil
161
+ }
162
+
163
+ func postprocessJsonResponse(res *http.Response, target interface{}) (interface{}, error) {
164
+ defer res.Body.Close()
165
+ body, err := ioutil.ReadAll(res.Body)
166
+ if err != nil {
167
+ return nil, err
168
+ }
169
+ err = json.Unmarshal(body, target)
170
+ return target, err
171
+ }
172
+
173
+ func newHTTPClient(verbose bool, unixSocket string) *http.Client {
174
+ var httpTransport *http.Transport
175
+
176
+ if unixSocket != "" {
177
+ dialFunc := func(network, addr string) (net.Conn, error) {
178
+ return net.Dial("unix", unixSocket)
179
+ }
180
+ dialContext := func(_ context.Context, _, _ string) (net.Conn, error) {
181
+ return net.Dial("unix", unixSocket)
182
+ }
183
+ httpTransport = &http.Transport{
184
+ DialContext: dialContext,
185
+ DialTLS: dialFunc,
186
+ ResponseHeaderTimeout: 30 * time.Second,
187
+ ExpectContinueTimeout: 10 * time.Second,
188
+ TLSHandshakeTimeout: 10 * time.Second,
189
+ }
190
+ } else {
191
+ httpTransport = &http.Transport{
192
+ Proxy: http.ProxyFromEnvironment,
193
+ DialContext: (&net.Dialer{
194
+ Timeout: 30 * time.Second,
195
+ KeepAlive: 30 * time.Second,
196
+ }).DialContext,
197
+ TLSHandshakeTimeout: 10 * time.Second,
198
+ }
199
+ }
200
+
201
+ tr := &verboseTransport{
202
+ Transport: httpTransport,
203
+ Verbose: verbose,
204
+ Out: os.Stderr,
205
+ }
206
+
207
+ return &http.Client{
208
+ Transport: tr,
209
+ }
210
+ }
@@ -0,0 +1,203 @@
1
+ package hookdeck
2
+
3
+ import (
4
+ "context"
5
+ "io"
6
+ "io/ioutil"
7
+ "net/http"
8
+ "net/http/httptest"
9
+ "net/url"
10
+ "strings"
11
+ "testing"
12
+
13
+ "github.com/stretchr/testify/require"
14
+ )
15
+
16
+ func TestPerformRequest_ParamsEncoding_Delete(t *testing.T) {
17
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18
+ require.Equal(t, "/delete", r.URL.Path)
19
+ require.Equal(t, "key_a=value_a&key_b=value_b", r.URL.RawQuery)
20
+
21
+ body, err := ioutil.ReadAll(r.Body)
22
+ require.NoError(t, err)
23
+ require.Equal(t, "", string(body))
24
+ }))
25
+ defer ts.Close()
26
+
27
+ baseURL, _ := url.Parse(ts.URL)
28
+ client := Client{
29
+ BaseURL: baseURL,
30
+ }
31
+
32
+ params := url.Values{}
33
+ params.Add("key_a", "value_a")
34
+ params.Add("key_b", "value_b")
35
+
36
+ req := &http.Request{
37
+ Method: http.MethodDelete,
38
+ URL: &url.URL{
39
+ Scheme: baseURL.Scheme,
40
+ Host: baseURL.Host,
41
+ Path: "/delete",
42
+ RawQuery: params.Encode(),
43
+ },
44
+ }
45
+ resp, err := client.PerformRequest(context.TODO(), req)
46
+ require.NoError(t, err)
47
+
48
+ defer resp.Body.Close()
49
+ }
50
+
51
+ func TestPerformRequest_ParamsEncoding_Get(t *testing.T) {
52
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
53
+ require.Equal(t, "/get", r.URL.Path)
54
+ require.Equal(t, "key_a=value_a&key_b=value_b", r.URL.RawQuery)
55
+
56
+ body, err := ioutil.ReadAll(r.Body)
57
+ require.NoError(t, err)
58
+ require.Equal(t, "", string(body))
59
+ }))
60
+ defer ts.Close()
61
+
62
+ baseURL, _ := url.Parse(ts.URL)
63
+ client := Client{
64
+ BaseURL: baseURL,
65
+ }
66
+
67
+ params := url.Values{}
68
+ params.Add("key_a", "value_a")
69
+ params.Add("key_b", "value_b")
70
+
71
+ req := &http.Request{
72
+ Method: http.MethodGet,
73
+ URL: &url.URL{
74
+ Scheme: baseURL.Scheme,
75
+ Host: baseURL.Host,
76
+ Path: "/get",
77
+ RawQuery: params.Encode(),
78
+ },
79
+ }
80
+
81
+ resp, err := client.PerformRequest(context.TODO(), req)
82
+ require.NoError(t, err)
83
+
84
+ defer resp.Body.Close()
85
+ }
86
+
87
+ func TestPerformRequest_ParamsEncoding_Post(t *testing.T) {
88
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
89
+ require.Equal(t, "/post", r.URL.Path)
90
+ require.Equal(t, "", r.URL.RawQuery)
91
+
92
+ body, err := ioutil.ReadAll(r.Body)
93
+ require.NoError(t, err)
94
+ require.Equal(t, "key_a=value_a&key_b=value_b", string(body))
95
+ }))
96
+ defer ts.Close()
97
+
98
+ baseURL, _ := url.Parse(ts.URL)
99
+ client := Client{
100
+ BaseURL: baseURL,
101
+ }
102
+
103
+ params := url.Values{}
104
+ params.Add("key_a", "value_a")
105
+ params.Add("key_b", "value_b")
106
+
107
+ req := &http.Request{
108
+ Method: http.MethodPost,
109
+ URL: &url.URL{
110
+ Scheme: baseURL.Scheme,
111
+ Host: baseURL.Host,
112
+ Path: "/post",
113
+ },
114
+ Body: io.NopCloser(strings.NewReader(params.Encode())),
115
+ }
116
+
117
+ resp, err := client.PerformRequest(context.TODO(), req)
118
+ require.NoError(t, err)
119
+
120
+ defer resp.Body.Close()
121
+ }
122
+
123
+ func TestPerformRequest_ApiKey_Provided(t *testing.T) {
124
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
125
+ require.Equal(t, "Basic c2tfdGVzdF8xMjM0Og==", r.Header.Get("Authorization"))
126
+ }))
127
+ defer ts.Close()
128
+
129
+ baseURL, _ := url.Parse(ts.URL)
130
+ client := Client{
131
+ BaseURL: baseURL,
132
+ APIKey: "sk_test_1234",
133
+ }
134
+
135
+ req := &http.Request{
136
+ Method: http.MethodGet,
137
+ URL: &url.URL{
138
+ Scheme: baseURL.Scheme,
139
+ Host: baseURL.Host,
140
+ Path: "/get",
141
+ },
142
+ }
143
+
144
+ resp, err := client.PerformRequest(context.TODO(), req)
145
+ require.NoError(t, err)
146
+
147
+ defer resp.Body.Close()
148
+ }
149
+
150
+ func TestPerformRequest_ApiKey_Omitted(t *testing.T) {
151
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
152
+ require.Equal(t, "", r.Header.Get("Authorization"))
153
+ }))
154
+ defer ts.Close()
155
+
156
+ baseURL, _ := url.Parse(ts.URL)
157
+ client := Client{
158
+ BaseURL: baseURL,
159
+ }
160
+
161
+ req := &http.Request{
162
+ Method: http.MethodGet,
163
+ URL: &url.URL{
164
+ Scheme: baseURL.Scheme,
165
+ Host: baseURL.Host,
166
+ Path: "/get",
167
+ },
168
+ }
169
+
170
+ resp, err := client.PerformRequest(context.TODO(), req)
171
+ require.NoError(t, err)
172
+
173
+ defer resp.Body.Close()
174
+ }
175
+
176
+ func TestPerformRequest_ConfigureFunc(t *testing.T) {
177
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
178
+ require.Equal(t, "2019-07-10", r.Header.Get("Hookdeck-Version"))
179
+ }))
180
+ defer ts.Close()
181
+
182
+ baseURL, _ := url.Parse(ts.URL)
183
+ client := Client{
184
+ BaseURL: baseURL,
185
+ }
186
+
187
+ req := &http.Request{
188
+ Method: http.MethodGet,
189
+ Header: http.Header{
190
+ "Hookdeck-Version": []string{"2019-07-10"},
191
+ },
192
+ URL: &url.URL{
193
+ Scheme: baseURL.Scheme,
194
+ Host: baseURL.Host,
195
+ Path: "/get",
196
+ },
197
+ }
198
+
199
+ resp, err := client.PerformRequest(context.TODO(), req)
200
+ require.NoError(t, err)
201
+
202
+ defer resp.Body.Close()
203
+ }
@@ -0,0 +1,61 @@
1
+ package hookdeck
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+ "fmt"
7
+ "io/ioutil"
8
+ "net/http"
9
+ )
10
+
11
+ type Connection struct {
12
+ Id string
13
+ Alias string
14
+ Label string
15
+ Destination Destination
16
+ }
17
+
18
+ type CreateConnectionInput struct {
19
+ Alias string `json:"alias"`
20
+ Label string `json:"label"`
21
+ SourceId string `json:"source_id"`
22
+ Destination CreateDestinationInput `json:"destination"`
23
+ }
24
+
25
+ type ConnectionList struct {
26
+ Count int
27
+ Models []Connection
28
+ }
29
+
30
+ func (c *Client) ListConnectionsBySource(source_id string) ([]Connection, error) {
31
+ res, err := c.Get(context.Background(), "/connections", "source_id="+source_id, nil)
32
+ if err != nil {
33
+ return []Connection{}, err
34
+ }
35
+ if res.StatusCode != http.StatusOK {
36
+ return []Connection{}, fmt.Errorf("unexpected http status code: %d %s", res.StatusCode, err)
37
+ }
38
+ sources := ConnectionList{}
39
+ postprocessJsonResponse(res, &sources)
40
+
41
+ return sources.Models, nil
42
+ }
43
+
44
+ func (c *Client) CreateConnection(input CreateConnectionInput) (Connection, error) {
45
+ input_bytes, err := json.Marshal(input)
46
+ if err != nil {
47
+ return Connection{}, err
48
+ }
49
+ res, err := c.Post(context.Background(), "/connections", input_bytes, nil)
50
+ if err != nil {
51
+ return Connection{}, err
52
+ }
53
+ if res.StatusCode != http.StatusOK {
54
+ defer res.Body.Close()
55
+ body, _ := ioutil.ReadAll(res.Body)
56
+ return Connection{}, fmt.Errorf("Unexpected http status code: %d %s", res.StatusCode, string(body))
57
+ }
58
+ source := Connection{}
59
+ postprocessJsonResponse(res, &source)
60
+ return source, nil
61
+ }
@@ -0,0 +1,14 @@
1
+ package hookdeck
2
+
3
+ type Destination struct {
4
+ Id string `json:"id"`
5
+ Alias string `json:"alias"`
6
+ Label string `json:"label"`
7
+ CliPath string `json:"cli_path"`
8
+ }
9
+
10
+ type CreateDestinationInput struct {
11
+ Alias string `json:"alias"`
12
+ Label string `json:"label"`
13
+ CliPath string `json:"cli_path"`
14
+ }
@@ -0,0 +1,37 @@
1
+ package hookdeck
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+ "fmt"
7
+ "net/http"
8
+ )
9
+
10
+ type GuestUser struct {
11
+ Id string `json:"id"`
12
+ APIKey string `json:"key"`
13
+ Url string `json:"link"`
14
+ BrowserURL string `json:"browser_url"`
15
+ PollURL string `json:"poll_url"`
16
+ }
17
+
18
+ type CreateGuestUserInput struct {
19
+ DeviceName string `json:"device_name"`
20
+ }
21
+
22
+ func (c *Client) CreateGuestUser(input CreateGuestUserInput) (GuestUser, error) {
23
+ input_bytes, err := json.Marshal(input)
24
+ if err != nil {
25
+ return GuestUser{}, err
26
+ }
27
+ res, err := c.Post(context.Background(), "/cli/guest", input_bytes, nil)
28
+ if err != nil {
29
+ return GuestUser{}, err
30
+ }
31
+ if res.StatusCode != http.StatusOK {
32
+ return GuestUser{}, fmt.Errorf("unexpected http status code: %d %s", res.StatusCode, err)
33
+ }
34
+ guest_user := GuestUser{}
35
+ postprocessJsonResponse(res, &guest_user)
36
+ return guest_user, nil
37
+ }
@@ -0,0 +1,37 @@
1
+ package hookdeck
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+ "fmt"
7
+ "io/ioutil"
8
+ "net/http"
9
+ )
10
+
11
+ type Session struct {
12
+ Id string
13
+ }
14
+
15
+ type CreateSessionInput struct {
16
+ SourceId string `json:"source_id"`
17
+ ConnectionIds []string `json:"webhook_ids"`
18
+ }
19
+
20
+ func (c *Client) CreateSession(input CreateSessionInput) (Session, error) {
21
+ input_bytes, err := json.Marshal(input)
22
+ if err != nil {
23
+ return Session{}, err
24
+ }
25
+ res, err := c.Post(context.Background(), "/cli-sessions", input_bytes, nil)
26
+ if err != nil {
27
+ return Session{}, err
28
+ }
29
+ if res.StatusCode != http.StatusOK {
30
+ defer res.Body.Close()
31
+ body, _ := ioutil.ReadAll(res.Body)
32
+ return Session{}, fmt.Errorf("Unexpected http status code: %d %s", res.StatusCode, string(body))
33
+ }
34
+ session := Session{}
35
+ postprocessJsonResponse(res, &session)
36
+ return session, nil
37
+ }