Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/kernel-go' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: |-
github.repository == 'stainless-sdks/kernel-go' &&
(github.event_name == 'push' || github.event.pull_request.head.repo.fork)
(github.event_name == 'push' || github.event.pull_request.head.repo.fork) &&
(github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- uses: actions/checkout@v6

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.prism.log
.stdy.log
codegen.log
Brewfile.lock.json
.idea/
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.44.0"
".": "0.45.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 104
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-bb2ac8e0d3a1c08e8afcbcbad7cb733d0f84bd22a8d233c1ec3100a01ee078ae.yml
openapi_spec_hash: a83f7d1c422c85d6dc6158af7afe1d09
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-aeb5ea5c2632fe7fd905d509bc6cbb06999d17c458ec44ffd713935ba5b848f9.yml
openapi_spec_hash: fef45a8569f1d3de04c86e95b1112665
config_hash: 16e4457a0bb26e98a335a1c2a572290a
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 0.45.0 (2026-03-26)

Full Changelog: [v0.44.0...v0.45.0](https://github.com/kernel/kernel-go-sdk/compare/v0.44.0...v0.45.0)

### Features

* [kernel-1008] browser pools add custom policy ([e740db7](https://github.com/kernel/kernel-go-sdk/commit/e740db79ec07414b5b0b5ff3be98b9e089a9bb45))


### Chores

* **ci:** skip lint on metadata-only changes ([8296238](https://github.com/kernel/kernel-go-sdk/commit/8296238ce0b45903e3d40420100aa29a3ab105fd))
* **client:** fix multipart serialisation of Default() fields ([cabda49](https://github.com/kernel/kernel-go-sdk/commit/cabda49a25334cd3fa3fc747f69b8a515e2b77d9))
* **internal:** support default value struct tag ([dd77af4](https://github.com/kernel/kernel-go-sdk/commit/dd77af45f77a98e96f5d140bb737377f1d72456a))
* **internal:** update gitignore ([48baab7](https://github.com/kernel/kernel-go-sdk/commit/48baab7aa0e23ed519a08b52142927340a8d451b))

## 0.44.0 (2026-03-20)

Full Changelog: [v0.43.0...v0.44.0](https://github.com/kernel/kernel-go-sdk/compare/v0.43.0...v0.44.0)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->

```sh
go get -u 'github.com/kernel/kernel-go-sdk@v0.44.0'
go get -u 'github.com/kernel/kernel-go-sdk@v0.45.0'
```

<!-- x-release-please-end -->
Expand Down
2 changes: 1 addition & 1 deletion app.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type AppListResponse struct {
// Environment variables configured for this app version
EnvVars map[string]string `json:"env_vars" api:"required"`
// Deployment region code
Region constant.AwsUsEast1a `json:"region" api:"required"`
Region constant.AwsUsEast1a `json:"region" default:"aws.us-east-1a"`
// Version label for the application
Version string `json:"version" api:"required"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
Expand Down
2 changes: 1 addition & 1 deletion authconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ func (r *AuthConnectionFollowResponseUnion) UnmarshalJSON(data []byte) error {
// An event representing the current state of a managed auth flow.
type AuthConnectionFollowResponseManagedAuthState struct {
// Event type identifier (always "managed_auth_state").
Event constant.ManagedAuthState `json:"event" api:"required"`
Event constant.ManagedAuthState `json:"event" default:"managed_auth_state"`
// Current flow status.
//
// Any of "IN_PROGRESS", "SUCCESS", "FAILED", "EXPIRED", "CANCELED".
Expand Down
16 changes: 16 additions & 0 deletions browserpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ type BrowserPoolBrowserPoolConfig struct {
// your organization's pooled sessions limit (the sum of all pool sizes cannot
// exceed your limit).
Size int64 `json:"size" api:"required"`
// Custom Chrome enterprise policy overrides applied to all browsers in this pool.
// Keys are Chrome enterprise policy names; values must match their expected types.
// Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See
// https://chromeenterprise.google/policies/
ChromePolicy map[string]any `json:"chrome_policy"`
// List of browser extensions to load into the session. Provide each by id or name.
Extensions []shared.BrowserExtension `json:"extensions"`
// Percentage of the pool to fill per minute. Defaults to 10%.
Expand Down Expand Up @@ -213,6 +218,7 @@ type BrowserPoolBrowserPoolConfig struct {
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Size respjson.Field
ChromePolicy respjson.Field
Extensions respjson.Field
FillRatePerMinute respjson.Field
Headless respjson.Field
Expand Down Expand Up @@ -337,6 +343,11 @@ type BrowserPoolNewParams struct {
// Default idle timeout in seconds for browsers acquired from this pool before they
// are destroyed. Defaults to 600 seconds if not specified
TimeoutSeconds param.Opt[int64] `json:"timeout_seconds,omitzero"`
// Custom Chrome enterprise policy overrides applied to all browsers in this pool.
// Keys are Chrome enterprise policy names; values must match their expected types.
// Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See
// https://chromeenterprise.google/policies/
ChromePolicy map[string]any `json:"chrome_policy,omitzero"`
// List of browser extensions to load into the session. Provide each by id or name.
Extensions []shared.BrowserExtensionParam `json:"extensions,omitzero"`
// Profile selection for the browser session. Provide either id or name. If
Expand Down Expand Up @@ -393,6 +404,11 @@ type BrowserPoolUpdateParams struct {
// Default idle timeout in seconds for browsers acquired from this pool before they
// are destroyed. Defaults to 600 seconds if not specified
TimeoutSeconds param.Opt[int64] `json:"timeout_seconds,omitzero"`
// Custom Chrome enterprise policy overrides applied to all browsers in this pool.
// Keys are Chrome enterprise policy names; values must match their expected types.
// Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See
// https://chromeenterprise.google/policies/
ChromePolicy map[string]any `json:"chrome_policy,omitzero"`
// List of browser extensions to load into the session. Provide each by id or name.
Extensions []shared.BrowserExtensionParam `json:"extensions,omitzero"`
// Profile selection for the browser session. Provide either id or name. If
Expand Down
8 changes: 7 additions & 1 deletion browserpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ func TestBrowserPoolNewWithOptionalParams(t *testing.T) {
)
_, err := client.BrowserPools.New(context.TODO(), kernel.BrowserPoolNewParams{
Size: 10,
ChromePolicy: map[string]any{
"foo": "bar",
},
Extensions: []shared.BrowserExtensionParam{{
ID: kernel.String("id"),
Name: kernel.String("name"),
Expand Down Expand Up @@ -100,7 +103,10 @@ func TestBrowserPoolUpdateWithOptionalParams(t *testing.T) {
context.TODO(),
"id_or_name",
kernel.BrowserPoolUpdateParams{
Size: 10,
Size: 10,
ChromePolicy: map[string]any{
"foo": "bar",
},
DiscardAllIdle: kernel.Bool(false),
Extensions: []shared.BrowserExtensionParam{{
ID: kernel.String("id"),
Expand Down
14 changes: 7 additions & 7 deletions deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ type DeploymentStateEvent struct {
// Deployment record information.
Deployment DeploymentStateEventDeployment `json:"deployment" api:"required"`
// Event type identifier (always "deployment_state").
Event constant.DeploymentState `json:"event" api:"required"`
Event constant.DeploymentState `json:"event" default:"deployment_state"`
// Time the state was reported.
Timestamp time.Time `json:"timestamp" api:"required" format:"date-time"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
Expand All @@ -156,7 +156,7 @@ type DeploymentStateEventDeployment struct {
// Timestamp when the deployment was created
CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"`
// Deployment region code
Region constant.AwsUsEast1a `json:"region" api:"required"`
Region constant.AwsUsEast1a `json:"region" default:"aws.us-east-1a"`
// Current status of the deployment
//
// Any of "queued", "in_progress", "running", "failed", "stopped".
Expand Down Expand Up @@ -197,7 +197,7 @@ type DeploymentNewResponse struct {
// Timestamp when the deployment was created
CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"`
// Deployment region code
Region constant.AwsUsEast1a `json:"region" api:"required"`
Region constant.AwsUsEast1a `json:"region" default:"aws.us-east-1a"`
// Current status of the deployment
//
// Any of "queued", "in_progress", "running", "failed", "stopped".
Expand Down Expand Up @@ -249,7 +249,7 @@ type DeploymentGetResponse struct {
// Timestamp when the deployment was created
CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"`
// Deployment region code
Region constant.AwsUsEast1a `json:"region" api:"required"`
Region constant.AwsUsEast1a `json:"region" default:"aws.us-east-1a"`
// Current status of the deployment
//
// Any of "queued", "in_progress", "running", "failed", "stopped".
Expand Down Expand Up @@ -301,7 +301,7 @@ type DeploymentListResponse struct {
// Timestamp when the deployment was created
CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"`
// Deployment region code
Region constant.AwsUsEast1a `json:"region" api:"required"`
Region constant.AwsUsEast1a `json:"region" default:"aws.us-east-1a"`
// Current status of the deployment
//
// Any of "queued", "in_progress", "running", "failed", "stopped".
Expand Down Expand Up @@ -433,9 +433,9 @@ type DeploymentFollowResponseAppVersionSummaryEvent struct {
// Name of the application
AppName string `json:"app_name" api:"required"`
// Event type identifier (always "app_version_summary").
Event constant.AppVersionSummary `json:"event" api:"required"`
Event constant.AppVersionSummary `json:"event" default:"app_version_summary"`
// Deployment region code
Region constant.AwsUsEast1a `json:"region" api:"required"`
Region constant.AwsUsEast1a `json:"region" default:"aws.us-east-1a"`
// Time the state was reported.
Timestamp time.Time `json:"timestamp" api:"required" format:"date-time"`
// Version label for the application
Expand Down
8 changes: 8 additions & 0 deletions internal/apiform/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,14 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc {
}
return typeEncoderFn(key, value, writer)
}
} else if ptag.defaultValue != nil {
typeEncoderFn := e.typeEncoder(field.Type)
encoderFn = func(key string, value reflect.Value, writer *multipart.Writer) error {
if value.IsZero() {
return typeEncoderFn(key, reflect.ValueOf(ptag.defaultValue), writer)
}
return typeEncoderFn(key, value, writer)
}
} else {
encoderFn = e.typeEncoder(field.Type)
}
Expand Down
36 changes: 36 additions & 0 deletions internal/apiform/form_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ type StructUnion struct {
param.APIUnion
}

type ConstantStruct struct {
Anchor string `form:"anchor" default:"created_at"`
Seconds int `form:"seconds"`
}

type MultipartMarshalerParent struct {
Middle MultipartMarshalerMiddleNext `form:"middle"`
}
Expand Down Expand Up @@ -554,6 +559,37 @@ Content-Disposition: form-data; name="union"
Union: UnionTime(time.Date(2010, 05, 23, 0, 0, 0, 0, time.UTC)),
},
},
"constant_zero_value": {
`--xxx
Content-Disposition: form-data; name="anchor"

created_at
--xxx
Content-Disposition: form-data; name="seconds"

3600
--xxx--
`,
ConstantStruct{
Seconds: 3600,
},
},
"constant_explicit_value": {
`--xxx
Content-Disposition: form-data; name="anchor"

created_at_override
--xxx
Content-Disposition: form-data; name="seconds"

3600
--xxx--
`,
ConstantStruct{
Anchor: "created_at_override",
Seconds: 3600,
},
},
"deeply-nested-struct,brackets": {
`--xxx
Content-Disposition: form-data; name="middle[middleNext][child]"
Expand Down
26 changes: 21 additions & 5 deletions internal/apiform/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ const apiStructTag = "api"
const jsonStructTag = "json"
const formStructTag = "form"
const formatStructTag = "format"
const defaultStructTag = "default"

type parsedStructTag struct {
name string
required bool
extras bool
metadata bool
omitzero bool
name string
required bool
extras bool
metadata bool
omitzero bool
defaultValue any
}

func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) {
Expand Down Expand Up @@ -45,9 +47,23 @@ func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool
}

parseApiStructTag(field, &tag)
parseDefaultStructTag(field, &tag)
return tag, ok
}

func parseDefaultStructTag(field reflect.StructField, tag *parsedStructTag) {
if field.Type.Kind() != reflect.String {
// Only strings are currently supported
return
}

raw, ok := field.Tag.Lookup(defaultStructTag)
if !ok {
return
}
tag.defaultValue = raw
}

func parseApiStructTag(field reflect.StructField, tag *parsedStructTag) {
raw, ok := field.Tag.Lookup(apiStructTag)
if !ok {
Expand Down
8 changes: 8 additions & 0 deletions internal/apijson/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"time"

"github.com/tidwall/sjson"

shimjson "github.com/kernel/kernel-go-sdk/internal/encoding/json"
)

var encoders sync.Map // map[encoderEntry]encoderFunc
Expand Down Expand Up @@ -271,6 +273,12 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc {
if err != nil {
return nil, err
}
if ef.tag.defaultValue != nil && (!field.IsValid() || field.IsZero()) {
encoded, err = shimjson.Marshal(ef.tag.defaultValue)
if err != nil {
return nil, err
}
}
if encoded == nil {
continue
}
Expand Down
17 changes: 17 additions & 0 deletions internal/apijson/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,3 +614,20 @@ func TestEncode(t *testing.T) {
})
}
}

type StructWithDefault struct {
Type string `json:"type" default:"foo"`
}

func TestDefault(t *testing.T) {
value := StructWithDefault{}
expected := `{"type":"foo"}`

raw, err := Marshal(value)
if err != nil {
t.Fatalf("serialization of %v failed with error %v", value, err)
}
if string(raw) != expected {
t.Fatalf("expected %+#v to serialize to %s but got %s", value, expected, string(raw))
}
}
26 changes: 21 additions & 5 deletions internal/apijson/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (
const apiStructTag = "api"
const jsonStructTag = "json"
const formatStructTag = "format"
const defaultStructTag = "default"

type parsedStructTag struct {
name string
required bool
extras bool
metadata bool
inline bool
name string
required bool
extras bool
metadata bool
inline bool
defaultValue any
}

func parseJSONStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) {
Expand Down Expand Up @@ -42,9 +44,23 @@ func parseJSONStructTag(field reflect.StructField) (tag parsedStructTag, ok bool

// the `api` struct tag is only used alongside `json` for custom behaviour
parseApiStructTag(field, &tag)
parseDefaultStructTag(field, &tag)
return tag, ok
}

func parseDefaultStructTag(field reflect.StructField, tag *parsedStructTag) {
if field.Type.Kind() != reflect.String {
// Only strings are currently supported
return
}

raw, ok := field.Tag.Lookup(defaultStructTag)
if !ok {
return
}
tag.defaultValue = raw
}

func parseApiStructTag(field reflect.StructField, tag *parsedStructTag) {
raw, ok := field.Tag.Lookup(apiStructTag)
if !ok {
Expand Down
Loading
Loading