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/.stats.yml b/.stats.yml index 7f48513..db7b03c 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 -config_hash: 16e4457a0bb26e98a335a1c2a572290a +configured_endpoints: 111 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-49a1a92e00d1eb87e91e8527275cb0705fce2edea30e70fea745f134dd451fbd.yml +openapi_spec_hash: 3aa6ab6939790f538332054162fbdedc +config_hash: 9818dd634f87b677410eefd013d7a179 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/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/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/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/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 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 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()) + } +}