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
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "2.4.0"
".": "2.5.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 48
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-70c42eda2bee929830b2537f758400a58dded1f1ef5686a286e2469c35a041a0.yml
openapi_spec_hash: cdaeed824e91657b45092765cf55eb42
config_hash: e3c2679d25f6235381dfb11962fbf3d9
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-c7f578172392bde58bbb72be2a25b9e917529cd07550358c645ce155debf2418.yml
openapi_spec_hash: f0d797a17b1e8e81707517700cd44b13
config_hash: 94f48fd13b7d41b8b6a203a3a8cee9ed
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## 2.5.0 (2026-04-27)

Full Changelog: [v2.4.0...v2.5.0](https://github.com/imagekit-developer/imagekit-go/compare/v2.4.0...v2.5.0)

### Features

* **api:** manual updates ([791dd8c](https://github.com/imagekit-developer/imagekit-go/commit/791dd8c9fa7b8e9ee247918f6aceffc77ad7f8cf))
* **go:** add default http client with timeout ([f4d5e6b](https://github.com/imagekit-developer/imagekit-go/commit/f4d5e6bc9096d5e51368b2aa8810c22352900643))
* support setting headers via env ([3872a5e](https://github.com/imagekit-developer/imagekit-go/commit/3872a5eb58f1c091b8be08183dd4c972e8a68f75))


### Chores

* configure new SDK language ([0951290](https://github.com/imagekit-developer/imagekit-go/commit/0951290e27f1568894dd90e717fc49612e24bedd))
* **internal:** codegen related update ([14d3582](https://github.com/imagekit-developer/imagekit-go/commit/14d3582a90625f39b54ffb31000db0e35a849027))
* **internal:** codegen related update ([904d9f3](https://github.com/imagekit-developer/imagekit-go/commit/904d9f3ebf4291f4142dcd99db48b832761fba7f))
* **internal:** more robust bootstrap script ([5888120](https://github.com/imagekit-developer/imagekit-go/commit/5888120dc9032b1826cc0b7018f53f34db89666e))


### Documentation

* remove example code for verifying webhook signatures ([799e47c](https://github.com/imagekit-developer/imagekit-go/commit/799e47c306c5f681891804c6e3ca738b0b2c053c))

## 2.4.0 (2026-04-13)

Full Changelog: [v2.3.0...v2.4.0](https://github.com/imagekit-developer/imagekit-go/compare/v2.3.0...v2.4.0)
Expand Down
96 changes: 3 additions & 93 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->

```sh
go get -u 'github.com/imagekit-developer/imagekit-go/v2@v2.4.0'
go get -u 'github.com/imagekit-developer/imagekit-go/v2@v2.5.0'
```

<!-- x-release-please-end -->
Expand Down Expand Up @@ -759,100 +759,10 @@ These authentication parameters can be used in client-side upload forms to secur

The ImageKit SDK provides utilities to verify webhook signatures for secure event handling. This ensures that webhook requests are actually coming from ImageKit and haven't been tampered with.

### Verifying webhook signatures

```go
package main

import (
"fmt"
"io"
"log"
"net/http"
"os"

"github.com/imagekit-developer/imagekit-go/v2"
"github.com/imagekit-developer/imagekit-go/v2/option"
)

func main() {
client := imagekit.NewClient(
option.WithPrivateKey("your_private_key"),
option.WithWebhookSecret("whsec_..."), // Copy from ImageKit dashboard
)

// Webhook handler with proper request body handling
http.HandleFunc("/webhook", func(w http.ResponseWriter, req *http.Request) {
// Limit request body size to prevent abuse (64KB should be sufficient for most webhooks)
const MaxBodyBytes = int64(65536)
req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes)

// Read the raw webhook payload
payload, err := io.ReadAll(req.Body)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}

// Verify and unwrap webhook payload
event, err := client.Webhooks.Unwrap(payload, req.Header)
if err != nil {
fmt.Fprintf(os.Stderr, "Invalid webhook signature or malformed payload: %v\n", err)
w.WriteHeader(http.StatusUnauthorized)
return
}

fmt.Printf("Verified webhook event: %s\n", event.Type)

// Handle different event types with full type safety
switch event.Type {
case "video.transformation.accepted":
videoEvent := event.AsVideoTransformationAcceptedEvent()
fmt.Printf("Video transformation accepted: %s\n", videoEvent.Data.Asset.URL)
// Debugging: Track transformation requests
// handleVideoTransformationAccepted(videoEvent)

case "video.transformation.ready":
videoEvent := event.AsVideoTransformationReadyEvent()
fmt.Printf("Video transformation ready: %s\n", videoEvent.Data.Transformation.Output.URL)
// Update your database/CMS to show the transformed video
// handleVideoTransformationReady(videoEvent)

case "video.transformation.error":
videoEvent := event.AsVideoTransformationErrorEvent()
fmt.Printf("Video transformation error: %s\n", videoEvent.Data.Transformation.Error.Reason)
// Log error and check your origin/URL endpoint settings
// handleVideoTransformationError(videoEvent)

case "upload.pre-transform.success":
uploadEvent := event.AsUploadPreTransformSuccessEvent()
fmt.Printf("Pre-transform success: %s\n", uploadEvent.Data.FileID)
// File uploaded and pre-transformation completed
// handleUploadPreTransformSuccess(uploadEvent)

case "upload.post-transform.success":
postEvent := event.AsUploadPostTransformSuccessEvent()
fmt.Printf("Post-transform success: %s\n", postEvent.Data.Name)
// Additional transformation completed
// handleUploadPostTransformSuccess(postEvent)

// Handle other event types as needed
default:
fmt.Printf("Unhandled event type: %s\n", event.Type)
}

w.WriteHeader(http.StatusOK)
})

// Start the server
fmt.Println("Webhook server listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
```

For detailed information about webhook setup, signature verification, and handling different webhook events, refer to the [ImageKit webhook documentation](https://imagekit.io/docs/webhooks#verify-webhook-signature).

## Advanced Usage

### Errors

When the API returns a non-success status code, we return an error with type
Expand Down
11 changes: 10 additions & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"os"
"slices"
"strings"

"github.com/imagekit-developer/imagekit-go/v2/internal/requestconfig"
"github.com/imagekit-developer/imagekit-go/v2/lib"
Expand Down Expand Up @@ -35,7 +36,7 @@ type Client struct {
// OPTIONAL_IMAGEKIT_IGNORES_THIS, IMAGEKIT_WEBHOOK_SECRET, IMAGE_KIT_BASE_URL).
// This should be used to initialize new clients.
func DefaultClientOptions() []option.RequestOption {
defaults := []option.RequestOption{option.WithEnvironmentProduction()}
defaults := []option.RequestOption{option.WithHTTPClient(defaultHTTPClient()), option.WithEnvironmentProduction()}
if o, ok := os.LookupEnv("IMAGE_KIT_BASE_URL"); ok {
defaults = append(defaults, option.WithBaseURL(o))
}
Expand All @@ -49,6 +50,14 @@ func DefaultClientOptions() []option.RequestOption {
if o, ok := os.LookupEnv("IMAGEKIT_WEBHOOK_SECRET"); ok {
defaults = append(defaults, option.WithWebhookSecret(o))
}
if o, ok := os.LookupEnv("IMAGE_KIT_CUSTOM_HEADERS"); ok {
for _, line := range strings.Split(o, "\n") {
colon := strings.Index(line, ":")
if colon >= 0 {
defaults = append(defaults, option.WithHeader(strings.TrimSpace(line[:colon]), strings.TrimSpace(line[colon+1:])))
}
}
}
return defaults
}

Expand Down
24 changes: 24 additions & 0 deletions default_http_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

package imagekit

import (
"net/http"
"time"
)

// defaultResponseHeaderTimeout bounds the time between a fully written request
// and the server's response headers. It does not apply to the response body,
// so long-running streams are unaffected. Without this, a server that accepts
// the connection but never responds would hang the request indefinitely.
const defaultResponseHeaderTimeout = 10 * time.Minute

// defaultHTTPClient returns an [*http.Client] used when the caller does not
// supply one via [option.WithHTTPClient]. It clones [http.DefaultTransport]
// and adds a [http.Transport.ResponseHeaderTimeout] so stuck connections
// fail fast instead of compounding across retries.
func defaultHTTPClient() *http.Client {
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.ResponseHeaderTimeout = defaultResponseHeaderTimeout
return &http.Client{Transport: transport}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/imagekit-developer/imagekit-go/v2
go 1.22

require (
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260309172517-425968d811b9
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260427160145-3afa6683f8b2
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260309172517-425968d811b9 h1:3Bb7YLURYzIPwqxoBpfhHaA/wu7zUNaHa2W6DJ1zD6s=
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260309172517-425968d811b9/go.mod h1:L1MQhA6x4dn9r007T033lsaZMv9EmBAdXyU/+EF40fo=
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260427160145-3afa6683f8b2 h1:q/QNlQMqBFYT7z9zt8vjbh0XvbcTXhN4Q+gi7aEBvkY=
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260427160145-3afa6683f8b2/go.mod h1:L1MQhA6x4dn9r007T033lsaZMv9EmBAdXyU/+EF40fo=
github.com/tidwall/gjson v1.14.2/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=
Expand Down
2 changes: 1 addition & 1 deletion internal/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

package internal

const PackageVersion = "2.4.0" // x-release-please-version
const PackageVersion = "2.5.0" // x-release-please-version
2 changes: 1 addition & 1 deletion scripts/bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -e

cd "$(dirname "$0")/.."

if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then
if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then
brew bundle check >/dev/null 2>&1 || {
echo -n "==> Install Homebrew dependencies? (y/N): "
read -r response
Expand Down
Loading