From af02011057b49e8e3f4899c43ecba7f6a18b27b2 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Thu, 12 Nov 2026 19:26:00 +0000 Subject: [PATCH 1/3] feat: Say how many certificates the refresh PR body leaves out Stainless-Generated-From: 45f8ceb682d0ba1e874e5bc79edcbfd1aa1ce3c7 --- .stats.yml | 2 +- api.md | 16 +++++ browser.go | 3 + browserliveview.go | 125 ++++++++++++++++++++++++++++++++++++++++ browserliveview_test.go | 46 +++++++++++++++ vaultitem.go | 91 ++++++++++++++++++++--------- 6 files changed, 254 insertions(+), 29 deletions(-) create mode 100644 browserliveview.go create mode 100644 browserliveview_test.go diff --git a/.stats.yml b/.stats.yml index 4725ed9..4731cdc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 178 +configured_endpoints: 179 diff --git a/api.md b/api.md index 414f7b4..eccd410 100644 --- a/api.md +++ b/api.md @@ -228,6 +228,22 @@ Methods: - client.Browsers.Telemetry.Events(ctx context.Context, idOrName string, query kernel.BrowserTelemetryEventsParams) (\*pagination.OffsetPagination[kernel.BrowserTelemetryEventsResponse], error) - client.Browsers.Telemetry.Stream(ctx context.Context, idOrName string, params kernel.BrowserTelemetryStreamParams) (\*kernel.BrowserTelemetryStreamResponse, error) +## LiveView + +Params Types: + +- kernel.BrowserLiveViewRequestParam +- kernel.BrowserLiveViewScope + +Response Types: + +- kernel.BrowserLiveView +- kernel.BrowserLiveViewScope + +Methods: + +- client.Browsers.LiveView.New(ctx context.Context, idOrName string, body kernel.BrowserLiveViewNewParams) (\*kernel.BrowserLiveView, error) + ## Replays Response Types: diff --git a/browser.go b/browser.go index a00d010..e8f2054 100644 --- a/browser.go +++ b/browser.go @@ -38,6 +38,8 @@ type BrowserService struct { // Stream live telemetry events from a browser session, and manage the destinations // sessions export them to. Telemetry BrowserTelemetryService + // Create and manage browser sessions. + LiveView BrowserLiveViewService // Record and manage browser session video replays. Replays BrowserReplayService // Read, write, and manage files on the browser instance. @@ -62,6 +64,7 @@ func NewBrowserService(opts ...option.RequestOption) (r BrowserService) { r = BrowserService{} r.Options = opts r.Telemetry = NewBrowserTelemetryService(opts...) + r.LiveView = NewBrowserLiveViewService(opts...) r.Replays = NewBrowserReplayService(opts...) r.Fs = NewBrowserFService(opts...) r.Process = NewBrowserProcessService(opts...) diff --git a/browserliveview.go b/browserliveview.go new file mode 100644 index 0000000..454b4e5 --- /dev/null +++ b/browserliveview.go @@ -0,0 +1,125 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel + +import ( + "context" + "errors" + "fmt" + "net/http" + "slices" + "time" + + "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 browser sessions. +// +// BrowserLiveViewService 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 [NewBrowserLiveViewService] method instead. +type BrowserLiveViewService struct { + Options []option.RequestOption +} + +// NewBrowserLiveViewService 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 NewBrowserLiveViewService(opts ...option.RequestOption) (r BrowserLiveViewService) { + r = BrowserLiveViewService{} + r.Options = opts + return +} + +// Creates a live view URL for a headful browser that grants either read-only or +// control access. The URL works only for the live view: it cannot connect to CDP, +// WebDriver, or any other browser endpoint. A read-only URL shows the browser but +// cannot send input, regardless of query parameters. The URL stays valid until the +// browser is deleted, or until `ttl_seconds` elapse when set. For a browser +// acquired from a pool, it stops working when the browser is released. Nothing is +// stored, so a URL cannot be revoked before then. +func (r *BrowserLiveViewService) New(ctx context.Context, idOrName string, body BrowserLiveViewNewParams, opts ...option.RequestOption) (res *BrowserLiveView, err error) { + opts = slices.Concat(r.Options, opts) + if idOrName == "" { + err = errors.New("missing required id_or_name parameter") + return nil, err + } + path := fmt.Sprintf("browsers/%s/live_view", idOrName) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) + return res, err +} + +type BrowserLiveView struct { + // `read` shows the browser without accepting input. `control` also lets the viewer + // drive the browser through the live view. + // + // Any of "read", "control". + Scope BrowserLiveViewScope `json:"scope" api:"required"` + // Live view URL. Treat it as a credential. + URL string `json:"url" api:"required"` + // When the URL expires. Absent when it stays valid until the browser is deleted. + ExpiresAt time.Time `json:"expires_at" format:"date-time"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + Scope respjson.Field + URL respjson.Field + ExpiresAt respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r BrowserLiveView) RawJSON() string { return r.JSON.raw } +func (r *BrowserLiveView) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type BrowserLiveViewRequestParam struct { + // Seconds until the URL expires. Omit to keep it valid until the browser is + // deleted. + TtlSeconds param.Opt[int64] `json:"ttl_seconds,omitzero"` + // `read` shows the browser without accepting input. `control` also lets the viewer + // drive the browser through the live view. + // + // Any of "read", "control". + Scope BrowserLiveViewScope `json:"scope,omitzero"` + paramObj +} + +func (r BrowserLiveViewRequestParam) MarshalJSON() (data []byte, err error) { + type shadow BrowserLiveViewRequestParam + return param.MarshalObject(r, (*shadow)(&r)) +} +func (r *BrowserLiveViewRequestParam) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// `read` shows the browser without accepting input. `control` also lets the viewer +// drive the browser through the live view. +type BrowserLiveViewScope string + +const ( + BrowserLiveViewScopeRead BrowserLiveViewScope = "read" + BrowserLiveViewScopeControl BrowserLiveViewScope = "control" +) + +type BrowserLiveViewNewParams struct { + BrowserLiveViewRequest BrowserLiveViewRequestParam + paramObj +} + +func (r BrowserLiveViewNewParams) MarshalJSON() (data []byte, err error) { + return shimjson.Marshal(r.BrowserLiveViewRequest) +} +func (r *BrowserLiveViewNewParams) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} diff --git a/browserliveview_test.go b/browserliveview_test.go new file mode 100644 index 0000000..a4f4260 --- /dev/null +++ b/browserliveview_test.go @@ -0,0 +1,46 @@ +// 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 TestBrowserLiveViewNewWithOptionalParams(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.Browsers.LiveView.New( + context.TODO(), + "htzv5orfit78e1m2biiifpbv", + kernel.BrowserLiveViewNewParams{ + BrowserLiveViewRequest: kernel.BrowserLiveViewRequestParam{ + Scope: kernel.BrowserLiveViewScopeRead, + TtlSeconds: kernel.Int(3600), + }, + }, + ) + 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/vaultitem.go b/vaultitem.go index 6bc58cf..5cc7992 100644 --- a/vaultitem.go +++ b/vaultitem.go @@ -2264,9 +2264,10 @@ type CredentialVaultItem struct { AvailableExpansions []CredentialVaultItemAvailableExpansion `json:"available_expansions" api:"required"` // Kernel credentials advertise collect and fill when eligible. 1Password // credentials advertise 1pw_create_access_request until a request is made, - // 1pw_access_request_status while its approval is pending, and 1pw_fill after - // access is granted. Managed auth credentials advertise fill while ready and - // nothing otherwise. + // 1pw_access_request_status while its approval is pending (and + // 1pw_create_access_request again once the 3-minute status-check window has + // passed), and 1pw_fill after access is granted. Managed auth credentials + // advertise fill while ready and nothing otherwise. AvailableOperations []CredentialVaultItemAvailableOperation `json:"available_operations" api:"required"` CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` // Immutable item key assigned when the item is created. @@ -2399,13 +2400,16 @@ type CredentialVaultItemActionUnion struct { Name string `json:"name"` URL string `json:"url"` // This field is from variant [CredentialVaultItemAction1passwordAccessApproval]. + AccessRequestReference string `json:"access_request_reference"` + // This field is from variant [CredentialVaultItemAction1passwordAccessApproval]. Instructions string `json:"instructions"` JSON struct { - ExpiresAt respjson.Field - Name respjson.Field - URL respjson.Field - Instructions respjson.Field - raw string + ExpiresAt respjson.Field + Name respjson.Field + URL respjson.Field + AccessRequestReference respjson.Field + Instructions respjson.Field + raw string } `json:"-"` } @@ -2455,20 +2459,29 @@ func (r *CredentialVaultItemActionUnion) UnmarshalJSON(data []byte) error { } type CredentialVaultItemAction1passwordAccessApproval struct { + // The access_request_reference value from url, for approving inside your own iOS + // or Android app with 1Password's action extension or authorization activity. Pass + // it unchanged; the grant comes back to your app, and 1pw_access_request_status + // records it in Kernel. Treat it like url, which carries the same request text, + // and keep it out of logs. + AccessRequestReference string `json:"access_request_reference" api:"required"` // Steps for the agent to hand approval to the human and poll the resulting // decision. Instructions string `json:"instructions" api:"required"` Name constant.String1passwordAccessApproval `json:"name" default:"1password_access_approval"` - // Native 1Password approval link. Present it to the account owner without - // modifying it; it does not grant access until they approve in their app. + // Native 1Password approval link. Present it to the account owner unchanged, + // except that you may append `&return_url=` so 1Password sends + // them back to your app after they decide (1Password 8.12.46 or later on iOS, + // Android and desktop). It does not grant access until they approve in their app. URL string `json:"url" api:"required" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { - Instructions respjson.Field - Name respjson.Field - URL respjson.Field - ExtraFields map[string]respjson.Field - raw string + AccessRequestReference respjson.Field + Instructions respjson.Field + Name respjson.Field + URL respjson.Field + ExtraFields map[string]respjson.Field + raw string } `json:"-"` } @@ -4735,7 +4748,9 @@ const ( type OnePasswordCredentialVaultItemStateAccessRequest struct { ID string `json:"id" api:"required"` HasAutofillToken bool `json:"has_autofill_token" api:"required"` - // One of pending, resolved, denied, or failed. + // One of pending, resolved, denied, failed, expired, or unknown. expired returns + // the item to pending_authorization so access can be requested again; unknown is a + // state 1Password added later and is treated as failed. State string `json:"state" api:"required"` // Provider-created timestamp as returned by the broker. CreatedAt string `json:"createdAt"` @@ -7438,14 +7453,17 @@ type VaultItemUnionAction struct { // This field is from variant [CredentialVaultItemActionUnion]. ExpiresAt time.Time `json:"expires_at"` // This field is from variant [CredentialVaultItemActionUnion]. + AccessRequestReference string `json:"access_request_reference"` + // This field is from variant [CredentialVaultItemActionUnion]. Instructions string `json:"instructions"` JSON struct { - Name respjson.Field - URL respjson.Field - CaptureToken respjson.Field - ExpiresAt respjson.Field - Instructions respjson.Field - raw string + Name respjson.Field + URL respjson.Field + CaptureToken respjson.Field + ExpiresAt respjson.Field + AccessRequestReference respjson.Field + Instructions respjson.Field + raw string } `json:"-"` } @@ -8604,14 +8622,17 @@ type VaultItemOperationResponseUnionAction struct { // This field is from variant [CredentialVaultItemActionUnion]. ExpiresAt time.Time `json:"expires_at"` // This field is from variant [CredentialVaultItemActionUnion]. + AccessRequestReference string `json:"access_request_reference"` + // This field is from variant [CredentialVaultItemActionUnion]. Instructions string `json:"instructions"` JSON struct { - Name respjson.Field - URL respjson.Field - CaptureToken respjson.Field - ExpiresAt respjson.Field - Instructions respjson.Field - raw string + Name respjson.Field + URL respjson.Field + CaptureToken respjson.Field + ExpiresAt respjson.Field + AccessRequestReference respjson.Field + Instructions respjson.Field + raw string } `json:"-"` } @@ -10404,6 +10425,12 @@ type VaultItemPerformOperationParams struct { Of1pwCreateAccessRequest *OnePasswordRequestAccessVaultItemOperationRequestParam `json:",inline"` // This field is a request body variant, only one variant field can be set. // Retrieve the status of a 1Password access request after presenting the approval + // link. Kernel paces checks on 1Password's schedule, timed from the first status + // check (at once, then every 2 seconds, slowing to every 10 and 20 seconds). Each + // call reads a fresh status, waiting up to 20 seconds for its first scheduled + // check. If 1Password rate limits the account, it returns 429 with Retry-After. + // After 3 minutes the approval prompt has closed; ask the owner whether they + // approved and check once more, or invoke 1pw_create_access_request for a new // link. On a confirmed failed status, ask the end-user before deleting and // recreating the credential item for at most one new request. Do not retry an // uncertain dispatched request. The response contains no secret values. @@ -10502,6 +10529,12 @@ func (r *VaultItemPerformOperationParams) UnmarshalJSON(data []byte) error { } // Retrieve the status of a 1Password access request after presenting the approval +// link. Kernel paces checks on 1Password's schedule, timed from the first status +// check (at once, then every 2 seconds, slowing to every 10 and 20 seconds). Each +// call reads a fresh status, waiting up to 20 seconds for its first scheduled +// check. If 1Password rate limits the account, it returns 429 with Retry-After. +// After 3 minutes the approval prompt has closed; ask the owner whether they +// approved and check once more, or invoke 1pw_create_access_request for a new // link. On a confirmed failed status, ask the end-user before deleting and // recreating the credential item for at most one new request. Do not retry an // uncertain dispatched request. The response contains no secret values. @@ -10510,6 +10543,8 @@ func (r *VaultItemPerformOperationParams) UnmarshalJSON(data []byte) error { // // The property Type is required. type VaultItemPerformOperationParamsBody1pwAccessRequestStatus struct { + // How long to keep checking on the schedule. The call still waits for its first + // scheduled check, at most 20 seconds, when that comes later. TimeoutSeconds param.Opt[int64] `json:"timeout_seconds,omitzero"` // This field can be elided, and will marshal its zero value as // "1pw_access_request_status". From 198927d239c7867726ce2562532ab3df4a8fce4d Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Thu, 12 Nov 2026 19:30:36 +0000 Subject: [PATCH 2/3] release: 0.148.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ README.md | 2 +- internal/version.go | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e205138..2b1627b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.147.0" + ".": "0.148.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 34545e1..4312f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.148.0](https://github.com/kernel/kernel-go-sdk/compare/v0.147.0...v0.148.0) (2026-11-12) + + +### Features + +* Say how many certificates the refresh PR body leaves out ([af02011](https://github.com/kernel/kernel-go-sdk/commit/af02011057b49e8e3f4899c43ecba7f6a18b27b2)) + ## [0.147.0](https://github.com/kernel/kernel-go-sdk/compare/v0.146.0...v0.147.0) (2026-11-12) diff --git a/README.md b/README.md index 29bd833..1d628fa 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.147.0' +go get -u 'github.com/kernel/kernel-go-sdk@v0.148.0' ``` diff --git a/internal/version.go b/internal/version.go index 489e078..5d2eeda 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.147.0" // x-release-please-version +const PackageVersion = "0.148.0" // x-release-please-version From b548486af8e2ef34991fbe7d6727f8d86f342ce6 Mon Sep 17 00:00:00 2001 From: masnwilliams <43387599+masnwilliams@users.noreply.github.com> Date: Thu, 12 Nov 2026 19:36:20 +0000 Subject: [PATCH 3/3] chore: correct 0.148.0 changelog entries --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4312f31..8f28796 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ ### Features -* Say how many certificates the refresh PR body leaves out ([af02011](https://github.com/kernel/kernel-go-sdk/commit/af02011057b49e8e3f4899c43ecba7f6a18b27b2)) +* Add scoped live view URLs ([af02011](https://github.com/kernel/kernel-go-sdk/commit/af02011057b49e8e3f4899c43ecba7f6a18b27b2)) +* Pace 1Password status checks on the partner schedule ([af02011](https://github.com/kernel/kernel-go-sdk/commit/af02011057b49e8e3f4899c43ecba7f6a18b27b2)) +* Return the 1Password access request reference on the approval action ([af02011](https://github.com/kernel/kernel-go-sdk/commit/af02011057b49e8e3f4899c43ecba7f6a18b27b2)) ## [0.147.0](https://github.com/kernel/kernel-go-sdk/compare/v0.146.0...v0.147.0) (2026-11-12)