diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 65f558e..656a2ef 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.0.0"
+ ".": "2.1.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 96e30e1..333dfb4 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 43
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-c7ad6f552b38f2145781847f8b390fa1ec43068d64e45a33012a97a9299edc10.yml
-openapi_spec_hash: 50f281e91210ad5018ac7e4eee216f56
-config_hash: 74a8263b80c732a2b016177e7d56bb9c
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-9d184cb502ab32a85db2889c796cdfebe812f2a55a604df79c85dd4b5e7e2add.yml
+openapi_spec_hash: a9aa620376fce66532c84f9364209b0b
+config_hash: 71cab8223bb5610c6c7ca6e9c4cc1f89
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 488241b..ca55236 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,36 @@
# Changelog
+## 2.1.0 (2025-12-19)
+
+Full Changelog: [v2.0.0...v2.1.0](https://github.com/imagekit-developer/imagekit-go/compare/v2.0.0...v2.1.0)
+
+### Features
+
+* **api:** add GetImageAttributesOptions and ResponsiveImageAttributes schemas; update resource references in main.yaml; remove dummy endpoint ([41072da](https://github.com/imagekit-developer/imagekit-go/commit/41072da63cd2ba891a911d932af3bc8b70c90588))
+* **api:** fix go sdk breaking changes ([6cbddff](https://github.com/imagekit-developer/imagekit-go/commit/6cbddffab95c89b964fc29ce119ceb70d7ebded5))
+* **encoder:** support bracket encoding form-data object members ([cb3e557](https://github.com/imagekit-developer/imagekit-go/commit/cb3e5572b00fe978ee93d595cc4d8775edccbc89))
+
+
+### Bug Fixes
+
+* **client:** correctly specify Accept header with */* instead of empty ([21a30a4](https://github.com/imagekit-developer/imagekit-go/commit/21a30a4d60b4b2da84d2314ddf6bcf76759da64d))
+* **client:** properly marshal embedded structs ([e55e614](https://github.com/imagekit-developer/imagekit-go/commit/e55e614fab629dfab68d7249e53ef602dd1a36b3))
+* **docs:** update go get command to include version path in README.md ([d7d4c82](https://github.com/imagekit-developer/imagekit-go/commit/d7d4c829ebccafd1242d79a03651f1189c9f24d0))
+* **mcp:** correct code tool API endpoint ([b32395e](https://github.com/imagekit-developer/imagekit-go/commit/b32395e36a3fdd2f8e37313a303a68135f13400f))
+* rename param to avoid collision ([5067fd4](https://github.com/imagekit-developer/imagekit-go/commit/5067fd4adfe3a7108f3799f270c4211ade385882))
+* skip usage tests that don't work with Prism ([429ad75](https://github.com/imagekit-developer/imagekit-go/commit/429ad75eb8c267b44a9c8e4f2c542344189563e3))
+
+
+### Chores
+
+* add float64 to valid types for RegisterFieldValidator ([2dc3cae](https://github.com/imagekit-developer/imagekit-go/commit/2dc3cae63386dc6b8c7743af3fdb0a9c4ed93ef5))
+* bump gjson version ([87ad44d](https://github.com/imagekit-developer/imagekit-go/commit/87ad44d7016dcb641158e26cc4f0d08e89770dc5))
+* elide duplicate aliases ([2f9eee1](https://github.com/imagekit-developer/imagekit-go/commit/2f9eee11c82bd0b6641dec1f0c20042863ad169f))
+* **internal:** codegen related update ([8877b4f](https://github.com/imagekit-developer/imagekit-go/commit/8877b4fbdce39a56785613a1172dda44399c6fe7))
+* **internal:** codegen related update ([d83769d](https://github.com/imagekit-developer/imagekit-go/commit/d83769df0486737f479694acc9421415fb11c523))
+* **internal:** codegen related update ([63165ac](https://github.com/imagekit-developer/imagekit-go/commit/63165ac51ec10df842ed8f9496c82294b4f9e61e))
+* **internal:** grammar fix (it's -> its) ([e35e192](https://github.com/imagekit-developer/imagekit-go/commit/e35e1922f7ad2541ed116db557bcedd8c9c088de))
+
## 2.0.0 (2025-10-05)
Full Changelog: [v0.0.1...v2.0.0](https://github.com/imagekit-developer/imagekit-go/compare/v0.0.1...v2.0.0)
diff --git a/README.md b/README.md
index 58286aa..9e5488d 100644
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ Or to pin the version:
```sh
-go get -u 'github.com/imagekit-developer/imagekit-go@v2.0.0'
+go get -u 'github.com/imagekit-developer/imagekit-go/v2@v2.1.0'
```
@@ -167,7 +167,7 @@ custom := param.Override[imagekit.FooParams](12)
### Request unions
-Unions are represented as a struct with fields prefixed by "Of" for each of it's variants,
+Unions are represented as a struct with fields prefixed by "Of" for each of its variants,
only one field can be non-zero. The non-zero field will be serialized.
Sub-properties of the union can be accessed via methods on the union struct.
diff --git a/accountorigin.go b/accountorigin.go
index 79a8d4a..52888b2 100644
--- a/accountorigin.go
+++ b/accountorigin.go
@@ -74,7 +74,7 @@ func (r *AccountOriginService) List(ctx context.Context, opts ...option.RequestO
// any URL‑endpoints, the API will return an error.
func (r *AccountOriginService) 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...)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...)
if id == "" {
err = errors.New("missing required id parameter")
return
diff --git a/accounturlendpoint.go b/accounturlendpoint.go
index 7991a84..dbd0224 100644
--- a/accounturlendpoint.go
+++ b/accounturlendpoint.go
@@ -75,7 +75,7 @@ func (r *AccountURLEndpointService) List(ctx context.Context, opts ...option.Req
// URL‑endpoint created by ImageKit during account creation.
func (r *AccountURLEndpointService) 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...)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...)
if id == "" {
err = errors.New("missing required id parameter")
return
diff --git a/aliases.go b/aliases.go
index be8fe53..33ed8d6 100644
--- a/aliases.go
+++ b/aliases.go
@@ -40,6 +40,13 @@ type ExtensionAutoTaggingParam = shared.ExtensionAutoTaggingParam
// This is an alias to an internal type.
type ExtensionAIAutoDescriptionParam = shared.ExtensionAIAutoDescriptionParam
+// Options for generating responsive image attributes including `src`, `srcSet`,
+// and `sizes` for HTML `
` elements. This schema extends `SrcOptions` to add
+// support for responsive image generation with breakpoints.
+//
+// This is an alias to an internal type.
+type GetImageAttributesOptionsParam = shared.GetImageAttributesOptionsParam
+
// This is an alias to an internal type.
type ImageOverlayParam = shared.ImageOverlayParam
@@ -133,6 +140,12 @@ type OverlayTimingEndUnionParam = shared.OverlayTimingEndUnionParam
// This is an alias to an internal type.
type OverlayTimingStartUnionParam = shared.OverlayTimingStartUnionParam
+// Resulting set of attributes suitable for an HTML `
` element. Useful for
+// enabling responsive image loading with `srcSet` and `sizes`.
+//
+// This is an alias to an internal type.
+type ResponsiveImageAttributesParam = shared.ResponsiveImageAttributesParam
+
// This is an alias to an internal type.
type SolidColorOverlayParam = shared.SolidColorOverlayParam
diff --git a/api.md b/api.md
index d1fe4eb..2589aa8 100644
--- a/api.md
+++ b/api.md
@@ -2,10 +2,12 @@
- shared.BaseOverlayParam
- shared.ExtensionsParam
+- shared.GetImageAttributesOptionsParam
- shared.ImageOverlayParam
- shared.OverlayUnionParam
- shared.OverlayPositionParam
- shared.OverlayTimingParam
+- shared.ResponsiveImageAttributesParam
- shared.SolidColorOverlayParam
- shared.SolidColorOverlayTransformationParam
- shared.SrcOptionsParam
@@ -18,6 +20,12 @@
- shared.TransformationPosition
- shared.VideoOverlayParam
+# Dummy
+
+Methods:
+
+- client.Dummy.New(ctx context.Context, body imagekit.DummyNewParams) error
+
# CustomMetadataFields
Response Types:
diff --git a/dummy.go b/dummy.go
index 9f26efb..80449e4 100644
--- a/dummy.go
+++ b/dummy.go
@@ -38,7 +38,7 @@ func NewDummyService(opts ...option.RequestOption) (r DummyService) {
// and is not intended for public consumption.
func (r *DummyService) New(ctx context.Context, body DummyNewParams, opts ...option.RequestOption) (err error) {
opts = slices.Concat(r.Options, opts)
- opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...)
path := "v1/dummy/test"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...)
return
@@ -48,15 +48,22 @@ type DummyNewParams struct {
BaseOverlay shared.BaseOverlayParam `json:"baseOverlay,omitzero"`
// Array of extensions to be applied to the asset. Each extension can be configured
// with specific parameters based on the extension type.
- Extensions shared.ExtensionsParam `json:"extensions,omitzero"`
- ImageOverlay shared.ImageOverlayParam `json:"imageOverlay,omitzero"`
+ Extensions shared.ExtensionsParam `json:"extensions,omitzero"`
+ // Options for generating responsive image attributes including `src`, `srcSet`,
+ // and `sizes` for HTML `
` elements. This schema extends `SrcOptions` to add
+ // support for responsive image generation with breakpoints.
+ GetImageAttributesOptions shared.GetImageAttributesOptionsParam `json:"getImageAttributesOptions,omitzero"`
+ ImageOverlay shared.ImageOverlayParam `json:"imageOverlay,omitzero"`
// Specifies an overlay to be applied on the parent image or video. ImageKit
// supports overlays including images, text, videos, subtitles, and solid colors.
// See
// [Overlay using layers](https://imagekit.io/docs/transformations#overlay-using-layers).
- Overlay shared.OverlayUnionParam `json:"overlay,omitzero"`
- OverlayPosition shared.OverlayPositionParam `json:"overlayPosition,omitzero"`
- OverlayTiming shared.OverlayTimingParam `json:"overlayTiming,omitzero"`
+ Overlay shared.OverlayUnionParam `json:"overlay,omitzero"`
+ OverlayPosition shared.OverlayPositionParam `json:"overlayPosition,omitzero"`
+ OverlayTiming shared.OverlayTimingParam `json:"overlayTiming,omitzero"`
+ // Resulting set of attributes suitable for an HTML `
` element. Useful for
+ // enabling responsive image loading with `srcSet` and `sizes`.
+ ResponsiveImageAttributes shared.ResponsiveImageAttributesParam `json:"responsiveImageAttributes,omitzero"`
SolidColorOverlay shared.SolidColorOverlayParam `json:"solidColorOverlay,omitzero"`
SolidColorOverlayTransformation shared.SolidColorOverlayTransformationParam `json:"solidColorOverlayTransformation,omitzero"`
// Options for generating ImageKit URLs with transformations. See the
diff --git a/dummy_test.go b/dummy_test.go
index 0548e6a..96a9a1c 100644
--- a/dummy_test.go
+++ b/dummy_test.go
@@ -69,6 +69,168 @@ func TestDummyNewWithOptionalParams(t *testing.T) {
}, shared.ExtensionUnionParam{
OfAIAutoDescription: &shared.ExtensionAIAutoDescriptionParam{},
}},
+ GetImageAttributesOptions: shared.GetImageAttributesOptionsParam{
+ SrcOptionsParam: shared.SrcOptionsParam{
+ Src: "/my-image.jpg",
+ URLEndpoint: "https://ik.imagekit.io/demo",
+ ExpiresIn: imagekit.Float(0),
+ QueryParameters: map[string]string{
+ "foo": "string",
+ },
+ Signed: imagekit.Bool(true),
+ Transformation: []shared.TransformationParam{{
+ AIChangeBackground: imagekit.String("aiChangeBackground"),
+ AIDropShadow: shared.TransformationAIDropShadowUnionParam{
+ OfTransformationAIDropShadowBoolean: imagekit.Bool(true),
+ },
+ AIEdit: imagekit.String("aiEdit"),
+ AIRemoveBackground: true,
+ AIRemoveBackgroundExternal: true,
+ AIRetouch: true,
+ AIUpscale: true,
+ AIVariation: true,
+ AspectRatio: shared.TransformationAspectRatioUnionParam{
+ OfString: imagekit.String("4:3"),
+ },
+ AudioCodec: shared.TransformationAudioCodecAac,
+ Background: imagekit.String("red"),
+ Blur: imagekit.Float(10),
+ Border: imagekit.String("5_FF0000"),
+ ColorProfile: imagekit.Bool(true),
+ ContrastStretch: true,
+ Crop: shared.TransformationCropForce,
+ CropMode: shared.TransformationCropModePadResize,
+ DefaultImage: imagekit.String("defaultImage"),
+ Dpr: imagekit.Float(2),
+ Duration: shared.TransformationDurationUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ EndOffset: shared.TransformationEndOffsetUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Flip: shared.TransformationFlipH,
+ Focus: imagekit.String("center"),
+ Format: shared.TransformationFormatAuto,
+ Gradient: shared.TransformationGradientUnionParam{
+ OfTransformationGradientBoolean: imagekit.Bool(true),
+ },
+ Grayscale: true,
+ Height: shared.TransformationHeightUnionParam{
+ OfFloat: imagekit.Float(200),
+ },
+ Lossless: imagekit.Bool(true),
+ Metadata: imagekit.Bool(true),
+ Named: imagekit.String("named"),
+ Opacity: imagekit.Float(0),
+ Original: imagekit.Bool(true),
+ Overlay: shared.OverlayUnionParam{
+ OfText: &shared.TextOverlayParam{
+ BaseOverlayParam: shared.BaseOverlayParam{
+ Position: shared.OverlayPositionParam{
+ Focus: shared.OverlayPositionFocusCenter,
+ X: shared.OverlayPositionXUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Y: shared.OverlayPositionYUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ },
+ Timing: shared.OverlayTimingParam{
+ Duration: shared.OverlayTimingDurationUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ End: shared.OverlayTimingEndUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Start: shared.OverlayTimingStartUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ },
+ },
+ Text: "text",
+ Encoding: "auto",
+ Transformation: []shared.TextOverlayTransformationParam{{
+ Alpha: imagekit.Float(1),
+ Background: imagekit.String("background"),
+ Flip: shared.TextOverlayTransformationFlipH,
+ FontColor: imagekit.String("fontColor"),
+ FontFamily: imagekit.String("fontFamily"),
+ FontSize: shared.TextOverlayTransformationFontSizeUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ InnerAlignment: shared.TextOverlayTransformationInnerAlignmentLeft,
+ LineHeight: shared.TextOverlayTransformationLineHeightUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Padding: shared.TextOverlayTransformationPaddingUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Radius: shared.TextOverlayTransformationRadiusUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Rotation: shared.TextOverlayTransformationRotationUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Typography: imagekit.String("typography"),
+ Width: shared.TextOverlayTransformationWidthUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ }},
+ },
+ },
+ Page: shared.TransformationPageUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Progressive: imagekit.Bool(true),
+ Quality: imagekit.Float(80),
+ Radius: shared.TransformationRadiusUnionParam{
+ OfFloat: imagekit.Float(20),
+ },
+ Raw: imagekit.String("raw"),
+ Rotation: shared.TransformationRotationUnionParam{
+ OfFloat: imagekit.Float(90),
+ },
+ Shadow: shared.TransformationShadowUnionParam{
+ OfTransformationShadowBoolean: imagekit.Bool(true),
+ },
+ Sharpen: shared.TransformationSharpenUnionParam{
+ OfTransformationSharpenBoolean: imagekit.Bool(true),
+ },
+ StartOffset: shared.TransformationStartOffsetUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ StreamingResolutions: []shared.StreamingResolution{shared.StreamingResolution240},
+ Trim: shared.TransformationTrimUnionParam{
+ OfTransformationTrimBoolean: imagekit.Bool(true),
+ },
+ UnsharpMask: shared.TransformationUnsharpMaskUnionParam{
+ OfTransformationUnsharpMaskBoolean: imagekit.Bool(true),
+ },
+ VideoCodec: shared.TransformationVideoCodecH264,
+ Width: shared.TransformationWidthUnionParam{
+ OfFloat: imagekit.Float(300),
+ },
+ X: shared.TransformationXUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ XCenter: shared.TransformationXCenterUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Y: shared.TransformationYUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ YCenter: shared.TransformationYCenterUnionParam{
+ OfFloat: imagekit.Float(0),
+ },
+ Zoom: imagekit.Float(0),
+ }},
+ TransformationPosition: shared.TransformationPositionPath,
+ },
+ DeviceBreakpoints: []float64{640, 750, 828, 1080, 1200, 1920, 2048, 3840},
+ ImageBreakpoints: []float64{16, 32, 48, 64, 96, 128, 256, 384},
+ Sizes: imagekit.String("(min-width: 768px) 50vw, 100vw"),
+ Width: imagekit.Float(400),
+ },
ImageOverlay: shared.ImageOverlayParam{
BaseOverlayParam: shared.BaseOverlayParam{
Position: shared.OverlayPositionParam{
@@ -316,6 +478,12 @@ func TestDummyNewWithOptionalParams(t *testing.T) {
OfFloat: imagekit.Float(0),
},
},
+ ResponsiveImageAttributes: shared.ResponsiveImageAttributesParam{
+ Src: "https://ik.imagekit.io/demo/image.jpg?tr=w-3840",
+ Sizes: imagekit.String("100vw"),
+ SrcSet: imagekit.String("https://ik.imagekit.io/demo/image.jpg?tr=w-640 640w, https://ik.imagekit.io/demo/image.jpg?tr=w-1080 1080w, https://ik.imagekit.io/demo/image.jpg?tr=w-1920 1920w"),
+ Width: imagekit.Float(400),
+ },
SolidColorOverlay: shared.SolidColorOverlayParam{
BaseOverlayParam: shared.BaseOverlayParam{
Position: shared.OverlayPositionParam{
diff --git a/file.go b/file.go
index 95a44c3..a35ca04 100644
--- a/file.go
+++ b/file.go
@@ -72,7 +72,7 @@ func (r *FileService) Update(ctx context.Context, fileID string, body FileUpdate
// the cache using purge cache API.
func (r *FileService) Delete(ctx context.Context, fileID string, opts ...option.RequestOption) (err error) {
opts = slices.Concat(r.Options, opts)
- opts = append([]option.RequestOption{option.WithHeader("Accept", "")}, opts...)
+ opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...)
if fileID == "" {
err = errors.New("missing required fileId parameter")
return
diff --git a/go.mod b/go.mod
index 11f9670..a0e1ba6 100644
--- a/go.mod
+++ b/go.mod
@@ -3,8 +3,8 @@ module github.com/imagekit-developer/imagekit-go/v2
go 1.22
require (
- github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20250711233419-a173a6c0125c
- github.com/tidwall/gjson v1.14.4
+ github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20251210175704-b03a68fe8b19
+ github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
)
diff --git a/go.sum b/go.sum
index 318dc77..f1261e2 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,8 @@
-github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20250711233419-a173a6c0125c h1:Mm99t6GdFMtZOwyyvu3q8gXeZX0sqnjvimTC9QCJwQc=
-github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20250711233419-a173a6c0125c/go.mod h1:L1MQhA6x4dn9r007T033lsaZMv9EmBAdXyU/+EF40fo=
+github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20251210175704-b03a68fe8b19 h1:8rMUmsyom6y/10iTAgqkfv8zHVKxVQxFwlOb42V23cA=
+github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20251210175704-b03a68fe8b19/go.mod h1:L1MQhA6x4dn9r007T033lsaZMv9EmBAdXyU/+EF40fo=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
-github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
-github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
+github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
diff --git a/internal/apiform/encoder.go b/internal/apiform/encoder.go
index 1d6afb2..58f5621 100644
--- a/internal/apiform/encoder.go
+++ b/internal/apiform/encoder.go
@@ -60,6 +60,7 @@ type encoderField struct {
type encoderEntry struct {
reflect.Type
dateFormat string
+ arrayFmt string
root bool
}
@@ -77,6 +78,7 @@ func (e *encoder) typeEncoder(t reflect.Type) encoderFunc {
entry := encoderEntry{
Type: t,
dateFormat: e.dateFormat,
+ arrayFmt: e.arrayFmt,
root: e.root,
}
@@ -178,34 +180,9 @@ func (e *encoder) newPrimitiveTypeEncoder(t reflect.Type) encoderFunc {
}
}
-func arrayKeyEncoder(arrayFmt string) func(string, int) string {
- var keyFn func(string, int) string
- switch arrayFmt {
- case "comma", "repeat":
- keyFn = func(k string, _ int) string { return k }
- case "brackets":
- keyFn = func(key string, _ int) string { return key + "[]" }
- case "indices:dots":
- keyFn = func(k string, i int) string {
- if k == "" {
- return strconv.Itoa(i)
- }
- return k + "." + strconv.Itoa(i)
- }
- case "indices:brackets":
- keyFn = func(k string, i int) string {
- if k == "" {
- return strconv.Itoa(i)
- }
- return k + "[" + strconv.Itoa(i) + "]"
- }
- }
- return keyFn
-}
-
func (e *encoder) newArrayTypeEncoder(t reflect.Type) encoderFunc {
itemEncoder := e.typeEncoder(t.Elem())
- keyFn := arrayKeyEncoder(e.arrayFmt)
+ keyFn := e.arrayKeyEncoder()
return func(key string, v reflect.Value, writer *multipart.Writer) error {
if keyFn == nil {
return fmt.Errorf("apiform: unsupported array format")
@@ -303,13 +280,10 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc {
})
return func(key string, value reflect.Value, writer *multipart.Writer) error {
- if key != "" {
- key = key + "."
- }
-
+ keyFn := e.objKeyEncoder(key)
for _, ef := range encoderFields {
field := value.FieldByIndex(ef.idx)
- err := ef.fn(key+ef.tag.name, field, writer)
+ err := ef.fn(keyFn(ef.tag.name), field, writer)
if err != nil {
return err
}
@@ -405,6 +379,43 @@ func (e *encoder) newReaderTypeEncoder() encoderFunc {
}
}
+func (e encoder) arrayKeyEncoder() func(string, int) string {
+ var keyFn func(string, int) string
+ switch e.arrayFmt {
+ case "comma", "repeat":
+ keyFn = func(k string, _ int) string { return k }
+ case "brackets":
+ keyFn = func(key string, _ int) string { return key + "[]" }
+ case "indices:dots":
+ keyFn = func(k string, i int) string {
+ if k == "" {
+ return strconv.Itoa(i)
+ }
+ return k + "." + strconv.Itoa(i)
+ }
+ case "indices:brackets":
+ keyFn = func(k string, i int) string {
+ if k == "" {
+ return strconv.Itoa(i)
+ }
+ return k + "[" + strconv.Itoa(i) + "]"
+ }
+ }
+ return keyFn
+}
+
+func (e encoder) objKeyEncoder(parent string) func(string) string {
+ if parent == "" {
+ return func(child string) string { return child }
+ }
+ switch e.arrayFmt {
+ case "brackets":
+ return func(child string) string { return parent + "[" + child + "]" }
+ default:
+ return func(child string) string { return parent + "." + child }
+ }
+}
+
// Given a []byte of json (may either be an empty object or an object that already contains entries)
// encode all of the entries in the map to the json byte array.
func (e *encoder) encodeMapEntries(key string, v reflect.Value, writer *multipart.Writer) error {
@@ -413,10 +424,6 @@ func (e *encoder) encodeMapEntries(key string, v reflect.Value, writer *multipar
value reflect.Value
}
- if key != "" {
- key = key + "."
- }
-
pairs := []mapPair{}
iter := v.MapRange()
@@ -434,8 +441,9 @@ func (e *encoder) encodeMapEntries(key string, v reflect.Value, writer *multipar
})
elementEncoder := e.typeEncoder(v.Type().Elem())
+ keyFn := e.objKeyEncoder(key)
for _, p := range pairs {
- err := elementEncoder(key+string(p.key), p.value, writer)
+ err := elementEncoder(keyFn(p.key), p.value, writer)
if err != nil {
return err
}
diff --git a/internal/apiform/form_test.go b/internal/apiform/form_test.go
index 3b95794..86cb43d 100644
--- a/internal/apiform/form_test.go
+++ b/internal/apiform/form_test.go
@@ -123,6 +123,18 @@ type StructUnion struct {
param.APIUnion
}
+type MultipartMarshalerParent struct {
+ Middle MultipartMarshalerMiddleNext `form:"middle"`
+}
+
+type MultipartMarshalerMiddleNext struct {
+ MiddleNext MultipartMarshalerMiddle `form:"middleNext"`
+}
+
+type MultipartMarshalerMiddle struct {
+ Child int `form:"child"`
+}
+
var tests = map[string]struct {
buf string
val any
@@ -366,6 +378,19 @@ true
},
},
},
+ "recursive_struct,brackets": {
+ `--xxx
+Content-Disposition: form-data; name="child[name]"
+
+Alex
+--xxx
+Content-Disposition: form-data; name="name"
+
+Robert
+--xxx--
+`,
+ Recursive{Name: "Robert", Child: &Recursive{Name: "Alex"}},
+ },
"recursive_struct": {
`--xxx
@@ -529,6 +554,30 @@ Content-Disposition: form-data; name="union"
Union: UnionTime(time.Date(2010, 05, 23, 0, 0, 0, 0, time.UTC)),
},
},
+ "deeply-nested-struct,brackets": {
+ `--xxx
+Content-Disposition: form-data; name="middle[middleNext][child]"
+
+10
+--xxx--
+`,
+ MultipartMarshalerParent{
+ Middle: MultipartMarshalerMiddleNext{
+ MiddleNext: MultipartMarshalerMiddle{
+ Child: 10,
+ },
+ },
+ },
+ },
+ "deeply-nested-map,brackets": {
+ `--xxx
+Content-Disposition: form-data; name="middle[middleNext][child]"
+
+10
+--xxx--
+`,
+ map[string]any{"middle": map[string]any{"middleNext": map[string]any{"child": 10}}},
+ },
}
func TestEncode(t *testing.T) {
@@ -553,7 +602,7 @@ func TestEncode(t *testing.T) {
}
raw := buf.Bytes()
if string(raw) != strings.ReplaceAll(test.buf, "\n", "\r\n") {
- t.Errorf("expected %+#v to serialize to '%s' but got '%s'", test.val, test.buf, string(raw))
+ t.Errorf("expected %+#v to serialize to '%s' but got '%s' (with format %s)", test.val, test.buf, string(raw), arrayFmt)
}
})
}
diff --git a/internal/apijson/enum.go b/internal/apijson/enum.go
index 18b218a..5bef11c 100644
--- a/internal/apijson/enum.go
+++ b/internal/apijson/enum.go
@@ -29,7 +29,7 @@ type validatorFunc func(reflect.Value) exactness
var validators sync.Map
var validationRegistry = map[reflect.Type][]validationEntry{}
-func RegisterFieldValidator[T any, V string | bool | int](fieldName string, values ...V) {
+func RegisterFieldValidator[T any, V string | bool | int | float64](fieldName string, values ...V) {
var t T
parentType := reflect.TypeOf(t)
diff --git a/internal/version.go b/internal/version.go
index fef6622..436f832 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -2,4 +2,4 @@
package internal
-const PackageVersion = "2.0.0" // x-release-please-version
+const PackageVersion = "2.1.0" // x-release-please-version
diff --git a/packages/respjson/respjson.go b/packages/respjson/respjson.go
index cc0088c..9e61c5c 100644
--- a/packages/respjson/respjson.go
+++ b/packages/respjson/respjson.go
@@ -5,7 +5,7 @@ package respjson
// Use [Field.Valid] to check if an optional value was null or omitted.
//
// A Field will always occur in the following structure, where it
-// mirrors the original field in it's parent struct:
+// mirrors the original field in its parent struct:
//
// type ExampleObject struct {
// Foo bool `json:"foo"`
diff --git a/shared/shared.go b/shared/shared.go
index 831548c..98859b1 100644
--- a/shared/shared.go
+++ b/shared/shared.go
@@ -196,6 +196,50 @@ func (r *ExtensionAIAutoDescriptionParam) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+// Options for generating responsive image attributes including `src`, `srcSet`,
+// and `sizes` for HTML `
` elements. This schema extends `SrcOptions` to add
+// support for responsive image generation with breakpoints.
+type GetImageAttributesOptionsParam struct {
+ // Custom list of **device-width breakpoints** in pixels. These define common
+ // screen widths for responsive image generation.
+ //
+ // Defaults to `[640, 750, 828, 1080, 1200, 1920, 2048, 3840]`. Sorted
+ // automatically.
+ DeviceBreakpoints []float64 `json:"deviceBreakpoints,omitzero"`
+ // Custom list of **image-specific breakpoints** in pixels. Useful for generating
+ // small variants (e.g., placeholders or thumbnails).
+ //
+ // Merged with `deviceBreakpoints` before calculating `srcSet`. Defaults to
+ // `[16, 32, 48, 64, 96, 128, 256, 384]`. Sorted automatically.
+ ImageBreakpoints []float64 `json:"imageBreakpoints,omitzero"`
+ // The value for the HTML `sizes` attribute (e.g., `"100vw"` or
+ // `"(min-width:768px) 50vw, 100vw"`).
+ //
+ // - If it includes one or more `vw` units, breakpoints smaller than the
+ // corresponding percentage of the smallest device width are excluded.
+ // - If it contains no `vw` units, the full breakpoint list is used.
+ //
+ // Enables a width-based strategy and generates `w` descriptors in `srcSet`.
+ Sizes param.Opt[string] `json:"sizes,omitzero"`
+ // The intended display width of the image in pixels, used **only when the `sizes`
+ // attribute is not provided**.
+ //
+ // Triggers a DPR-based strategy (1x and 2x variants) and generates `x` descriptors
+ // in `srcSet`.
+ //
+ // Ignored if `sizes` is present.
+ Width param.Opt[float64] `json:"width,omitzero"`
+ SrcOptionsParam
+}
+
+func (r GetImageAttributesOptionsParam) MarshalJSON() (data []byte, err error) {
+ type shadow struct {
+ *GetImageAttributesOptionsParam
+ MarshalJSON bool `json:"-"` // Prevent inheriting [json.Marshaler] from the embedded field
+ }
+ return param.MarshalObject(r, shadow{&r, false})
+}
+
type ImageOverlayParam struct {
// Specifies the relative path to the image used as an overlay.
Input string `json:"input,required"`
@@ -216,8 +260,11 @@ type ImageOverlayParam struct {
}
func (r ImageOverlayParam) MarshalJSON() (data []byte, err error) {
- type shadow ImageOverlayParam
- return param.MarshalObject(r, (*shadow)(&r))
+ type shadow struct {
+ *ImageOverlayParam
+ MarshalJSON bool `json:"-"` // Prevent inheriting [json.Marshaler] from the embedded field
+ }
+ return param.MarshalObject(r, shadow{&r, false})
}
func OverlayParamOfText(text string) OverlayUnionParam {
@@ -623,6 +670,32 @@ func (u *OverlayTimingStartUnionParam) asAny() any {
return nil
}
+// Resulting set of attributes suitable for an HTML `
` element. Useful for
+// enabling responsive image loading with `srcSet` and `sizes`.
+//
+// The property Src is required.
+type ResponsiveImageAttributesParam struct {
+ // URL for the _largest_ candidate (assigned to plain `src`).
+ Src string `json:"src,required" format:"uri"`
+ // `sizes` returned (or synthesised as `100vw`). The value for the HTML `sizes`
+ // attribute.
+ Sizes param.Opt[string] `json:"sizes,omitzero"`
+ // Candidate set with `w` or `x` descriptors. Multiple image URLs separated by
+ // commas, each with a descriptor.
+ SrcSet param.Opt[string] `json:"srcSet,omitzero"`
+ // Width as a number (if `width` was provided in the input options).
+ Width param.Opt[float64] `json:"width,omitzero"`
+ paramObj
+}
+
+func (r ResponsiveImageAttributesParam) MarshalJSON() (data []byte, err error) {
+ type shadow ResponsiveImageAttributesParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *ResponsiveImageAttributesParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
type SolidColorOverlayParam struct {
// Specifies the color of the block using an RGB hex code (e.g., `FF0000`), an RGBA
// code (e.g., `FFAABB50`), or a color name (e.g., `red`). If an 8-character value
@@ -640,8 +713,11 @@ type SolidColorOverlayParam struct {
}
func (r SolidColorOverlayParam) MarshalJSON() (data []byte, err error) {
- type shadow SolidColorOverlayParam
- return param.MarshalObject(r, (*shadow)(&r))
+ type shadow struct {
+ *SolidColorOverlayParam
+ MarshalJSON bool `json:"-"` // Prevent inheriting [json.Marshaler] from the embedded field
+ }
+ return param.MarshalObject(r, shadow{&r, false})
}
type SolidColorOverlayTransformationParam struct {
@@ -874,8 +950,11 @@ type SubtitleOverlayParam struct {
}
func (r SubtitleOverlayParam) MarshalJSON() (data []byte, err error) {
- type shadow SubtitleOverlayParam
- return param.MarshalObject(r, (*shadow)(&r))
+ type shadow struct {
+ *SubtitleOverlayParam
+ MarshalJSON bool `json:"-"` // Prevent inheriting [json.Marshaler] from the embedded field
+ }
+ return param.MarshalObject(r, shadow{&r, false})
}
// Subtitle styling options.
@@ -964,8 +1043,11 @@ type TextOverlayParam struct {
}
func (r TextOverlayParam) MarshalJSON() (data []byte, err error) {
- type shadow TextOverlayParam
- return param.MarshalObject(r, (*shadow)(&r))
+ type shadow struct {
+ *TextOverlayParam
+ MarshalJSON bool `json:"-"` // Prevent inheriting [json.Marshaler] from the embedded field
+ }
+ return param.MarshalObject(r, shadow{&r, false})
}
type TextOverlayTransformationParam struct {
@@ -2134,6 +2216,9 @@ type VideoOverlayParam struct {
}
func (r VideoOverlayParam) MarshalJSON() (data []byte, err error) {
- type shadow VideoOverlayParam
- return param.MarshalObject(r, (*shadow)(&r))
+ type shadow struct {
+ *VideoOverlayParam
+ MarshalJSON bool `json:"-"` // Prevent inheriting [json.Marshaler] from the embedded field
+ }
+ return param.MarshalObject(r, shadow{&r, false})
}
diff --git a/usage_test.go b/usage_test.go
index 9e38cfd..6792db9 100644
--- a/usage_test.go
+++ b/usage_test.go
@@ -27,6 +27,7 @@ func TestUsage(t *testing.T) {
option.WithPrivateKey("My Private Key"),
option.WithPassword("My Password"),
)
+ t.Skip("Prism tests are disabled")
response, err := client.Files.Upload(context.TODO(), imagekit.FileUploadParams{
File: io.Reader(bytes.NewBuffer([]byte("https://www.example.com/public-url.jpg"))),
FileName: "file-name.jpg",
diff --git a/webhook.go b/webhook.go
index 6984cf2..192b6ca 100644
--- a/webhook.go
+++ b/webhook.go
@@ -1552,13 +1552,16 @@ func (r *VideoTransformationReadyEventTimings) UnmarshalJSON(data []byte) error
// [UploadPreTransformErrorEvent], [UploadPostTransformSuccessEvent],
// [UploadPostTransformErrorEvent].
//
+// Use the [UnsafeUnwrapWebhookEventUnion.AsAny] method to switch on the variant.
+//
// Use the methods beginning with 'As' to cast the union to one of its variants.
type UnsafeUnwrapWebhookEventUnion struct {
// This field is from variant [VideoTransformationAcceptedEvent],
// [VideoTransformationReadyEvent], [VideoTransformationErrorEvent],
// [UploadPreTransformSuccessEvent], [UploadPreTransformErrorEvent],
// [UploadPostTransformSuccessEvent], [UploadPostTransformErrorEvent].
- ID string `json:"id"`
+ ID string `json:"id"`
+ // Any of nil, nil, nil, nil, nil, nil, nil.
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
// This field is a union of [VideoTransformationAcceptedEventData],
@@ -1890,13 +1893,16 @@ func (r *UnsafeUnwrapWebhookEventUnionRequestTransformation) UnmarshalJSON(data
// [UploadPreTransformErrorEvent], [UploadPostTransformSuccessEvent],
// [UploadPostTransformErrorEvent].
//
+// Use the [UnwrapWebhookEventUnion.AsAny] method to switch on the variant.
+//
// Use the methods beginning with 'As' to cast the union to one of its variants.
type UnwrapWebhookEventUnion struct {
// This field is from variant [VideoTransformationAcceptedEvent],
// [VideoTransformationReadyEvent], [VideoTransformationErrorEvent],
// [UploadPreTransformSuccessEvent], [UploadPreTransformErrorEvent],
// [UploadPostTransformSuccessEvent], [UploadPostTransformErrorEvent].
- ID string `json:"id"`
+ ID string `json:"id"`
+ // Any of nil, nil, nil, nil, nil, nil, nil.
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
// This field is a union of [VideoTransformationAcceptedEventData],