Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.14.0"
".": "0.14.1"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 51
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-8a6175a75caa75c3de5400edf97a34e526ac3f62c63955375437461581deb0c2.yml
openapi_spec_hash: 1a880e4ce337a0e44630e6d87ef5162a
config_hash: 49c2ff978aaa5ccb4ce324a72f116010
configured_endpoints: 57
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-936db268b3dcae5d64bd5d590506d8134304ffcbf67389eb9b1555b3febfd4cb.yml
openapi_spec_hash: 145485087adf1b28c052bacb4df68462
config_hash: 15cd063f8e308686ac71bf9ee9634625
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.14.1 (2025-10-07)

Full Changelog: [v0.14.0...v0.14.1](https://github.com/onkernel/kernel-go-sdk/compare/v0.14.0...v0.14.1)

### Features

* WIP browser extensions ([22323cd](https://github.com/onkernel/kernel-go-sdk/commit/22323cdf2376bf2016cf1ebd1384f4c1b5ca6752))

## 0.14.0 (2025-10-03)

Full Changelog: [v0.13.0...v0.14.0](https://github.com/onkernel/kernel-go-sdk/compare/v0.13.0...v0.14.0)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->

```sh
go get -u 'github.com/onkernel/kernel-go-sdk@v0.14.0'
go get -u 'github.com/onkernel/kernel-go-sdk@v0.14.1'
```

<!-- x-release-please-end -->
Expand Down
16 changes: 16 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Methods:
- <code title="get /browsers">client.Browsers.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#BrowserService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#BrowserListResponse">BrowserListResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="delete /browsers">client.Browsers.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#BrowserService.Delete">Delete</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/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#BrowserDeleteParams">BrowserDeleteParams</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
- <code title="delete /browsers/{id}">client.Browsers.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#BrowserService.DeleteByID">DeleteByID</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
- <code title="post /browsers/{id}/extensions">client.Browsers.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#BrowserService.UploadExtensions">UploadExtensions</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#BrowserUploadExtensionsParams">BrowserUploadExtensionsParams</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>

## Replays

Expand Down Expand Up @@ -175,3 +176,18 @@ Methods:
- <code title="get /proxies/{id}">client.Proxies.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ProxyService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ProxyGetResponse">ProxyGetResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /proxies">client.Proxies.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ProxyService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ProxyListResponse">ProxyListResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="delete /proxies/{id}">client.Proxies.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ProxyService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>

# Extensions

Response Types:

- <a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionListResponse">ExtensionListResponse</a>
- <a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionUploadResponse">ExtensionUploadResponse</a>

Methods:

- <code title="get /extensions">client.Extensions.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionListResponse">ExtensionListResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="delete /extensions/{id_or_name}">client.Extensions.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, idOrName <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
- <code title="get /extensions/{id_or_name}">client.Extensions.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionService.Download">Download</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, idOrName <a href="https://pkg.go.dev/builtin#string">string</a>) (http.Response, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /extensions/from_chrome_store">client.Extensions.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionService.DownloadFromChromeStore">DownloadFromChromeStore</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/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionDownloadFromChromeStoreParams">ExtensionDownloadFromChromeStoreParams</a>) (http.Response, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /extensions">client.Extensions.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionService.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/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionUploadParams">ExtensionUploadParams</a>) (<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/onkernel/kernel-go-sdk#ExtensionUploadResponse">ExtensionUploadResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
81 changes: 81 additions & 0 deletions browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
package kernel

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"slices"
"time"

"github.com/onkernel/kernel-go-sdk/internal/apiform"
"github.com/onkernel/kernel-go-sdk/internal/apijson"
"github.com/onkernel/kernel-go-sdk/internal/apiquery"
"github.com/onkernel/kernel-go-sdk/internal/requestconfig"
Expand Down Expand Up @@ -97,6 +101,20 @@ func (r *BrowserService) DeleteByID(ctx context.Context, id string, opts ...opti
return
}

// Loads one or more unpacked extensions and restarts Chromium on the browser
// instance.
func (r *BrowserService) UploadExtensions(ctx context.Context, id string, body BrowserUploadExtensionsParams, 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/extensions", id)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
return
}

// Optional persistence configuration for the browser session.
type BrowserPersistence struct {
// Unique identifier for the persistent browser session.
Expand Down Expand Up @@ -325,6 +343,8 @@ type BrowserNewParams struct {
// seconds, so the actual timeout behavior you will see is +/- 5 seconds around the
// specified value.
TimeoutSeconds param.Opt[int64] `json:"timeout_seconds,omitzero"`
// List of browser extensions to load into the session. Provide each by id or name.
Extensions []BrowserNewParamsExtension `json:"extensions,omitzero"`
// Optional persistence configuration for the browser session.
Persistence BrowserPersistenceParam `json:"persistence,omitzero"`
// Profile selection for the browser session. Provide either id or name. If
Expand All @@ -342,6 +362,25 @@ func (r *BrowserNewParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}

// Extension selection for the browser session. Provide either id or name of an
// extension uploaded to Kernel.
type BrowserNewParamsExtension struct {
// Extension ID to load for this browser session
ID param.Opt[string] `json:"id,omitzero"`
// Extension name to load for this browser session (instead of id). Must be 1-255
// characters, using letters, numbers, dots, underscores, or hyphens.
Name param.Opt[string] `json:"name,omitzero"`
paramObj
}

func (r BrowserNewParamsExtension) MarshalJSON() (data []byte, err error) {
type shadow BrowserNewParamsExtension
return param.MarshalObject(r, (*shadow)(&r))
}
func (r *BrowserNewParamsExtension) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}

// Profile selection for the browser session. Provide either id or name. If
// specified, the matching profile will be loaded into the browser session.
// Profiles must be created beforehand.
Expand Down Expand Up @@ -378,3 +417,45 @@ func (r BrowserDeleteParams) URLQuery() (v url.Values, err error) {
NestedFormat: apiquery.NestedQueryFormatBrackets,
})
}

type BrowserUploadExtensionsParams struct {
// List of extensions to upload and activate
Extensions []BrowserUploadExtensionsParamsExtension `json:"extensions,omitzero,required"`
paramObj
}

func (r BrowserUploadExtensionsParams) 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
}

// The properties Name, ZipFile are required.
type BrowserUploadExtensionsParamsExtension struct {
// Folder name to place the extension under /home/kernel/extensions/<name>
Name string `json:"name,required"`
// Zip archive containing an unpacked Chromium extension (must include
// manifest.json)
ZipFile io.Reader `json:"zip_file,omitzero,required" format:"binary"`
paramObj
}

func (r BrowserUploadExtensionsParamsExtension) MarshalJSON() (data []byte, err error) {
type shadow BrowserUploadExtensionsParamsExtension
return param.MarshalObject(r, (*shadow)(&r))
}
func (r *BrowserUploadExtensionsParamsExtension) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
38 changes: 38 additions & 0 deletions browser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
package kernel_test

import (
"bytes"
"context"
"errors"
"io"
"os"
"testing"

Expand All @@ -27,6 +29,10 @@ func TestBrowserNewWithOptionalParams(t *testing.T) {
option.WithAPIKey("My API Key"),
)
_, err := client.Browsers.New(context.TODO(), kernel.BrowserNewParams{
Extensions: []kernel.BrowserNewParamsExtension{{
ID: kernel.String("id"),
Name: kernel.String("name"),
}},
Headless: kernel.Bool(false),
InvocationID: kernel.String("rr33xuugxj9h0bkf1rdt2bet"),
Persistence: kernel.BrowserPersistenceParam{
Expand Down Expand Up @@ -143,3 +149,35 @@ func TestBrowserDeleteByID(t *testing.T) {
t.Fatalf("err should be nil: %s", err.Error())
}
}

func TestBrowserUploadExtensions(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.UploadExtensions(
context.TODO(),
"id",
kernel.BrowserUploadExtensionsParams{
Extensions: []kernel.BrowserUploadExtensionsParamsExtension{{
Name: "name",
ZipFile: io.Reader(bytes.NewBuffer([]byte("some file contents"))),
}},
},
)
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())
}
}
2 changes: 2 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Client struct {
Browsers BrowserService
Profiles ProfileService
Proxies ProxyService
Extensions ExtensionService
}

// DefaultClientOptions read from the environment (KERNEL_API_KEY,
Expand Down Expand Up @@ -53,6 +54,7 @@ func NewClient(opts ...option.RequestOption) (r Client) {
r.Browsers = NewBrowserService(opts...)
r.Profiles = NewProfileService(opts...)
r.Proxies = NewProxyService(opts...)
r.Extensions = NewExtensionService(opts...)

return
}
Expand Down
Loading