diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c18333e..0c2ecec 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.19.2" + ".": "0.20.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 53123c9..11b820d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 66 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-d611cf8b0301a07123eab0e92498bea5ad69c5292b28aca1016c362cca0a0564.yml -openapi_spec_hash: 6d30f4ad9d61a7da8a75d543cf3d3d75 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2af1b468584cb44aa9babbbfb82bff4055614fbb5c815084a6b7dacc1cf1a822.yml +openapi_spec_hash: 891affa2849341ea01d62011125f7edc config_hash: 9421eb86b7f3f4b274f123279da3858e diff --git a/CHANGELOG.md b/CHANGELOG.md index 42f8939..1e52afc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.20.0 (2025-11-19) + +Full Changelog: [v0.19.2...v0.20.0](https://github.com/onkernel/kernel-go-sdk/compare/v0.19.2...v0.20.0) + +### Features + +* Add pagination to list browsers method and allow it to include deleted browsers when `include_deleted = true` ([2bebf78](https://github.com/onkernel/kernel-go-sdk/commit/2bebf78af2a6a385743700fd8342f2c4f6efd20f)) + + +### Bug Fixes + +* **client:** correctly specify Accept header with */* instead of empty ([2a95394](https://github.com/onkernel/kernel-go-sdk/commit/2a95394194865cffa351c650924f41dc6262fce8)) + ## 0.19.2 (2025-11-17) Full Changelog: [v0.19.1...v0.19.2](https://github.com/onkernel/kernel-go-sdk/compare/v0.19.1...v0.19.2) diff --git a/README.md b/README.md index da059ee..89f902d 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.19.2' +go get -u 'github.com/onkernel/kernel-go-sdk@v0.20.0' ``` diff --git a/api.md b/api.md index f37c010..86298d1 100644 --- a/api.md +++ b/api.md @@ -72,7 +72,7 @@ Methods: - client.Browsers.New(ctx context.Context, body kernel.BrowserNewParams) (kernel.BrowserNewResponse, error) - client.Browsers.Get(ctx context.Context, id string) (kernel.BrowserGetResponse, error) -- client.Browsers.List(ctx context.Context) ([]kernel.BrowserListResponse, error) +- client.Browsers.List(ctx context.Context, query kernel.BrowserListParams) (pagination.OffsetPagination[kernel.BrowserListResponse], error) - client.Browsers.Delete(ctx context.Context, body kernel.BrowserDeleteParams) error - client.Browsers.DeleteByID(ctx context.Context, id string) error - client.Browsers.LoadExtensions(ctx context.Context, id string, body kernel.BrowserLoadExtensionsParams) error diff --git a/browser.go b/browser.go index 9b51387..a172b4d 100644 --- a/browser.go +++ b/browser.go @@ -20,6 +20,7 @@ import ( "github.com/onkernel/kernel-go-sdk/internal/apiquery" "github.com/onkernel/kernel-go-sdk/internal/requestconfig" "github.com/onkernel/kernel-go-sdk/option" + "github.com/onkernel/kernel-go-sdk/packages/pagination" "github.com/onkernel/kernel-go-sdk/packages/param" "github.com/onkernel/kernel-go-sdk/packages/respjson" ) @@ -75,18 +76,35 @@ func (r *BrowserService) Get(ctx context.Context, id string, opts ...option.Requ return } -// List active browser sessions -func (r *BrowserService) List(ctx context.Context, opts ...option.RequestOption) (res *[]BrowserListResponse, err error) { +// List all browser sessions with pagination support. Use include_deleted=true to +// include soft-deleted sessions in the results. +func (r *BrowserService) List(ctx context.Context, query BrowserListParams, opts ...option.RequestOption) (res *pagination.OffsetPagination[BrowserListResponse], err error) { + var raw *http.Response opts = slices.Concat(r.Options, opts) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) path := "browsers" - err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// List all browser sessions with pagination support. Use include_deleted=true to +// include soft-deleted sessions in the results. +func (r *BrowserService) ListAutoPaging(ctx context.Context, query BrowserListParams, opts ...option.RequestOption) *pagination.OffsetPaginationAutoPager[BrowserListResponse] { + return pagination.NewOffsetPaginationAutoPager(r.List(ctx, query, opts...)) } // Delete a persistent browser session by its persistent_id. func (r *BrowserService) Delete(ctx context.Context, body BrowserDeleteParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) path := "browsers" err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, body, nil, opts...) return @@ -95,7 +113,7 @@ func (r *BrowserService) Delete(ctx context.Context, body BrowserDeleteParams, o // Delete a browser session by ID func (r *BrowserService) DeleteByID(ctx context.Context, id string, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -109,7 +127,7 @@ func (r *BrowserService) DeleteByID(ctx context.Context, id string, opts ...opti // instance. func (r *BrowserService) LoadExtensions(ctx context.Context, id string, body BrowserLoadExtensionsParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -209,6 +227,8 @@ type BrowserNewResponse struct { // Remote URL for live viewing the browser session. Only available for non-headless // browsers. BrowserLiveViewURL string `json:"browser_live_view_url"` + // When the browser session was soft-deleted. Only present for deleted sessions. + DeletedAt time.Time `json:"deleted_at" format:"date-time"` // Whether the browser session is running in kiosk mode. KioskMode bool `json:"kiosk_mode"` // Optional persistence configuration for the browser session. @@ -235,6 +255,7 @@ type BrowserNewResponse struct { Stealth respjson.Field TimeoutSeconds respjson.Field BrowserLiveViewURL respjson.Field + DeletedAt respjson.Field KioskMode respjson.Field Persistence respjson.Field Profile respjson.Field @@ -299,6 +320,8 @@ type BrowserGetResponse struct { // Remote URL for live viewing the browser session. Only available for non-headless // browsers. BrowserLiveViewURL string `json:"browser_live_view_url"` + // When the browser session was soft-deleted. Only present for deleted sessions. + DeletedAt time.Time `json:"deleted_at" format:"date-time"` // Whether the browser session is running in kiosk mode. KioskMode bool `json:"kiosk_mode"` // Optional persistence configuration for the browser session. @@ -325,6 +348,7 @@ type BrowserGetResponse struct { Stealth respjson.Field TimeoutSeconds respjson.Field BrowserLiveViewURL respjson.Field + DeletedAt respjson.Field KioskMode respjson.Field Persistence respjson.Field Profile respjson.Field @@ -389,6 +413,8 @@ type BrowserListResponse struct { // Remote URL for live viewing the browser session. Only available for non-headless // browsers. BrowserLiveViewURL string `json:"browser_live_view_url"` + // When the browser session was soft-deleted. Only present for deleted sessions. + DeletedAt time.Time `json:"deleted_at" format:"date-time"` // Whether the browser session is running in kiosk mode. KioskMode bool `json:"kiosk_mode"` // Optional persistence configuration for the browser session. @@ -415,6 +441,7 @@ type BrowserListResponse struct { Stealth respjson.Field TimeoutSeconds respjson.Field BrowserLiveViewURL respjson.Field + DeletedAt respjson.Field KioskMode respjson.Field Persistence respjson.Field Profile respjson.Field @@ -584,6 +611,25 @@ func (r *BrowserNewParamsViewport) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) } +type BrowserListParams struct { + // When true, includes soft-deleted browser sessions in the results alongside + // active sessions. + IncludeDeleted param.Opt[bool] `query:"include_deleted,omitzero" json:"-"` + // Maximum number of results to return. Defaults to 20, maximum 100. + Limit param.Opt[int64] `query:"limit,omitzero" json:"-"` + // Number of results to skip. Defaults to 0. + Offset param.Opt[int64] `query:"offset,omitzero" json:"-"` + paramObj +} + +// URLQuery serializes [BrowserListParams]'s query parameters as `url.Values`. +func (r BrowserListParams) URLQuery() (v url.Values, err error) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatComma, + NestedFormat: apiquery.NestedQueryFormatBrackets, + }) +} + type BrowserDeleteParams struct { // Persistent browser identifier PersistentID string `query:"persistent_id,required" json:"-"` diff --git a/browser_test.go b/browser_test.go index 2ccd3ae..96377fd 100644 --- a/browser_test.go +++ b/browser_test.go @@ -85,7 +85,7 @@ func TestBrowserGet(t *testing.T) { } } -func TestBrowserList(t *testing.T) { +func TestBrowserListWithOptionalParams(t *testing.T) { t.Skip("Prism tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { @@ -98,7 +98,11 @@ func TestBrowserList(t *testing.T) { option.WithBaseURL(baseURL), option.WithAPIKey("My API Key"), ) - _, err := client.Browsers.List(context.TODO()) + _, err := client.Browsers.List(context.TODO(), kernel.BrowserListParams{ + IncludeDeleted: kernel.Bool(true), + Limit: kernel.Int(1), + Offset: kernel.Int(0), + }) if err != nil { var apierr *kernel.Error if errors.As(err, &apierr) { diff --git a/browsercomputer.go b/browsercomputer.go index 321830f..c0a9165 100644 --- a/browsercomputer.go +++ b/browsercomputer.go @@ -51,7 +51,7 @@ func (r *BrowserComputerService) CaptureScreenshot(ctx context.Context, id strin // 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -64,7 +64,7 @@ func (r *BrowserComputerService) ClickMouse(ctx context.Context, id string, body // 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -77,7 +77,7 @@ func (r *BrowserComputerService) DragMouse(ctx context.Context, id string, body // 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -90,7 +90,7 @@ func (r *BrowserComputerService) MoveMouse(ctx context.Context, id string, body // 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -103,7 +103,7 @@ func (r *BrowserComputerService) PressKey(ctx context.Context, id string, body B // 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -128,7 +128,7 @@ func (r *BrowserComputerService) SetCursorVisibility(ctx context.Context, id str // 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return diff --git a/browserf.go b/browserf.go index 330bb2a..4d1c499 100644 --- a/browserf.go +++ b/browserf.go @@ -47,7 +47,7 @@ func NewBrowserFService(opts ...option.RequestOption) (r BrowserFService) { // Create a new directory func (r *BrowserFService) NewDirectory(ctx context.Context, id string, body BrowserFNewDirectoryParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -60,7 +60,7 @@ func (r *BrowserFService) NewDirectory(ctx context.Context, id string, body Brow // Delete a directory func (r *BrowserFService) DeleteDirectory(ctx context.Context, id string, body BrowserFDeleteDirectoryParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -73,7 +73,7 @@ func (r *BrowserFService) DeleteDirectory(ctx context.Context, id string, body B // Delete a file func (r *BrowserFService) DeleteFile(ctx context.Context, id string, body BrowserFDeleteFileParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -123,7 +123,7 @@ func (r *BrowserFService) ListFiles(ctx context.Context, id string, query Browse // Move or rename a file or directory func (r *BrowserFService) Move(ctx context.Context, id string, body BrowserFMoveParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -149,7 +149,7 @@ func (r *BrowserFService) ReadFile(ctx context.Context, id string, query Browser // Set file or directory permissions/ownership func (r *BrowserFService) SetFilePermissions(ctx context.Context, id string, body BrowserFSetFilePermissionsParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -162,7 +162,7 @@ func (r *BrowserFService) SetFilePermissions(ctx context.Context, id string, bod // Allows uploading single or multiple files to the remote filesystem. func (r *BrowserFService) Upload(ctx context.Context, id string, body BrowserFUploadParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -175,7 +175,7 @@ func (r *BrowserFService) Upload(ctx context.Context, id string, body BrowserFUp // Upload a zip file and extract its contents to the specified destination path. func (r *BrowserFService) UploadZip(ctx context.Context, id string, body BrowserFUploadZipParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return @@ -188,7 +188,7 @@ func (r *BrowserFService) UploadZip(ctx context.Context, id string, body Browser // Write or create a file func (r *BrowserFService) WriteFile(ctx context.Context, id string, contents io.Reader, body BrowserFWriteFileParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", ""), option.WithRequestBody("application/octet-stream", contents)}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*"), option.WithRequestBody("application/octet-stream", contents)}, opts...) if id == "" { err = errors.New("missing required id parameter") return diff --git a/browserfwatch.go b/browserfwatch.go index a03face..d1ed5d1 100644 --- a/browserfwatch.go +++ b/browserfwatch.go @@ -72,7 +72,7 @@ func (r *BrowserFWatchService) Start(ctx context.Context, id string, body Browse // Stop watching a directory func (r *BrowserFWatchService) Stop(ctx context.Context, watchID string, body BrowserFWatchStopParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if body.ID == "" { err = errors.New("missing required id parameter") return diff --git a/browserreplay.go b/browserreplay.go index 77ac762..d90018c 100644 --- a/browserreplay.go +++ b/browserreplay.go @@ -80,7 +80,7 @@ func (r *BrowserReplayService) Start(ctx context.Context, id string, body Browse // Stop the specified replay recording and persist the video. func (r *BrowserReplayService) Stop(ctx context.Context, replayID string, body BrowserReplayStopParams, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if body.ID == "" { err = errors.New("missing required id parameter") return diff --git a/extension.go b/extension.go index 204b126..27eabe1 100644 --- a/extension.go +++ b/extension.go @@ -53,7 +53,7 @@ func (r *ExtensionService) List(ctx context.Context, opts ...option.RequestOptio // 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if idOrName == "" { err = errors.New("missing required id_or_name parameter") return diff --git a/internal/version.go b/internal/version.go index 37a9f46..6c84346 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.19.2" // x-release-please-version +const PackageVersion = "0.20.0" // x-release-please-version diff --git a/invocation.go b/invocation.go index 485508b..2fdbc66 100644 --- a/invocation.go +++ b/invocation.go @@ -104,7 +104,7 @@ func (r *InvocationService) ListAutoPaging(ctx context.Context, query Invocation // Delete all browser sessions created within the specified invocation. func (r *InvocationService) DeleteBrowsers(ctx context.Context, id string, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return diff --git a/profile.go b/profile.go index 3acf89c..1443fd1 100644 --- a/profile.go +++ b/profile.go @@ -66,7 +66,7 @@ func (r *ProfileService) List(ctx context.Context, opts ...option.RequestOption) // Delete a profile by its ID or by its name. func (r *ProfileService) 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...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if idOrName == "" { err = errors.New("missing required id_or_name parameter") return diff --git a/proxy.go b/proxy.go index 7bcc464..5d254e6 100644 --- a/proxy.go +++ b/proxy.go @@ -68,7 +68,7 @@ func (r *ProxyService) List(ctx context.Context, opts ...option.RequestOption) ( // Soft delete a proxy. Sessions referencing it are not modified. func (r *ProxyService) Delete(ctx context.Context, id string, opts ...option.RequestOption) (err error) { opts = slices.Concat(r.Options, opts) - opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") return