diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 536ca31..d87cca6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.11.4" + ".": "0.11.5" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index be90d46..2b8a4b6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 51 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-8b5a722e4964d2d1dcdc34afccb6d742e1c927cbbd622264c8734f132e31a0f5.yml -openapi_spec_hash: ed101ff177c2e962653ca65acf939336 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-da8bfd5cfb5a6d9ccb7e4edd123b49284f4eccb32fc9b6fb7165548535122e12.yml +openapi_spec_hash: fd6ded34689331831b5c077f71b5f08f config_hash: 49c2ff978aaa5ccb4ce324a72f116010 diff --git a/CHANGELOG.md b/CHANGELOG.md index c35b759..5b48b8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 0.11.5 (2025-09-29) + +Full Changelog: [v0.11.4...v0.11.5](https://github.com/onkernel/kernel-go-sdk/compare/v0.11.4...v0.11.5) + +### Features + +* Add App Version to Invocation and add filtering on App Version ([81f87e2](https://github.com/onkernel/kernel-go-sdk/commit/81f87e27ae242be9f7cfc75a6147e9eac669d4c4)) +* Fix my incorrect grammer ([f04186f](https://github.com/onkernel/kernel-go-sdk/commit/f04186fd786d47e49c42028c0237e02fd08d03b1)) + + +### Bug Fixes + +* bugfix for setting JSON keys with special characters ([32304ba](https://github.com/onkernel/kernel-go-sdk/commit/32304baca3b01de677fd705da2b03787b56fdf35)) + ## 0.11.4 (2025-09-25) Full Changelog: [v0.11.3...v0.11.4](https://github.com/onkernel/kernel-go-sdk/compare/v0.11.3...v0.11.4) diff --git a/README.md b/README.md index fd83fc8..7fa2ad9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Or to pin the version: ```sh -go get -u 'github.com/onkernel/kernel-go-sdk@v0.11.4' +go get -u 'github.com/onkernel/kernel-go-sdk@v0.11.5' ``` diff --git a/internal/apijson/encoder.go b/internal/apijson/encoder.go index 8358a2f..ab7a3c1 100644 --- a/internal/apijson/encoder.go +++ b/internal/apijson/encoder.go @@ -16,6 +16,10 @@ import ( var encoders sync.Map // map[encoderEntry]encoderFunc +// If we want to set a literal key value into JSON using sjson, we need to make sure it doesn't have +// special characters that sjson interprets as a path. +var EscapeSJSONKey = strings.NewReplacer("\\", "\\\\", "|", "\\|", "#", "\\#", "@", "\\@", "*", "\\*", ".", "\\.", ":", "\\:", "?", "\\?").Replace + func Marshal(value any) ([]byte, error) { e := &encoder{dateFormat: time.RFC3339} return e.marshal(value) @@ -270,7 +274,7 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { if encoded == nil { continue } - json, err = sjson.SetRawBytes(json, ef.tag.name, encoded) + json, err = sjson.SetRawBytes(json, EscapeSJSONKey(ef.tag.name), encoded) if err != nil { return nil, err } @@ -348,7 +352,7 @@ func (e *encoder) encodeMapEntries(json []byte, v reflect.Value) ([]byte, error) } encodedKeyString = string(encodedKeyBytes) } - encodedKey := []byte(sjsonReplacer.Replace(encodedKeyString)) + encodedKey := []byte(encodedKeyString) pairs = append(pairs, mapPair{key: encodedKey, value: iter.Value()}) } @@ -366,7 +370,7 @@ func (e *encoder) encodeMapEntries(json []byte, v reflect.Value) ([]byte, error) if len(encodedValue) == 0 { continue } - json, err = sjson.SetRawBytes(json, string(p.key), encodedValue) + json, err = sjson.SetRawBytes(json, EscapeSJSONKey(string(p.key)), encodedValue) if err != nil { return nil, err } @@ -386,7 +390,3 @@ func (e *encoder) newMapEncoder(_ reflect.Type) encoderFunc { return json, nil } } - -// If we want to set a literal key value into JSON using sjson, we need to make sure it doesn't have -// special characters that sjson interprets as a path. -var sjsonReplacer *strings.Replacer = strings.NewReplacer(".", "\\.", ":", "\\:", "*", "\\*") diff --git a/internal/apijson/union.go b/internal/apijson/union.go index 9d717e7..47546b5 100644 --- a/internal/apijson/union.go +++ b/internal/apijson/union.go @@ -78,7 +78,7 @@ func (d *decoderBuilder) newStructUnionDecoder(t reflect.Type) decoderFunc { return func(n gjson.Result, v reflect.Value, state *decoderState) error { if discriminated && n.Type == gjson.JSON && len(unionEntry.discriminatorKey) != 0 { - discriminator := n.Get(unionEntry.discriminatorKey).Value() + discriminator := n.Get(EscapeSJSONKey(unionEntry.discriminatorKey)).Value() for _, decoder := range discriminatedDecoders { if discriminator == decoder.discriminator { inner := v.FieldByIndex(decoder.field.Index) @@ -162,7 +162,7 @@ func (d *decoderBuilder) newUnionDecoder(t reflect.Type) decoderFunc { } if len(unionEntry.discriminatorKey) != 0 { - discriminatorValue := n.Get(unionEntry.discriminatorKey).Value() + discriminatorValue := n.Get(EscapeSJSONKey(unionEntry.discriminatorKey)).Value() if discriminatorValue == variant.DiscriminatorValue { inner := reflect.New(variant.Type).Elem() err := decoder(n, inner, state) diff --git a/internal/version.go b/internal/version.go index 5711c5e..cd5053a 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.11.4" // x-release-please-version +const PackageVersion = "0.11.5" // x-release-please-version diff --git a/invocation.go b/invocation.go index 4fc359f..485508b 100644 --- a/invocation.go +++ b/invocation.go @@ -63,8 +63,8 @@ func (r *InvocationService) Get(ctx context.Context, id string, opts ...option.R return } -// Update an invocation's status or output. This can used to cancel an invocation -// by setting the status to "failed". +// Update an invocation's status or output. This can be used to cancel an +// invocation by setting the status to "failed". func (r *InvocationService) Update(ctx context.Context, id string, body InvocationUpdateParams, opts ...option.RequestOption) (res *InvocationUpdateResponse, err error) { opts = slices.Concat(r.Options, opts) if id == "" { @@ -169,6 +169,8 @@ type InvocationStateEventInvocation struct { // // Any of "queued", "running", "succeeded", "failed". Status string `json:"status,required"` + // Version label for the application + Version string `json:"version,required"` // RFC 3339 Nanoseconds timestamp when the invocation finished (null if still // running) FinishedAt time.Time `json:"finished_at,nullable" format:"date-time"` @@ -186,6 +188,7 @@ type InvocationStateEventInvocation struct { AppName respjson.Field StartedAt respjson.Field Status respjson.Field + Version respjson.Field FinishedAt respjson.Field Output respjson.Field Payload respjson.Field @@ -256,6 +259,8 @@ type InvocationGetResponse struct { // // Any of "queued", "running", "succeeded", "failed". Status InvocationGetResponseStatus `json:"status,required"` + // Version label for the application + Version string `json:"version,required"` // RFC 3339 Nanoseconds timestamp when the invocation finished (null if still // running) FinishedAt time.Time `json:"finished_at,nullable" format:"date-time"` @@ -273,6 +278,7 @@ type InvocationGetResponse struct { AppName respjson.Field StartedAt respjson.Field Status respjson.Field + Version respjson.Field FinishedAt respjson.Field Output respjson.Field Payload respjson.Field @@ -311,6 +317,8 @@ type InvocationUpdateResponse struct { // // Any of "queued", "running", "succeeded", "failed". Status InvocationUpdateResponseStatus `json:"status,required"` + // Version label for the application + Version string `json:"version,required"` // RFC 3339 Nanoseconds timestamp when the invocation finished (null if still // running) FinishedAt time.Time `json:"finished_at,nullable" format:"date-time"` @@ -328,6 +336,7 @@ type InvocationUpdateResponse struct { AppName respjson.Field StartedAt respjson.Field Status respjson.Field + Version respjson.Field FinishedAt respjson.Field Output respjson.Field Payload respjson.Field @@ -366,6 +375,8 @@ type InvocationListResponse struct { // // Any of "queued", "running", "succeeded", "failed". Status InvocationListResponseStatus `json:"status,required"` + // Version label for the application + Version string `json:"version,required"` // RFC 3339 Nanoseconds timestamp when the invocation finished (null if still // running) FinishedAt time.Time `json:"finished_at,nullable" format:"date-time"` @@ -383,6 +394,7 @@ type InvocationListResponse struct { AppName respjson.Field StartedAt respjson.Field Status respjson.Field + Version respjson.Field FinishedAt respjson.Field Output respjson.Field Payload respjson.Field @@ -558,6 +570,8 @@ type InvocationListParams struct { // Show invocations that have started since the given time (RFC timestamps or // durations like 5m). Since param.Opt[string] `query:"since,omitzero" json:"-"` + // Filter results by application version. + Version param.Opt[string] `query:"version,omitzero" json:"-"` // Filter results by invocation status. // // Any of "queued", "running", "succeeded", "failed". diff --git a/invocation_test.go b/invocation_test.go index 4adc977..c99ca1a 100644 --- a/invocation_test.go +++ b/invocation_test.go @@ -116,6 +116,7 @@ func TestInvocationListWithOptionalParams(t *testing.T) { Offset: kernel.Int(0), Since: kernel.String("2025-06-20T12:00:00Z"), Status: kernel.InvocationListParamsStatusQueued, + Version: kernel.String("version"), }) if err != nil { var apierr *kernel.Error diff --git a/packages/param/encoder.go b/packages/param/encoder.go index 4ecb57b..6197202 100644 --- a/packages/param/encoder.go +++ b/packages/param/encoder.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "reflect" + "strings" "time" shimjson "github.com/onkernel/kernel-go-sdk/internal/encoding/json" @@ -14,6 +15,10 @@ import ( // EncodedAsDate is not be stable and shouldn't be relied upon type EncodedAsDate Opt[time.Time] +// If we want to set a literal key value into JSON using sjson, we need to make sure it doesn't have +// special characters that sjson interprets as a path. +var EscapeSJSONKey = strings.NewReplacer("\\", "\\\\", "|", "\\|", "#", "\\#", "@", "\\@", "*", "\\*", ".", "\\.", ":", "\\:", "?", "\\?").Replace + type forceOmit int func (m EncodedAsDate) MarshalJSON() ([]byte, error) { @@ -52,7 +57,7 @@ func MarshalWithExtras[T ParamStruct, R any](f T, underlying any, extras map[str } continue } - bytes, err = sjson.SetBytes(bytes, k, v) + bytes, err = sjson.SetBytes(bytes, EscapeSJSONKey(k), v) if err != nil { return nil, err }