From 5e04228a5fdd20381b24b230c64e65761a444300 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 16 Oct 2025 20:31:09 +0000
Subject: [PATCH 1/3] feat: Phani/deploy with GitHub url
---
.stats.yml | 6 +--
README.md | 9 ++--
api.md | 6 +--
deployment.go | 70 ++++++++++++++++++++++++++++--
deployment_test.go | 21 ++++++---
extension.go | 104 ++++++++++++++++++++++-----------------------
extension_test.go | 102 ++++++++++++++++++++++----------------------
7 files changed, 195 insertions(+), 123 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 6bb4af8..2bd40cc 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 57
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-6c765f1c4ce1c4dd4ceb371f56bf047aa79af36031ba43cbd68fa16a5fdb9bb3.yml
-openapi_spec_hash: e9086f69281360f4e0895c9274a59531
-config_hash: deadfc4d2b0a947673bcf559b5db6e1b
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-6eaa6f5654abc94549962d7db1e8c7936af1f815bb3abe2f8249959394da1278.yml
+openapi_spec_hash: 31ece7cd801e74228b80a8112a762e56
+config_hash: 3fc2057ce765bc5f27785a694ed0f553
diff --git a/README.md b/README.md
index 6d5b4dd..ce6e3e1 100644
--- a/README.md
+++ b/README.md
@@ -391,20 +391,17 @@ which can be used to wrap any `io.Reader` with the appropriate file name and con
// A file from the file system
file, err := os.Open("/path/to/file")
kernel.DeploymentNewParams{
- EntrypointRelPath: "src/app.py",
- File: file,
+ File: file,
}
// A file from a string
kernel.DeploymentNewParams{
- EntrypointRelPath: "src/app.py",
- File: strings.NewReader("my file contents"),
+ File: strings.NewReader("my file contents"),
}
// With a custom filename and contentType
kernel.DeploymentNewParams{
- EntrypointRelPath: "src/app.py",
- File: kernel.File(strings.NewReader(`{"hello": "foo"}`), "file.go", "application/json"),
+ File: kernel.File(strings.NewReader(`{"hello": "foo"}`), "file.go", "application/json"),
}
```
diff --git a/api.md b/api.md
index 9c71da3..9f88845 100644
--- a/api.md
+++ b/api.md
@@ -181,13 +181,13 @@ Methods:
Response Types:
+- kernel.ExtensionNewResponse
- kernel.ExtensionListResponse
-- kernel.ExtensionUploadResponse
Methods:
+- client.Extensions.New(ctx context.Context, body kernel.ExtensionNewParams) (kernel.ExtensionNewResponse, error)
+- client.Extensions.Get(ctx context.Context, idOrName string) (http.Response, error)
- client.Extensions.List(ctx context.Context) ([]kernel.ExtensionListResponse, error)
- client.Extensions.Delete(ctx context.Context, idOrName string) error
-- client.Extensions.Download(ctx context.Context, idOrName string) (http.Response, error)
- client.Extensions.DownloadFromChromeStore(ctx context.Context, query kernel.ExtensionDownloadFromChromeStoreParams) (http.Response, error)
-- client.Extensions.Upload(ctx context.Context, body kernel.ExtensionUploadParams) (kernel.ExtensionUploadResponse, error)
diff --git a/deployment.go b/deployment.go
index c6d4779..7feea55 100644
--- a/deployment.go
+++ b/deployment.go
@@ -449,9 +449,7 @@ func (r *DeploymentFollowResponseAppVersionSummaryEvent) UnmarshalJSON(data []by
type DeploymentNewParams struct {
// Relative path to the entrypoint of the application
- EntrypointRelPath string `json:"entrypoint_rel_path,required"`
- // ZIP file containing the application source directory
- File io.Reader `json:"file,omitzero,required" format:"binary"`
+ EntrypointRelPath param.Opt[string] `json:"entrypoint_rel_path,omitzero"`
// Allow overwriting an existing app version
Force param.Opt[bool] `json:"force,omitzero"`
// Version of the application. Can be any string.
@@ -459,10 +457,14 @@ type DeploymentNewParams struct {
// Map of environment variables to set for the deployed application. Each key-value
// pair represents an environment variable.
EnvVars map[string]string `json:"env_vars,omitzero"`
+ // ZIP file containing the application source directory
+ File io.Reader `json:"file,omitzero" format:"binary"`
// Region for deployment. Currently we only support "aws.us-east-1a"
//
// Any of "aws.us-east-1a".
Region DeploymentNewParamsRegion `json:"region,omitzero"`
+ // Source from which to fetch application code.
+ Source DeploymentNewParamsSource `json:"source,omitzero"`
paramObj
}
@@ -491,6 +493,68 @@ const (
DeploymentNewParamsRegionAwsUsEast1a DeploymentNewParamsRegion = "aws.us-east-1a"
)
+// Source from which to fetch application code.
+//
+// The properties Entrypoint, Ref, Type, URL are required.
+type DeploymentNewParamsSource struct {
+ // Relative path to the application entrypoint within the selected path.
+ Entrypoint string `json:"entrypoint,required"`
+ // Git ref (branch, tag, or commit SHA) to fetch.
+ Ref string `json:"ref,required"`
+ // Source type identifier.
+ //
+ // Any of "github".
+ Type string `json:"type,omitzero,required"`
+ // Base repository URL (without blob/tree suffixes).
+ URL string `json:"url,required"`
+ // Path within the repo to deploy (omit to use repo root).
+ Path param.Opt[string] `json:"path,omitzero"`
+ // Authentication for private repositories.
+ Auth DeploymentNewParamsSourceAuth `json:"auth,omitzero"`
+ paramObj
+}
+
+func (r DeploymentNewParamsSource) MarshalJSON() (data []byte, err error) {
+ type shadow DeploymentNewParamsSource
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *DeploymentNewParamsSource) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func init() {
+ apijson.RegisterFieldValidator[DeploymentNewParamsSource](
+ "type", "github",
+ )
+}
+
+// Authentication for private repositories.
+//
+// The properties Token, Method are required.
+type DeploymentNewParamsSourceAuth struct {
+ // GitHub PAT or installation access token
+ Token string `json:"token,required" format:"password"`
+ // Auth method
+ //
+ // Any of "github_token".
+ Method string `json:"method,omitzero,required"`
+ paramObj
+}
+
+func (r DeploymentNewParamsSourceAuth) MarshalJSON() (data []byte, err error) {
+ type shadow DeploymentNewParamsSourceAuth
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *DeploymentNewParamsSourceAuth) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func init() {
+ apijson.RegisterFieldValidator[DeploymentNewParamsSourceAuth](
+ "method", "github_token",
+ )
+}
+
type DeploymentListParams struct {
// Filter results by application name.
AppName param.Opt[string] `query:"app_name,omitzero" json:"-"`
diff --git a/deployment_test.go b/deployment_test.go
index 81715eb..5472dfb 100644
--- a/deployment_test.go
+++ b/deployment_test.go
@@ -29,13 +29,24 @@ func TestDeploymentNewWithOptionalParams(t *testing.T) {
option.WithAPIKey("My API Key"),
)
_, err := client.Deployments.New(context.TODO(), kernel.DeploymentNewParams{
- EntrypointRelPath: "src/app.py",
- File: io.Reader(bytes.NewBuffer([]byte("some file contents"))),
+ EntrypointRelPath: kernel.String("src/app.py"),
EnvVars: map[string]string{
- "foo": "string",
+ "FOO": "bar",
+ },
+ File: io.Reader(bytes.NewBuffer([]byte("some file contents"))),
+ Force: kernel.Bool(false),
+ Region: kernel.DeploymentNewParamsRegionAwsUsEast1a,
+ Source: kernel.DeploymentNewParamsSource{
+ Entrypoint: "src/index.ts",
+ Ref: "main",
+ Type: "github",
+ URL: "https://github.com/org/repo",
+ Auth: kernel.DeploymentNewParamsSourceAuth{
+ Token: "ghs_***",
+ Method: "github_token",
+ },
+ Path: kernel.String("apps/api"),
},
- Force: kernel.Bool(false),
- Region: kernel.DeploymentNewParamsRegionAwsUsEast1a,
Version: kernel.String("1.0.0"),
})
if err != nil {
diff --git a/extension.go b/extension.go
index 204b126..b1af774 100644
--- a/extension.go
+++ b/extension.go
@@ -42,37 +42,46 @@ func NewExtensionService(opts ...option.RequestOption) (r ExtensionService) {
return
}
-// List extensions owned by the caller's organization.
-func (r *ExtensionService) List(ctx context.Context, opts ...option.RequestOption) (res *[]ExtensionListResponse, err error) {
+// Upload a zip file containing an unpacked browser extension. Optionally provide a
+// unique name for later reference.
+func (r *ExtensionService) New(ctx context.Context, body ExtensionNewParams, opts ...option.RequestOption) (res *ExtensionNewResponse, err error) {
opts = slices.Concat(r.Options, opts)
path := "extensions"
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
return
}
-// Delete an extension by its ID or by its name.
-func (r *ExtensionService) Delete(ctx context.Context, idOrName string, opts ...option.RequestOption) (err error) {
+// Download the extension as a ZIP archive by ID or name.
+func (r *ExtensionService) Get(ctx context.Context, idOrName string, opts ...option.RequestOption) (res *http.Response, err error) {
opts = slices.Concat(r.Options, opts)
- opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "application/octet-stream")}, opts...)
if idOrName == "" {
err = errors.New("missing required id_or_name parameter")
return
}
path := fmt.Sprintf("extensions/%s", idOrName)
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}
-// Download the extension as a ZIP archive by ID or name.
-func (r *ExtensionService) Download(ctx context.Context, idOrName string, opts ...option.RequestOption) (res *http.Response, err error) {
+// List extensions owned by the caller's organization.
+func (r *ExtensionService) List(ctx context.Context, opts ...option.RequestOption) (res *[]ExtensionListResponse, err error) {
opts = slices.Concat(r.Options, opts)
- opts = append([]option.RequestOption{option.WithHeader("Accept", "application/octet-stream")}, opts...)
+ path := "extensions"
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ return
+}
+
+// Delete an extension by its ID or by its name.
+func (r *ExtensionService) Delete(ctx context.Context, idOrName string, opts ...option.RequestOption) (err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
if idOrName == "" {
err = errors.New("missing required id_or_name parameter")
return
}
path := fmt.Sprintf("extensions/%s", idOrName)
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...)
return
}
@@ -86,17 +95,8 @@ func (r *ExtensionService) DownloadFromChromeStore(ctx context.Context, query Ex
return
}
-// Upload a zip file containing an unpacked browser extension. Optionally provide a
-// unique name for later reference.
-func (r *ExtensionService) Upload(ctx context.Context, body ExtensionUploadParams, opts ...option.RequestOption) (res *ExtensionUploadResponse, err error) {
- opts = slices.Concat(r.Options, opts)
- path := "extensions"
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
- return
-}
-
// A browser extension uploaded to Kernel.
-type ExtensionListResponse struct {
+type ExtensionNewResponse struct {
// Unique identifier for the extension
ID string `json:"id,required"`
// Timestamp when the extension was created
@@ -121,13 +121,13 @@ type ExtensionListResponse struct {
}
// Returns the unmodified JSON received from the API
-func (r ExtensionListResponse) RawJSON() string { return r.JSON.raw }
-func (r *ExtensionListResponse) UnmarshalJSON(data []byte) error {
+func (r ExtensionNewResponse) RawJSON() string { return r.JSON.raw }
+func (r *ExtensionNewResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
// A browser extension uploaded to Kernel.
-type ExtensionUploadResponse struct {
+type ExtensionListResponse struct {
// Unique identifier for the extension
ID string `json:"id,required"`
// Timestamp when the extension was created
@@ -152,11 +152,37 @@ type ExtensionUploadResponse struct {
}
// Returns the unmodified JSON received from the API
-func (r ExtensionUploadResponse) RawJSON() string { return r.JSON.raw }
-func (r *ExtensionUploadResponse) UnmarshalJSON(data []byte) error {
+func (r ExtensionListResponse) RawJSON() string { return r.JSON.raw }
+func (r *ExtensionListResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+type ExtensionNewParams struct {
+ // ZIP file containing the browser extension.
+ File io.Reader `json:"file,omitzero,required" format:"binary"`
+ // Optional unique name within the organization to reference this extension.
+ Name param.Opt[string] `json:"name,omitzero"`
+ paramObj
+}
+
+func (r ExtensionNewParams) MarshalMultipart() (data []byte, contentType string, err error) {
+ buf := bytes.NewBuffer(nil)
+ writer := multipart.NewWriter(buf)
+ err = apiform.MarshalRoot(r, writer)
+ if err == nil {
+ err = apiform.WriteExtras(writer, r.ExtraFields())
+ }
+ if err != nil {
+ writer.Close()
+ return nil, "", err
+ }
+ err = writer.Close()
+ if err != nil {
+ return nil, "", err
+ }
+ return buf.Bytes(), writer.FormDataContentType(), nil
+}
+
type ExtensionDownloadFromChromeStoreParams struct {
// Chrome Web Store URL for the extension.
URL string `query:"url,required" json:"-"`
@@ -184,29 +210,3 @@ const (
ExtensionDownloadFromChromeStoreParamsOsMac ExtensionDownloadFromChromeStoreParamsOs = "mac"
ExtensionDownloadFromChromeStoreParamsOsLinux ExtensionDownloadFromChromeStoreParamsOs = "linux"
)
-
-type ExtensionUploadParams struct {
- // ZIP file containing the browser extension.
- File io.Reader `json:"file,omitzero,required" format:"binary"`
- // Optional unique name within the organization to reference this extension.
- Name param.Opt[string] `json:"name,omitzero"`
- paramObj
-}
-
-func (r ExtensionUploadParams) MarshalMultipart() (data []byte, contentType string, err error) {
- buf := bytes.NewBuffer(nil)
- writer := multipart.NewWriter(buf)
- err = apiform.MarshalRoot(r, writer)
- if err == nil {
- err = apiform.WriteExtras(writer, r.ExtraFields())
- }
- if err != nil {
- writer.Close()
- return nil, "", err
- }
- err = writer.Close()
- if err != nil {
- return nil, "", err
- }
- return buf.Bytes(), writer.FormDataContentType(), nil
-}
diff --git a/extension_test.go b/extension_test.go
index af2089a..2df18d2 100644
--- a/extension_test.go
+++ b/extension_test.go
@@ -17,7 +17,7 @@ import (
"github.com/onkernel/kernel-go-sdk/option"
)
-func TestExtensionList(t *testing.T) {
+func TestExtensionNewWithOptionalParams(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
@@ -30,7 +30,10 @@ func TestExtensionList(t *testing.T) {
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
- _, err := client.Extensions.List(context.TODO())
+ _, err := client.Extensions.New(context.TODO(), kernel.ExtensionNewParams{
+ File: io.Reader(bytes.NewBuffer([]byte("some file contents"))),
+ Name: kernel.String("name"),
+ })
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
@@ -40,20 +43,18 @@ func TestExtensionList(t *testing.T) {
}
}
-func TestExtensionDelete(t *testing.T) {
- t.Skip("Prism tests are disabled")
- baseURL := "http://localhost:4010"
- if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
- baseURL = envURL
- }
- if !testutil.CheckTestServer(t, baseURL) {
- return
- }
+func TestExtensionGet(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(200)
+ w.Write([]byte("abc"))
+ }))
+ defer server.Close()
+ baseURL := server.URL
client := kernel.NewClient(
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
- err := client.Extensions.Delete(context.TODO(), "id_or_name")
+ resp, err := client.Extensions.Get(context.TODO(), "id_or_name")
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
@@ -61,20 +62,35 @@ func TestExtensionDelete(t *testing.T) {
}
t.Fatalf("err should be nil: %s", err.Error())
}
+ defer resp.Body.Close()
+
+ b, err := io.ReadAll(resp.Body)
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+ if !bytes.Equal(b, []byte("abc")) {
+ t.Fatalf("return value not %s: %s", "abc", b)
+ }
}
-func TestExtensionDownload(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(200)
- w.Write([]byte("abc"))
- }))
- defer server.Close()
- baseURL := server.URL
+func TestExtensionList(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
client := kernel.NewClient(
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
- resp, err := client.Extensions.Download(context.TODO(), "id_or_name")
+ _, err := client.Extensions.List(context.TODO())
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
@@ -82,9 +98,22 @@ func TestExtensionDownload(t *testing.T) {
}
t.Fatalf("err should be nil: %s", err.Error())
}
- defer resp.Body.Close()
+}
- b, err := io.ReadAll(resp.Body)
+func TestExtensionDelete(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ err := client.Extensions.Delete(context.TODO(), "id_or_name")
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
@@ -92,9 +121,6 @@ func TestExtensionDownload(t *testing.T) {
}
t.Fatalf("err should be nil: %s", err.Error())
}
- if !bytes.Equal(b, []byte("abc")) {
- t.Fatalf("return value not %s: %s", "abc", b)
- }
}
func TestExtensionDownloadFromChromeStoreWithOptionalParams(t *testing.T) {
@@ -133,29 +159,3 @@ func TestExtensionDownloadFromChromeStoreWithOptionalParams(t *testing.T) {
t.Fatalf("return value not %s: %s", "abc", b)
}
}
-
-func TestExtensionUploadWithOptionalParams(t *testing.T) {
- t.Skip("Prism tests are disabled")
- baseURL := "http://localhost:4010"
- if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
- baseURL = envURL
- }
- if !testutil.CheckTestServer(t, baseURL) {
- return
- }
- client := kernel.NewClient(
- option.WithBaseURL(baseURL),
- option.WithAPIKey("My API Key"),
- )
- _, err := client.Extensions.Upload(context.TODO(), kernel.ExtensionUploadParams{
- File: io.Reader(bytes.NewBuffer([]byte("some file contents"))),
- Name: kernel.String("name"),
- })
- if err != nil {
- var apierr *kernel.Error
- if errors.As(err, &apierr) {
- t.Log(string(apierr.DumpRequest(true)))
- }
- t.Fatalf("err should be nil: %s", err.Error())
- }
-}
From b1dcdedf9662f112048d27622a787b2bacb5ac84 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 17 Oct 2025 18:33:21 +0000
Subject: [PATCH 2/3] feat: click mouse, move mouse, screenshot
---
.stats.yml | 8 +-
api.md | 18 ++-
browser.go | 12 +-
browsercomputer.go | 323 ++++++++++++++++++++++++++++++++++++++++
browsercomputer_test.go | 256 +++++++++++++++++++++++++++++++
extension.go | 104 ++++++-------
extension_test.go | 102 ++++++-------
7 files changed, 708 insertions(+), 115 deletions(-)
create mode 100644 browsercomputer.go
create mode 100644 browsercomputer_test.go
diff --git a/.stats.yml b/.stats.yml
index 2bd40cc..b4dc606 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 57
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-6eaa6f5654abc94549962d7db1e8c7936af1f815bb3abe2f8249959394da1278.yml
-openapi_spec_hash: 31ece7cd801e74228b80a8112a762e56
-config_hash: 3fc2057ce765bc5f27785a694ed0f553
+configured_endpoints: 64
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-e21f0324774a1762bc2bba0da3a8a6b0d0e74720d7a1c83dec813f9e027fcf58.yml
+openapi_spec_hash: f1b636abfd6cb8e7c2ba7ffb8e53b9ba
+config_hash: 09a2df23048cb16689c9a390d9e5bc47
diff --git a/api.md b/api.md
index 9f88845..906226c 100644
--- a/api.md
+++ b/api.md
@@ -152,6 +152,18 @@ Methods:
- client.Browsers.Logs.Stream(ctx context.Context, id string, query kernel.BrowserLogStreamParams) (shared.LogEvent, error)
+## Computer
+
+Methods:
+
+- client.Browsers.Computer.CaptureScreenshot(ctx context.Context, id string, body kernel.BrowserComputerCaptureScreenshotParams) (http.Response, error)
+- client.Browsers.Computer.ClickMouse(ctx context.Context, id string, body kernel.BrowserComputerClickMouseParams) error
+- client.Browsers.Computer.DragMouse(ctx context.Context, id string, body kernel.BrowserComputerDragMouseParams) error
+- client.Browsers.Computer.MoveMouse(ctx context.Context, id string, body kernel.BrowserComputerMoveMouseParams) error
+- client.Browsers.Computer.PressKey(ctx context.Context, id string, body kernel.BrowserComputerPressKeyParams) error
+- client.Browsers.Computer.Scroll(ctx context.Context, id string, body kernel.BrowserComputerScrollParams) error
+- client.Browsers.Computer.TypeText(ctx context.Context, id string, body kernel.BrowserComputerTypeTextParams) error
+
# Profiles
Methods:
@@ -181,13 +193,13 @@ Methods:
Response Types:
-- kernel.ExtensionNewResponse
- kernel.ExtensionListResponse
+- kernel.ExtensionUploadResponse
Methods:
-- client.Extensions.New(ctx context.Context, body kernel.ExtensionNewParams) (kernel.ExtensionNewResponse, error)
-- client.Extensions.Get(ctx context.Context, idOrName string) (http.Response, error)
- client.Extensions.List(ctx context.Context) ([]kernel.ExtensionListResponse, error)
- client.Extensions.Delete(ctx context.Context, idOrName string) error
+- client.Extensions.Download(ctx context.Context, idOrName string) (http.Response, error)
- client.Extensions.DownloadFromChromeStore(ctx context.Context, query kernel.ExtensionDownloadFromChromeStoreParams) (http.Response, error)
+- client.Extensions.Upload(ctx context.Context, body kernel.ExtensionUploadParams) (kernel.ExtensionUploadResponse, error)
diff --git a/browser.go b/browser.go
index b5b4222..6e067e8 100644
--- a/browser.go
+++ b/browser.go
@@ -31,11 +31,12 @@ import (
// automatically. You should not instantiate this service directly, and instead use
// the [NewBrowserService] method instead.
type BrowserService struct {
- Options []option.RequestOption
- Replays BrowserReplayService
- Fs BrowserFService
- Process BrowserProcessService
- Logs BrowserLogService
+ Options []option.RequestOption
+ Replays BrowserReplayService
+ Fs BrowserFService
+ Process BrowserProcessService
+ Logs BrowserLogService
+ Computer BrowserComputerService
}
// NewBrowserService generates a new service that applies the given options to each
@@ -48,6 +49,7 @@ func NewBrowserService(opts ...option.RequestOption) (r BrowserService) {
r.Fs = NewBrowserFService(opts...)
r.Process = NewBrowserProcessService(opts...)
r.Logs = NewBrowserLogService(opts...)
+ r.Computer = NewBrowserComputerService(opts...)
return
}
diff --git a/browsercomputer.go b/browsercomputer.go
new file mode 100644
index 0000000..4158a7c
--- /dev/null
+++ b/browsercomputer.go
@@ -0,0 +1,323 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "slices"
+
+ "github.com/onkernel/kernel-go-sdk/internal/apijson"
+ "github.com/onkernel/kernel-go-sdk/internal/requestconfig"
+ "github.com/onkernel/kernel-go-sdk/option"
+ "github.com/onkernel/kernel-go-sdk/packages/param"
+)
+
+// BrowserComputerService contains methods and other services that help with
+// interacting with the kernel API.
+//
+// Note, unlike clients, this service does not read variables from the environment
+// automatically. You should not instantiate this service directly, and instead use
+// the [NewBrowserComputerService] method instead.
+type BrowserComputerService struct {
+ Options []option.RequestOption
+}
+
+// NewBrowserComputerService generates a new service that applies the given options
+// to each request. These options are applied after the parent client's options (if
+// there is one), and before any request-specific options.
+func NewBrowserComputerService(opts ...option.RequestOption) (r BrowserComputerService) {
+ r = BrowserComputerService{}
+ r.Options = opts
+ return
+}
+
+// Capture a screenshot of the browser instance
+func (r *BrowserComputerService) CaptureScreenshot(ctx context.Context, id string, body BrowserComputerCaptureScreenshotParams, opts ...option.RequestOption) (res *http.Response, err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "image/png")}, opts...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return
+ }
+ path := fmt.Sprintf("browsers/%s/computer/screenshot", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
+ return
+}
+
+// Simulate a mouse click action on the browser instance
+func (r *BrowserComputerService) ClickMouse(ctx context.Context, id string, body BrowserComputerClickMouseParams, opts ...option.RequestOption) (err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return
+ }
+ path := fmt.Sprintf("browsers/%s/computer/click_mouse", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
+ return
+}
+
+// Drag the mouse along a path
+func (r *BrowserComputerService) DragMouse(ctx context.Context, id string, body BrowserComputerDragMouseParams, opts ...option.RequestOption) (err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return
+ }
+ path := fmt.Sprintf("browsers/%s/computer/drag_mouse", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
+ return
+}
+
+// Move the mouse cursor to the specified coordinates on the browser instance
+func (r *BrowserComputerService) MoveMouse(ctx context.Context, id string, body BrowserComputerMoveMouseParams, opts ...option.RequestOption) (err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return
+ }
+ path := fmt.Sprintf("browsers/%s/computer/move_mouse", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
+ return
+}
+
+// Press one or more keys on the host computer
+func (r *BrowserComputerService) PressKey(ctx context.Context, id string, body BrowserComputerPressKeyParams, opts ...option.RequestOption) (err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return
+ }
+ path := fmt.Sprintf("browsers/%s/computer/press_key", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
+ return
+}
+
+// Scroll the mouse wheel at a position on the host computer
+func (r *BrowserComputerService) Scroll(ctx context.Context, id string, body BrowserComputerScrollParams, opts ...option.RequestOption) (err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return
+ }
+ path := fmt.Sprintf("browsers/%s/computer/scroll", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
+ return
+}
+
+// Type text on the browser instance
+func (r *BrowserComputerService) TypeText(ctx context.Context, id string, body BrowserComputerTypeTextParams, opts ...option.RequestOption) (err error) {
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return
+ }
+ path := fmt.Sprintf("browsers/%s/computer/type", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
+ return
+}
+
+type BrowserComputerCaptureScreenshotParams struct {
+ Region BrowserComputerCaptureScreenshotParamsRegion `json:"region,omitzero"`
+ paramObj
+}
+
+func (r BrowserComputerCaptureScreenshotParams) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerCaptureScreenshotParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerCaptureScreenshotParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// The properties Height, Width, X, Y are required.
+type BrowserComputerCaptureScreenshotParamsRegion struct {
+ // Height of the region in pixels
+ Height int64 `json:"height,required"`
+ // Width of the region in pixels
+ Width int64 `json:"width,required"`
+ // X coordinate of the region's top-left corner
+ X int64 `json:"x,required"`
+ // Y coordinate of the region's top-left corner
+ Y int64 `json:"y,required"`
+ paramObj
+}
+
+func (r BrowserComputerCaptureScreenshotParamsRegion) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerCaptureScreenshotParamsRegion
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerCaptureScreenshotParamsRegion) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type BrowserComputerClickMouseParams struct {
+ // X coordinate of the click position
+ X int64 `json:"x,required"`
+ // Y coordinate of the click position
+ Y int64 `json:"y,required"`
+ // Number of times to repeat the click
+ NumClicks param.Opt[int64] `json:"num_clicks,omitzero"`
+ // Mouse button to interact with
+ //
+ // Any of "left", "right", "middle", "back", "forward".
+ Button BrowserComputerClickMouseParamsButton `json:"button,omitzero"`
+ // Type of click action
+ //
+ // Any of "down", "up", "click".
+ ClickType BrowserComputerClickMouseParamsClickType `json:"click_type,omitzero"`
+ // Modifier keys to hold during the click
+ HoldKeys []string `json:"hold_keys,omitzero"`
+ paramObj
+}
+
+func (r BrowserComputerClickMouseParams) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerClickMouseParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerClickMouseParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// Mouse button to interact with
+type BrowserComputerClickMouseParamsButton string
+
+const (
+ BrowserComputerClickMouseParamsButtonLeft BrowserComputerClickMouseParamsButton = "left"
+ BrowserComputerClickMouseParamsButtonRight BrowserComputerClickMouseParamsButton = "right"
+ BrowserComputerClickMouseParamsButtonMiddle BrowserComputerClickMouseParamsButton = "middle"
+ BrowserComputerClickMouseParamsButtonBack BrowserComputerClickMouseParamsButton = "back"
+ BrowserComputerClickMouseParamsButtonForward BrowserComputerClickMouseParamsButton = "forward"
+)
+
+// Type of click action
+type BrowserComputerClickMouseParamsClickType string
+
+const (
+ BrowserComputerClickMouseParamsClickTypeDown BrowserComputerClickMouseParamsClickType = "down"
+ BrowserComputerClickMouseParamsClickTypeUp BrowserComputerClickMouseParamsClickType = "up"
+ BrowserComputerClickMouseParamsClickTypeClick BrowserComputerClickMouseParamsClickType = "click"
+)
+
+type BrowserComputerDragMouseParams struct {
+ // Ordered list of [x, y] coordinate pairs to move through while dragging. Must
+ // contain at least 2 points.
+ Path [][]int64 `json:"path,omitzero,required"`
+ // Delay in milliseconds between button down and starting to move along the path.
+ Delay param.Opt[int64] `json:"delay,omitzero"`
+ // Delay in milliseconds between relative steps while dragging (not the initial
+ // delay).
+ StepDelayMs param.Opt[int64] `json:"step_delay_ms,omitzero"`
+ // Number of relative move steps per segment in the path. Minimum 1.
+ StepsPerSegment param.Opt[int64] `json:"steps_per_segment,omitzero"`
+ // Mouse button to drag with
+ //
+ // Any of "left", "middle", "right".
+ Button BrowserComputerDragMouseParamsButton `json:"button,omitzero"`
+ // Modifier keys to hold during the drag
+ HoldKeys []string `json:"hold_keys,omitzero"`
+ paramObj
+}
+
+func (r BrowserComputerDragMouseParams) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerDragMouseParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerDragMouseParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// Mouse button to drag with
+type BrowserComputerDragMouseParamsButton string
+
+const (
+ BrowserComputerDragMouseParamsButtonLeft BrowserComputerDragMouseParamsButton = "left"
+ BrowserComputerDragMouseParamsButtonMiddle BrowserComputerDragMouseParamsButton = "middle"
+ BrowserComputerDragMouseParamsButtonRight BrowserComputerDragMouseParamsButton = "right"
+)
+
+type BrowserComputerMoveMouseParams struct {
+ // X coordinate to move the cursor to
+ X int64 `json:"x,required"`
+ // Y coordinate to move the cursor to
+ Y int64 `json:"y,required"`
+ // Modifier keys to hold during the move
+ HoldKeys []string `json:"hold_keys,omitzero"`
+ paramObj
+}
+
+func (r BrowserComputerMoveMouseParams) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerMoveMouseParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerMoveMouseParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type BrowserComputerPressKeyParams struct {
+ // List of key symbols to press. Each item should be a key symbol supported by
+ // xdotool (see X11 keysym definitions). Examples include "Return", "Shift",
+ // "Ctrl", "Alt", "F5". Items in this list could also be combinations, e.g.
+ // "Ctrl+t" or "Ctrl+Shift+Tab".
+ Keys []string `json:"keys,omitzero,required"`
+ // Duration to hold the keys down in milliseconds. If omitted or 0, keys are
+ // tapped.
+ Duration param.Opt[int64] `json:"duration,omitzero"`
+ // Optional modifier keys to hold during the key press sequence.
+ HoldKeys []string `json:"hold_keys,omitzero"`
+ paramObj
+}
+
+func (r BrowserComputerPressKeyParams) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerPressKeyParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerPressKeyParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type BrowserComputerScrollParams struct {
+ // X coordinate at which to perform the scroll
+ X int64 `json:"x,required"`
+ // Y coordinate at which to perform the scroll
+ Y int64 `json:"y,required"`
+ // Horizontal scroll amount. Positive scrolls right, negative scrolls left.
+ DeltaX param.Opt[int64] `json:"delta_x,omitzero"`
+ // Vertical scroll amount. Positive scrolls down, negative scrolls up.
+ DeltaY param.Opt[int64] `json:"delta_y,omitzero"`
+ // Modifier keys to hold during the scroll
+ HoldKeys []string `json:"hold_keys,omitzero"`
+ paramObj
+}
+
+func (r BrowserComputerScrollParams) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerScrollParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerScrollParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type BrowserComputerTypeTextParams struct {
+ // Text to type on the browser instance
+ Text string `json:"text,required"`
+ // Delay in milliseconds between keystrokes
+ Delay param.Opt[int64] `json:"delay,omitzero"`
+ paramObj
+}
+
+func (r BrowserComputerTypeTextParams) MarshalJSON() (data []byte, err error) {
+ type shadow BrowserComputerTypeTextParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BrowserComputerTypeTextParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
diff --git a/browsercomputer_test.go b/browsercomputer_test.go
new file mode 100644
index 0000000..0391cd9
--- /dev/null
+++ b/browsercomputer_test.go
@@ -0,0 +1,256 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel_test
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "testing"
+
+ "github.com/onkernel/kernel-go-sdk"
+ "github.com/onkernel/kernel-go-sdk/internal/testutil"
+ "github.com/onkernel/kernel-go-sdk/option"
+)
+
+func TestBrowserComputerCaptureScreenshotWithOptionalParams(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(200)
+ w.Write([]byte("abc"))
+ }))
+ defer server.Close()
+ baseURL := server.URL
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ resp, err := client.Browsers.Computer.CaptureScreenshot(
+ context.TODO(),
+ "id",
+ kernel.BrowserComputerCaptureScreenshotParams{
+ Region: kernel.BrowserComputerCaptureScreenshotParamsRegion{
+ Height: 0,
+ Width: 0,
+ X: 0,
+ Y: 0,
+ },
+ },
+ )
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+ defer resp.Body.Close()
+
+ b, err := io.ReadAll(resp.Body)
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+ if !bytes.Equal(b, []byte("abc")) {
+ t.Fatalf("return value not %s: %s", "abc", b)
+ }
+}
+
+func TestBrowserComputerClickMouseWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ err := client.Browsers.Computer.ClickMouse(
+ context.TODO(),
+ "id",
+ kernel.BrowserComputerClickMouseParams{
+ X: 0,
+ Y: 0,
+ Button: kernel.BrowserComputerClickMouseParamsButtonLeft,
+ ClickType: kernel.BrowserComputerClickMouseParamsClickTypeDown,
+ HoldKeys: []string{"string"},
+ NumClicks: kernel.Int(0),
+ },
+ )
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
+func TestBrowserComputerDragMouseWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ err := client.Browsers.Computer.DragMouse(
+ context.TODO(),
+ "id",
+ kernel.BrowserComputerDragMouseParams{
+ Path: [][]int64{{0, 0}, {0, 0}},
+ Button: kernel.BrowserComputerDragMouseParamsButtonLeft,
+ Delay: kernel.Int(0),
+ HoldKeys: []string{"string"},
+ StepDelayMs: kernel.Int(0),
+ StepsPerSegment: kernel.Int(1),
+ },
+ )
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
+func TestBrowserComputerMoveMouseWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ err := client.Browsers.Computer.MoveMouse(
+ context.TODO(),
+ "id",
+ kernel.BrowserComputerMoveMouseParams{
+ X: 0,
+ Y: 0,
+ HoldKeys: []string{"string"},
+ },
+ )
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
+func TestBrowserComputerPressKeyWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ err := client.Browsers.Computer.PressKey(
+ context.TODO(),
+ "id",
+ kernel.BrowserComputerPressKeyParams{
+ Keys: []string{"string"},
+ Duration: kernel.Int(0),
+ HoldKeys: []string{"string"},
+ },
+ )
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
+func TestBrowserComputerScrollWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ err := client.Browsers.Computer.Scroll(
+ context.TODO(),
+ "id",
+ kernel.BrowserComputerScrollParams{
+ X: 0,
+ Y: 0,
+ DeltaX: kernel.Int(0),
+ DeltaY: kernel.Int(0),
+ HoldKeys: []string{"string"},
+ },
+ )
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
+func TestBrowserComputerTypeTextWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ err := client.Browsers.Computer.TypeText(
+ context.TODO(),
+ "id",
+ kernel.BrowserComputerTypeTextParams{
+ Text: "text",
+ Delay: kernel.Int(0),
+ },
+ )
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
diff --git a/extension.go b/extension.go
index b1af774..204b126 100644
--- a/extension.go
+++ b/extension.go
@@ -42,46 +42,37 @@ func NewExtensionService(opts ...option.RequestOption) (r ExtensionService) {
return
}
-// Upload a zip file containing an unpacked browser extension. Optionally provide a
-// unique name for later reference.
-func (r *ExtensionService) New(ctx context.Context, body ExtensionNewParams, opts ...option.RequestOption) (res *ExtensionNewResponse, err error) {
+// List extensions owned by the caller's organization.
+func (r *ExtensionService) List(ctx context.Context, opts ...option.RequestOption) (res *[]ExtensionListResponse, err error) {
opts = slices.Concat(r.Options, opts)
path := "extensions"
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}
-// Download the extension as a ZIP archive by ID or name.
-func (r *ExtensionService) Get(ctx context.Context, idOrName string, opts ...option.RequestOption) (res *http.Response, err error) {
+// Delete an extension by its ID or by its name.
+func (r *ExtensionService) Delete(ctx context.Context, idOrName string, opts ...option.RequestOption) (err error) {
opts = slices.Concat(r.Options, opts)
- opts = append([]option.RequestOption{option.WithHeader("Accept", "application/octet-stream")}, opts...)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
if idOrName == "" {
err = errors.New("missing required id_or_name parameter")
return
}
path := fmt.Sprintf("extensions/%s", idOrName)
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
- return
-}
-
-// List extensions owned by the caller's organization.
-func (r *ExtensionService) List(ctx context.Context, opts ...option.RequestOption) (res *[]ExtensionListResponse, err error) {
- opts = slices.Concat(r.Options, opts)
- path := "extensions"
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...)
return
}
-// Delete an extension by its ID or by its name.
-func (r *ExtensionService) Delete(ctx context.Context, idOrName string, opts ...option.RequestOption) (err error) {
+// Download the extension as a ZIP archive by ID or name.
+func (r *ExtensionService) Download(ctx context.Context, idOrName string, opts ...option.RequestOption) (res *http.Response, err error) {
opts = slices.Concat(r.Options, opts)
- opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "application/octet-stream")}, opts...)
if idOrName == "" {
err = errors.New("missing required id_or_name parameter")
return
}
path := fmt.Sprintf("extensions/%s", idOrName)
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}
@@ -95,8 +86,17 @@ func (r *ExtensionService) DownloadFromChromeStore(ctx context.Context, query Ex
return
}
+// Upload a zip file containing an unpacked browser extension. Optionally provide a
+// unique name for later reference.
+func (r *ExtensionService) Upload(ctx context.Context, body ExtensionUploadParams, opts ...option.RequestOption) (res *ExtensionUploadResponse, err error) {
+ opts = slices.Concat(r.Options, opts)
+ path := "extensions"
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
+ return
+}
+
// A browser extension uploaded to Kernel.
-type ExtensionNewResponse struct {
+type ExtensionListResponse struct {
// Unique identifier for the extension
ID string `json:"id,required"`
// Timestamp when the extension was created
@@ -121,13 +121,13 @@ type ExtensionNewResponse struct {
}
// Returns the unmodified JSON received from the API
-func (r ExtensionNewResponse) RawJSON() string { return r.JSON.raw }
-func (r *ExtensionNewResponse) UnmarshalJSON(data []byte) error {
+func (r ExtensionListResponse) RawJSON() string { return r.JSON.raw }
+func (r *ExtensionListResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
// A browser extension uploaded to Kernel.
-type ExtensionListResponse struct {
+type ExtensionUploadResponse struct {
// Unique identifier for the extension
ID string `json:"id,required"`
// Timestamp when the extension was created
@@ -152,37 +152,11 @@ type ExtensionListResponse struct {
}
// Returns the unmodified JSON received from the API
-func (r ExtensionListResponse) RawJSON() string { return r.JSON.raw }
-func (r *ExtensionListResponse) UnmarshalJSON(data []byte) error {
+func (r ExtensionUploadResponse) RawJSON() string { return r.JSON.raw }
+func (r *ExtensionUploadResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
-type ExtensionNewParams struct {
- // ZIP file containing the browser extension.
- File io.Reader `json:"file,omitzero,required" format:"binary"`
- // Optional unique name within the organization to reference this extension.
- Name param.Opt[string] `json:"name,omitzero"`
- paramObj
-}
-
-func (r ExtensionNewParams) MarshalMultipart() (data []byte, contentType string, err error) {
- buf := bytes.NewBuffer(nil)
- writer := multipart.NewWriter(buf)
- err = apiform.MarshalRoot(r, writer)
- if err == nil {
- err = apiform.WriteExtras(writer, r.ExtraFields())
- }
- if err != nil {
- writer.Close()
- return nil, "", err
- }
- err = writer.Close()
- if err != nil {
- return nil, "", err
- }
- return buf.Bytes(), writer.FormDataContentType(), nil
-}
-
type ExtensionDownloadFromChromeStoreParams struct {
// Chrome Web Store URL for the extension.
URL string `query:"url,required" json:"-"`
@@ -210,3 +184,29 @@ const (
ExtensionDownloadFromChromeStoreParamsOsMac ExtensionDownloadFromChromeStoreParamsOs = "mac"
ExtensionDownloadFromChromeStoreParamsOsLinux ExtensionDownloadFromChromeStoreParamsOs = "linux"
)
+
+type ExtensionUploadParams struct {
+ // ZIP file containing the browser extension.
+ File io.Reader `json:"file,omitzero,required" format:"binary"`
+ // Optional unique name within the organization to reference this extension.
+ Name param.Opt[string] `json:"name,omitzero"`
+ paramObj
+}
+
+func (r ExtensionUploadParams) MarshalMultipart() (data []byte, contentType string, err error) {
+ buf := bytes.NewBuffer(nil)
+ writer := multipart.NewWriter(buf)
+ err = apiform.MarshalRoot(r, writer)
+ if err == nil {
+ err = apiform.WriteExtras(writer, r.ExtraFields())
+ }
+ if err != nil {
+ writer.Close()
+ return nil, "", err
+ }
+ err = writer.Close()
+ if err != nil {
+ return nil, "", err
+ }
+ return buf.Bytes(), writer.FormDataContentType(), nil
+}
diff --git a/extension_test.go b/extension_test.go
index 2df18d2..af2089a 100644
--- a/extension_test.go
+++ b/extension_test.go
@@ -17,7 +17,7 @@ import (
"github.com/onkernel/kernel-go-sdk/option"
)
-func TestExtensionNewWithOptionalParams(t *testing.T) {
+func TestExtensionList(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
@@ -30,41 +30,7 @@ func TestExtensionNewWithOptionalParams(t *testing.T) {
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
- _, err := client.Extensions.New(context.TODO(), kernel.ExtensionNewParams{
- File: io.Reader(bytes.NewBuffer([]byte("some file contents"))),
- Name: kernel.String("name"),
- })
- if err != nil {
- var apierr *kernel.Error
- if errors.As(err, &apierr) {
- t.Log(string(apierr.DumpRequest(true)))
- }
- t.Fatalf("err should be nil: %s", err.Error())
- }
-}
-
-func TestExtensionGet(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(200)
- w.Write([]byte("abc"))
- }))
- defer server.Close()
- baseURL := server.URL
- client := kernel.NewClient(
- option.WithBaseURL(baseURL),
- option.WithAPIKey("My API Key"),
- )
- resp, err := client.Extensions.Get(context.TODO(), "id_or_name")
- if err != nil {
- var apierr *kernel.Error
- if errors.As(err, &apierr) {
- t.Log(string(apierr.DumpRequest(true)))
- }
- t.Fatalf("err should be nil: %s", err.Error())
- }
- defer resp.Body.Close()
-
- b, err := io.ReadAll(resp.Body)
+ _, err := client.Extensions.List(context.TODO())
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
@@ -72,12 +38,9 @@ func TestExtensionGet(t *testing.T) {
}
t.Fatalf("err should be nil: %s", err.Error())
}
- if !bytes.Equal(b, []byte("abc")) {
- t.Fatalf("return value not %s: %s", "abc", b)
- }
}
-func TestExtensionList(t *testing.T) {
+func TestExtensionDelete(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
@@ -90,7 +53,7 @@ func TestExtensionList(t *testing.T) {
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
- _, err := client.Extensions.List(context.TODO())
+ err := client.Extensions.Delete(context.TODO(), "id_or_name")
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
@@ -100,20 +63,28 @@ func TestExtensionList(t *testing.T) {
}
}
-func TestExtensionDelete(t *testing.T) {
- t.Skip("Prism tests are disabled")
- baseURL := "http://localhost:4010"
- if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
- baseURL = envURL
- }
- if !testutil.CheckTestServer(t, baseURL) {
- return
- }
+func TestExtensionDownload(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(200)
+ w.Write([]byte("abc"))
+ }))
+ defer server.Close()
+ baseURL := server.URL
client := kernel.NewClient(
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
- err := client.Extensions.Delete(context.TODO(), "id_or_name")
+ resp, err := client.Extensions.Download(context.TODO(), "id_or_name")
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+ defer resp.Body.Close()
+
+ b, err := io.ReadAll(resp.Body)
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
@@ -121,6 +92,9 @@ func TestExtensionDelete(t *testing.T) {
}
t.Fatalf("err should be nil: %s", err.Error())
}
+ if !bytes.Equal(b, []byte("abc")) {
+ t.Fatalf("return value not %s: %s", "abc", b)
+ }
}
func TestExtensionDownloadFromChromeStoreWithOptionalParams(t *testing.T) {
@@ -159,3 +133,29 @@ func TestExtensionDownloadFromChromeStoreWithOptionalParams(t *testing.T) {
t.Fatalf("return value not %s: %s", "abc", b)
}
}
+
+func TestExtensionUploadWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ _, err := client.Extensions.Upload(context.TODO(), kernel.ExtensionUploadParams{
+ File: io.Reader(bytes.NewBuffer([]byte("some file contents"))),
+ Name: kernel.String("name"),
+ })
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
From cd965956eada2de5e2e55257c66840a0b3d8c7a4 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 17 Oct 2025 18:33:38 +0000
Subject: [PATCH 3/3] release: 0.15.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 9 +++++++++
README.md | 2 +-
internal/version.go | 2 +-
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 3d26904..8f3e0a4 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.14.2"
+ ".": "0.15.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4c9f937..0155032 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## 0.15.0 (2025-10-17)
+
+Full Changelog: [v0.14.2...v0.15.0](https://github.com/onkernel/kernel-go-sdk/compare/v0.14.2...v0.15.0)
+
+### Features
+
+* click mouse, move mouse, screenshot ([b1dcded](https://github.com/onkernel/kernel-go-sdk/commit/b1dcdedf9662f112048d27622a787b2bacb5ac84))
+* Phani/deploy with GitHub url ([5e04228](https://github.com/onkernel/kernel-go-sdk/commit/5e04228a5fdd20381b24b230c64e65761a444300))
+
## 0.14.2 (2025-10-16)
Full Changelog: [v0.14.1...v0.14.2](https://github.com/onkernel/kernel-go-sdk/compare/v0.14.1...v0.14.2)
diff --git a/README.md b/README.md
index ce6e3e1..ba522c0 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Or to pin the version:
```sh
-go get -u 'github.com/onkernel/kernel-go-sdk@v0.14.2'
+go get -u 'github.com/onkernel/kernel-go-sdk@v0.15.0'
```
diff --git a/internal/version.go b/internal/version.go
index c843cf5..1f338c3 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -2,4 +2,4 @@
package internal
-const PackageVersion = "0.14.2" // x-release-please-version
+const PackageVersion = "0.15.0" // x-release-please-version