From 5adf2a69de3e0d29a2da29badf98e3b3ca54229c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 20:44:33 +0000 Subject: [PATCH 1/4] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4dfbf42..6d03c39 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 5 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-1fe396b957ced73281fc0a61a69b630836aa5c89a8dccce2c5a1716bc9775e80.yml -openapi_spec_hash: 9a0d67fb0781be034b77839584109638 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-3b19f5e2b96ede3193aa7a24d3f82d1406b8a16ea25e98ba3956e4a1a2376ad7.yml +openapi_spec_hash: b62a6e73ddcec71674973f795a5790ac config_hash: df889df131f7438197abd59faace3c77 From 4a122041257d78d3b583408e912d4d8a5b10cdc0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 21:18:13 +0000 Subject: [PATCH 2/4] feat(api): update via SDK Studio --- .stats.yml | 8 +- api.md | 10 ++ app.go | 64 +++++++++ app_test.go | 40 ++++++ appdeployment.go | 175 +++++++++++++++++++++++++ client_test.go | 103 +++++++++++++++ packages/ssestream/ssestream.go | 221 ++++++++++++++++++++++++++++++++ shared/constant/constants.go | 12 ++ 8 files changed, 629 insertions(+), 4 deletions(-) create mode 100644 app_test.go create mode 100644 packages/ssestream/ssestream.go diff --git a/.stats.yml b/.stats.yml index 6d03c39..01c41ad 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 5 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-3b19f5e2b96ede3193aa7a24d3f82d1406b8a16ea25e98ba3956e4a1a2376ad7.yml -openapi_spec_hash: b62a6e73ddcec71674973f795a5790ac -config_hash: df889df131f7438197abd59faace3c77 +configured_endpoints: 7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-c9d64df733f286f09d2203f4e3d820ce57e8d4c629c5e2db4e2bfac91fbc1598.yml +openapi_spec_hash: fa407611fc566d55f403864fbfaa6c23 +config_hash: 7f67c5b95af1e4b39525515240b72275 diff --git a/api.md b/api.md index afe95d1..eb9c93c 100644 --- a/api.md +++ b/api.md @@ -1,14 +1,24 @@ # Apps +Response Types: + +- kernel.AppListResponse + +Methods: + +- client.Apps.List(ctx context.Context, query kernel.AppListParams) ([]kernel.AppListResponse, error) + ## Deployments Response Types: - kernel.AppDeploymentNewResponse +- kernel.AppDeploymentFollowResponseUnion Methods: - client.Apps.Deployments.New(ctx context.Context, body kernel.AppDeploymentNewParams) (kernel.AppDeploymentNewResponse, error) +- client.Apps.Deployments.Follow(ctx context.Context, id string) ([]kernel.AppDeploymentFollowResponseUnion, error) ## Invocations diff --git a/app.go b/app.go index a5d6f7a..c3d26dc 100644 --- a/app.go +++ b/app.go @@ -3,7 +3,16 @@ package kernel import ( + "context" + "net/http" + "net/url" + + "github.com/onkernel/kernel-go-sdk/internal/apijson" + "github.com/onkernel/kernel-go-sdk/internal/apiquery" + "github.com/onkernel/kernel-go-sdk/internal/requestconfig" "github.com/onkernel/kernel-go-sdk/option" + "github.com/onkernel/kernel-go-sdk/packages/param" + "github.com/onkernel/kernel-go-sdk/packages/respjson" ) // AppService contains methods and other services that help with interacting with @@ -28,3 +37,58 @@ func NewAppService(opts ...option.RequestOption) (r AppService) { r.Invocations = NewAppInvocationService(opts...) return } + +// List application versions for the authenticated user. Optionally filter by app +// name and/or version label. +func (r *AppService) List(ctx context.Context, query AppListParams, opts ...option.RequestOption) (res *[]AppListResponse, err error) { + opts = append(r.Options[:], opts...) + path := "apps" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...) + return +} + +// Summary of an application version. +type AppListResponse struct { + // Unique identifier for the app version + ID string `json:"id,required"` + // Name of the application + AppName string `json:"app_name,required"` + // Deployment region code + Region string `json:"region,required"` + // Version label for the application + Version string `json:"version,required"` + // Environment variables configured for this app version + EnvVars map[string]string `json:"env_vars"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + ID respjson.Field + AppName respjson.Field + Region respjson.Field + Version respjson.Field + EnvVars respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AppListResponse) RawJSON() string { return r.JSON.raw } +func (r *AppListResponse) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AppListParams struct { + // Filter results by application name. + AppName param.Opt[string] `query:"app_name,omitzero" json:"-"` + // Filter results by version label. + Version param.Opt[string] `query:"version,omitzero" json:"-"` + paramObj +} + +// URLQuery serializes [AppListParams]'s query parameters as `url.Values`. +func (r AppListParams) URLQuery() (v url.Values, err error) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatComma, + NestedFormat: apiquery.NestedQueryFormatBrackets, + }) +} diff --git a/app_test.go b/app_test.go new file mode 100644 index 0000000..0b9b741 --- /dev/null +++ b/app_test.go @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/onkernel/kernel-go-sdk" + "github.com/onkernel/kernel-go-sdk/internal/testutil" + "github.com/onkernel/kernel-go-sdk/option" +) + +func TestAppListWithOptionalParams(t *testing.T) { + t.Skip("skipped: tests are disabled for the time being") + 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.Apps.List(context.TODO(), kernel.AppListParams{ + AppName: kernel.String("app_name"), + Version: kernel.String("version"), + }) + 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/appdeployment.go b/appdeployment.go index 1e9b914..67ebe32 100644 --- a/appdeployment.go +++ b/appdeployment.go @@ -5,9 +5,13 @@ package kernel import ( "bytes" "context" + "encoding/json" + "errors" + "fmt" "io" "mime/multipart" "net/http" + "time" "github.com/onkernel/kernel-go-sdk/internal/apiform" "github.com/onkernel/kernel-go-sdk/internal/apijson" @@ -15,6 +19,8 @@ import ( "github.com/onkernel/kernel-go-sdk/option" "github.com/onkernel/kernel-go-sdk/packages/param" "github.com/onkernel/kernel-go-sdk/packages/respjson" + "github.com/onkernel/kernel-go-sdk/packages/ssestream" + "github.com/onkernel/kernel-go-sdk/shared/constant" ) // AppDeploymentService contains methods and other services that help with @@ -44,6 +50,25 @@ func (r *AppDeploymentService) New(ctx context.Context, body AppDeploymentNewPar return } +// Establishes a Server-Sent Events (SSE) stream that delivers real-time logs and +// status updates for a deployed application. The stream terminates automatically +// once the application reaches a terminal state. +func (r *AppDeploymentService) FollowStreaming(ctx context.Context, id string, opts ...option.RequestOption) (stream *ssestream.Stream[[]AppDeploymentFollowResponseUnion]) { + var ( + raw *http.Response + err error + ) + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithHeader("Accept", "text/event-stream")}, opts...) + if id == "" { + err = errors.New("missing required id parameter") + return + } + path := fmt.Sprintf("apps/%s/events", id) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &raw, opts...) + return ssestream.NewStream[[]AppDeploymentFollowResponseUnion](ssestream.NewDecoder(raw), err) +} + type AppDeploymentNewResponse struct { // List of apps deployed Apps []AppDeploymentNewResponseApp `json:"apps,required"` @@ -119,6 +144,156 @@ const ( AppDeploymentNewResponseStatusFailed AppDeploymentNewResponseStatus = "failed" ) +// AppDeploymentFollowResponseUnion contains all possible properties and values +// from [AppDeploymentFollowResponseState], +// [AppDeploymentFollowResponseStateUpdate], [AppDeploymentFollowResponseLog]. +// +// Use the [AppDeploymentFollowResponseUnion.AsAny] method to switch on the +// variant. +// +// Use the methods beginning with 'As' to cast the union to one of its variants. +type AppDeploymentFollowResponseUnion struct { + // Any of "state", "state_update", "log". + Event string `json:"event"` + State string `json:"state"` + Timestamp time.Time `json:"timestamp"` + // This field is from variant [AppDeploymentFollowResponseLog]. + Message string `json:"message"` + JSON struct { + Event respjson.Field + State respjson.Field + Timestamp respjson.Field + Message respjson.Field + raw string + } `json:"-"` +} + +// anyAppDeploymentFollowResponse is implemented by each variant of +// [AppDeploymentFollowResponseUnion] to add type safety for the return type of +// [AppDeploymentFollowResponseUnion.AsAny] +type anyAppDeploymentFollowResponse interface { + implAppDeploymentFollowResponseUnion() +} + +func (AppDeploymentFollowResponseState) implAppDeploymentFollowResponseUnion() {} +func (AppDeploymentFollowResponseStateUpdate) implAppDeploymentFollowResponseUnion() {} +func (AppDeploymentFollowResponseLog) implAppDeploymentFollowResponseUnion() {} + +// Use the following switch statement to find the correct variant +// +// switch variant := AppDeploymentFollowResponseUnion.AsAny().(type) { +// case kernel.AppDeploymentFollowResponseState: +// case kernel.AppDeploymentFollowResponseStateUpdate: +// case kernel.AppDeploymentFollowResponseLog: +// default: +// fmt.Errorf("no variant present") +// } +func (u AppDeploymentFollowResponseUnion) AsAny() anyAppDeploymentFollowResponse { + switch u.Event { + case "state": + return u.AsState() + case "state_update": + return u.AsStateUpdate() + case "log": + return u.AsLog() + } + return nil +} + +func (u AppDeploymentFollowResponseUnion) AsState() (v AppDeploymentFollowResponseState) { + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) + return +} + +func (u AppDeploymentFollowResponseUnion) AsStateUpdate() (v AppDeploymentFollowResponseStateUpdate) { + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) + return +} + +func (u AppDeploymentFollowResponseUnion) AsLog() (v AppDeploymentFollowResponseLog) { + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) + return +} + +// Returns the unmodified JSON received from the API +func (u AppDeploymentFollowResponseUnion) RawJSON() string { return u.JSON.raw } + +func (r *AppDeploymentFollowResponseUnion) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// Initial state of the application, emitted once when subscribing. +type AppDeploymentFollowResponseState struct { + // Event type identifier (always "state"). + Event constant.State `json:"event,required"` + // Current application state (e.g., "deploying", "running", "succeeded", "failed"). + State string `json:"state,required"` + // Time the state was reported. + Timestamp time.Time `json:"timestamp" format:"date-time"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + Event respjson.Field + State respjson.Field + Timestamp respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AppDeploymentFollowResponseState) RawJSON() string { return r.JSON.raw } +func (r *AppDeploymentFollowResponseState) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// An update emitted when the application's state changes. +type AppDeploymentFollowResponseStateUpdate struct { + // Event type identifier (always "state_update"). + Event constant.StateUpdate `json:"event,required"` + // New application state (e.g., "running", "succeeded", "failed"). + State string `json:"state,required"` + // Time the state change occurred. + Timestamp time.Time `json:"timestamp" format:"date-time"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + Event respjson.Field + State respjson.Field + Timestamp respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AppDeploymentFollowResponseStateUpdate) RawJSON() string { return r.JSON.raw } +func (r *AppDeploymentFollowResponseStateUpdate) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// A log entry from the application. +type AppDeploymentFollowResponseLog struct { + // Event type identifier (always "log"). + Event constant.Log `json:"event,required"` + // Log message text. + Message string `json:"message,required"` + // Time the log entry was produced. + Timestamp time.Time `json:"timestamp" format:"date-time"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + Event respjson.Field + Message respjson.Field + Timestamp respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AppDeploymentFollowResponseLog) RawJSON() string { return r.JSON.raw } +func (r *AppDeploymentFollowResponseLog) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + type AppDeploymentNewParams struct { // Relative path to the entrypoint of the application EntrypointRelPath string `json:"entrypoint_rel_path,required"` diff --git a/client_test.go b/client_test.go index 6a04877..d9846bd 100644 --- a/client_test.go +++ b/client_test.go @@ -5,6 +5,7 @@ package kernel_test import ( "context" "fmt" + "io" "net/http" "reflect" "testing" @@ -257,3 +258,105 @@ func TestContextDeadline(t *testing.T) { } } } + +func TestContextDeadlineStreaming(t *testing.T) { + testTimeout := time.After(3 * time.Second) + testDone := make(chan struct{}) + + deadline := time.Now().Add(100 * time.Millisecond) + deadlineCtx, cancel := context.WithDeadline(context.Background(), deadline) + defer cancel() + + go func() { + client := kernel.NewClient( + option.WithAPIKey("My API Key"), + option.WithHTTPClient(&http.Client{ + Transport: &closureTransport{ + fn: func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: 200, + Status: "200 OK", + Body: io.NopCloser( + io.Reader(readerFunc(func([]byte) (int, error) { + <-req.Context().Done() + return 0, req.Context().Err() + })), + ), + }, nil + }, + }, + }), + ) + stream := client.Apps.Deployments.FollowStreaming(deadlineCtx, "id") + for stream.Next() { + _ = stream.Current() + } + if stream.Err() == nil { + t.Error("expected there to be a deadline error") + } + close(testDone) + }() + + select { + case <-testTimeout: + t.Fatal("client didn't finish in time") + case <-testDone: + if diff := time.Since(deadline); diff < -30*time.Millisecond || 30*time.Millisecond < diff { + t.Fatalf("client did not return within 30ms of context deadline, got %s", diff) + } + } +} + +func TestContextDeadlineStreamingWithRequestTimeout(t *testing.T) { + testTimeout := time.After(3 * time.Second) + testDone := make(chan struct{}) + deadline := time.Now().Add(100 * time.Millisecond) + + go func() { + client := kernel.NewClient( + option.WithAPIKey("My API Key"), + option.WithHTTPClient(&http.Client{ + Transport: &closureTransport{ + fn: func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: 200, + Status: "200 OK", + Body: io.NopCloser( + io.Reader(readerFunc(func([]byte) (int, error) { + <-req.Context().Done() + return 0, req.Context().Err() + })), + ), + }, nil + }, + }, + }), + ) + stream := client.Apps.Deployments.FollowStreaming( + context.Background(), + "id", + option.WithRequestTimeout((100 * time.Millisecond)), + ) + for stream.Next() { + _ = stream.Current() + } + if stream.Err() == nil { + t.Error("expected there to be a deadline error") + } + close(testDone) + }() + + select { + case <-testTimeout: + t.Fatal("client didn't finish in time") + case <-testDone: + if diff := time.Since(deadline); diff < -30*time.Millisecond || 30*time.Millisecond < diff { + t.Fatalf("client did not return within 30ms of context deadline, got %s", diff) + } + } +} + +type readerFunc func([]byte) (int, error) + +func (f readerFunc) Read(p []byte) (int, error) { return f(p) } +func (f readerFunc) Close() error { return nil } diff --git a/packages/ssestream/ssestream.go b/packages/ssestream/ssestream.go new file mode 100644 index 0000000..d6f6f3e --- /dev/null +++ b/packages/ssestream/ssestream.go @@ -0,0 +1,221 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package ssestream + +import ( + "bufio" + "bytes" + "encoding/json" + "io" + "net/http" + "strings" +) + +type Decoder interface { + Event() Event + Next() bool + Close() error + Err() error +} + +func NewDecoder(res *http.Response) Decoder { + if res == nil || res.Body == nil { + return nil + } + + var decoder Decoder + contentType := res.Header.Get("content-type") + if t, ok := decoderTypes[contentType]; ok { + decoder = t(res.Body) + } else { + decoder = &eventStreamDecoder{rc: res.Body, rdr: bufio.NewReader(res.Body)} + } + return decoder +} + +var decoderTypes = map[string](func(io.ReadCloser) Decoder){} + +func RegisterDecoder(contentType string, decoder func(io.ReadCloser) Decoder) { + decoderTypes[strings.ToLower(contentType)] = decoder +} + +type Event struct { + Type string + Data []byte +} + +// A base implementation of a Decoder for text/event-stream. +type eventStreamDecoder struct { + evt Event + rc io.ReadCloser + rdr *bufio.Reader + err error +} + +func line(r *bufio.Reader) ([]byte, error) { + var overflow bytes.Buffer + + // To prevent infinite loops, the failsafe stops when a line is + // 100 times longer than the [io.Reader] default buffer size, + // or after 20 failed attempts to find an end of line. + for f := 0; f < 100; f++ { + part, isPrefix, err := r.ReadLine() + if err != nil { + return nil, err + } + + // Happy case, the line fits in the default buffer. + if !isPrefix && overflow.Len() == 0 { + return part, nil + } + + // Overflow case, append to the buffer. + if isPrefix || overflow.Len() > 0 { + n, err := overflow.Write(part) + if err != nil { + return nil, err + } + + // Didn't find an end of line, heavily increment the failsafe. + if n != r.Size() { + f += 5 + } + } + + if !isPrefix { + return overflow.Bytes(), nil + } + } + + return nil, fmt.Errorf("ssestream: too many attempts to read a line") +} + +func (s *eventStreamDecoder) Next() bool { + if s.err != nil { + return false + } + + event := "" + data := bytes.NewBuffer(nil) + + for { + txt, err := line(s.rdr) + if err == io.EOF { + return false + } + + if err != nil { + s.err = err + break + } + + // Dispatch event on an empty line + if len(txt) == 0 { + s.evt = Event{ + Type: event, + Data: data.Bytes(), + } + return true + } + + // Split a string like "event: bar" into name="event" and value=" bar". + name, value, _ := bytes.Cut(txt, []byte(":")) + + // Consume an optional space after the colon if it exists. + if len(value) > 0 && value[0] == ' ' { + value = value[1:] + } + + switch string(name) { + case "": + // An empty line in the for ": something" is a comment and should be ignored. + continue + case "event": + event = string(value) + case "data": + _, s.err = data.Write(value) + if s.err != nil { + break + } + _, s.err = data.WriteRune('\n') + if s.err != nil { + break + } + } + } + + return false +} + +func (s *eventStreamDecoder) Event() Event { + return s.evt +} + +func (s *eventStreamDecoder) Close() error { + return s.rc.Close() +} + +func (s *eventStreamDecoder) Err() error { + return s.err +} + +type Stream[T any] struct { + decoder Decoder + cur T + err error +} + +func NewStream[T any](decoder Decoder, err error) *Stream[T] { + return &Stream[T]{ + decoder: decoder, + err: err, + } +} + +// Next returns false if the stream has ended or an error occurred. +// Call Stream.Current() to get the current value. +// Call Stream.Err() to get the error. +// +// for stream.Next() { +// data := stream.Current() +// } +// +// if stream.Err() != nil { +// ... +// } +func (s *Stream[T]) Next() bool { + if s.err != nil { + return false + } + + for s.decoder.Next() { + var nxt T + s.err = json.Unmarshal(s.decoder.Event().Data, &nxt) + if s.err != nil { + return false + } + s.cur = nxt + return true + } + + // decoder.Next() may be false because of an error + s.err = s.decoder.Err() + + return false +} + +func (s *Stream[T]) Current() T { + return s.cur +} + +func (s *Stream[T]) Err() error { + return s.err +} + +func (s *Stream[T]) Close() error { + if s.decoder == nil { + // already closed + return nil + } + return s.decoder.Close() +} diff --git a/shared/constant/constants.go b/shared/constant/constants.go index 60d880f..b109097 100644 --- a/shared/constant/constants.go +++ b/shared/constant/constants.go @@ -18,6 +18,18 @@ func ValueOf[T Constant[T]]() T { return t.Default() } +type Log string // Always "log" +type State string // Always "state" +type StateUpdate string // Always "state_update" + +func (c Log) Default() Log { return "log" } +func (c State) Default() State { return "state" } +func (c StateUpdate) Default() StateUpdate { return "state_update" } + +func (c Log) MarshalJSON() ([]byte, error) { return marshalString(c) } +func (c State) MarshalJSON() ([]byte, error) { return marshalString(c) } +func (c StateUpdate) MarshalJSON() ([]byte, error) { return marshalString(c) } + type constant[T any] interface { Constant[T] *T From b963ddcc96d51998117db01f916127ffd2a0338c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 21:18:27 +0000 Subject: [PATCH 3/4] release: 0.1.0-alpha.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ README.md | 2 +- internal/version.go | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f14b480..aaf968a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.2" + ".": "0.1.0-alpha.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d63d5..a8f222a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.1.0-alpha.3 (2025-05-19) + +Full Changelog: [v0.1.0-alpha.2...v0.1.0-alpha.3](https://github.com/onkernel/kernel-go-sdk/compare/v0.1.0-alpha.2...v0.1.0-alpha.3) + +### Features + +* **api:** update via SDK Studio ([4a12204](https://github.com/onkernel/kernel-go-sdk/commit/4a122041257d78d3b583408e912d4d8a5b10cdc0)) + ## 0.1.0-alpha.2 (2025-05-19) Full Changelog: [v0.1.0-alpha.1...v0.1.0-alpha.2](https://github.com/onkernel/kernel-go-sdk/compare/v0.1.0-alpha.1...v0.1.0-alpha.2) diff --git a/README.md b/README.md index 532eb7e..b2add49 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Or to pin the version: ```sh -go get -u 'github.com/onkernel/kernel-go-sdk@v0.1.0-alpha.2' +go get -u 'github.com/onkernel/kernel-go-sdk@v0.1.0-alpha.3' ``` diff --git a/internal/version.go b/internal/version.go index d6f40b3..2d1d85e 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.1.0-alpha.2" // x-release-please-version +const PackageVersion = "0.1.0-alpha.3" // x-release-please-version From c39e15485c44c2291b939cce3d77632c06ef0551 Mon Sep 17 00:00:00 2001 From: Rafael Date: Mon, 19 May 2025 17:21:43 -0400 Subject: [PATCH 4/4] fix ssestream fmt import --- packages/ssestream/ssestream.go | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ssestream/ssestream.go b/packages/ssestream/ssestream.go index d6f6f3e..02962ca 100644 --- a/packages/ssestream/ssestream.go +++ b/packages/ssestream/ssestream.go @@ -9,6 +9,7 @@ import ( "io" "net/http" "strings" + "fmt" ) type Decoder interface {