diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 57726a4..b429f96 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.65.0" + ".": "0.66.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index dcde96d..5ad6924 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 117 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-08c2d6a44f4cdcbfb6803a3043fdc1a3e33911dec4652cb3a870f01bc584421f.yml -openapi_spec_hash: c816491451347eb93b793cddf6a78648 -config_hash: 9e45c27425021d49b5391f5cc980b046 +configured_endpoints: 119 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e66c3f8aedccc39104386a3ec619f3fdcef7e8b00d9e5aa82e414a1b387351c2.yml +openapi_spec_hash: afeddf18ebc3da1521b3e6f6739411fa +config_hash: 80eef1b592110714ea55cd26c470fabb diff --git a/CHANGELOG.md b/CHANGELOG.md index a63adb2..8510537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.66.0 (2026-06-10) + +Full Changelog: [v0.65.0...v0.66.0](https://github.com/kernel/kernel-go-sdk/compare/v0.65.0...v0.66.0) + +### Features + +* Add org-level default per-project concurrency cap ([da8ea41](https://github.com/kernel/kernel-go-sdk/commit/da8ea416e8e2d00f38c7a811cbdd515053b37f89)) +* Support updating browser session name and tags via PATCH ([f530bfb](https://github.com/kernel/kernel-go-sdk/commit/f530bfb8b6822f3774eee1fb7bbe81fc4ce9fa41)) + ## 0.65.0 (2026-06-08) Full Changelog: [v0.64.0...v0.65.0](https://github.com/kernel/kernel-go-sdk/compare/v0.64.0...v0.65.0) diff --git a/README.md b/README.md index 1530141..de19a92 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.65.0' +go get -u 'github.com/kernel/kernel-go-sdk@v0.66.0' ``` diff --git a/api.md b/api.md index 9eb99c1..f4a6c67 100644 --- a/api.md +++ b/api.md @@ -400,6 +400,23 @@ 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) +# Organization + +## Limits + +Params Types: + +- kernel.UpdateOrgLimitsRequestParam + +Response Types: + +- kernel.OrgLimits + +Methods: + +- client.Organization.Limits.Get(ctx context.Context) (\*kernel.OrgLimits, error) +- client.Organization.Limits.Update(ctx context.Context, body kernel.OrganizationLimitUpdateParams) (\*kernel.OrgLimits, error) + # APIKeys Response Types: diff --git a/browser.go b/browser.go index cfb8067..cc42ba4 100644 --- a/browser.go +++ b/browser.go @@ -676,8 +676,8 @@ type BrowserNewParams struct { // view. KioskMode param.Opt[bool] `json:"kiosk_mode,omitzero"` // Optional human-readable name for the browser session, used to find it later in - // the dashboard. Must be unique among active sessions within the project. Set at - // creation time only. + // the dashboard. Must be unique among active sessions within the project. Can be + // changed later via PATCH /browsers/{id_or_name}. Name param.Opt[string] `json:"name,omitzero"` // Optional proxy to associate to the browser session. Must reference a proxy // belonging to the caller's org. @@ -713,7 +713,8 @@ type BrowserNewParams struct { // Profiles must be created beforehand. Profile shared.BrowserProfileParam `json:"profile,omitzero"` // Optional user-defined key-value tags for the browser session, used to find and - // group sessions later. Set at creation time only. Up to 50 pairs. + // group sessions later. Can be changed later via PATCH /browsers/{id_or_name}. Up + // to 50 pairs. Tags Tags `json:"tags,omitzero"` // Initial browser window size in pixels with optional refresh rate. If omitted, // image defaults apply (1920x1080@25). For GPU images, the default is @@ -781,6 +782,10 @@ func (r BrowserGetParams) URLQuery() (v url.Values, err error) { } type BrowserUpdateParams struct { + // Human-readable name for the browser session. Omit to leave unchanged, set to an + // empty string to clear the name. When set, must be unique among active sessions + // within the project. + Name param.Opt[string] `json:"name,omitzero"` // ID of the proxy to use. Omit to leave unchanged, set to empty string to remove // proxy. ProxyID param.Opt[string] `json:"proxy_id,omitzero"` @@ -796,6 +801,10 @@ type BrowserUpdateParams struct { // Profile to load into the browser session. Only allowed if the session does not // already have a profile loaded. Profile shared.BrowserProfileParam `json:"profile,omitzero"` + // User-defined key-value tags for the browser session. Omit to leave unchanged. + // Provide a map to replace the entire tag set (full replace, not a merge). Set to + // an empty object ({}) to clear all tags. Up to 50 pairs. + Tags Tags `json:"tags,omitzero"` // Viewport configuration to apply to the browser session. Viewport BrowserUpdateParamsViewport `json:"viewport,omitzero"` paramObj diff --git a/browser_test.go b/browser_test.go index 245bdea..06ffaa3 100644 --- a/browser_test.go +++ b/browser_test.go @@ -149,12 +149,17 @@ func TestBrowserUpdateWithOptionalParams(t *testing.T) { "htzv5orfit78e1m2biiifpbv", kernel.BrowserUpdateParams{ DisableDefaultProxy: kernel.Bool(true), + Name: kernel.String("checkout-flow-1"), Profile: shared.BrowserProfileParam{ ID: kernel.String("id"), Name: kernel.String("name"), SaveChanges: kernel.Bool(true), }, ProxyID: kernel.String("proxy_id"), + Tags: kernel.Tags{ + "team": "backend", + "env": "staging", + }, Telemetry: kernel.BrowserUpdateParamsTelemetry{ Browser: kernel.BrowserTelemetryCategoriesConfigParam{ Captcha: kernel.BrowserTelemetryCategoryConfigParam{ diff --git a/client.go b/client.go index 5060e16..9f7b615 100644 --- a/client.go +++ b/client.go @@ -41,7 +41,8 @@ type Client struct { // Create and manage credentials for authentication. Credentials CredentialService // Create and manage projects for resource isolation within an organization. - Projects ProjectService + Projects ProjectService + Organization OrganizationService // Create and manage API keys for organization and project-scoped access. APIKeys APIKeyService // Configure external credential providers like 1Password. @@ -94,6 +95,7 @@ func NewClient(opts ...option.RequestOption) (r Client) { r.BrowserPools = NewBrowserPoolService(opts...) r.Credentials = NewCredentialService(opts...) r.Projects = NewProjectService(opts...) + r.Organization = NewOrganizationService(opts...) r.APIKeys = NewAPIKeyService(opts...) r.CredentialProviders = NewCredentialProviderService(opts...) diff --git a/internal/version.go b/internal/version.go index 5d1e9f9..0ccbf2a 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.65.0" // x-release-please-version +const PackageVersion = "0.66.0" // x-release-please-version diff --git a/organization.go b/organization.go new file mode 100644 index 0000000..39b22ce --- /dev/null +++ b/organization.go @@ -0,0 +1,29 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel + +import ( + "github.com/kernel/kernel-go-sdk/option" +) + +// OrganizationService 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 [NewOrganizationService] method instead. +type OrganizationService struct { + Options []option.RequestOption + // Read and manage organization-level limits. + Limits OrganizationLimitService +} + +// NewOrganizationService 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 NewOrganizationService(opts ...option.RequestOption) (r OrganizationService) { + r = OrganizationService{} + r.Options = opts + r.Limits = NewOrganizationLimitService(opts...) + return +} diff --git a/organizationlimit.go b/organizationlimit.go new file mode 100644 index 0000000..0860565 --- /dev/null +++ b/organizationlimit.go @@ -0,0 +1,110 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel + +import ( + "context" + "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" +) + +// Read and manage organization-level limits. +// +// OrganizationLimitService 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 [NewOrganizationLimitService] method instead. +type OrganizationLimitService struct { + Options []option.RequestOption +} + +// NewOrganizationLimitService 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 NewOrganizationLimitService(opts ...option.RequestOption) (r OrganizationLimitService) { + r = OrganizationLimitService{} + r.Options = opts + return +} + +// Get the organization's concurrent session ceiling and the default per-project +// concurrency cap applied to projects without an explicit override. +func (r *OrganizationLimitService) Get(ctx context.Context, opts ...option.RequestOption) (res *OrgLimits, err error) { + opts = slices.Concat(r.Options, opts) + path := "org/limits" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) + return res, err +} + +// Set the default per-project concurrency cap applied to projects without an +// explicit override. Set the value to 0 to remove the default; omit to leave it +// unchanged. The default cannot exceed the organization's concurrent session +// ceiling. +func (r *OrganizationLimitService) Update(ctx context.Context, body OrganizationLimitUpdateParams, opts ...option.RequestOption) (res *OrgLimits, err error) { + opts = slices.Concat(r.Options, opts) + path := "org/limits" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...) + return res, err +} + +type OrgLimits struct { + // Default maximum concurrent browser sessions applied to every project that has no + // explicit per-project override. Null means no org-level default, so such projects + // are uncapped (only the org-wide limit applies). Applies to existing and newly + // created projects. + DefaultProjectMaxConcurrentSessions int64 `json:"default_project_max_concurrent_sessions" api:"nullable"` + // The organization's effective concurrent browser session ceiling, from its plan + // or an override. Read-only and shared across all projects in the org; a + // per-project default cannot exceed it. + MaxConcurrentSessions int64 `json:"max_concurrent_sessions"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + DefaultProjectMaxConcurrentSessions respjson.Field + MaxConcurrentSessions respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r OrgLimits) RawJSON() string { return r.JSON.raw } +func (r *OrgLimits) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type UpdateOrgLimitsRequestParam struct { + // Default maximum concurrent browser sessions for projects without an explicit + // override. Set to 0 to remove the default; omit to leave unchanged. Cannot exceed + // the organization's concurrent session ceiling. + DefaultProjectMaxConcurrentSessions param.Opt[int64] `json:"default_project_max_concurrent_sessions,omitzero"` + paramObj +} + +func (r UpdateOrgLimitsRequestParam) MarshalJSON() (data []byte, err error) { + type shadow UpdateOrgLimitsRequestParam + return param.MarshalObject(r, (*shadow)(&r)) +} +func (r *UpdateOrgLimitsRequestParam) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type OrganizationLimitUpdateParams struct { + UpdateOrgLimitsRequest UpdateOrgLimitsRequestParam + paramObj +} + +func (r OrganizationLimitUpdateParams) MarshalJSON() (data []byte, err error) { + return shimjson.Marshal(r.UpdateOrgLimitsRequest) +} +func (r *OrganizationLimitUpdateParams) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} diff --git a/organizationlimit_test.go b/organizationlimit_test.go new file mode 100644 index 0000000..b52399e --- /dev/null +++ b/organizationlimit_test.go @@ -0,0 +1,64 @@ +// 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 TestOrganizationLimitGet(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.Organization.Limits.Get(context.TODO()) + 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 TestOrganizationLimitUpdateWithOptionalParams(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.Organization.Limits.Update(context.TODO(), kernel.OrganizationLimitUpdateParams{ + UpdateOrgLimitsRequest: kernel.UpdateOrgLimitsRequestParam{ + DefaultProjectMaxConcurrentSessions: 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()) + } +}