From 6e529727c5fc0a122df257f58a2fa3dd285f66a7 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 8 Apr 2026 13:11:57 +0000
Subject: [PATCH 1/4] feat: [kernel-1116] add base_url field to browser session
response
---
.stats.yml | 4 ++--
browser.go | 12 ++++++++++++
browserpool.go | 3 +++
invocation.go | 3 +++
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 7f48513..b81754a 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 104
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-ac10847d991ef8ed89124b5550922cb5726af2b4a4c3396ee6ff82938302fc25.yml
-openapi_spec_hash: 0d902563108fe2461708c05336eab40a
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-aee09720882ec1d78f845fee6ceecb0466c264629e4edecd3230406dd06d7983.yml
+openapi_spec_hash: 438da0d38d169897595f301d82fa7e2c
config_hash: 16e4457a0bb26e98a335a1c2a572290a
diff --git a/browser.go b/browser.go
index 87daf2e..fad1f24 100644
--- a/browser.go
+++ b/browser.go
@@ -292,6 +292,8 @@ type BrowserNewResponse struct {
TimeoutSeconds int64 `json:"timeout_seconds" api:"required"`
// Websocket URL for WebDriver BiDi connections to the browser session
WebdriverWsURL string `json:"webdriver_ws_url" api:"required"`
+ // Metro-API HTTP base URL for this browser session.
+ BaseURL string `json:"base_url"`
// Remote URL for live viewing the browser session. Only available for non-headless
// browsers.
BrowserLiveViewURL string `json:"browser_live_view_url"`
@@ -336,6 +338,7 @@ type BrowserNewResponse struct {
Stealth respjson.Field
TimeoutSeconds respjson.Field
WebdriverWsURL respjson.Field
+ BaseURL respjson.Field
BrowserLiveViewURL respjson.Field
DeletedAt respjson.Field
GPU respjson.Field
@@ -372,6 +375,8 @@ type BrowserGetResponse struct {
TimeoutSeconds int64 `json:"timeout_seconds" api:"required"`
// Websocket URL for WebDriver BiDi connections to the browser session
WebdriverWsURL string `json:"webdriver_ws_url" api:"required"`
+ // Metro-API HTTP base URL for this browser session.
+ BaseURL string `json:"base_url"`
// Remote URL for live viewing the browser session. Only available for non-headless
// browsers.
BrowserLiveViewURL string `json:"browser_live_view_url"`
@@ -416,6 +421,7 @@ type BrowserGetResponse struct {
Stealth respjson.Field
TimeoutSeconds respjson.Field
WebdriverWsURL respjson.Field
+ BaseURL respjson.Field
BrowserLiveViewURL respjson.Field
DeletedAt respjson.Field
GPU respjson.Field
@@ -452,6 +458,8 @@ type BrowserUpdateResponse struct {
TimeoutSeconds int64 `json:"timeout_seconds" api:"required"`
// Websocket URL for WebDriver BiDi connections to the browser session
WebdriverWsURL string `json:"webdriver_ws_url" api:"required"`
+ // Metro-API HTTP base URL for this browser session.
+ BaseURL string `json:"base_url"`
// Remote URL for live viewing the browser session. Only available for non-headless
// browsers.
BrowserLiveViewURL string `json:"browser_live_view_url"`
@@ -496,6 +504,7 @@ type BrowserUpdateResponse struct {
Stealth respjson.Field
TimeoutSeconds respjson.Field
WebdriverWsURL respjson.Field
+ BaseURL respjson.Field
BrowserLiveViewURL respjson.Field
DeletedAt respjson.Field
GPU respjson.Field
@@ -532,6 +541,8 @@ type BrowserListResponse struct {
TimeoutSeconds int64 `json:"timeout_seconds" api:"required"`
// Websocket URL for WebDriver BiDi connections to the browser session
WebdriverWsURL string `json:"webdriver_ws_url" api:"required"`
+ // Metro-API HTTP base URL for this browser session.
+ BaseURL string `json:"base_url"`
// Remote URL for live viewing the browser session. Only available for non-headless
// browsers.
BrowserLiveViewURL string `json:"browser_live_view_url"`
@@ -576,6 +587,7 @@ type BrowserListResponse struct {
Stealth respjson.Field
TimeoutSeconds respjson.Field
WebdriverWsURL respjson.Field
+ BaseURL respjson.Field
BrowserLiveViewURL respjson.Field
DeletedAt respjson.Field
GPU respjson.Field
diff --git a/browserpool.go b/browserpool.go
index 54ac2aa..3069e49 100644
--- a/browserpool.go
+++ b/browserpool.go
@@ -255,6 +255,8 @@ type BrowserPoolAcquireResponse struct {
TimeoutSeconds int64 `json:"timeout_seconds" api:"required"`
// Websocket URL for WebDriver BiDi connections to the browser session
WebdriverWsURL string `json:"webdriver_ws_url" api:"required"`
+ // Metro-API HTTP base URL for this browser session.
+ BaseURL string `json:"base_url"`
// Remote URL for live viewing the browser session. Only available for non-headless
// browsers.
BrowserLiveViewURL string `json:"browser_live_view_url"`
@@ -299,6 +301,7 @@ type BrowserPoolAcquireResponse struct {
Stealth respjson.Field
TimeoutSeconds respjson.Field
WebdriverWsURL respjson.Field
+ BaseURL respjson.Field
BrowserLiveViewURL respjson.Field
DeletedAt respjson.Field
GPU respjson.Field
diff --git a/invocation.go b/invocation.go
index 775dd29..872a775 100644
--- a/invocation.go
+++ b/invocation.go
@@ -552,6 +552,8 @@ type InvocationListBrowsersResponseBrowser struct {
TimeoutSeconds int64 `json:"timeout_seconds" api:"required"`
// Websocket URL for WebDriver BiDi connections to the browser session
WebdriverWsURL string `json:"webdriver_ws_url" api:"required"`
+ // Metro-API HTTP base URL for this browser session.
+ BaseURL string `json:"base_url"`
// Remote URL for live viewing the browser session. Only available for non-headless
// browsers.
BrowserLiveViewURL string `json:"browser_live_view_url"`
@@ -596,6 +598,7 @@ type InvocationListBrowsersResponseBrowser struct {
Stealth respjson.Field
TimeoutSeconds respjson.Field
WebdriverWsURL respjson.Field
+ BaseURL respjson.Field
BrowserLiveViewURL respjson.Field
DeletedAt respjson.Field
GPU respjson.Field
From a655e65c060f29512913972372cb7b12424567ba Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 8 Apr 2026 20:48:12 +0000
Subject: [PATCH 2/4] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index b81754a..d184bbd 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 104
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-aee09720882ec1d78f845fee6ceecb0466c264629e4edecd3230406dd06d7983.yml
-openapi_spec_hash: 438da0d38d169897595f301d82fa7e2c
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-49a1a92e00d1eb87e91e8527275cb0705fce2edea30e70fea745f134dd451fbd.yml
+openapi_spec_hash: 3aa6ab6939790f538332054162fbdedc
config_hash: 16e4457a0bb26e98a335a1c2a572290a
From 3e1b78f44879ed57afb128c103276a9bcf84a209 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 10 Apr 2026 02:14:24 +0000
Subject: [PATCH 3/4] chore: retrigger Stainless codegen for projects resource
---
.stats.yml | 4 +-
api.md | 34 +++++++
client.go | 3 +
project.go | 235 +++++++++++++++++++++++++++++++++++++++++++
project_test.go | 145 ++++++++++++++++++++++++++
projectlimit.go | 132 ++++++++++++++++++++++++
projectlimit_test.go | 71 +++++++++++++
7 files changed, 622 insertions(+), 2 deletions(-)
create mode 100644 project.go
create mode 100644 project_test.go
create mode 100644 projectlimit.go
create mode 100644 projectlimit_test.go
diff --git a/.stats.yml b/.stats.yml
index d184bbd..db7b03c 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 104
+configured_endpoints: 111
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-49a1a92e00d1eb87e91e8527275cb0705fce2edea30e70fea745f134dd451fbd.yml
openapi_spec_hash: 3aa6ab6939790f538332054162fbdedc
-config_hash: 16e4457a0bb26e98a335a1c2a572290a
+config_hash: 9818dd634f87b677410eefd013d7a179
diff --git a/api.md b/api.md
index 5959743..89832f0 100644
--- a/api.md
+++ b/api.md
@@ -312,6 +312,40 @@ Methods:
- client.Credentials.Delete(ctx context.Context, idOrName string) error
- client.Credentials.TotpCode(ctx context.Context, idOrName string) (\*kernel.CredentialTotpCodeResponse, error)
+# Projects
+
+Params Types:
+
+- kernel.CreateProjectRequestParam
+- kernel.UpdateProjectRequestParam
+
+Response Types:
+
+- kernel.Project
+
+Methods:
+
+- client.Projects.New(ctx context.Context, body kernel.ProjectNewParams) (\*kernel.Project, error)
+- client.Projects.Get(ctx context.Context, id string) (\*kernel.Project, error)
+- client.Projects.Update(ctx context.Context, id string, body kernel.ProjectUpdateParams) (\*kernel.Project, error)
+- client.Projects.List(ctx context.Context, query kernel.ProjectListParams) (\*pagination.OffsetPagination[kernel.Project], error)
+- client.Projects.Delete(ctx context.Context, id string) error
+
+## Limits
+
+Params Types:
+
+- kernel.UpdateProjectLimitsRequestParam
+
+Response Types:
+
+- kernel.ProjectLimits
+
+Methods:
+
+- client.Projects.Limits.Get(ctx context.Context, id string) (\*kernel.ProjectLimits, error)
+- client.Projects.Limits.Update(ctx context.Context, id string, body kernel.ProjectLimitUpdateParams) (\*kernel.ProjectLimits, error)
+
# CredentialProviders
Params Types:
diff --git a/client.go b/client.go
index e3450b2..880a657 100644
--- a/client.go
+++ b/client.go
@@ -36,6 +36,8 @@ type Client struct {
BrowserPools BrowserPoolService
// Create and manage credentials for authentication.
Credentials CredentialService
+ // Create and manage projects for resource isolation within an organization.
+ Projects ProjectService
// Configure external credential providers like 1Password.
CredentialProviders CredentialProviderService
}
@@ -72,6 +74,7 @@ func NewClient(opts ...option.RequestOption) (r Client) {
r.Extensions = NewExtensionService(opts...)
r.BrowserPools = NewBrowserPoolService(opts...)
r.Credentials = NewCredentialService(opts...)
+ r.Projects = NewProjectService(opts...)
r.CredentialProviders = NewCredentialProviderService(opts...)
return
diff --git a/project.go b/project.go
new file mode 100644
index 0000000..6163195
--- /dev/null
+++ b/project.go
@@ -0,0 +1,235 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/url"
+ "slices"
+ "time"
+
+ "github.com/kernel/kernel-go-sdk/internal/apijson"
+ "github.com/kernel/kernel-go-sdk/internal/apiquery"
+ shimjson "github.com/kernel/kernel-go-sdk/internal/encoding/json"
+ "github.com/kernel/kernel-go-sdk/internal/requestconfig"
+ "github.com/kernel/kernel-go-sdk/option"
+ "github.com/kernel/kernel-go-sdk/packages/pagination"
+ "github.com/kernel/kernel-go-sdk/packages/param"
+ "github.com/kernel/kernel-go-sdk/packages/respjson"
+)
+
+// Create and manage projects for resource isolation within an organization.
+//
+// ProjectService 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 [NewProjectService] method instead.
+type ProjectService struct {
+ Options []option.RequestOption
+ // Create and manage projects for resource isolation within an organization.
+ Limits ProjectLimitService
+}
+
+// NewProjectService 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 NewProjectService(opts ...option.RequestOption) (r ProjectService) {
+ r = ProjectService{}
+ r.Options = opts
+ r.Limits = NewProjectLimitService(opts...)
+ return
+}
+
+// Create a new project within the authenticated organization. Requires a paid plan
+// and the projects feature flag.
+func (r *ProjectService) New(ctx context.Context, body ProjectNewParams, opts ...option.RequestOption) (res *Project, err error) {
+ opts = slices.Concat(r.Options, opts)
+ path := "projects"
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
+ return res, err
+}
+
+// Get a project by ID.
+func (r *ProjectService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *Project, err error) {
+ opts = slices.Concat(r.Options, opts)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return nil, err
+ }
+ path := fmt.Sprintf("projects/%s", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ return res, err
+}
+
+// Update a project's name or status.
+func (r *ProjectService) Update(ctx context.Context, id string, body ProjectUpdateParams, opts ...option.RequestOption) (res *Project, err error) {
+ opts = slices.Concat(r.Options, opts)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return nil, err
+ }
+ path := fmt.Sprintf("projects/%s", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...)
+ return res, err
+}
+
+// List projects for the authenticated organization.
+func (r *ProjectService) List(ctx context.Context, query ProjectListParams, opts ...option.RequestOption) (res *pagination.OffsetPagination[Project], err error) {
+ var raw *http.Response
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
+ path := "projects"
+ 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 projects for the authenticated organization.
+func (r *ProjectService) ListAutoPaging(ctx context.Context, query ProjectListParams, opts ...option.RequestOption) *pagination.OffsetPaginationAutoPager[Project] {
+ return pagination.NewOffsetPaginationAutoPager(r.List(ctx, query, opts...))
+}
+
+// Soft-delete a project. The project must be empty (no active resources).
+func (r *ProjectService) 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...)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return err
+ }
+ path := fmt.Sprintf("projects/%s", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...)
+ return err
+}
+
+// The property Name is required.
+type CreateProjectRequestParam struct {
+ // Project name (1-255 characters)
+ Name string `json:"name" api:"required"`
+ paramObj
+}
+
+func (r CreateProjectRequestParam) MarshalJSON() (data []byte, err error) {
+ type shadow CreateProjectRequestParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *CreateProjectRequestParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type Project struct {
+ // Unique project identifier
+ ID string `json:"id" api:"required"`
+ // When the project was created
+ CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"`
+ // Project name
+ Name string `json:"name" api:"required"`
+ // Project status
+ //
+ // Any of "active", "archived".
+ Status ProjectStatus `json:"status" api:"required"`
+ // When the project was last updated
+ UpdatedAt time.Time `json:"updated_at" api:"required" format:"date-time"`
+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
+ JSON struct {
+ ID respjson.Field
+ CreatedAt respjson.Field
+ Name respjson.Field
+ Status respjson.Field
+ UpdatedAt respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+// Returns the unmodified JSON received from the API
+func (r Project) RawJSON() string { return r.JSON.raw }
+func (r *Project) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// Project status
+type ProjectStatus string
+
+const (
+ ProjectStatusActive ProjectStatus = "active"
+ ProjectStatusArchived ProjectStatus = "archived"
+)
+
+type UpdateProjectRequestParam struct {
+ // New project name
+ Name param.Opt[string] `json:"name,omitzero"`
+ // New project status
+ //
+ // Any of "active", "archived".
+ Status UpdateProjectRequestStatus `json:"status,omitzero"`
+ paramObj
+}
+
+func (r UpdateProjectRequestParam) MarshalJSON() (data []byte, err error) {
+ type shadow UpdateProjectRequestParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *UpdateProjectRequestParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// New project status
+type UpdateProjectRequestStatus string
+
+const (
+ UpdateProjectRequestStatusActive UpdateProjectRequestStatus = "active"
+ UpdateProjectRequestStatusArchived UpdateProjectRequestStatus = "archived"
+)
+
+type ProjectNewParams struct {
+ CreateProjectRequest CreateProjectRequestParam
+ paramObj
+}
+
+func (r ProjectNewParams) MarshalJSON() (data []byte, err error) {
+ return shimjson.Marshal(r.CreateProjectRequest)
+}
+func (r *ProjectNewParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type ProjectUpdateParams struct {
+ UpdateProjectRequest UpdateProjectRequestParam
+ paramObj
+}
+
+func (r ProjectUpdateParams) MarshalJSON() (data []byte, err error) {
+ return shimjson.Marshal(r.UpdateProjectRequest)
+}
+func (r *ProjectUpdateParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type ProjectListParams struct {
+ // Maximum number of results to return
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ // Number of results to skip
+ Offset param.Opt[int64] `query:"offset,omitzero" json:"-"`
+ paramObj
+}
+
+// URLQuery serializes [ProjectListParams]'s query parameters as `url.Values`.
+func (r ProjectListParams) URLQuery() (v url.Values, err error) {
+ return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
+ ArrayFormat: apiquery.ArrayQueryFormatComma,
+ NestedFormat: apiquery.NestedQueryFormatBrackets,
+ })
+}
diff --git a/project_test.go b/project_test.go
new file mode 100644
index 0000000..047ac95
--- /dev/null
+++ b/project_test.go
@@ -0,0 +1,145 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel_test
+
+import (
+ "context"
+ "errors"
+ "os"
+ "testing"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/internal/testutil"
+ "github.com/kernel/kernel-go-sdk/option"
+)
+
+func TestProjectNew(t *testing.T) {
+ t.Skip("Mock server 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.Projects.New(context.TODO(), kernel.ProjectNewParams{
+ CreateProjectRequest: kernel.CreateProjectRequestParam{
+ Name: "staging",
+ },
+ })
+ 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 TestProjectGet(t *testing.T) {
+ t.Skip("Mock server 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.Projects.Get(context.TODO(), "id")
+ 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 TestProjectUpdateWithOptionalParams(t *testing.T) {
+ t.Skip("Mock server 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.Projects.Update(
+ context.TODO(),
+ "id",
+ kernel.ProjectUpdateParams{
+ UpdateProjectRequest: kernel.UpdateProjectRequestParam{
+ Name: kernel.String("name"),
+ Status: kernel.UpdateProjectRequestStatusActive,
+ },
+ },
+ )
+ 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 TestProjectListWithOptionalParams(t *testing.T) {
+ t.Skip("Mock server 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.Projects.List(context.TODO(), kernel.ProjectListParams{
+ Limit: kernel.Int(100),
+ Offset: 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 TestProjectDelete(t *testing.T) {
+ t.Skip("Mock server 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.Projects.Delete(context.TODO(), "id")
+ 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/projectlimit.go b/projectlimit.go
new file mode 100644
index 0000000..94121a2
--- /dev/null
+++ b/projectlimit.go
@@ -0,0 +1,132 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "slices"
+
+ "github.com/kernel/kernel-go-sdk/internal/apijson"
+ shimjson "github.com/kernel/kernel-go-sdk/internal/encoding/json"
+ "github.com/kernel/kernel-go-sdk/internal/requestconfig"
+ "github.com/kernel/kernel-go-sdk/option"
+ "github.com/kernel/kernel-go-sdk/packages/param"
+ "github.com/kernel/kernel-go-sdk/packages/respjson"
+)
+
+// Create and manage projects for resource isolation within an organization.
+//
+// ProjectLimitService 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 [NewProjectLimitService] method instead.
+type ProjectLimitService struct {
+ Options []option.RequestOption
+}
+
+// NewProjectLimitService 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 NewProjectLimitService(opts ...option.RequestOption) (r ProjectLimitService) {
+ r = ProjectLimitService{}
+ r.Options = opts
+ return
+}
+
+// Get the resource limit overrides for a project. Null values mean no
+// project-level cap (org limit applies).
+func (r *ProjectLimitService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *ProjectLimits, err error) {
+ opts = slices.Concat(r.Options, opts)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return nil, err
+ }
+ path := fmt.Sprintf("projects/%s/limits", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ return res, err
+}
+
+// Update resource limit overrides for a project. Only fields present in the
+// request are modified. Set a field to 0 to remove that limit cap; omit a field to
+// leave it unchanged.
+func (r *ProjectLimitService) Update(ctx context.Context, id string, body ProjectLimitUpdateParams, opts ...option.RequestOption) (res *ProjectLimits, err error) {
+ opts = slices.Concat(r.Options, opts)
+ if id == "" {
+ err = errors.New("missing required id parameter")
+ return nil, err
+ }
+ path := fmt.Sprintf("projects/%s/limits", id)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...)
+ return res, err
+}
+
+type ProjectLimits struct {
+ // Maximum concurrent app invocations for this project. Null means no project-level
+ // cap.
+ MaxConcurrentInvocations int64 `json:"max_concurrent_invocations" api:"nullable"`
+ // Maximum concurrent browser sessions for this project. Null means no
+ // project-level cap.
+ MaxConcurrentSessions int64 `json:"max_concurrent_sessions" api:"nullable"`
+ // Maximum persistent browser sessions for this project. Null means no
+ // project-level cap.
+ MaxPersistentSessions int64 `json:"max_persistent_sessions" api:"nullable"`
+ // Maximum pooled sessions capacity for this project. Null means no project-level
+ // cap.
+ MaxPooledSessions int64 `json:"max_pooled_sessions" api:"nullable"`
+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
+ JSON struct {
+ MaxConcurrentInvocations respjson.Field
+ MaxConcurrentSessions respjson.Field
+ MaxPersistentSessions respjson.Field
+ MaxPooledSessions respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+// Returns the unmodified JSON received from the API
+func (r ProjectLimits) RawJSON() string { return r.JSON.raw }
+func (r *ProjectLimits) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type UpdateProjectLimitsRequestParam struct {
+ // Maximum concurrent app invocations for this project. Set to 0 to remove the cap;
+ // omit to leave unchanged.
+ MaxConcurrentInvocations param.Opt[int64] `json:"max_concurrent_invocations,omitzero"`
+ // Maximum concurrent browser sessions for this project. Set to 0 to remove the
+ // cap; omit to leave unchanged.
+ MaxConcurrentSessions param.Opt[int64] `json:"max_concurrent_sessions,omitzero"`
+ // Maximum persistent browser sessions for this project. Set to 0 to remove the
+ // cap; omit to leave unchanged.
+ MaxPersistentSessions param.Opt[int64] `json:"max_persistent_sessions,omitzero"`
+ // Maximum pooled sessions capacity for this project. Set to 0 to remove the cap;
+ // omit to leave unchanged.
+ MaxPooledSessions param.Opt[int64] `json:"max_pooled_sessions,omitzero"`
+ paramObj
+}
+
+func (r UpdateProjectLimitsRequestParam) MarshalJSON() (data []byte, err error) {
+ type shadow UpdateProjectLimitsRequestParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *UpdateProjectLimitsRequestParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type ProjectLimitUpdateParams struct {
+ UpdateProjectLimitsRequest UpdateProjectLimitsRequestParam
+ paramObj
+}
+
+func (r ProjectLimitUpdateParams) MarshalJSON() (data []byte, err error) {
+ return shimjson.Marshal(r.UpdateProjectLimitsRequest)
+}
+func (r *ProjectLimitUpdateParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
diff --git a/projectlimit_test.go b/projectlimit_test.go
new file mode 100644
index 0000000..928783f
--- /dev/null
+++ b/projectlimit_test.go
@@ -0,0 +1,71 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel_test
+
+import (
+ "context"
+ "errors"
+ "os"
+ "testing"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/internal/testutil"
+ "github.com/kernel/kernel-go-sdk/option"
+)
+
+func TestProjectLimitGet(t *testing.T) {
+ t.Skip("Mock server 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.Projects.Limits.Get(context.TODO(), "id")
+ 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 TestProjectLimitUpdateWithOptionalParams(t *testing.T) {
+ t.Skip("Mock server 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.Projects.Limits.Update(
+ context.TODO(),
+ "id",
+ kernel.ProjectLimitUpdateParams{
+ UpdateProjectLimitsRequest: kernel.UpdateProjectLimitsRequestParam{
+ MaxConcurrentInvocations: kernel.Int(0),
+ MaxConcurrentSessions: kernel.Int(0),
+ MaxPersistentSessions: kernel.Int(0),
+ MaxPooledSessions: 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())
+ }
+}
From 9497d64fb431e9ebca0e2281339836f63f5c2990 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 10 Apr 2026 02:14:44 +0000
Subject: [PATCH 4/4] release: 0.48.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 13 +++++++++++++
README.md | 2 +-
internal/version.go | 2 +-
4 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 141e7cd..ff66120 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.47.0"
+ ".": "0.48.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b638bfd..369839a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## 0.48.0 (2026-04-10)
+
+Full Changelog: [v0.47.0...v0.48.0](https://github.com/kernel/kernel-go-sdk/compare/v0.47.0...v0.48.0)
+
+### Features
+
+* [kernel-1116] add base_url field to browser session response ([6e52972](https://github.com/kernel/kernel-go-sdk/commit/6e529727c5fc0a122df257f58a2fa3dd285f66a7))
+
+
+### Chores
+
+* retrigger Stainless codegen for projects resource ([3e1b78f](https://github.com/kernel/kernel-go-sdk/commit/3e1b78f44879ed57afb128c103276a9bcf84a209))
+
## 0.47.0 (2026-04-07)
Full Changelog: [v0.46.0...v0.47.0](https://github.com/kernel/kernel-go-sdk/compare/v0.46.0...v0.47.0)
diff --git a/README.md b/README.md
index 2d1b3a4..8288f23 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Or to pin the version:
```sh
-go get -u 'github.com/kernel/kernel-go-sdk@v0.47.0'
+go get -u 'github.com/kernel/kernel-go-sdk@v0.48.0'
```
diff --git a/internal/version.go b/internal/version.go
index 7e14e79..4850846 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -2,4 +2,4 @@
package internal
-const PackageVersion = "0.47.0" // x-release-please-version
+const PackageVersion = "0.48.0" // x-release-please-version