diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b44b287..4dedeae 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.4.0" + ".": "2.5.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index f9ac8b4..655bd5f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ab64eb..b2b9cca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/README.md b/README.md index a136d08..5c4165c 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@v2.4.0' +go get -u 'github.com/imagekit-developer/imagekit-go/v2@v2.5.0' ``` @@ -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 diff --git a/client.go b/client.go index 9d76257..b768a40 100644 --- a/client.go +++ b/client.go @@ -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" @@ -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)) } @@ -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 } diff --git a/default_http_client.go b/default_http_client.go new file mode 100644 index 0000000..b0a3e6c --- /dev/null +++ b/default_http_client.go @@ -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} +} diff --git a/go.mod b/go.mod index 12b1fb0..aa2f58e 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/go.sum b/go.sum index ff28d75..4fda201 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/internal/version.go b/internal/version.go index eaba12d..0d6e599 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "2.4.0" // x-release-please-version +const PackageVersion = "2.5.0" // x-release-please-version diff --git a/scripts/bootstrap b/scripts/bootstrap index 5ab3066..46547f1 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -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